Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

initial plugin commit

  • Loading branch information...
commit 38491d919ea3269a599368d54cb2d90b6074f2ea 0 parents
@bshaffer authored
7 LICENSE
@@ -0,0 +1,7 @@
+Copyright (c) 2004-2006 Fabien Potencier
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
5 README
@@ -0,0 +1,5 @@
+= sfImageCache plugin =
+
+The `sfImageCachePlugin` is under development. It also requires that you install the sfThumbnailPlugin
+
+
4 config/app.yml
@@ -0,0 +1,4 @@
+all:
+ imagecache:
+ service_class: sfImageCacheService
+ web_path: /sfImageCachePlugin/cached_images
111 config/sfImageCachePluginConfiguration.class.php
@@ -0,0 +1,111 @@
+<?php
+
+/**
+*
+*/
+class sfImageCachePluginConfiguration extends sfPluginConfiguration
+{
+ protected $_imageCacheService;
+
+ public function initialize()
+ {
+ $this->dispatcher->connect('context.load_factories', array($this, 'listenToContextLoadFactories'));
+ $this->dispatcher->connect('command.post_command', array($this, 'observeCommandPostCommand'));
+ $this->dispatcher->connect('request.filter_parameters', array($this, 'filterRequestParametersEvent'));
+ }
+
+ /**
+ * Returns the image cache service, which acts like a singleton
+ * within the current configuration instance.
+ *
+ * @return ioImageCacheService
+ */
+ public function getImageCacheService()
+ {
+ return $this->_imageCacheService;
+ }
+
+ /**
+ * Automatic plugin modules and helper loading
+ *
+ * @param sfEvent $event
+ */
+ public function listenToContextLoadFactories(sfEvent $event)
+ {
+ // create the image cache service
+ $this->_imageCacheService = $this->_createImageCacheService();
+
+ // create symlinks if necessary
+ if (!is_writable($this->getImageCacheService()->getImageCacheWebDir()))
+ {
+ $this->createSymlinks();
+ }
+ }
+
+ /**
+ * Creates the image cache service class.
+ *
+ * @param sfUser $user
+ * @return ioImageCacheService
+ */
+ protected function _createImageCacheService()
+ {
+ $class = sfConfig::get('app_imagecache_service_class', 'sfImageCacheService');
+
+ return new $class($this->dispatcher);
+ }
+
+ /**
+ * observe the command post_command event
+ *
+ * Add a symlink to the cache directory where your images are cached
+ * set app_imagecache_cache_dir to false to disable this
+ */
+ public function observeCommandPostCommand(sfEvent $event)
+ {
+ $task = $event->getSubject();
+
+ if ($task->getName() == 'publish-assets')
+ {
+ $this->createSymlinks($task->getFilesystem());
+ }
+ }
+
+ public function createSymlinks($filesystem = null)
+ {
+ if (!$filesystem)
+ {
+ $filesystem = new sfFilesystem($this->dispatcher);
+ }
+
+ if (!$this->_imageCacheService)
+ {
+ $this->_imageCacheService = $this->_createImageCacheService();
+ }
+
+ umask(0000);
+
+ $cachePath = $this->getImageCacheService()->getCacheSymlinkDir();
+ $webPath = $this->getImageCacheService()->getWebSymlinkDir();
+ $filesystem->mkdirs($cachePath.DIRECTORY_SEPARATOR.'cached_images', 0777);
+ $filesystem->relativeSymlink($cachePath, $webPath);
+ }
+
+ /**
+ * listen to the request filter_parameters event
+ * Add "Web Root" to settings if it doesn't exist
+ */
+ public function filterRequestParametersEvent(sfEvent $event, $parameters)
+ {
+ if (!sfConfig::get('sf_web_root'))
+ {
+ $context = $event->getParameters();
+
+ // Set the root URL of the website in sfConfig
+ $root = 'http'.(isset($context['is_secure']) && $context['is_secure'] ? 's' : '').'://'.$context['host'];
+ sfConfig::set('sf_web_root', $root);
+ }
+
+ return $parameters;
+ }
+}
9 lib/cache/sfImageCache.class.php
@@ -0,0 +1,9 @@
+<?php
+
+/**
+*
+*/
+class sfImageCache extends sfFileCache
+{
+
+}
66 lib/helper/ImageCacheHelper.php
@@ -0,0 +1,66 @@
+<?php
+
+function imagecache_path($source, $cacheName, $absolute = false)
+{
+ $file = basename($source);
+ $sourcePath = canonicalize_path(sprintf('%s/%s', sfConfig::get('sf_web_dir'), image_path($source)));
+ $cachePath = sprintf('%s/%s-%s', get_imagecache_service()->getImageCacheWebDir(), $cacheName, $file);
+ $webPath = sprintf('%s/%s', sfConfig::get('app_imagecache_web_path'), basename($cachePath));
+
+ if (!is_readable($cachePath) && is_writable(dirname($cachePath)) && is_readable($sourcePath))
+ {
+ $dimensions = array_merge(array('width' => '', 'height' => ''), sfConfig::get('app_imagecache_'.$cacheName));
+ get_imagecache_service()->createCachedImage($sourcePath, $cachePath, $dimensions['width'], $dimensions['height']);
+
+ return image_path($webPath, $absolute);
+ }
+
+ return image_path($source, $absolute);
+}
+
+function imagecache_tag($source, $cacheName, $options = array())
+{
+ $path = imagecache_path($source, $cacheName);
+ $dimensions = sfConfig::get('app_imagecache_'.$cacheName, array());
+
+ return image_tag($path, array_merge($options, $dimensions));
+}
+
+function get_imagecache_service()
+{
+ return sfApplicationConfiguration::getActive()
+ ->getPluginConfiguration('sfImageCachePlugin')
+ ->getImageCacheService();
+}
+
+function canonicalize_path($path)
+{
+ if (empty($path))
+ {
+ return '';
+ }
+
+ $out = array();
+ foreach (explode(DIRECTORY_SEPARATOR, $path) as $i => $fold)
+ {
+ if ('' == $fold || '.' == $fold)
+ {
+ continue;
+ }
+
+ if ('..' == $fold && $i > 0 && '..' != end($out))
+ {
+ array_pop($out);
+ }
+ else
+ {
+ $out[] = $fold;
+ }
+ }
+
+ $result = DIRECTORY_SEPARATOR == $path[0] ? DIRECTORY_SEPARATOR : '';
+ $result .= implode(DIRECTORY_SEPARATOR, $out);
+ $result .= DIRECTORY_SEPARATOR == $path[strlen($path) - 1] ? DIRECTORY_SEPARATOR : '';
+
+ return $result;
+}
97 lib/image/sfGDAdapterCrop.class.php
@@ -0,0 +1,97 @@
+<?php
+
+/**
+* Class to allow for cropping of images to fill entire space of maxWidth and maxHeight
+*/
+class sfGDAdapterCrop extends sfGDAdapter
+{
+ public function loadData($thumbnail, $image, $mime)
+ {
+ if (in_array($mime,$this->imgTypes))
+ {
+ $this->source = imagecreatefromstring($image);
+ $this->sourceWidth = imagesx($this->source);
+ $this->sourceHeight = imagesy($this->source);
+ $this->sourceMime = $mime;
+
+ $this->calculateProportions();
+ $this->doCreateImage();
+
+ return true;
+ }
+ else
+ {
+ throw new Exception(sprintf('Image MIME type %s not supported', $mime));
+ }
+ }
+
+ public function loadFile($thumbnail, $image)
+ {
+ $imgData = @GetImageSize($image);
+
+ if (!$imgData)
+ {
+ throw new Exception(sprintf('Could not load image %s', $image));
+ }
+
+ if (in_array($imgData['mime'], $this->imgTypes))
+ {
+ $loader = $this->imgLoaders[$imgData['mime']];
+ if(!function_exists($loader))
+ {
+ throw new Exception(sprintf('Function %s not available. Please enable the GD extension.', $loader));
+ }
+
+ $this->source = $loader($image);
+ $this->sourceWidth = $imgData[0];
+ $this->sourceHeight = $imgData[1];
+ $this->sourceMime = $imgData['mime'];
+
+ $this->calculateProportions();
+ $this->doCreateImage($imgData);
+
+ return true;
+ }
+ else
+ {
+ throw new Exception(sprintf('Image MIME type %s not supported', $imgData['mime']));
+ }
+ }
+
+ public function calculateProportions()
+ {
+ if ($this->sourceWidth / $this->maxWidth > $this->sourceHeight / $this->maxHeight)
+ {
+ // Broad format
+ $this->thumbWidth = ($this->sourceWidth * $this->maxHeight) / $this->sourceHeight;
+ $this->thumbHeight = $this->maxHeight;
+ }
+ else
+ {
+ // High format
+ $this->thumbWidth = $this->maxWidth;
+ $this->thumbHeight = ($this->sourceHeight * $this->maxWidth) / $this->sourceWidth;
+ }
+ }
+
+ protected function doCreateImage($imgData)
+ {
+ $this->thumb = imagecreatetruecolor($this->maxWidth, $this->maxHeight);
+
+ // Allocate for colors / transparency
+ imagealphablending($this->thumb, false);
+ $color = imagecolortransparent($this->thumb, imagecolorallocatealpha($this->thumb, 0, 0, 0, 127));
+ imagefill($this->thumb, 0, 0, $color);
+ imagesavealpha($this->thumb, true);
+
+
+ if ($imgData[0] == $this->maxWidth && $imgData[1] == $this->maxHeight)
+ {
+ $this->thumb = $this->source;
+ }
+ else
+ {
+ imagecopyresampled($this->thumb, $this->source, - ($this->thumbWidth-$this->maxWidth) / 2, - ($this->thumbHeight - $this->maxHeight) / 2, 0, 0, $this->thumbWidth, $this->thumbHeight, $this->sourceWidth, $this->sourceHeight);
+ }
+ }
+}
55 lib/service/sfImageCacheService.class.php
@@ -0,0 +1,55 @@
+<?php
+
+/**
+*
+*/
+class sfImageCacheService
+{
+ protected
+ $dispatcher;
+
+ public function __construct(sfEventDispatcher $dispatcher)
+ {
+ $this->dispatcher = $dispatcher;
+ }
+
+ public function createCachedImage($imagePath, $savePath, $width, $height)
+ {
+ /*
+ TODO - Allow configuration of "type"
+ */
+ if (extension_loaded('gd'))
+ {
+ // The "crop" method is default.
+ $adapterClass = 'sfGDAdapterCrop';
+ }
+ else
+ {
+ $adapterClass = 'sfImageMagickAdapter';
+ }
+
+ $thumbnail = new sfThumbnail($width, $height, true, true, 75, $adapterClass);
+ $thumbnail->loadFile($imagePath);
+ $thumbnail->save($savePath);
+ }
+
+ public function getCacheSymlinkDir()
+ {
+ return sfConfig::get('sf_cache_dir').DIRECTORY_SEPARATOR.'sfImageCachePlugin';
+ }
+
+ public function getWebSymlinkDir()
+ {
+ return sfConfig::get('sf_web_dir').DIRECTORY_SEPARATOR.'sfImageCachePlugin';
+ }
+
+ public function getImageCacheCacheDir()
+ {
+ return $this->getCacheSymlinkDir().DIRECTORY_SEPARATOR.'cached_images';
+ }
+
+ public function getImageCacheWebDir()
+ {
+ return $this->getWebSymlinkDir().DIRECTORY_SEPARATOR.'cached_images';
+ }
+}
11 lib/sfImageCacheApplicationConfiguration.class.php
@@ -0,0 +1,11 @@
+<?php
+
+/**
+*
+*/
+class sfImageCacheApplicationConfiguration extends sfApplicationConfiguration
+{
+ public function configure()
+ {
+ }
+}
53 lib/validator/sfImageCacheValidatedFile.class.php
@@ -0,0 +1,53 @@
+<?php
+
+class sfImageCacheValidatedFile extends sfValidatedFile
+{
+ public function __construct($originalName, $type, $tempName, $size, $path = null)
+ {
+ if (!$this->variants)
+ {
+ throw new sfException('Please set the protected property "$variants" in the sfThumbnailValidatedFile subclass');
+ }
+
+ parent::__construct($originalName, $type, $tempName, $size, $path);
+ }
+
+ public function save($file = null, $fileMode = 0666, $create = true, $dirMode = 0777)
+ {
+ $savedName = parent::save($file, $fileMode, $create, $dirMode);
+ $fileInfo = pathinfo($this->getSavedName());
+
+ foreach ($this->variants as $variant)
+ {
+ $sizeFunc = sprintf('get%sSize', sfInflector::camelize($variant));
+
+ if (!method_exists($this, $sizeFunc))
+ {
+ throw new sfException(sprintf('Please create a %s function to return the image variant width and height', $sizeFunc));
+ }
+
+ $params = $this->$sizeFunc();
+
+ if (!isset($params['width']) || !isset($params['height']))
+ {
+ throw new InvalidArgumentException(sprintf('Please make sure both "width" and "height" are set for method "%s"', $sizeFunc));
+ }
+
+ $pathFunc = sprintf('get%sPath', sfInflector::camelize($variant));
+
+ // Configure a custom path to upload your variant
+ $savePath = method_exists($this, $pathFunc) ? $this->$pathFunc() : $this->getPath();
+
+ $this->createThumbnail($params['width'], $params['height'], sprintf('%s/%s-%s', $savePath, $variant, $fileInfo['basename']));
+ }
+
+ return $savedName;
+ }
+
+ protected function createThumbnail($width, $height, $name)
+ {
+ $thumbnail = new sfThumbnail($width, $height);
+ $thumbnail->loadFile($this->getSavedName());
+ $thumbnail->save($name);
+ }
+}
56 lib/validator/sfImageVariantValidatedFile.class.php
@@ -0,0 +1,56 @@
+<?php
+
+abstract class sfImageVariantValidatedFile extends sfValidatedFile
+{
+ protected
+ $variants = array();
+
+ public function __construct($originalName, $type, $tempName, $size, $path = null)
+ {
+ if (!$this->variants)
+ {
+ throw new sfException('Please set the protected property "$variants" in the sfThumbnailValidatedFile subclass');
+ }
+
+ parent::__construct($originalName, $type, $tempName, $size, $path);
+ }
+
+ public function save($file = null, $fileMode = 0666, $create = true, $dirMode = 0777)
+ {
+ $savedName = parent::save($file, $fileMode, $create, $dirMode);
+ $fileInfo = pathinfo($this->getSavedName());
+
+ foreach ($this->variants as $variant)
+ {
+ $sizeFunc = sprintf('get%sSize', sfInflector::camelize($variant));
+
+ if (!method_exists($this, $sizeFunc))
+ {
+ throw new sfException(sprintf('Please create a %s function to return the image variant width and height', $sizeFunc));
+ }
+
+ $params = $this->$sizeFunc();
+
+ if (!isset($params['width']) || !isset($params['height']))
+ {
+ throw new InvalidArgumentException(sprintf('Please make sure both "width" and "height" are set for method "%s"', $sizeFunc));
+ }
+
+ $pathFunc = sprintf('get%sPath', sfInflector::camelize($variant));
+
+ // Configure a custom path to upload your variant
+ $savePath = method_exists($this, $pathFunc) ? $this->$pathFunc() : $this->getPath();
+
+ $this->createThumbnail($params['width'], $params['height'], sprintf('%s/%s-%s', $savePath, $variant, $fileInfo['basename']));
+ }
+
+ return $savedName;
+ }
+
+ protected function createThumbnail($width, $height, $name)
+ {
+ $thumbnail = new sfThumbnail($width, $height);
+ $thumbnail->loadFile($this->getSavedName());
+ $thumbnail->save($name);
+ }
+}
97 lib/widget/sfWidgetFormImage.class.php
@@ -0,0 +1,97 @@
+<?php
+
+/*
+ * This file is part of the symfony package.
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * sfWidgetFormInputFileEditable represents an upload HTML input tag with the possibility
+ * to remove a previously uploaded file.
+ *
+ * @package symfony
+ * @subpackage widget
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ * @version SVN: $Id: sfWidgetFormInputFileEditable.class.php 28709 2010-03-23 13:57:27Z Kris.Wallsmith $
+ */
+class sfWidgetFormImage extends sfWidgetFormInputFile
+{
+ /**
+ * Constructor.
+ *
+ * Available options:
+ *
+ * * path: The current image web source path (required)
+ * * with_delete: Whether to add a delete checkbox or not
+ * * delete_label: The delete label used by the template
+ * * template: The HTML template to use to render this widget when in edit mode
+ * The available placeholders are:
+ * * %input% (the image upload widget)
+ * * %delete% (the delete checkbox)
+ * * %delete_label% (the delete label text)
+ * * %image% (the image tag)
+ *
+ * If with_delete is enabled, this widget renders an additional widget named after the
+ * upload widget with a "_delete" suffix. So, when creating a form,
+ * don't forget to add a validator for this additional field.
+ *
+ * @param array $options An array of options
+ * @param array $attributes An array of default HTML attributes
+ *
+ * @see sfWidgetFormInputFile
+ */
+ protected function configure($options = array(), $attributes = array())
+ {
+ parent::configure($options, $attributes);
+
+ $this->setOption('type', 'file');
+ $this->setOption('needs_multipart', true);
+
+ $this->addRequiredOption('path');
+ $this->addOption('with_delete', false);
+ $this->addOption('delete_label', 'remove the current file');
+ $this->addOption('template', '%image%<br />%input%<br />%delete% %delete_label%');
+ }
+
+ /**
+ * @param string $name The element name
+ * @param string $value The value displayed in this widget
+ * @param array $attributes An array of HTML attributes to be merged with the default HTML attributes
+ * @param array $errors An array of errors for the field
+ *
+ * @return string An HTML tag string
+ *
+ * @see sfWidgetForm
+ */
+ public function render($name, $value = null, $attributes = array(), $errors = array())
+ {
+ $input = parent::render($name, $value, $attributes, $errors);
+
+ if ($this->getOption('with_delete'))
+ {
+ $deleteName = ']' == substr($name, -1) ? substr($name, 0, -1).'_delete]' : $name.'_delete';
+
+ $delete = $this->renderTag('input', array_merge(array('type' => 'checkbox', 'name' => $deleteName), $attributes));
+ $deleteLabel = $this->translate($this->getOption('delete_label'));
+ $deleteLabel = $this->renderContentTag('label', $deleteLabel, array_merge(array('for' => $this->generateId($deleteName))));
+ }
+ else
+ {
+ $delete = '';
+ $deleteLabel = '';
+ }
+
+ return strtr($this->getOption('template'), array('%input%' => $input, '%delete%' => $delete, '%delete_label%' => $deleteLabel, '%image%' => $this->getImageTag($value, $attributes)));
+ }
+
+ protected function getImageTag($value, $attributes)
+ {
+ sfProjectConfiguration::getActive()->loadHelpers(array('Asset'));
+
+ return $value ? $this->renderTag('img', array_merge(array(
+ 'src' => image_path($this->getOption('path').'/'.$value)), $attributes)) : '';
+ }
+}
Please sign in to comment.
Something went wrong with that request. Please try again.