Author: uncleringo
Date: 2010-01-20 18:19:32 +0100 (Wed, 20 Jan 2010)
New Revision: 26951
Added:
plugins/sfDoctrineJCroppablePlugin/tags/sfDoctrineJCroppablePlugin-1.0.7/
plugins/sfDoctrineJCroppablePlugin/tags/sfDoctrineJCroppablePlugin-1.0.7/LICENSE
plugins/sfDoctrineJCroppablePlugin/tags/sfDoctrineJCroppablePlugin-1.0.7/README
plugins/sfDoctrineJCroppablePlugin/tags/sfDoctrineJCroppablePlugin-1.0.7/lib/
plugins/sfDoctrineJCroppablePlugin/tags/sfDoctrineJCroppablePlugin-1.0.7/lib/doctrine/
plugins/sfDoctrineJCroppablePlugin/tags/sfDoctrineJCroppablePlugin-1.0.7/lib/doctrine/JCroppable.php
plugins/sfDoctrineJCroppablePlugin/tags/sfDoctrineJCroppablePlugin-1.0.7/lib/doctrine/Listener/
plugins/sfDoctrineJCroppablePlugin/tags/sfDoctrineJCroppablePlugin-1.0.7/lib/doctrine/Listener/JCroppable.php
plugins/sfDoctrineJCroppablePlugin/tags/sfDoctrineJCroppablePlugin-1.0.7/lib/widget/
plugins/sfDoctrineJCroppablePlugin/tags/sfDoctrineJCroppablePlugin-1.0.7/lib/widget/sfWidgetFormInputImageJCroppable.class.php
Log:
Tagging the 1.0.7 release
Copied:
plugins/sfDoctrineJCroppablePlugin/tags/sfDoctrineJCroppablePlugin-1.0.7/LICENSE
(from rev 24100, plugins/sfDoctrineJCroppablePlugin/trunk/LICENSE)
===================================================================
---
plugins/sfDoctrineJCroppablePlugin/tags/sfDoctrineJCroppablePlugin-1.0.7/LICENSE
(rev 0)
+++
plugins/sfDoctrineJCroppablePlugin/tags/sfDoctrineJCroppablePlugin-1.0.7/LICENSE
2010-01-20 17:19:32 UTC (rev 26951)
@@ -0,0 +1,19 @@
+Copyright (c) 2008 Rich Birch
+
+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.
\ No newline at end of file
Copied:
plugins/sfDoctrineJCroppablePlugin/tags/sfDoctrineJCroppablePlugin-1.0.7/README
(from rev 24100, plugins/sfDoctrineJCroppablePlugin/trunk/README)
===================================================================
---
plugins/sfDoctrineJCroppablePlugin/tags/sfDoctrineJCroppablePlugin-1.0.7/README
(rev 0)
+++
plugins/sfDoctrineJCroppablePlugin/tags/sfDoctrineJCroppablePlugin-1.0.7/README
2010-01-20 17:19:32 UTC (rev 26951)
@@ -0,0 +1,189 @@
+sfDoctrineJCroppablePlugin
+==========================
+
+This plugin allows you to effortlessly add image editing capabilities to your
+admin generator backend. You'll be able to add images to your models and be
+presented with the awesome Jcrop (http://deepliquid.com/content/Jcrop.html)
+jQuery plugin.
+
+
+Features
+--------
+
+The plugin already has a few very useful features
+
+* Create as many different sized crops of each of your image fields as you like
+* Add any amount of coloured padding around the croppable image
+* Fix the aspect ratio of the cropper to add consistency to your images'
+ dimensions
+* Change the directory that uploaded images are stored in
+* Use the getImageSrc() or getImageTag() method in your frontend app to easily
display your
+ neatly cropped images
+
+Installation
+------------
+
+To install the plugin for a symfony project, the usual process is to use the
+symfony command line:
+
+ php symfony plugin:install sfDoctrineJCroppablePlugin
+
+sfDoctrineJCroppablePlugin depends on the excellent sfImageTransformPlugin, but
+until I can figure out how to specify that dependency in the package then
you'll
+have to install it yourself (it's getting late!)
+
+ php symfony plugin:install sfImageTransformPlugin
+
+If the installation of either package fails (because you're running symfony 1.3
+for example) then you can manually download the tgz files from
+
+
http://plugins.symfony-project.org/get/sfImageTransformPlugin/sfImageTransformPlugin-1.2.0.tgz
+
http://plugins.symfony-project.org/get/sfDoctrineJCroppablePlugin/sfDoctrineJCroppablePlugin-1.0.2.tgz
+
+and then ask symfony to install the downloaded files
+
+ php symfony plugin:install sfImageTransformPlugin-1.2.0.tgz
+ php symfony plugin:install sfDoctrineJCroppablePlugin-1.0.2.tgz
+
+Enable the plugins if necessary by editing
config/ProjectConfiguration.class.php:
+
+ $this->enablePlugins(array('sfDoctrinePlugin', 'sfImageTransformPlugin',
'sfDoctrineJCroppablePlugin'));
+
+
+Symfony 1.2 & Doctrine 1.0
+--------------------------
+
+If you're using symfony 1.2 which comes with doctrine 1.0 this plugin will not
+be able to delete the old versions of its images when it creates new ones. This
+is because we've not been able to find a way of getting the old filename.
+Upgrading to doctrine 1.1 fixes this and is a reasonably straightforward
+exorcise. There is a good guide here:
+
+ http://www.brandonturner.net/blog/2009/05/doctrine11-with-symfony12/
+
+Symfony 1.3 comes with doctrine 1.2 and so this is not an issue.
+
+
+Usage
+-----
+
+You'll first want to edit config/doctrine/schema.yml to add the behaviour to
one
+of your models:
+
+ Person:
+ actAs:
+ JCroppable:
+ images: [ mugshot ]
+ columns:
+ first_name: { type: string(128), notnull: true }
+ last_name: { type: string(128), notnull: false }
+
+Here we have told the plugin we want one jcroppable image field called mugshot.
+The plugin will take care of the creation of the relevant fields in the person
+table.
+
+Now we've updated/created our schema, we can tell symfony to rebuild our
+database.
+
+Caution! This step will erase any data in the database that is not included in
any
+fixtures:
+
+ php symfony doctrine:build-all-reload
+
+
+Next let's configure sfImageTransform to use the gd library and to auto-detect
+images' mime-types (apps/backend/config/app.yml)
+
+ all:
+ sfImageTransformPlugin:
+ default_adapter: GD
+ mime_type:
+ auto_detect: true
+ library: gd_mime_type
+
+If you haven't aleady done so let's create an admin module for our person
model:
+
+ php symfony doctrine:generate-admin backend Person --module=person
+
+The plugin also depends on the jquery & jcrop libraries, so you must download
+them (http://deepliquid.com/content/Jcrop.html) and place the two js files
+(jquery.Jcrop.min.js & jquery.min.js) in web/js, and the css file
+(jquery.Jcrop.css) in web/css:
+
+ web/js/jquery.min.js
+ web/js/jquery.Jcrop.min.js
+ web/css/jquery.Jcrop.css
+
+Now we need to tell our module's view to include them. We can do this
+specifically for our module by editing
+apps/backend/modules/person/config/view.yml, or for the whole application by
+editing apps/backend/config/view.yml:
+
+ default:
+ javascripts: [jquery.min.js, jquery.Jcrop.min.js]
+ stylesheets: [jquery.Jcrop.css]
+
+We're almost finished now! Just two things left to do. First we have to
+configure the widget & validator for our jcroppable image field. Add the
+following calls to configure the widgets & validators to the form's configure
+function (lib/form/doctrine/PersonForm.class.php):
+
+ public function configure()
+ {
+ $this->getObject()->configureJCropWidgets($this);
+ $this->getObject()->configureJCropValidators($this);
+ }
+
+And finally create the upload directory for the images to be stored in and make
+them writeable:
+
+ mkdir -p web/uploads/images/Person
+ chmod 777 web/uploads/images/Person
+
+That's it! Now if you followed the instructions carefully then you should be
+able to aim your browser at the backend app's person module and add a few
+people and their mug shots.
+
+To show the images in your frontend templates, simply pass a Person object, and
+call the getImageSrc() or the getImageTag() function, passing the desired image
+& size, eg
+
+ <img src="<?php echo $person->getImageSrc('mugshot', 'thumb') ?>" alt="Mug
shot!" />
+
+or
+
+ <?php echo $person->getImageTag('mugshot', 'thumb') ?>
+
+Configuration
+-------------
+
+Now the above example has used a load of default values which you'll almost
+definitely want to configure. Here's an example of some config you can place in
+your config/app.yml:
+
+ all:
+ sfDoctrineJCroppablePlugin:
+ models:
+ Person:
+ directory: people
+ images:
+ mugshot:
+ padding: { percent: 35, color: #ffffff }
+ ratio: 1.5
+ sizes:
+ thumb: { width: 450 }
+ main: { width: 675 }
+
+Let's run through these options:
+
+* directory - overrides the default web/uploads/images/Person to instead be
+ web/uploads/people
+* padding - adds padding to the image, of the specified color, using either a
+ 'percent' or 'pixels' value
+* ratio - fixes the aspect ratio of the cropper and therefore the generated
+ cropped images
+* sizes - allows you to specify any number of different sized images to be
+ created. You specify the width and the height will be calculated using the
+ ratio if there is one, otherwise it will be variable according to the
+ selected crop. The default sizes are thumb (width 120px) &
+ main (width 360px)
Copied:
plugins/sfDoctrineJCroppablePlugin/tags/sfDoctrineJCroppablePlugin-1.0.7/lib/doctrine/JCroppable.php
(from rev 24100,
plugins/sfDoctrineJCroppablePlugin/trunk/lib/doctrine/JCroppable.php)
===================================================================
---
plugins/sfDoctrineJCroppablePlugin/tags/sfDoctrineJCroppablePlugin-1.0.7/lib/doctrine/JCroppable.php
(rev 0)
+++
plugins/sfDoctrineJCroppablePlugin/tags/sfDoctrineJCroppablePlugin-1.0.7/lib/doctrine/JCroppable.php
2010-01-20 17:19:32 UTC (rev 26951)
@@ -0,0 +1,526 @@
+<?php
+
+class Doctrine_Template_JCroppable extends Doctrine_Template
+{
+ /**
+ * Array of ageable options
+ *
+ * @var string
+ */
+ protected $_options = array();
+
+ private $editableImages = array();
+ private $originalImages = array();
+
+ /**
+ * __construct
+ *
+ * @param string $array
+ * @return void
+ */
+ public function __construct(array $options = array())
+ {
+ $this->_options = Doctrine_Lib::arrayDeepMerge($this->_options, $options);
+ }
+
+ /**
+ * Set table definition for JCroppable behavior
+ *
+ * @return void
+ */
+ public function setTableDefinition()
+ {
+ if (empty($this->_options['images']))
+ {
+ return false;
+ }
+
+ foreach ($this->_options['images'] as $fieldName) {
+ $this->hasColumn($fieldName, 'string', 255, array('type' => 'string',
'length' => '255'));
+
+ foreach (array('x1', 'y1', 'x2', 'y2') as $suffix) {
+ $this->hasColumn($fieldName . '_' . $suffix, 'integer', null,
array('type' => 'integer'));
+ }
+ }
+
+ $this->addListener(new
Doctrine_Template_Listener_JCroppable($this->_options));
+
+ $this->createChildFormClass();
+ }
+
+ private function getTableNameCamelCase() {
+ return preg_replace('/(?:^|_)(.?)/e',"strtoupper('$1')",
+ $this->getInvoker()->getTable()->getTableName());
+ }
+
+ /**
+ * Performs the following operations for a given image:
+ * 1) removes any old files if the image has been re-uploaded
+ * 2) creates a scaled down version for editing in the cropper if the image
has been (re)uploaded
+ * 3) creates the cropped versions of the image
+ *
+ * This method is called from the listener if the image has been edited in
any way
+ *
+ * @param string $fieldName
+ */
+ public function updateImage($fieldName) {
+// die($fieldName);
+ $oldValues = $this->getInvoker()->getModified(true);
+
+ if (!empty($oldValues[$fieldName]) && $oldValues[$fieldName] !=
$this->getInvoker()->$fieldName) {
+
+ $this->removeImages($fieldName, $oldValues[$fieldName]);
+
+ }
+
+ if (in_array($fieldName, array_keys($this->getInvoker()->getModified()))) {
+
+ $this->createEditableImage($fieldName);
+
+ }
+
+ $this->createCrops($fieldName);
+ }
+
+ /**
+ * Takes a form and configures each image's widget.
+ *
+ * This is one of only 2 methods the user needs to call manually (the other
being configureJCropValidators)
+ * Should be called from the form's configure() method
+ *
+ * @param sfForm $form
+ */
+ public function configureJCropWidgets(sfForm $form, $formOptions = array()) {
+
+ foreach ($this->_options['images'] as $fieldName) {
+ if (!$imageConfig = $this->getImageConfig($fieldName))
+ {
+ continue;
+ }
+
+ $form->setWidget($fieldName,
+ new sfWidgetFormInputFileInputImageJCroppable(array(
+ 'invoker' => $this->getInvoker(),
+ 'image_field' => $fieldName,
+ 'image_ratio' => isset($imageConfig['ratio']) ?
$imageConfig['ratio'] : false,
+ 'with_delete' => true,
+ 'file_src' => $this->getImageSrc($fieldName, 'editable'),
+ 'template' => '%file%<br />%input%<br />%delete% %delete_label%',
+ 'form' => $form
+ ))
+ );
+
+ foreach (array('x1', 'y1', 'x2', 'y2') as $suffix) {
+ $form->setWidget($fieldName . '_' . $suffix, new
sfWidgetFormInputHidden());
+ }
+ }
+ }
+
+ /**
+ * Takes a form and configures each image's widget.
+ *
+ * This is one of only 2 methods the user needs to call manually (the other
being configureJCropWidgets)
+ * Should be called from the form's configure() method
+ *
+ * @param sfForm $form
+ */
+ public function configureJCropValidators($form) {
+
+ foreach ($this->_options['images'] as $fieldName) {
+
+ $form->setValidator($fieldName . '_delete', new sfValidatorPass());
+
+ $form->setValidator($fieldName,
+ new sfValidatorFile(array(
+ 'required' => false,
+ 'path' => $this->getImageDir(),
+ 'mime_types' => 'web_images',
+ ),
+ array('mime_types' => 'Unsupported image type (%mime_type%)')
+ )
+ );
+ }
+ }
+
+ /**
+ * Get the directory to store the images in by looking in the following
places:
+ *
+ * 1) table specific config
+ * 2) global plugin config
+ * 3) default location
+ *
+ * @return string
+ */
+ private function getImageDir() {
+ $config = sfConfig::get('app_sfDoctrineJCroppablePlugin_models');
+
+ $basePath = sfConfig::get('sf_upload_dir');
+
+ $tableName = $this->getTableNameCamelCase();
+
+ if (!empty($config[$tableName]['directory'])) {
+
+ $relativePath = $config[$tableName]['directory'];
+
+ } else {
+
+ $relativePath = $this->getImageDirDefault();
+
+ }
+
+ return $basePath . DIRECTORY_SEPARATOR . $relativePath;
+ }
+
+ /**
+ * Generate's the default directory to store the model's images in (relative
to uploads/)
+ *
+ * @return string
+ */
+ private function getImageDirDefault() {
+ return 'images' . DIRECTORY_SEPARATOR . $this->getTableNameCamelCase();
+ }
+
+ /**
+ * Gets the model's image directory relative to the web root (sf_web_dir)
+ *
+ * @return string
+ */
+ private function getImageDirWeb() {
+ $webDir = str_replace('\\', '/', sfConfig::get('sf_web_dir'));
+ $imageDir = str_replace('\\', '/', $this->getImageDir());
+
+ return (string)str_replace($webDir . '/', '', $imageDir);
+ }
+
+ /**
+ * Gets the given field's absolute editable image path, and warns if the
directory
+ * doesn't exist or is not writable
+ *
+ * @param string $fieldName
+ * @return string
+ */
+ public function getImageSrc($fieldName, $size = 'thumb') {
+ $fileDir = $this->getImageDirWeb();
+
+ if (!file_exists($fileDir)) {
+ print("image upload directory <strong>$fileDir</strong> doesn't exist");
+ }
+ if (!is_writable($fileDir)) {
+ print("image upload directory <strong>$fileDir</strong> is not
writable");
+ }
+
+ $fileSrc = '/' . $fileDir . '/' . $this->getImageFromName($fieldName,
$size);
+
+ return $fileSrc;
+ }
+
+ /**
+ * Returns an img tag for the specified image field & size (default thumb)
+ *
+ * @param string $fieldName
+ * @param string $size
+ * @param array $attributes
+ * @return string
+ */
+ public function getImageTag($fieldName, $size = 'thumb', $attributes =
array())
+ {
+ return tag(
+ 'img',
+ array_merge(
+ $attributes,
+ array('src' => $this->getImageSrc($fieldName, $size))
+ )
+ );
+ }
+
+ /**
+ * Takes the original image, adds and padding to it and creates an editable
version
+ * for use in the cropper
+ *
+ * @param string $fieldName
+ */
+ private function createEditableImage($fieldName) {
+ $imageConfig = $this->getImageConfig($fieldName);
+ /**
+ * Get the filenames for the editoable and original versions of the image
+ */
+ $original = $this->getImageFromName($fieldName, 'original');
+ $editable = $this->getImageFromName($fieldName, 'editable');
+
+ if (empty($original) || empty($editable))
+ {
+ return false;
+ }
+
+ $dir = $this->getImageDir();
+
+ /**
+ * Move the new image to be named as the original
+ */
+ rename($dir . DIRECTORY_SEPARATOR . $editable, $dir . DIRECTORY_SEPARATOR
. $original);
+ //print("mv $editable $original<br/>");exit;
+ /**
+ * Load the original and resize it for the editable version
+ */
+ $img = new sfImage($dir . DIRECTORY_SEPARATOR . $original);
+
+ if (isset($imageConfig['padding'])) {
+ $img = $this->addPadding($img, $imageConfig['padding']);
+
+ $img->saveAs($dir . DIRECTORY_SEPARATOR . $original);
+ }
+
+ $img->resize(400, null);
+ $img->saveAs($dir . DIRECTORY_SEPARATOR . $editable);
+
+ $this->getInvoker()->{$fieldName . '_x1'} = 0;
+ $this->getInvoker()->{$fieldName . '_y1'} = 0;
+ $this->getInvoker()->{$fieldName . '_x2'} = $img->getWidth();
+ $this->getInvoker()->{$fieldName . '_y2'} = $img->getHeight();
+ }
+
+ /**
+ * Adds any padding to the given image using the supplied padding config
+ *
+ * @param $img
+ * @param array $padding
+ * @return $img
+ */
+ private function addPadding($img, $padding) {
+ if (!$padding) {
+ return $img;
+ }
+
+ if (isset($padding['percent']) && is_numeric($padding['percent'])) {
+
+ $width = $img->getWidth() * (1 + ($padding['percent'] / 100));
+ $height = $img->getHeight() * (1 + ($padding['percent'] / 100));
+
+ } else if (isset($padding['pixels']) && is_numeric($padding['pixels'])) {
+
+ $width = $img->getWidth() + $padding['pixels'];
+ $height = $img->getHeight() + $padding['pixels'];
+
+ } else {
+
+ return $img;
+
+ }
+
+ $canvas = new sfImage();
+ $canvas
+ ->fill(0, 0, isset($padding['color']) ? $padding['color'] : '#ffffff')
+ ->resize($width, $height)
+ ->overlay($img, 'center');
+
+ return $canvas;
+ }
+
+ /**
+ * Gets the filename for the given image field and size. Uses the current
field value,
+ * but can be overriden by passing a different value as the 3rd parameter
+ *
+ * @param $fieldName
+ * @param $size
+ * @param $editable
+ * @return $image
+ */
+ private function getImageFromName($fieldName, $size = 'editable', $editable
= null) {
+ if (!$imageConfig = $this->getImageConfig($fieldName)) {
+ return false;
+ }
+
+ if ($editable == null) {
+ $editable = $this->getInvoker()->$fieldName;
+ }
+
+ if ($size == 'editable' || (!isset($imageConfig['sizes'][$size]) && $size
!= 'original')) {
+ return $editable;
+ }
+
+ $extensionPosition = strrpos($editable, '.');
+ $stub = substr($editable, 0, $extensionPosition);
+
+ $image = str_replace($stub, $stub . '_' . $size, $editable);
+
+ return $image;
+ }
+
+ /**
+ * Creates the cropped version of the given field's images
+ *
+ * @param string $fieldName
+ * @return bool
+ */
+ private function createCrops($fieldName) {
+ if (!$imageConfig = $this->getImageConfig($fieldName)) {
+ return false;
+ }
+
+ $this->loadImage($fieldName, 'editable');
+ $this->loadImage($fieldName, 'original');
+
+ foreach ($imageConfig['sizes'] as $size => $dims) {
+
+ $this->createCropForSize($fieldName, $size);
+
+ }
+
+ return true;
+ }
+
+ /**
+ * Loads either the editable or original version of the given image field
+ *
+ * @param string $fieldName
+ * @param string $version - editable or original
+ * @param $force - try to load the image even if there's no config for image
+ */
+ private function loadImage($fieldName, $version, $force = false) {
+ $imageConfig = $this->getImageConfig($fieldName);
+
+ if (!$this->getInvoker()->$fieldName || (!$imageConfig && !$force)) {
+ return;
+ }
+
+ $this->{$version . 'Images'}[$fieldName] =
+ new sfImage($this->getImageDir() . DIRECTORY_SEPARATOR .
$this->getImageFromName($fieldName, $version));
+ }
+
+ /**
+ * Creates the crop of the given field's image at the specified size
+ *
+ * @param $fieldName
+ * @param $size
+ */
+ private function createCropForSize($fieldName, $size) {
+ if (!$imageConfig = $this->getImageConfig($fieldName)) {
+ return false;
+ }
+
+ $this->loadImage($fieldName, 'original');
+ $this->loadImage($fieldName, 'editable');
+
+ if (empty($this->originalImages[$fieldName]) ||
empty($this->editableImages[$fieldName]))
+ {
+ return false;
+ }
+
+ $ratio = $this->originalImages[$fieldName]->getWidth() /
+ $this->editableImages[$fieldName]->getWidth();
+
+ $dims['x'] = (int)$this->getInvoker()->{$fieldName . '_x1'} * $ratio;
+ $dims['y'] = (int)$this->getInvoker()->{$fieldName . '_y1'} * $ratio;
+ $dims['w'] = (int)($this->getInvoker()->{$fieldName . '_x2'} * $ratio) -
$dims['x'];
+ $dims['h'] = (int)($this->getInvoker()->{$fieldName . '_y2'} * $ratio) -
$dims['y'];
+
+ $origCrop = $this->originalImages[$fieldName]
+ ->crop($dims['x'], $dims['y'], $dims['w'], $dims['h']);
+
+ $finalCrop = $origCrop->resize(
+ $imageConfig['sizes'][$size]['width'],
+ empty($imageConfig['ratio']) ?
+ null :
+ $imageConfig['sizes'][$size]['width'] / $imageConfig['ratio']);
+
+ $fullPath = $this->getImageDir() . DIRECTORY_SEPARATOR .
$this->getImageFromName($fieldName, $size);
+
+ $finalCrop->saveAs($fullPath);
+ }
+
+ /**
+ * Removes all existing images for the given field, and the field's value
+ * can be overridden using the second parameter
+ *
+ * @param $fieldName
+ * @param $editable
+ */
+ private function removeImages($fieldName, $editable) {
+ if (!$imageConfig = $this->getImageConfig($fieldName)) {
+ return;
+ }
+
+ /**
+ * Remove the editable & original images
+ */
+ foreach (array('editable', 'original') as $type) {
+ $fullPath = $this->getImageDir() . DIRECTORY_SEPARATOR
+ . $this->getImageFromName($fieldName, $type, $editable);
+
+ if (file_exists($fullPath)) {
+ unlink($fullPath);
+ }
+ }
+
+ /**
+ * Loop through the sizes and remove them
+ */
+ foreach ($imageConfig['sizes'] as $size => $dims) {
+
+ $filename = $this->getImageFromName($fieldName, $size, $editable);
+
+ $fullPath = $this->getImageDir() . DIRECTORY_SEPARATOR . $filename;
+
+ if (file_exists($fullPath)) {
+ unlink($fullPath);
+ }
+
+ }
+ }
+
+ /**
+ * Get's the config for the given field's image
+ *
+ * @param $fieldName
+ * @return array
+ */
+ private function getImageConfig($fieldName) {
+ $config = sfConfig::get('app_sfDoctrineJCroppablePlugin_models');
+
+ if (!isset($config[$this->getTableNameCamelCase()]['images'][$fieldName]))
{
+ return array('sizes' => array(
+ 'thumb' => array('width' => 120),
+ 'main' => array('width' => 360)
+ ));
+ }
+
+ return $config[$this->getTableNameCamelCase()]['images'][$fieldName];
+ }
+
+ /**
+ * Get's the table name of the invoking model
+ *
+ * @return string
+ */
+ private function getTableName() {
+ return $this->getInvoker()->getTable()->getTableName();
+ }
+
+ private function createChildFormClass()
+ {
+ $tableName = $this->getTableNameCamelCase();
+
+ $baseForm = $tableName . 'Form';
+ $extendedForm = 'JCroppable' . $baseForm;
+
+ if (!class_exists($tableName . 'Form') || class_exists($extendedForm))
+ {
+ return false;
+ }
+
+ $class = '
+class ' . $extendedForm . ' extends ' . $baseForm . '
+{
+
+ public function configure()
+ {
+ $this->getObject()->configureJCropWidgets($this, $this->options);
+ $this->getObject()->configureJCropValidators($this);
+
+ parent::configure();
+ }
+}';
+
+ eval($class);
+ }
+}
Copied:
plugins/sfDoctrineJCroppablePlugin/tags/sfDoctrineJCroppablePlugin-1.0.7/lib/doctrine/Listener/JCroppable.php
(from rev 24100,
plugins/sfDoctrineJCroppablePlugin/trunk/lib/doctrine/Listener/JCroppable.php)
===================================================================
---
plugins/sfDoctrineJCroppablePlugin/tags/sfDoctrineJCroppablePlugin-1.0.7/lib/doctrine/Listener/JCroppable.php
(rev 0)
+++
plugins/sfDoctrineJCroppablePlugin/tags/sfDoctrineJCroppablePlugin-1.0.7/lib/doctrine/Listener/JCroppable.php
2010-01-20 17:19:32 UTC (rev 26951)
@@ -0,0 +1,57 @@
+<?php
+
+class Doctrine_Template_Listener_JCroppable extends Doctrine_Record_Listener
+{
+ /**
+ * Array of ageable options
+ *
+ * @var array
+ */
+ protected $_options = array();
+
+ /**
+ * __construct
+ *
+ * @param array $options
+ * @return void
+ */
+ public function __construct(array $options)
+ {
+ $this->_options = $options;
+ }
+
+ public function preInsert(Doctrine_Event $event)
+ {
+ $this->checkImages($event);
+ }
+
+ public function preUpdate(Doctrine_Event $event)
+ {
+ $this->checkImages($event);
+ }
+
+ private function checkImages(Doctrine_Event $event) {
+ $invoker = $event->getInvoker();
+
+ $modifiedFields = array_keys($invoker->getModified());
+ $imageFieldSuffixes = array('', '_x1', '_y1', '_x2', '_y2');
+// print("<pre>");var_dump($modifiedFields);exit;
+ foreach ($this->_options['images'] as $imageName) {
+
+ $needsUpdate = false;
+
+ foreach ($imageFieldSuffixes as $suff) {
+
+ if (in_array($imageName . $suff, $modifiedFields)) {
+ $needsUpdate = true;
+ break;
+ }
+
+ }
+
+ if ($needsUpdate) {
+ $invoker->updateImage($imageName);
+ }
+ }
+ }
+}
\ No newline at end of file
Copied:
plugins/sfDoctrineJCroppablePlugin/tags/sfDoctrineJCroppablePlugin-1.0.7/lib/widget/sfWidgetFormInputImageJCroppable.class.php
(from rev 24100,
plugins/sfDoctrineJCroppablePlugin/trunk/lib/widget/sfWidgetFormInputImageJCroppable.class.php)
===================================================================
---
plugins/sfDoctrineJCroppablePlugin/tags/sfDoctrineJCroppablePlugin-1.0.7/lib/widget/sfWidgetFormInputImageJCroppable.class.php
(rev 0)
+++
plugins/sfDoctrineJCroppablePlugin/tags/sfDoctrineJCroppablePlugin-1.0.7/lib/widget/sfWidgetFormInputImageJCroppable.class.php
2010-01-20 17:19:32 UTC (rev 26951)
@@ -0,0 +1,184 @@
+<?php
+
+/**
+ * sfWidgetFormInputFileInputImageJCroppable represents an upload HTML input
tag which will
+ * also display the uploaded image with the JCrop functionality.
+ *
+ * @author Rich Birch <[email protected]>
+ */
+class sfWidgetFormInputFileInputImageJCroppable extends sfWidgetFormInputFile
+{
+ /**
+ * Constructor.
+ *
+ * Available options:
+ *
+ * * file_src: 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
+ * * image_field:
+ * * image_ratio:
+ * * invoker:
+ * * template: The HTML template to use to render this widget
+ * The available placeholders are:
+ * * input (the image upload widget)
+ * * delete (the delete checkbox)
+ * * delete_label (the delete label text)
+ * * file (the file tag)
+ * * form:
+ *
+ * In edit mode, this widget renders an additional widget named after the
+ * file 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('file_src');
+ $this->addOption('with_delete', true);
+ $this->addOption('delete_label', 'remove the current file');
+ $this->addOption('image_field', null);
+ $this->addOption('image_ratio', null);
+ $this->addOption('invoker', null);
+ $this->addOption('template', '%file%<br />%input%<br />%delete%
%delete_label%');
+ $this->addOption('form', null);
+ }
+
+ /**
+ * @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);
+
+ $object = $this->getOption('invoker');
+
+ if (!$object->exists())
+ {
+ return $input;
+ }
+
+ if (class_exists('sfJSLibManager'))
+ {
+ sfJSLibManager::addLib('jcrop');
+ }
+
+ if ($this->getOption('with_delete'))
+ {
+ $deleteName = ']' == substr($name, -1) ? substr($name, 0, -1).'_delete]'
: $name.'_delete';
+ $form = $this->getOption('form');
+
+ if ($form->getOption('embedded', false) &&
$form->getOption('parent_model', false))
+ {
+ $delete = $form->getOption('parent_model')->getDeleteLinkFor($object);
+ $deleteLabel = '';
+ }
+ else
+ {
+ $delete = $this->renderTag('input', array_merge(array('type' =>
'checkbox', 'name' => $deleteName), $attributes));
+ $deleteLabel = $this->renderContentTag('label',
$this->getOption('delete_label'), array_merge(array('for' =>
$this->generateId($deleteName))));
+ }
+ }
+ else
+ {
+ $delete = '';
+ $deleteLabel = '';
+ }
+
+ return strtr($this->getOption('template') . $this->getJCropJS(),
array('%input%' => $input, '%delete%' => $delete, '%delete_label%' =>
$deleteLabel, '%file%' => $this->getFileAsTag($attributes)));
+ }
+
+ protected function getFileAsTag($attributes)
+ {
+ $id = $this->getIdStub() . '_img';
+
+ return false !== $this->getOption('file_src')
+ ?
+ $this->renderTag(
+ 'img',
+ array_merge(
+ array(
+ 'src' => $this->getOption('file_src'),
+ 'id' => $id
+ ),
+ $attributes
+ )
+ )
+ :
+ '';
+
+ }
+
+ private function getJCropJS() {
+ $idStub = $this->getIdStub();
+ $ratio = $this->getOption('image_ratio') ? 'aspectRatio: ' .
$this->getOption('image_ratio') . ',' : '';
+
+ $js = "
+<script language=\"Javascript\">
+ jQuery(document).ready(function(){
+
+ jQuery('#{$idStub}_img').Jcrop({
+ $ratio
+ setSelect: [document.getElementById('{$idStub}_x1').value,
+ document.getElementById('{$idStub}_y1').value,
+ document.getElementById('{$idStub}_x2').value,
+ document.getElementById('{$idStub}_y2').value
+ ],
+ onChange: _jCropUpdateCoords" . ucfirst($idStub) . ",
+ onSelect: _jCropUpdateCoords" . ucfirst($idStub) . "
+ });
+
+ });
+
+ function _jCropUpdateCoords" . ucfirst($idStub) . "(c) {
+ jQuery('#{$idStub}_x1').val(c.x);
+ jQuery('#{$idStub}_y1').val(c.y);
+ jQuery('#{$idStub}_x2').val(c.x2);
+ jQuery('#{$idStub}_y2').val(c.y2);
+ }
+</script>
+ ";
+
+ return $js;
+ }
+
+ private function getIdStub() {
+ $form = $this->getOption('form');
+ $separator = '';
+
+ $imageName = $this->getOption('image_field');
+ $tableName = str_replace("[%s]", '',
$form->getWidgetSchema()->getNameFormat());
+
+ if ($form->getOption('embedded'))
+ {
+ $parentTableName =
$form->getOption('parent_model')->getTable()->getTableName();
+
+ $separator = 'embedded_' . $tableName . '_' . $tableName .
+ '_' . $this->getOption('invoker')->getId();
+
+ $idStub = $parentTableName . '_' . $separator . '_' . $imageName;
+ }
+ else
+ {
+ $idStub = $tableName . '_' . $imageName;
+ }
+
+ return $idStub;
+ }
+}
--
You received this message because you are subscribed to the Google Groups
"symfony SVN" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/symfony-svn?hl=en.