You are here

recipe_plaintext.module in Recipe 6

File

plugins/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) {
  $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($text) {

  // region constants
  define('TITLE', 0);
  define('INGREDIENTS', 1);
  define('DIRECTIONS', 2);
  $recipe = array();

  // init ingredients here
  $recipe['ingredients'] = array();
  $region = TITLE;
  foreach (split("\n", $text) 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'] = $matches[1];
        $i['unit_name'] = $matches[2];
        $i['ingredient_name'] = $matches[3];

        // FALSE if no-match
        $i['unit_obj'] = recipe_unit_fuzzymatch($i['unit_name']);
        if ($i['unit_obj'] == FALSE) {
          $i['unit_name'] = 'Unit';
          $i['unit_obj'] = recipe_unit_fuzzymatch($i['unit_name']);
          drupal_set_message(t('Could not find the ingredient units in "%s"', array(
            '%s' => $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'] = $matches[1];
        $i['unit_name'] = 'Unit';
        $i['ingredient_name'] = $matches[2];

        // FALSE if no-match
        $i['unit_obj'] = recipe_unit_fuzzymatch($i['unit_name']);

        // 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_obj'] = 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
  $rs = db_query("SELECT n.nid from {node} n WHERE n.type='recipe' and n.status>0 ORDER BY n.title");
  $o = '';
  while ($row = db_fetch_object($rs)) {
    $o .= recipe_plaintext_export($row->nid);
    $o .= "\n====\n";
  }
  drupal_set_header('Content-type: text');
  return $o;
}
function recipe_plaintext_export($nid = NULL) {
  if ($nid === NULL) {
    drupal_set_message(t('Recipe not found.'));
    drupal_not_found();
  }
  $node = node_load(array(
    'nid' => $nid,
    'type' => 'recipe',
  ));

  // you should not be able to export unpublished recipes
  if ($node->status == 0) {
    drupal_access_denied();
    return;
  }
  $output = $node->title . "\n\n";
  $output .= t('Ingredients:') . "\n";
  $output .= format_plaintext_ingredients($node) . "\n";
  $output .= t('Instructions:') . "\n";
  $node->instructions = wordwrap(strip_html_and_encode_entities($node->instructions), 75, "\n");
  $output .= $node->instructions . "\n\n";
  $output .= t('Description:') . "\n";
  $node->body = strip_html_and_encode_entities($node->body);
  $output .= $node->body . "\n\n";
  $output .= t('Notes:') . "\n";
  $node->notes = strip_html_and_encode_entities($node->notes);
  $output .= $node->notes . "\n";
  drupal_set_header('Content-type: text');
  return $output;
}
function format_plaintext_ingredients($node = NULL) {
  $col_widths = array(
    'quantity' => 0,
    'unit' => 0,
  );
  foreach (array_keys($node->ingredients) as $key) {

    // Translate decimal quantity to text fraction.
    $node->ingredients[$key]['str_quantity'] = recipe_ingredient_quantity_from_decimal($node->ingredients[$key]['quantity'], TRUE);

    // Strip html entities.
    $node->ingredients[$key]['str_quantity'] = str_replace('&frasl;', '/', $node->ingredients[$key]['str_quantity']);

    // Collect column widths.
    if (strlen($node->ingredients[$key]['str_quantity']) > $col_widths['quantity']) {
      $col_widths['quantity'] = strlen($node->ingredients[$key]['str_quantity']);
    }
    $node->ingredients[$key]['str_ingredient'] = strlen($node->ingredients[$key]['note']) > 0 ? $node->ingredients[$key]['name'] . ' (' . $node->ingredients[$key]['note'] . ')' : $node->ingredients[$key]['name'];

    // Display units or abbreviation.
    // Print the abbreviation if recipe_unit_display says too or the abbreviation is blank (ie = Unit, which we don't print).
    if (variable_get('recipe_unit_display', 0) == 0 || $node->ingredients[$key]['abbreviation'] == '&nbsp;') {
      $node->ingredients[$key]['str_unit'] = $node->ingredients[$key]['abbreviation'];
    }
    else {
      $node->ingredients[$key]['str_unit'] = recipe_unit_name($node->ingredients[$key]['unit_id']);
    }
    if (strlen($node->ingredients[$key]['str_unit']) > $col_widths['unit']) {
      $col_widths['unit'] = strlen($node->ingredients[$key]['str_unit']);
    }
  }
  $wrap_pad = str_repeat(" ", $col_widths['unit'] + $col_widths['quantity'] + 2);

  // Render output with the correct column padding.
  $output = '';
  foreach ($node->ingredients as $key => $i) {
    $output .= wordwrap(sprintf("%" . $col_widths['quantity'] . "s %-" . $col_widths['unit'] . "s %s\n", $i['str_quantity'], $i['str_unit'], $i['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