Subversion Repositories web.active

Rev

Rev 23 | Blame | Compare with Previous | Last modification | View Log | Download

<?php namespace ProcessWire;

/**
 * ProcessWire Image Fieldtype
 *
 * Field that stores one or more image files. 
 *
 * For documentation about the fields used in this class, please see:  
 * /wire/core/Fieldtype.php
 * /wire/core/FieldtypeMulti.php
 * 
 * ProcessWire 3.x, Copyright 2023 by Ryan Cramer
 * https://processwire.com
 *
 *
 */

class FieldtypeImage extends FieldtypeFile implements FieldtypeHasFiles, FieldtypeHasPageimages {
  
  /**
   * File schema is configured to store dimensions for image files 'width', 'height', 'ratio' (flag)
   *
   */
  const fileSchemaDimensions = 256;

  /**
   * Get module info
   * 
   * @return array
   * 
   */
  public static function getModuleInfo() {
    return array(
      'title' => 'Images',
      'version' => 102,
      'summary' => 'Field that stores one or more GIF, JPG, or PNG images',
      'permanent' => true, 
    );
  }

  /**
   * Get blank value
   * 
   * @param Page $page
   * @param Field $field
   * @return Pageimages|Pagefiles
   * 
   */
  public function getBlankValue(Page $page, Field $field) {
    /** @var Pageimages $pageimages */
    $pageimages = $this->wire(new Pageimages($page));
    $pageimages->setField($field);
    $pageimages->setTrackChanges(true); 
    return $pageimages; 
  }

  /**
   * @param Pagefiles $pagefiles
   * @param string $filename
   * @return Pageimage|Pagefile
   * 
   */
  protected function getBlankPagefile(Pagefiles $pagefiles, $filename) {
    return $this->wire(new Pageimage($pagefiles, $filename)); 
  }

  /**
   * Get default file extensions 
   * @return string
   * 
   */
  protected function getDefaultFileExtensions() {
    return "gif jpg jpeg png";
  }
  
  /**
   * Check and update database schema according to current version and features
   *
   * @param Field $field
   * @param array $schema Updated directly
   * @param int $fileSchema The fileSchema version flags integer
   * @return int Updated fileSchema flags integer
   * @since 3.0.154
   *
   */
  protected function updateDatabaseSchema(Field $field, array &$schema, $fileSchema) {
    
    $fileSchema = parent::updateDatabaseSchema($field, $schema, $fileSchema); 

    $hasDimensions = $fileSchema & self::fileSchemaDimensions;
    
    $schema['width'] = 'int';
    $schema['height'] = 'int';
    $schema['ratio'] = 'decimal(4,2)';
    
    $schema['keys']['width'] = 'index (width)';
    $schema['keys']['height'] = 'index (height)';
    $schema['keys']['ratio'] = 'index (ratio)';
    
    if(!$hasDimensions) {
      $numErrors = 0;
      if($this->wire()->database->tableExists($field->getTable())) {
        $columns = array('width', 'height', 'ratio');
        foreach($columns as $column) {
          if(!$this->addColumn($field, $column, $schema)) $numErrors++;
          if($numErrors) break;
        }
      } else {
        // new field being created that is getting initial schema to create table
      }
      if(!$numErrors) {
        $fileSchema = $fileSchema | self::fileSchemaDimensions;
      }
    }
    
    return $fileSchema;
  }
  
  /**
   * Convert individual Pagefile to array for storage in DB
   *
   * @param Page $page
   * @param Field $field
   * @param Pagefile|Pageimage $pagefile
   * @return array
   *
   */
  protected function sleepFile(Page $page, Field $field, Pagefile $pagefile) {
    
    $item = parent::sleepFile($page, $field, $pagefile); 

    $fileSchema = (int) $field->get('fileSchema');

    if($fileSchema & self::fileSchemaDimensions) {
      $info = $pagefile->getImageInfo(true);
      
      if(strpos($info['width'], '%')) $info['width'] = (-1 * (int) rtrim($info['width'], '%'));
      if(strpos($info['height'], '%')) $info['height'] = (-1 * (int) rtrim($info['height'], '%'));
      
      $item['width'] = (int) $info['width'];
      $item['height'] = (int) $info['height'];
      $item['ratio'] = number_format($pagefile->ratio, 2, '.', '');
    }
    
    return $item;
  }


  /**
   * Wakeup individual file converting array of data to Pagefile and adding it to Pagefiles
   *
   * @param Page $page
   * @param Field $field
   * @param Pagefiles $pagefiles
   * @param array $a Data from DB
   * @return Pagefile
   *
   */
  protected function wakeupFile(Page $page, Field $field, Pagefiles $pagefiles, array $a) {
  
    /** @var Pageimage $pagefile */
    $pagefile = parent::wakeupFile($page, $field, $pagefiles, $a); 
    $info = false;
    
    if(!empty($a['width'])) {
      // dimension info already present in DB: populate to Pageimage object
      $info = array('width' => (int) $a['width'], 'height' => (int) $a['height']);
    } else if(self::autoUpdateOnWakeup && (((int) $field->get('fileSchema')) & self::fileSchemaDimensions) && $pagefile->width()) {
      // dimension info not yet in DB: detect and populate in DB
      list($width, $height, $ratio) = array($pagefile->width(), $pagefile->height(), $pagefile->ratio);
      if(strpos($width, '%')) $width = (-1 * (int) rtrim($width, '%'));
      if(strpos($height, '%')) $height = (-1 * (int) rtrim($height, '%'));
      $info = array('width' => $width, 'height' => $height, 'ratio' => $ratio);
      $this->saveFileCols($page, $field, $pagefile, $info);
    }
    
    if($info) {
      unset($info['ratio']); // ratio not stored in runtime image info
      $pagefile->setImageInfo($info);
    }

    return $pagefile;
  }

  /**
   * Export a Pageimages value to a portable PHP array
   * 
   * @param Page $page
   * @param Field $field
   * @param array|float|int|null|object|string $value
   * @param array $options
   * @return array
   * 
   */
  public function ___exportValue(Page $page, Field $field, $value, array $options = array()) {
    /** @var Pageimages $pagefiles */
    $pagefiles = $value; 
    $value = parent::___exportValue($page, $field, $value, $options); 
    if(empty($options['system'])) {
      foreach($value as $k => $v) {
        $img = $pagefiles->get($v['name']);
        $value[$k]['width'] = $img->width();
        $value[$k]['height'] = $img->height();
      }
    }
    
    if(!empty($options['FieldtypeImage'])) {
      $o = $options['FieldtypeImage']; 
      if(!empty($o['variations'])) {
        // include URLs to image variations
        foreach($value as $k => $v) {
          if(empty($options['system'])) {
            $img = $pagefiles->get($v['name']);
          } else {
            $img = $pagefiles->get($k); 
          }
          $variations = array();
          foreach($img->getVariations() as $variation) {
            /** @var Pageimage $variation */
            $variations[$variation->name] = $variation->httpUrl();
          }
          $value[$k]['variations'] = $variations;
          
        }
      }
    }
    
    return $value;  
  }
  
  /**
   * Get array of full path/file for all files managed by given page and field (also includes image variations)
   *
   * #pw-internal For FieldtypeHasFiles interface
   *
   * @param Page $page
   * @param Field $field
   * @return array
   * @since 3.0.181
   *
   */
  public function getFiles(Page $page, Field $field) {
    
    $value = $page->get($field->name);
    $files = array();
    
    if($value instanceof Pageimage) {
      $value = array($value);
    } else if(!$value instanceof Pageimages) {
      return array();
    }
    
    foreach($value as $pageimage) {
      /** @var Pageimage $pageimage */
      $file = $pageimage->filename();
      $path = dirname($file) . '/';
      $files[] = $file;
      $variations = $pageimage->getVariations(array('info' => true, 'verbose' => false));
      foreach($variations as $basename) {
        $files[] = $path . $basename;
      }
    }
    
    return $files;
  }

  /**
   * Get Pageimages
   *
   * @param Page $page
   * @param Field $field
   * @return Pageimages
   *
   */
  public function getPageimages(Page $page, Field $field) {
    /** @var Pageimages|Pageimage|null $value */
    $value = $page->get($field->name);
    if($value instanceof Pageimages) return $value;
    $pageimages = $this->getBlankValue($page, $field);
    if($value instanceof Pageimage) $pageimages->add($value);
    return $pageimages;
  }

  /**
   * Get setup options and setup functions for new fields
   *
   * @return array
   * @since 3.0.213
   *
   */
  public function ___getFieldSetups() {
    $setups = parent::___getFieldSetups();
    $setups['single']['title'] = $this->_('Single image');
    $setups['multiple']['title'] = $this->_('Multiple images');
    return $setups;
  }
  
  /**
   * Get Inputfields to configure fields using this Fieldtype
   *
   * @param Field $field
   * @return InputfieldWrapper
   *
   */
  public function ___getConfigInputfields(Field $field) {
    $inputfields = parent::___getConfigInputfields($field);
    return $inputfields;
  }

  /**
   * Get Inputfields to advanced configure fields using this Fieldtype
   * 
   * @param Field $field
   * @return InputfieldWrapper
   * 
   */
  public function ___getConfigAdvancedInputfields(Field $field) {
    $inputfields = parent::___getConfigAdvancedInputfields($field);
    return $inputfields; 
  }

  /*
  public function getInputfield(Page $page, Field $field) {

    // even though we don't want this input field, call it anyway
    parent::getInputfield($page, $field); 

    $inputfield = $this->modules->get("InputfieldImage"); 
    $inputfield->class = $this->className();

    $this->setupHooks($page, $field, $inputfield);

    return $inputfield;
  }
  */


}