You are here

recipe_plaintext.module in Recipe 7

File

includes/recipe_plaintext.module
View source
<?php

/**
 * @file
 * recipe_plaintext.module - Support for the plaintext format input and output.
 */
$recipe_plaintext_example = '
Recipe Title
<--blank line-->
3 lb salt
4 T pepper
5-1/2 t oregano
<--blank line-->
Free-form instuctions.
Step 1.
Step 2.  Step3.
Whatever
';

/**
 * Implementation of hook_recipeio($type).
 */
function recipe_plaintext_recipeio($type) {
  global $recipe_plaintext_example;
  $supported = array(
    'import_single' => array(
      'format_name' => t('Plain Text'),
      'callback' => 'recipe_plaintext_import',
      'format_help' => '',
      'format_example' => "{$recipe_plaintext_example}",
    ),
    'export_single' => array(
      'format_name' => t('Plain Text'),
      'callback' => 'recipe_plaintext_export',
      'format_help' => t('Export to a plaintext format.'),
    ),
    'export_multi' => array(
      'format_name' => t('Plain Text'),
      'callback' => 'recipe_plaintext_export_multi',
      'format_help' => t('Export all recipes to a plaintext format.'),
    ),
  );
  if (isset($supported[$type])) {
    return array(
      'plaintext' => $supported[$type],
    );
  }
  else {
    return FALSE;
  }
}

/**
 * Parsing instance for plain text recipes
 */
function recipe_plaintext_import($recipe_txt = NULL) {

  // region constants
  define('TITLE', 0);
  define('INGREDIENTS', 1);
  define('DIRECTIONS', 2);
  $recipe = array(
    'title' => '',
    'yield' => '1',
    'yield_unit' => 'Servings',
    'preptime' => 0,
    'cooktime' => 0,
    'categories' => array(),
    'ingredients' => array(),
    'instructions' => '',
    'notes' => '',
    'source' => '',
  );
  $region = TITLE;
  $recipe_lines = explode("\n", $recipe_txt);
  foreach ($recipe_lines as $line) {
    $line = trim($line);
    if ($region < DIRECTIONS && $line == '') {
      $region++;
      continue;
    }
    if ($region == TITLE) {
      $recipe['title'] = $line;
    }
    elseif ($region == INGREDIENTS) {

      // Replace a decimal quantity with a fractional one.  Needs to be done before ' ' to '-' below.
      $line = preg_replace_callback('/^(\\d+\\.\\d+)/', 'decimal_to_fraction_callback', $line);

      // Replace a space separated fraction with a '-' to normalize the input string.
      $line = preg_replace('/^(\\d+)[ \\-](\\d+)[\\/](\\d+)/', '${1}-${2}/${3}', $line);

      // 1 cup flour
      if (preg_match('/^([0-9\\-\\.\\/]+) +([A-Za-z\\.]+) +(.*)/', $line, $matches)) {
        $i = array();
        $i['quantity'] = recipe_ingredient_quantity_from_fraction($matches[1]);
        $i['unit_name'] = $matches[2];
        $i['ingredient_name'] = $matches[3];
        $i['ingredient_note'] = '';
        $i['unit_key'] = recipe_unit_fuzzymatch($i['unit_name']);
        if ($i['unit_key'] == FALSE) {
          $i['ingredient_note'] = $i['unit_name'] . '! ' . $i['ingredient_note'];
          $i['unit_key'] = 'unit';
          drupal_set_message(t('Could not find the ingredient units in :recipe (:line)', array(
            ':recipe' => $recipe['title'],
            ':line' => $line,
          )), 'warning');
        }

        // FALSE if no-match
        $i['ingred_obj'] = recipe_ingredient_match($i['ingredient_name']);
        $recipe['ingredients'][] = $i;
      }
      elseif (preg_match('/^([0-9\\-\\.\\/]+) +(.*)/', $line, $matches)) {
        $i = array();
        $i['quantity'] = recipe_ingredient_quantity_from_fraction($matches[1]);
        $i['unit_name'] = 'Unit';
        $i['ingredient_name'] = $matches[2];
        $i['ingredient_note'] = '';
        $i['unit_key'] = recipe_unit_fuzzymatch($i['unit_name']);
        if ($i['unit_key'] == FALSE) {
          $i['ingredient_note'] = $i['unit_name'] . '! ' . $i['ingredient_note'];
          $i['unit_key'] = 'unit';
          drupal_set_message(t('Could not find the ingredient units in :recipe (:line)', array(
            ':recipe' => $recipe['title'],
            ':line' => $line,
          )), 'warning');
        }

        // FALSE if no-match
        $i['ingred_obj'] = recipe_ingredient_match($i['ingredient_name']);
        $recipe['ingredients'][] = $i;
      }
      else {
        $i = array();
        $i['quantity'] = 0;
        $i['unit_name'] = 'Unit';
        $i['ingredient_name'] = "failed: " . $line;
        $i['unit_key'] = FALSE;
        $i['ingred_obj'] = FALSE;
        $recipe['ingredients'][] = $i;
      }
    }
    elseif ($region == DIRECTIONS) {
      $recipe['instructions'] .= $line . "\n";
    }
  }
  return $recipe;
}
function recipe_plaintext_export_multi() {

  // you should not be able to export unpublished recipes
  $result = db_query("SELECT n.nid from {node} n WHERE n.type='recipe' and n.status>0 ORDER BY n.title");
  $o = '';
  foreach ($result as $record) {
    $o .= recipe_plaintext_export($record->nid);
    $o .= "\n====\n";
  }
  drupal_add_http_header('Content-type', 'text/plain; charset=utf-8');
  print $o;
}
function recipe_plaintext_export($nid = NULL, $yield = NULL) {
  if ($nid === NULL) {
    drupal_set_message(t('Recipe not found.'));
    drupal_not_found();
    return;
  }
  $node = node_load($nid);

  // you should not be able to export unpublished recipes
  if ($node->status == 0) {
    drupal_access_denied();
    return;
  }

  // Set the custom yield so we can scale up/down the recipe quantities.
  $node->recipe_custom_yield = $yield;
  $output = $node->title . "\n\n";
  $output .= t('Ingredients:') . "\n";
  $output .= format_plaintext_ingredients($node) . "\n";
  $output .= t('Instructions:') . "\n";
  $output .= wordwrap(strip_html_and_encode_entities($node->recipe_instructions), 75, "\n") . "\n\n";
  $output .= t('Description:') . "\n";
  $output .= strip_html_and_encode_entities($node->recipe_description) . "\n\n";
  $output .= t('Notes:') . "\n";
  $output .= strip_html_and_encode_entities($node->recipe_notes) . "\n";
  drupal_add_http_header('Content-type', 'text/plain; charset=utf-8');
  return $output;
}
function format_plaintext_ingredients($node = NULL) {
  $col_widths = array(
    'quantity' => 0,
    'unit' => 0,
  );

  //prepare ingredients factor
  $factor = 1;
  if (isset($node->recipe_custom_yield)) {
    $factor = $node->recipe_custom_yield / $node->recipe_yield;
    $node->recipe_yield = $node->recipe_custom_yield;
  }
  $unit_list = recipe_get_units();
  foreach ($node->recipe_ingredients['ing'] as $key => &$i) {

    // Translate decimal quantity to text fraction.
    if ($i['quantity'] > 0) {
      $i['quantity'] *= $factor;
    }
    else {
      $i['quantity'] = ' ';
    }
    $i['str_quantity'] = recipe_ingredient_quantity_from_decimal($i['quantity'], TRUE);

    // Strip html entities.
    $i['str_quantity'] = str_replace('&frasl;', '/', $i['str_quantity']);

    // Collect column widths.
    if (strlen($i['str_quantity']) > $col_widths['quantity']) {
      $col_widths['quantity'] = strlen($i['str_quantity']);
    }
    $i['str_ingredient'] = strlen($i['note']) > 0 ? $i['name'] . ' (' . $i['note'] . ')' : $i['name'];
    if (isset($unit_list[$i['unit_key']])) {

      // Print the singular or plural term depending on the quantity.
      $title = $i['quantity'] > 1 ? $unit_list[$i['unit_key']]['plural'] : $unit_list[$i['unit_key']]['name'];
    }
    else {
      $title = $i['unit_key'];
    }

    // Print the abbreviation if recipe_unit_display says to or the abbreviation is blank (ie = Unit, which we don't print).
    if (!isset($i['abbreviation']) && isset($unit_list[$i['unit_key']])) {
      $i['abbreviation'] = $unit_list[$i['unit_key']]['abbreviation'];
    }
    if (empty($i['abbreviation'])) {
      $i['abbreviation'] = ' ';
    }
    $i['str_unit'] = '';
    if (variable_get('recipe_unit_display', 0) == 0 || $i['abbreviation'] == ' ') {
      $i['str_unit'] = $i['abbreviation'];
    }
    else {
      $i['str_unit'] = $title;
    }
    if (strlen($i['str_unit']) > $col_widths['unit']) {
      $col_widths['unit'] = strlen($i['str_unit']);
    }
  }

  // Render output with the correct column padding.
  $output = '';
  $wrap_pad = str_repeat(" ", $col_widths['unit'] + $col_widths['quantity'] + 2);
  foreach ($node->recipe_ingredients['ing'] as $key => $j) {
    $output .= wordwrap(sprintf("%" . $col_widths['quantity'] . "s %-" . $col_widths['unit'] . "s %s\n", $j['str_quantity'], $j['str_unit'], $j['str_ingredient']), 75, "\n{$wrap_pad}");
  }
  return $output;
}
function decimal_to_fraction_callback($matches) {
  $fraction_str = recipe_ingredient_quantity_from_decimal($matches[1], TRUE);

  // Don't want the frasl hassle.
  $fraction_str = preg_replace('/\\&frasl;/', '/', $fraction_str);
  return $fraction_str;
}

Functions