Finalized images action and loop

This commit is contained in:
franck
2013-08-15 20:47:05 +02:00
parent 5762711146
commit d61eeef0d6
24 changed files with 812 additions and 166 deletions

2
.gitignore vendored
View File

@@ -15,6 +15,8 @@ coverage
.project
.settings/
local/cache/*
local/media/documents/*
local/media/images/*
web/assets/*
web/cache/*
web/.htaccess

View File

@@ -36,12 +36,37 @@ use Imagine\Image\Box;
use Imagine\Image\Color;
use Imagine\Image\Point;
use Thelia\Exception\ImageException;
use Thelia\Log\Tlog;
use Thelia\Core\Event\TheliaEvents;
/**
*
* Image management actions
* Image management actions. This class handles image processing an caching.
*
* Basically, images are stored outside the web space (by default in local/media/images),
* and cached in the web space (by default in web/local/images).
*
* In the images caches directory, a subdirectory for images categories (eg. product, category, folder, etc.) is
* automatically created, and the cached image is created here. Plugin may use their own subdirectory as required.
*
* The cached image name contains a hash of the processing options, and the original (normalized) name of the image.
*
* A copy (or symbolic link, by default) of the original image is always created in the cache, so that the full
* resolution image is always available.
*
* Various image processing options are available :
*
* - resizing, with border, crop, or by keeping image aspect ratio
* - rotation, in degrees, positive or negative
* - background color, applyed to empty background when creating borders or rotating
* - effects. The effects are applied in the specified order. The following effects are available:
* - gamma:value : change the image Gamma to the specified value. Example: gamma:0.7
* - grayscale or greyscale: switch image to grayscale
* - colorize:color : apply a color mask to the image. Exemple: colorize:#ff2244
* - negative : transform the image in its negative equivalent
* - vflip or vertical_flip : vertical flip
* - hflip or horizontal_flip : horizontal flip
*
* If a problem occurs, an ImageException may be thrown.
*
* @package Thelia\Action
* @author Franck Allimant <franck@cqfdev.fr>
@@ -54,6 +79,42 @@ class Image extends BaseAction implements EventSubscriberInterface
const EXACT_RATIO_WITH_CROP = 2;
const KEEP_IMAGE_RATIO = 3;
/**
* Clear the image cache. Is a subdirectory is specified, only this directory is cleared.
* If no directory is specified, the whole cache is cleared.
* Only files are deleted, directories will remain.
*
* @param ImageEvent $event
*/
public function clearCache(ImageEvent $event) {
$path = $this->getCachePath($event->getCacheSubdirectory(), false);
$this->clearDirectory($path);
}
/**
* Recursively clears the specified directory.
*
* @param string $path the directory path
*/
protected function clearDirectory($path) {
$iterator = new \DirectoryIterator($path);
foreach ($iterator as $fileinfo) {
if ($fileinfo->isDot()) continue;
if ($fileinfo->isFile() || $fileinfo->isLink()) {
@unlink($fileinfo->getPathname());
}
else if ($fileinfo->isDir()) {
$this->clearDirectory($fileinfo->getPathname());
}
}
}
/**
* Process image and write the result in the image cache.
*
@@ -85,23 +146,24 @@ class Image extends BaseAction implements EventSubscriberInterface
if (! file_exists($cacheFilePath)) {
if (! file_exists($source_file)) {
throw new ImageException(sprintf("Source image file %s does not exists.", $source_file));
}
// Create a chached version of the original image in the web space, if not exists
if (! file_exists($originalImagePathInCache)) {
$mode = ConfigQuery::read('original_image_delivery_mode', 'symlink');
if ($mode == 'symlink') {
if (false == @symlink($source_file, $originalImagePathInCache)) {
$error_message = sprintf("Failed to create symbolic link for %s in %s image cache directory", basename($source_file), $subdir);
Tlog::getInstance()->addError($error_message);
throw new ImageException($error_message);
if (false == symlink($source_file, $originalImagePathInCache)) {
throw new ImageException(sprintf("Failed to create symbolic link for %s in %s image cache directory", basename($source_file), $subdir));
}
}
else {// mode = 'copy'
if (false == @copy($source_file, $originalImagePathInCache)) {
$error_message = sprintf("Failed to copy %s in %s image cache directory", basename($source_file), $subdir);
Tlog::getInstance()->addError($error_message);
throw new ImageException($error_message);
throw new ImageException(sprintf("Failed to copy %s in %s image cache directory", basename($source_file), $subdir));
}
}
}
@@ -191,11 +253,11 @@ class Image extends BaseAction implements EventSubscriberInterface
array('quality' => $quality)
);
}
}
}
else {
throw new ImageException(sprintf("Source file %s cannot be opened.", basename($source_file)));
}
}
}
// Compute the image URL
$processed_image_url = $this->getCacheFileURL($subdir, basename($cacheFilePath));
@@ -207,8 +269,8 @@ class Image extends BaseAction implements EventSubscriberInterface
$event->setCacheFilepath($cacheFilePath);
$event->setCacheOriginalFilepath($originalImagePathInCache);
$event->setFileUrl(URL::absoluteUrl($processed_image_url));
$event->setOriginalFileUrl(URL::absoluteUrl($original_image_url));
$event->setFileUrl(URL::absoluteUrl($processed_image_url, null, URL::PATH_TO_FILE));
$event->setOriginalFileUrl(URL::absoluteUrl($original_image_url, null, URL::PATH_TO_FILE));
}
/**
@@ -320,7 +382,7 @@ class Image extends BaseAction implements EventSubscriberInterface
{
$path = $this->getCachePathFromWebRoot($subdir);
return URL::absoluteUrl(sprintf("%s/%s", $path, $safe_filename));
return URL::absoluteUrl(sprintf("%s/%s", $path, $safe_filename), null, URL::PATH_TO_FILE);
}
/**
@@ -341,22 +403,28 @@ class Image extends BaseAction implements EventSubscriberInterface
if ($forceOriginalImage || $event->isOriginalImage())
return sprintf("%s/%s", $path, $safe_filename);
else
return sprintf("%s/%s-%s", $path, $event->getSignature(), $safe_filename);
return sprintf("%s/%s-%s", $path, $event->getOptionsHash(), $safe_filename);
}
/**
* Return the cache directory path relative to Web Root
*
* @param string $subdir the subdirectory related to cache base
* @param string $subdir the subdirectory related to cache base, or null to get the cache directory only.
* @return string the cache directory path relative to Web Root
*/
protected function getCachePathFromWebRoot($subdir)
protected function getCachePathFromWebRoot($subdir = null)
{
$safe_subdir = basename($subdir);
$cache_dir_from_web_root = ConfigQuery::read('image_cache_dir_from_web_root', 'cache');
if ($subdir != null) {
$safe_subdir = basename($subdir);
$path = sprintf("%s/%s", $cache_dir_from_web_root, $safe_subdir);
}
else
$path = $cache_dir_from_web_root;
// Check if path is valid, e.g. in the cache dir
return $path;
}
@@ -364,11 +432,11 @@ class Image extends BaseAction implements EventSubscriberInterface
/**
* Return the absolute cache directory path
*
* @param string $subdir the subdirectory related to cache base
* @param string $subdir the subdirectory related to cache base, or null to get the cache base directory.
* @throws \RuntimeException if cache directory cannot be created
* @return string the absolute cache directory path
*/
protected function getCachePath($subdir)
protected function getCachePath($subdir = null, $create_if_not_exists = true)
{
$cache_base = $this->getCachePathFromWebRoot($subdir);
@@ -377,15 +445,19 @@ class Image extends BaseAction implements EventSubscriberInterface
$path = sprintf("%s/%s", $web_root, $cache_base);
// Create directory (recursively) if it does not exists.
if (!is_dir($path)) {
if ($create_if_not_exists && !is_dir($path)) {
if (!@mkdir($path, 0777, true)) {
$error_message = sprintf("Failed to create %s/%s image cache directory", $cache_base);
Tlog::getInstance()->addError($error_message);
throw new ImageException($error_message);
throw new ImageException(sprintf("Failed to create %s/%s image cache directory", $cache_base));
}
}
// Check if path is valid, e.g. in the cache dir
$cache_base = realpath(sprintf("%s/%s", $web_root, $this->getCachePathFromWebRoot()));
if (strpos(realpath($path), $cache_base) !== 0) {
throw new \InvalidArgumentException(sprintf("Invalid cache path %s, with subdirectory %s", $path, $subdir));
}
return $path;
}
@@ -396,7 +468,7 @@ class Image extends BaseAction implements EventSubscriberInterface
*/
protected function createImagineInstance()
{
$driver = ConfigQuery::read("imagine_driver", "gd");
$driver = ConfigQuery::read("imagine_graphic_driver", "gd");
switch ($driver) {
case 'imagik':

View File

@@ -189,7 +189,8 @@ class Install extends ContainerAwareCommand
file_put_contents($configFile, $configContent);
$fs->remove($sampleConfigFile);
// FA - no, as no further install will be possible
// $fs->remove($sampleConfigFile);
$fs->remove($this->getContainer()->getParameter("kernel.cache_dir"));

View File

@@ -27,6 +27,11 @@
<tag name="kernel.event_subscriber"/>
</service>
<service id="thelia.action.category" class="Thelia\Action\Image">
<argument type="service" id="service_container"/>
<tag name="kernel.event_subscriber"/>
</service>
</services>
</config>

View File

@@ -25,6 +25,7 @@
<loop class="Thelia\Core\Template\Loop\Lang" name="lang"/>
<loop class="Thelia\Core\Template\Loop\CategoryTree" name="category-tree"/>
<loop class="Thelia\Core\Template\Loop\Cart" name="cart"/>
<loop class="Thelia\Core\Template\Loop\Image" name="image"/>
</loops>
<forms>

View File

@@ -97,18 +97,18 @@ class ImageEvent extends ActionEvent
protected $quality = null;
/**
* @return boolean true if the required image is the original image
* @return boolean true if the required image is the original image (resize_mode and background_color are not significant)
*/
public function isOriginalImage()
{
return empty($this->width) && empty($this->height) && empty($this->resize_mode) && empty($this->background_color)
&& empty($this->effects) && empty($this->rotation);
return empty($this->width) && empty($this->height) /* && empty($this->resize_mode) && empty($this->background_color) not significant */
&& empty($this->effects) && empty($this->rotation) && empty($this->quality);
}
/**
* @return string a hash identifiying the processing options
*/
public function getSignature()
public function getOptionsHash()
{
return md5(
$this->width . $this->height . $this->resize_mode . $this->background_color . implode(',', $this->effects)

View File

@@ -28,6 +28,15 @@ use Thelia\Core\Event\ImageEvent;
use Thelia\Model\CategoryImageQuery;
use Thelia\Model\ProductImageQuery;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
use Thelia\Type\TypeCollection;
use Thelia\Type\EnumListType;
use Propel\Runtime\ActiveQuery\Criteria;
use Thelia\Model\ConfigQuery;
use Thelia\Core\Template\Element\LoopResultRow;
use Thelia\Core\Template\Element\LoopResult;
use Thelia\Type\EnumType;
use Thelia\Log\Tlog;
/**
* The image loop
@@ -44,31 +53,25 @@ class Image extends BaseLoop
/**
* Dynamically create the search query, and set the proper filter and order
*
* @param string $source a valid source identifier (@see $possible_sources)
* @param int $object_id the source object ID
* @return ModelCriteria the propel Query object
*/
protected function getSearchQuery() {
$search = null;
foreach($this->possible_sources as $source) {
$argValue = intval($this->getArgValue($source));
if ($argValue > 0) {
protected function createSearchQuery($source, $object_id) {
$object = ucfirst($source);
$queryClass = sprintf("%sImageQuery", $object);
$filterMethod = sprintf("filterBy%s", $object);
$queryClass = sprintf("\Thelia\Model\%sImageQuery", $object);
$filterMethod = sprintf("filterBy%sId", $object);
$mapClass = sprintf("\Thelia\Model\Map\%sI18nTableMap", $object);
// xxxImageQuery::create()
$method = new \ReflectionMethod($queryClass, 'create');
$search = $reflectionMethod->invoke(null); // Static !
$search = $method->invoke(null); // Static !
// $query->filterByXXX($id)
// $query->filterByXXX(id)
$method = new \ReflectionMethod($queryClass, $filterMethod);
$method->invoke($search, $argValue);
$method->invoke($search, $object_id);
$map = new \ReflectionClass($mapClass);
$title_map = $map->getConstant('TITLE');
@@ -98,9 +101,55 @@ class Image extends BaseLoop
}
}
return $search;
}
/**
* Dynamically create the search query, and set the proper filter and order
*
* @param string $object_type (returned) the a valid source identifier (@see $possible_sources)
* @param string $object_id (returned) the ID of the source object
* @return ModelCriteria the propel Query object
*/
protected function getSearchQuery(&$object_type, &$object_id) {
$search = null;
// Check form source="product" source_id="123" style arguments
$source = $this->getSource();
if (! is_null($source)) {
$source_id = $this->getSourceId();
// echo "source = ".$this->getSource().", id=".$id."<br />";
if (is_null($source_id)) {
throw new \InvalidArgumentException("'source_id' argument cannot be null if 'source' argument is specified.");
}
$search = $this->createSearchQuery($source, $source_id);
$object_type = $source;
$object_id = $source_id;
}
else {
// Check for product="id" folder="id", etc. style arguments
foreach($this->possible_sources as $source) {
$argValue = intval($this->getArgValue($source));
if ($argValue > 0) {
$search = $this->createSearchQuery($source, $argValue);
$object_type = $source;
$object_id = $argValue;
break;
}
}
}
if ($search == null)
throw new \InvalidArgumentException(sprintf("Unable to find image source. Valid sources are %s", implode(',', $this->possible_sources)));
@@ -111,10 +160,12 @@ class Image extends BaseLoop
/**
* @param unknown $pagination
*/
public function exec($pagination)
public function exec(&$pagination)
{
// Select the proper query to use
$search = $this->getSearchQuery();
// Select the proper query to use, and get the object type
$object_type = $object_id = null;
$search = $this->getSearchQuery($object_type, $object_id);
$id = $this->getId();
@@ -130,10 +181,8 @@ class Image extends BaseLoop
$event = new ImageEvent($this->request);
// Prepare tranformations
// Setup required transformations
$width = $this->getWidth();
$height = $this->getHeight();
$resize_mode = $this->getResizeMode();
$rotation = $this->getRotation();
$background_color = $this->getBackgroundColor();
$quality = $this->getQuality();
@@ -143,6 +192,21 @@ class Image extends BaseLoop
$effects = explode(',', $effects);
}
switch($this->getResizeMode()) {
case 'crop' :
$resize_mode = \Thelia\Action\Image::EXACT_RATIO_WITH_CROP;
break;
case 'borders' :
$resize_mode = \Thelia\Action\Image::EXACT_RATIO_WITH_BORDERS;
break;
case 'none' :
default:
$resize_mode = \Thelia\Action\Image::KEEP_IMAGE_RATIO;
}
/**
* \Criteria::INNER_JOIN in second parameter for joinWithI18n exclude query without translation.
*
@@ -165,13 +229,25 @@ class Image extends BaseLoop
// Setup required transformations
if (! is_null($width)) $event->setWidth($width);
if (! is_null($height)) $event->setHeigth($height);
if (! is_null($resize_mode)) $event->setResizeMode($resize_mode);
if (! is_null($height)) $event->setHeight($height);
$event->setResizeMode($resize_mode);
if (! is_null($rotation)) $event->setRotation($rotation);
if (! is_null($background_color)) $event->setBackgroundColor($background_color);
if (! is_null($quality)) $event->setQuality($quality);
if (! is_null($effects)) $event->setEffects($effects);
// Put source image file path
$source_filepath = sprintf("%s%s/%s/%s",
THELIA_ROOT,
ConfigQuery::read('documents_library_path', 'local/media/images'),
$object_type,
$result->getFile()
);
$event->setSourceFilepath($source_filepath);
$event->setCacheSubdirectory($object_type);
try {
// Dispatch image processing event
$this->dispatcher->dispatch(TheliaEvents::IMAGE_PROCESS, $event);
@@ -180,11 +256,25 @@ class Image extends BaseLoop
$loopResultRow
->set("ID", $result->getId())
->set("IMAGE_URL", $event->getFileUrl())
->set("FILE_URL", $event->
->set("ORIGINAL_IMAGE_URL", $event->getOriginalFileUrl())
->set("IMAGE_PATH", $event->getCacheFilepath())
->set("ORIGINAL_IMAGE_PATH", $source_filepath)
->set("TITLE", $result->getTitle())
->set("CHAPO", $result->getChapo())
->set("DESCRIPTION", $result->getDescription())
->set("POSTSCRIPTUM", $result->getPostscriptum())
->set("POSITION", $result->getPosition())
->set("OBJECT_TYPE", $object_type)
->set("OBJECT_ID", $object_id)
;
$loopResult->addRow($loopResultRow);
}
catch (\Exception $ex) {
// Ignore the result and log an error
Tlog::getInstance()->addError("Failed to process image in image loop: ", $this->args);
}
}
return $loopResult;
/*
@@ -200,6 +290,7 @@ class Image extends BaseLoop
#IMAGE : URL de l'image transformée (redimensionnée, inversée, etc. suivant les paramètres d'entrée de la boucle).
#FICHIER : URL de l'image originale
#ID : identifiant de l'image
#TITRE : titre de l'image
#CHAPO : description courte de l'image
#DESCRIPTION : description longue de l'image
@@ -219,7 +310,7 @@ class Image extends BaseLoop
new Argument(
'order',
new TypeCollection(
new Type\EnumListType(array('alpha', 'alpha-reverse', 'manual', 'manual-reverse', 'random'))
new EnumListType(array('alpha', 'alpha-reverse', 'manual', 'manual-reverse', 'random'))
),
'manual'
),
@@ -232,7 +323,7 @@ class Image extends BaseLoop
new Argument(
'resize_mode',
new TypeCollection(
new Type\EnumListType(array('crop', 'borders', 'none'))
new EnumType(array('crop', 'borders', 'none'))
),
'none'
),
@@ -246,16 +337,17 @@ class Image extends BaseLoop
new Argument(
'source',
new TypeCollection(
new Type\EnumListType($this->possible_sources)
new EnumType($this->possible_sources)
)
),
Argument::createIntTypeArgument('source_id'),
Argument::createIntListTypeArgument('lang')
);
// Add possible image sources
foreach($possible_sources as $source) {
$collection->addArgument(Argument::createIntTypeArgument($source))
foreach($this->possible_sources as $source) {
$collection->addArgument(Argument::createIntTypeArgument($source));
}
return $collection;

View File

@@ -70,7 +70,7 @@ class SmartyAssetsManager
$url = $this->assetic_manager->asseticize(
$asset_dir.'/'.$asset_file,
$this->web_root."/".$this->path_relative_to_web_root,
URL::absoluteUrl($this->path_relative_to_web_root, array(), true /* path only */),
URL::absoluteUrl($this->path_relative_to_web_root, null, URL::PATH_TO_FILE /* path only */),
$assetType,
$filters,
$debug

View File

@@ -23,6 +23,14 @@
namespace Thelia\Exception;
use Thelia\Log\Tlog;
class ImageException extends \RuntimeException
{
public function __construct($message, $code = null, $previous = null) {
Tlog::getInstance()->addError($message);
parent::__construct($message, $code, $previous);
}
}

View File

@@ -87,6 +87,12 @@ abstract class Currency implements ActiveRecordInterface
*/
protected $rate;
/**
* The value for the position field.
* @var int
*/
protected $position;
/**
* The value for the by_default field.
* @var int
@@ -473,6 +479,17 @@ abstract class Currency implements ActiveRecordInterface
return $this->rate;
}
/**
* Get the [position] column value.
*
* @return int
*/
public function getPosition()
{
return $this->position;
}
/**
* Get the [by_default] column value.
*
@@ -608,6 +625,27 @@ abstract class Currency implements ActiveRecordInterface
return $this;
} // setRate()
/**
* Set the value of [position] column.
*
* @param int $v new value
* @return \Thelia\Model\Currency The current object (for fluent API support)
*/
public function setPosition($v)
{
if ($v !== null) {
$v = (int) $v;
}
if ($this->position !== $v) {
$this->position = $v;
$this->modifiedColumns[] = CurrencyTableMap::POSITION;
}
return $this;
} // setPosition()
/**
* Set the value of [by_default] column.
*
@@ -720,16 +758,19 @@ abstract class Currency implements ActiveRecordInterface
$col = $row[TableMap::TYPE_NUM == $indexType ? 3 + $startcol : CurrencyTableMap::translateFieldName('Rate', TableMap::TYPE_PHPNAME, $indexType)];
$this->rate = (null !== $col) ? (double) $col : null;
$col = $row[TableMap::TYPE_NUM == $indexType ? 4 + $startcol : CurrencyTableMap::translateFieldName('ByDefault', TableMap::TYPE_PHPNAME, $indexType)];
$col = $row[TableMap::TYPE_NUM == $indexType ? 4 + $startcol : CurrencyTableMap::translateFieldName('Position', TableMap::TYPE_PHPNAME, $indexType)];
$this->position = (null !== $col) ? (int) $col : null;
$col = $row[TableMap::TYPE_NUM == $indexType ? 5 + $startcol : CurrencyTableMap::translateFieldName('ByDefault', TableMap::TYPE_PHPNAME, $indexType)];
$this->by_default = (null !== $col) ? (int) $col : null;
$col = $row[TableMap::TYPE_NUM == $indexType ? 5 + $startcol : CurrencyTableMap::translateFieldName('CreatedAt', TableMap::TYPE_PHPNAME, $indexType)];
$col = $row[TableMap::TYPE_NUM == $indexType ? 6 + $startcol : CurrencyTableMap::translateFieldName('CreatedAt', TableMap::TYPE_PHPNAME, $indexType)];
if ($col === '0000-00-00 00:00:00') {
$col = null;
}
$this->created_at = (null !== $col) ? PropelDateTime::newInstance($col, null, '\DateTime') : null;
$col = $row[TableMap::TYPE_NUM == $indexType ? 6 + $startcol : CurrencyTableMap::translateFieldName('UpdatedAt', TableMap::TYPE_PHPNAME, $indexType)];
$col = $row[TableMap::TYPE_NUM == $indexType ? 7 + $startcol : CurrencyTableMap::translateFieldName('UpdatedAt', TableMap::TYPE_PHPNAME, $indexType)];
if ($col === '0000-00-00 00:00:00') {
$col = null;
}
@@ -742,7 +783,7 @@ abstract class Currency implements ActiveRecordInterface
$this->ensureConsistency();
}
return $startcol + 7; // 7 = CurrencyTableMap::NUM_HYDRATE_COLUMNS.
return $startcol + 8; // 8 = CurrencyTableMap::NUM_HYDRATE_COLUMNS.
} catch (Exception $e) {
throw new PropelException("Error populating \Thelia\Model\Currency object", 0, $e);
@@ -1052,6 +1093,9 @@ abstract class Currency implements ActiveRecordInterface
if ($this->isColumnModified(CurrencyTableMap::RATE)) {
$modifiedColumns[':p' . $index++] = 'RATE';
}
if ($this->isColumnModified(CurrencyTableMap::POSITION)) {
$modifiedColumns[':p' . $index++] = 'POSITION';
}
if ($this->isColumnModified(CurrencyTableMap::BY_DEFAULT)) {
$modifiedColumns[':p' . $index++] = 'BY_DEFAULT';
}
@@ -1084,6 +1128,9 @@ abstract class Currency implements ActiveRecordInterface
case 'RATE':
$stmt->bindValue($identifier, $this->rate, PDO::PARAM_STR);
break;
case 'POSITION':
$stmt->bindValue($identifier, $this->position, PDO::PARAM_INT);
break;
case 'BY_DEFAULT':
$stmt->bindValue($identifier, $this->by_default, PDO::PARAM_INT);
break;
@@ -1168,12 +1215,15 @@ abstract class Currency implements ActiveRecordInterface
return $this->getRate();
break;
case 4:
return $this->getByDefault();
return $this->getPosition();
break;
case 5:
return $this->getCreatedAt();
return $this->getByDefault();
break;
case 6:
return $this->getCreatedAt();
break;
case 7:
return $this->getUpdatedAt();
break;
default:
@@ -1209,9 +1259,10 @@ abstract class Currency implements ActiveRecordInterface
$keys[1] => $this->getCode(),
$keys[2] => $this->getSymbol(),
$keys[3] => $this->getRate(),
$keys[4] => $this->getByDefault(),
$keys[5] => $this->getCreatedAt(),
$keys[6] => $this->getUpdatedAt(),
$keys[4] => $this->getPosition(),
$keys[5] => $this->getByDefault(),
$keys[6] => $this->getCreatedAt(),
$keys[7] => $this->getUpdatedAt(),
);
$virtualColumns = $this->virtualColumns;
foreach($virtualColumns as $key => $virtualColumn)
@@ -1279,12 +1330,15 @@ abstract class Currency implements ActiveRecordInterface
$this->setRate($value);
break;
case 4:
$this->setByDefault($value);
$this->setPosition($value);
break;
case 5:
$this->setCreatedAt($value);
$this->setByDefault($value);
break;
case 6:
$this->setCreatedAt($value);
break;
case 7:
$this->setUpdatedAt($value);
break;
} // switch()
@@ -1315,9 +1369,10 @@ abstract class Currency implements ActiveRecordInterface
if (array_key_exists($keys[1], $arr)) $this->setCode($arr[$keys[1]]);
if (array_key_exists($keys[2], $arr)) $this->setSymbol($arr[$keys[2]]);
if (array_key_exists($keys[3], $arr)) $this->setRate($arr[$keys[3]]);
if (array_key_exists($keys[4], $arr)) $this->setByDefault($arr[$keys[4]]);
if (array_key_exists($keys[5], $arr)) $this->setCreatedAt($arr[$keys[5]]);
if (array_key_exists($keys[6], $arr)) $this->setUpdatedAt($arr[$keys[6]]);
if (array_key_exists($keys[4], $arr)) $this->setPosition($arr[$keys[4]]);
if (array_key_exists($keys[5], $arr)) $this->setByDefault($arr[$keys[5]]);
if (array_key_exists($keys[6], $arr)) $this->setCreatedAt($arr[$keys[6]]);
if (array_key_exists($keys[7], $arr)) $this->setUpdatedAt($arr[$keys[7]]);
}
/**
@@ -1333,6 +1388,7 @@ abstract class Currency implements ActiveRecordInterface
if ($this->isColumnModified(CurrencyTableMap::CODE)) $criteria->add(CurrencyTableMap::CODE, $this->code);
if ($this->isColumnModified(CurrencyTableMap::SYMBOL)) $criteria->add(CurrencyTableMap::SYMBOL, $this->symbol);
if ($this->isColumnModified(CurrencyTableMap::RATE)) $criteria->add(CurrencyTableMap::RATE, $this->rate);
if ($this->isColumnModified(CurrencyTableMap::POSITION)) $criteria->add(CurrencyTableMap::POSITION, $this->position);
if ($this->isColumnModified(CurrencyTableMap::BY_DEFAULT)) $criteria->add(CurrencyTableMap::BY_DEFAULT, $this->by_default);
if ($this->isColumnModified(CurrencyTableMap::CREATED_AT)) $criteria->add(CurrencyTableMap::CREATED_AT, $this->created_at);
if ($this->isColumnModified(CurrencyTableMap::UPDATED_AT)) $criteria->add(CurrencyTableMap::UPDATED_AT, $this->updated_at);
@@ -1402,6 +1458,7 @@ abstract class Currency implements ActiveRecordInterface
$copyObj->setCode($this->getCode());
$copyObj->setSymbol($this->getSymbol());
$copyObj->setRate($this->getRate());
$copyObj->setPosition($this->getPosition());
$copyObj->setByDefault($this->getByDefault());
$copyObj->setCreatedAt($this->getCreatedAt());
$copyObj->setUpdatedAt($this->getUpdatedAt());
@@ -2578,6 +2635,7 @@ abstract class Currency implements ActiveRecordInterface
$this->code = null;
$this->symbol = null;
$this->rate = null;
$this->position = null;
$this->by_default = null;
$this->created_at = null;
$this->updated_at = null;

View File

@@ -26,6 +26,7 @@ use Thelia\Model\Map\CurrencyTableMap;
* @method ChildCurrencyQuery orderByCode($order = Criteria::ASC) Order by the code column
* @method ChildCurrencyQuery orderBySymbol($order = Criteria::ASC) Order by the symbol column
* @method ChildCurrencyQuery orderByRate($order = Criteria::ASC) Order by the rate column
* @method ChildCurrencyQuery orderByPosition($order = Criteria::ASC) Order by the position column
* @method ChildCurrencyQuery orderByByDefault($order = Criteria::ASC) Order by the by_default column
* @method ChildCurrencyQuery orderByCreatedAt($order = Criteria::ASC) Order by the created_at column
* @method ChildCurrencyQuery orderByUpdatedAt($order = Criteria::ASC) Order by the updated_at column
@@ -34,6 +35,7 @@ use Thelia\Model\Map\CurrencyTableMap;
* @method ChildCurrencyQuery groupByCode() Group by the code column
* @method ChildCurrencyQuery groupBySymbol() Group by the symbol column
* @method ChildCurrencyQuery groupByRate() Group by the rate column
* @method ChildCurrencyQuery groupByPosition() Group by the position column
* @method ChildCurrencyQuery groupByByDefault() Group by the by_default column
* @method ChildCurrencyQuery groupByCreatedAt() Group by the created_at column
* @method ChildCurrencyQuery groupByUpdatedAt() Group by the updated_at column
@@ -65,6 +67,7 @@ use Thelia\Model\Map\CurrencyTableMap;
* @method ChildCurrency findOneByCode(string $code) Return the first ChildCurrency filtered by the code column
* @method ChildCurrency findOneBySymbol(string $symbol) Return the first ChildCurrency filtered by the symbol column
* @method ChildCurrency findOneByRate(double $rate) Return the first ChildCurrency filtered by the rate column
* @method ChildCurrency findOneByPosition(int $position) Return the first ChildCurrency filtered by the position column
* @method ChildCurrency findOneByByDefault(int $by_default) Return the first ChildCurrency filtered by the by_default column
* @method ChildCurrency findOneByCreatedAt(string $created_at) Return the first ChildCurrency filtered by the created_at column
* @method ChildCurrency findOneByUpdatedAt(string $updated_at) Return the first ChildCurrency filtered by the updated_at column
@@ -73,6 +76,7 @@ use Thelia\Model\Map\CurrencyTableMap;
* @method array findByCode(string $code) Return ChildCurrency objects filtered by the code column
* @method array findBySymbol(string $symbol) Return ChildCurrency objects filtered by the symbol column
* @method array findByRate(double $rate) Return ChildCurrency objects filtered by the rate column
* @method array findByPosition(int $position) Return ChildCurrency objects filtered by the position column
* @method array findByByDefault(int $by_default) Return ChildCurrency objects filtered by the by_default column
* @method array findByCreatedAt(string $created_at) Return ChildCurrency objects filtered by the created_at column
* @method array findByUpdatedAt(string $updated_at) Return ChildCurrency objects filtered by the updated_at column
@@ -164,7 +168,7 @@ abstract class CurrencyQuery extends ModelCriteria
*/
protected function findPkSimple($key, $con)
{
$sql = 'SELECT ID, CODE, SYMBOL, RATE, BY_DEFAULT, CREATED_AT, UPDATED_AT FROM currency WHERE ID = :p0';
$sql = 'SELECT ID, CODE, SYMBOL, RATE, POSITION, BY_DEFAULT, CREATED_AT, UPDATED_AT FROM currency WHERE ID = :p0';
try {
$stmt = $con->prepare($sql);
$stmt->bindValue(':p0', $key, PDO::PARAM_INT);
@@ -393,6 +397,47 @@ abstract class CurrencyQuery extends ModelCriteria
return $this->addUsingAlias(CurrencyTableMap::RATE, $rate, $comparison);
}
/**
* Filter the query on the position column
*
* Example usage:
* <code>
* $query->filterByPosition(1234); // WHERE position = 1234
* $query->filterByPosition(array(12, 34)); // WHERE position IN (12, 34)
* $query->filterByPosition(array('min' => 12)); // WHERE position > 12
* </code>
*
* @param mixed $position The value to use as filter.
* Use scalar values for equality.
* Use array values for in_array() equivalent.
* Use associative array('min' => $minValue, 'max' => $maxValue) for intervals.
* @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL
*
* @return ChildCurrencyQuery The current query, for fluid interface
*/
public function filterByPosition($position = null, $comparison = null)
{
if (is_array($position)) {
$useMinMax = false;
if (isset($position['min'])) {
$this->addUsingAlias(CurrencyTableMap::POSITION, $position['min'], Criteria::GREATER_EQUAL);
$useMinMax = true;
}
if (isset($position['max'])) {
$this->addUsingAlias(CurrencyTableMap::POSITION, $position['max'], Criteria::LESS_EQUAL);
$useMinMax = true;
}
if ($useMinMax) {
return $this;
}
if (null === $comparison) {
$comparison = Criteria::IN;
}
}
return $this->addUsingAlias(CurrencyTableMap::POSITION, $position, $comparison);
}
/**
* Filter the query on the by_default column
*

View File

@@ -84,6 +84,12 @@ abstract class Lang implements ActiveRecordInterface
*/
protected $url;
/**
* The value for the position field.
* @var int
*/
protected $position;
/**
* The value for the by_default field.
* @var int
@@ -419,6 +425,17 @@ abstract class Lang implements ActiveRecordInterface
return $this->url;
}
/**
* Get the [position] column value.
*
* @return int
*/
public function getPosition()
{
return $this->position;
}
/**
* Get the [by_default] column value.
*
@@ -575,6 +592,27 @@ abstract class Lang implements ActiveRecordInterface
return $this;
} // setUrl()
/**
* Set the value of [position] column.
*
* @param int $v new value
* @return \Thelia\Model\Lang The current object (for fluent API support)
*/
public function setPosition($v)
{
if ($v !== null) {
$v = (int) $v;
}
if ($this->position !== $v) {
$this->position = $v;
$this->modifiedColumns[] = LangTableMap::POSITION;
}
return $this;
} // setPosition()
/**
* Set the value of [by_default] column.
*
@@ -690,16 +728,19 @@ abstract class Lang implements ActiveRecordInterface
$col = $row[TableMap::TYPE_NUM == $indexType ? 4 + $startcol : LangTableMap::translateFieldName('Url', TableMap::TYPE_PHPNAME, $indexType)];
$this->url = (null !== $col) ? (string) $col : null;
$col = $row[TableMap::TYPE_NUM == $indexType ? 5 + $startcol : LangTableMap::translateFieldName('ByDefault', TableMap::TYPE_PHPNAME, $indexType)];
$col = $row[TableMap::TYPE_NUM == $indexType ? 5 + $startcol : LangTableMap::translateFieldName('Position', TableMap::TYPE_PHPNAME, $indexType)];
$this->position = (null !== $col) ? (int) $col : null;
$col = $row[TableMap::TYPE_NUM == $indexType ? 6 + $startcol : LangTableMap::translateFieldName('ByDefault', TableMap::TYPE_PHPNAME, $indexType)];
$this->by_default = (null !== $col) ? (int) $col : null;
$col = $row[TableMap::TYPE_NUM == $indexType ? 6 + $startcol : LangTableMap::translateFieldName('CreatedAt', TableMap::TYPE_PHPNAME, $indexType)];
$col = $row[TableMap::TYPE_NUM == $indexType ? 7 + $startcol : LangTableMap::translateFieldName('CreatedAt', TableMap::TYPE_PHPNAME, $indexType)];
if ($col === '0000-00-00 00:00:00') {
$col = null;
}
$this->created_at = (null !== $col) ? PropelDateTime::newInstance($col, null, '\DateTime') : null;
$col = $row[TableMap::TYPE_NUM == $indexType ? 7 + $startcol : LangTableMap::translateFieldName('UpdatedAt', TableMap::TYPE_PHPNAME, $indexType)];
$col = $row[TableMap::TYPE_NUM == $indexType ? 8 + $startcol : LangTableMap::translateFieldName('UpdatedAt', TableMap::TYPE_PHPNAME, $indexType)];
if ($col === '0000-00-00 00:00:00') {
$col = null;
}
@@ -712,7 +753,7 @@ abstract class Lang implements ActiveRecordInterface
$this->ensureConsistency();
}
return $startcol + 8; // 8 = LangTableMap::NUM_HYDRATE_COLUMNS.
return $startcol + 9; // 9 = LangTableMap::NUM_HYDRATE_COLUMNS.
} catch (Exception $e) {
throw new PropelException("Error populating \Thelia\Model\Lang object", 0, $e);
@@ -947,6 +988,9 @@ abstract class Lang implements ActiveRecordInterface
if ($this->isColumnModified(LangTableMap::URL)) {
$modifiedColumns[':p' . $index++] = 'URL';
}
if ($this->isColumnModified(LangTableMap::POSITION)) {
$modifiedColumns[':p' . $index++] = 'POSITION';
}
if ($this->isColumnModified(LangTableMap::BY_DEFAULT)) {
$modifiedColumns[':p' . $index++] = 'BY_DEFAULT';
}
@@ -982,6 +1026,9 @@ abstract class Lang implements ActiveRecordInterface
case 'URL':
$stmt->bindValue($identifier, $this->url, PDO::PARAM_STR);
break;
case 'POSITION':
$stmt->bindValue($identifier, $this->position, PDO::PARAM_INT);
break;
case 'BY_DEFAULT':
$stmt->bindValue($identifier, $this->by_default, PDO::PARAM_INT);
break;
@@ -1069,12 +1116,15 @@ abstract class Lang implements ActiveRecordInterface
return $this->getUrl();
break;
case 5:
return $this->getByDefault();
return $this->getPosition();
break;
case 6:
return $this->getCreatedAt();
return $this->getByDefault();
break;
case 7:
return $this->getCreatedAt();
break;
case 8:
return $this->getUpdatedAt();
break;
default:
@@ -1110,9 +1160,10 @@ abstract class Lang implements ActiveRecordInterface
$keys[2] => $this->getCode(),
$keys[3] => $this->getLocale(),
$keys[4] => $this->getUrl(),
$keys[5] => $this->getByDefault(),
$keys[6] => $this->getCreatedAt(),
$keys[7] => $this->getUpdatedAt(),
$keys[5] => $this->getPosition(),
$keys[6] => $this->getByDefault(),
$keys[7] => $this->getCreatedAt(),
$keys[8] => $this->getUpdatedAt(),
);
$virtualColumns = $this->virtualColumns;
foreach($virtualColumns as $key => $virtualColumn)
@@ -1169,12 +1220,15 @@ abstract class Lang implements ActiveRecordInterface
$this->setUrl($value);
break;
case 5:
$this->setByDefault($value);
$this->setPosition($value);
break;
case 6:
$this->setCreatedAt($value);
$this->setByDefault($value);
break;
case 7:
$this->setCreatedAt($value);
break;
case 8:
$this->setUpdatedAt($value);
break;
} // switch()
@@ -1206,9 +1260,10 @@ abstract class Lang implements ActiveRecordInterface
if (array_key_exists($keys[2], $arr)) $this->setCode($arr[$keys[2]]);
if (array_key_exists($keys[3], $arr)) $this->setLocale($arr[$keys[3]]);
if (array_key_exists($keys[4], $arr)) $this->setUrl($arr[$keys[4]]);
if (array_key_exists($keys[5], $arr)) $this->setByDefault($arr[$keys[5]]);
if (array_key_exists($keys[6], $arr)) $this->setCreatedAt($arr[$keys[6]]);
if (array_key_exists($keys[7], $arr)) $this->setUpdatedAt($arr[$keys[7]]);
if (array_key_exists($keys[5], $arr)) $this->setPosition($arr[$keys[5]]);
if (array_key_exists($keys[6], $arr)) $this->setByDefault($arr[$keys[6]]);
if (array_key_exists($keys[7], $arr)) $this->setCreatedAt($arr[$keys[7]]);
if (array_key_exists($keys[8], $arr)) $this->setUpdatedAt($arr[$keys[8]]);
}
/**
@@ -1225,6 +1280,7 @@ abstract class Lang implements ActiveRecordInterface
if ($this->isColumnModified(LangTableMap::CODE)) $criteria->add(LangTableMap::CODE, $this->code);
if ($this->isColumnModified(LangTableMap::LOCALE)) $criteria->add(LangTableMap::LOCALE, $this->locale);
if ($this->isColumnModified(LangTableMap::URL)) $criteria->add(LangTableMap::URL, $this->url);
if ($this->isColumnModified(LangTableMap::POSITION)) $criteria->add(LangTableMap::POSITION, $this->position);
if ($this->isColumnModified(LangTableMap::BY_DEFAULT)) $criteria->add(LangTableMap::BY_DEFAULT, $this->by_default);
if ($this->isColumnModified(LangTableMap::CREATED_AT)) $criteria->add(LangTableMap::CREATED_AT, $this->created_at);
if ($this->isColumnModified(LangTableMap::UPDATED_AT)) $criteria->add(LangTableMap::UPDATED_AT, $this->updated_at);
@@ -1295,6 +1351,7 @@ abstract class Lang implements ActiveRecordInterface
$copyObj->setCode($this->getCode());
$copyObj->setLocale($this->getLocale());
$copyObj->setUrl($this->getUrl());
$copyObj->setPosition($this->getPosition());
$copyObj->setByDefault($this->getByDefault());
$copyObj->setCreatedAt($this->getCreatedAt());
$copyObj->setUpdatedAt($this->getUpdatedAt());
@@ -1336,6 +1393,7 @@ abstract class Lang implements ActiveRecordInterface
$this->code = null;
$this->locale = null;
$this->url = null;
$this->position = null;
$this->by_default = null;
$this->created_at = null;
$this->updated_at = null;

View File

@@ -23,6 +23,7 @@ use Thelia\Model\Map\LangTableMap;
* @method ChildLangQuery orderByCode($order = Criteria::ASC) Order by the code column
* @method ChildLangQuery orderByLocale($order = Criteria::ASC) Order by the locale column
* @method ChildLangQuery orderByUrl($order = Criteria::ASC) Order by the url column
* @method ChildLangQuery orderByPosition($order = Criteria::ASC) Order by the position column
* @method ChildLangQuery orderByByDefault($order = Criteria::ASC) Order by the by_default column
* @method ChildLangQuery orderByCreatedAt($order = Criteria::ASC) Order by the created_at column
* @method ChildLangQuery orderByUpdatedAt($order = Criteria::ASC) Order by the updated_at column
@@ -32,6 +33,7 @@ use Thelia\Model\Map\LangTableMap;
* @method ChildLangQuery groupByCode() Group by the code column
* @method ChildLangQuery groupByLocale() Group by the locale column
* @method ChildLangQuery groupByUrl() Group by the url column
* @method ChildLangQuery groupByPosition() Group by the position column
* @method ChildLangQuery groupByByDefault() Group by the by_default column
* @method ChildLangQuery groupByCreatedAt() Group by the created_at column
* @method ChildLangQuery groupByUpdatedAt() Group by the updated_at column
@@ -48,6 +50,7 @@ use Thelia\Model\Map\LangTableMap;
* @method ChildLang findOneByCode(string $code) Return the first ChildLang filtered by the code column
* @method ChildLang findOneByLocale(string $locale) Return the first ChildLang filtered by the locale column
* @method ChildLang findOneByUrl(string $url) Return the first ChildLang filtered by the url column
* @method ChildLang findOneByPosition(int $position) Return the first ChildLang filtered by the position column
* @method ChildLang findOneByByDefault(int $by_default) Return the first ChildLang filtered by the by_default column
* @method ChildLang findOneByCreatedAt(string $created_at) Return the first ChildLang filtered by the created_at column
* @method ChildLang findOneByUpdatedAt(string $updated_at) Return the first ChildLang filtered by the updated_at column
@@ -57,6 +60,7 @@ use Thelia\Model\Map\LangTableMap;
* @method array findByCode(string $code) Return ChildLang objects filtered by the code column
* @method array findByLocale(string $locale) Return ChildLang objects filtered by the locale column
* @method array findByUrl(string $url) Return ChildLang objects filtered by the url column
* @method array findByPosition(int $position) Return ChildLang objects filtered by the position column
* @method array findByByDefault(int $by_default) Return ChildLang objects filtered by the by_default column
* @method array findByCreatedAt(string $created_at) Return ChildLang objects filtered by the created_at column
* @method array findByUpdatedAt(string $updated_at) Return ChildLang objects filtered by the updated_at column
@@ -148,7 +152,7 @@ abstract class LangQuery extends ModelCriteria
*/
protected function findPkSimple($key, $con)
{
$sql = 'SELECT ID, TITLE, CODE, LOCALE, URL, BY_DEFAULT, CREATED_AT, UPDATED_AT FROM lang WHERE ID = :p0';
$sql = 'SELECT ID, TITLE, CODE, LOCALE, URL, POSITION, BY_DEFAULT, CREATED_AT, UPDATED_AT FROM lang WHERE ID = :p0';
try {
$stmt = $con->prepare($sql);
$stmt->bindValue(':p0', $key, PDO::PARAM_INT);
@@ -394,6 +398,47 @@ abstract class LangQuery extends ModelCriteria
return $this->addUsingAlias(LangTableMap::URL, $url, $comparison);
}
/**
* Filter the query on the position column
*
* Example usage:
* <code>
* $query->filterByPosition(1234); // WHERE position = 1234
* $query->filterByPosition(array(12, 34)); // WHERE position IN (12, 34)
* $query->filterByPosition(array('min' => 12)); // WHERE position > 12
* </code>
*
* @param mixed $position The value to use as filter.
* Use scalar values for equality.
* Use array values for in_array() equivalent.
* Use associative array('min' => $minValue, 'max' => $maxValue) for intervals.
* @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL
*
* @return ChildLangQuery The current query, for fluid interface
*/
public function filterByPosition($position = null, $comparison = null)
{
if (is_array($position)) {
$useMinMax = false;
if (isset($position['min'])) {
$this->addUsingAlias(LangTableMap::POSITION, $position['min'], Criteria::GREATER_EQUAL);
$useMinMax = true;
}
if (isset($position['max'])) {
$this->addUsingAlias(LangTableMap::POSITION, $position['max'], Criteria::LESS_EQUAL);
$useMinMax = true;
}
if ($useMinMax) {
return $this;
}
if (null === $comparison) {
$comparison = Criteria::IN;
}
}
return $this->addUsingAlias(LangTableMap::POSITION, $position, $comparison);
}
/**
* Filter the query on the by_default column
*

View File

@@ -57,7 +57,7 @@ class CurrencyTableMap extends TableMap
/**
* The total number of columns
*/
const NUM_COLUMNS = 7;
const NUM_COLUMNS = 8;
/**
* The number of lazy-loaded columns
@@ -67,7 +67,7 @@ class CurrencyTableMap extends TableMap
/**
* The number of columns to hydrate (NUM_COLUMNS - NUM_LAZY_LOAD_COLUMNS)
*/
const NUM_HYDRATE_COLUMNS = 7;
const NUM_HYDRATE_COLUMNS = 8;
/**
* the column name for the ID field
@@ -89,6 +89,11 @@ class CurrencyTableMap extends TableMap
*/
const RATE = 'currency.RATE';
/**
* the column name for the POSITION field
*/
const POSITION = 'currency.POSITION';
/**
* the column name for the BY_DEFAULT field
*/
@@ -125,12 +130,12 @@ class CurrencyTableMap extends TableMap
* e.g. self::$fieldNames[self::TYPE_PHPNAME][0] = 'Id'
*/
protected static $fieldNames = array (
self::TYPE_PHPNAME => array('Id', 'Code', 'Symbol', 'Rate', 'ByDefault', 'CreatedAt', 'UpdatedAt', ),
self::TYPE_STUDLYPHPNAME => array('id', 'code', 'symbol', 'rate', 'byDefault', 'createdAt', 'updatedAt', ),
self::TYPE_COLNAME => array(CurrencyTableMap::ID, CurrencyTableMap::CODE, CurrencyTableMap::SYMBOL, CurrencyTableMap::RATE, CurrencyTableMap::BY_DEFAULT, CurrencyTableMap::CREATED_AT, CurrencyTableMap::UPDATED_AT, ),
self::TYPE_RAW_COLNAME => array('ID', 'CODE', 'SYMBOL', 'RATE', 'BY_DEFAULT', 'CREATED_AT', 'UPDATED_AT', ),
self::TYPE_FIELDNAME => array('id', 'code', 'symbol', 'rate', 'by_default', 'created_at', 'updated_at', ),
self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, )
self::TYPE_PHPNAME => array('Id', 'Code', 'Symbol', 'Rate', 'Position', 'ByDefault', 'CreatedAt', 'UpdatedAt', ),
self::TYPE_STUDLYPHPNAME => array('id', 'code', 'symbol', 'rate', 'position', 'byDefault', 'createdAt', 'updatedAt', ),
self::TYPE_COLNAME => array(CurrencyTableMap::ID, CurrencyTableMap::CODE, CurrencyTableMap::SYMBOL, CurrencyTableMap::RATE, CurrencyTableMap::POSITION, CurrencyTableMap::BY_DEFAULT, CurrencyTableMap::CREATED_AT, CurrencyTableMap::UPDATED_AT, ),
self::TYPE_RAW_COLNAME => array('ID', 'CODE', 'SYMBOL', 'RATE', 'POSITION', 'BY_DEFAULT', 'CREATED_AT', 'UPDATED_AT', ),
self::TYPE_FIELDNAME => array('id', 'code', 'symbol', 'rate', 'position', 'by_default', 'created_at', 'updated_at', ),
self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, 7, )
);
/**
@@ -140,12 +145,12 @@ class CurrencyTableMap extends TableMap
* e.g. self::$fieldKeys[self::TYPE_PHPNAME]['Id'] = 0
*/
protected static $fieldKeys = array (
self::TYPE_PHPNAME => array('Id' => 0, 'Code' => 1, 'Symbol' => 2, 'Rate' => 3, 'ByDefault' => 4, 'CreatedAt' => 5, 'UpdatedAt' => 6, ),
self::TYPE_STUDLYPHPNAME => array('id' => 0, 'code' => 1, 'symbol' => 2, 'rate' => 3, 'byDefault' => 4, 'createdAt' => 5, 'updatedAt' => 6, ),
self::TYPE_COLNAME => array(CurrencyTableMap::ID => 0, CurrencyTableMap::CODE => 1, CurrencyTableMap::SYMBOL => 2, CurrencyTableMap::RATE => 3, CurrencyTableMap::BY_DEFAULT => 4, CurrencyTableMap::CREATED_AT => 5, CurrencyTableMap::UPDATED_AT => 6, ),
self::TYPE_RAW_COLNAME => array('ID' => 0, 'CODE' => 1, 'SYMBOL' => 2, 'RATE' => 3, 'BY_DEFAULT' => 4, 'CREATED_AT' => 5, 'UPDATED_AT' => 6, ),
self::TYPE_FIELDNAME => array('id' => 0, 'code' => 1, 'symbol' => 2, 'rate' => 3, 'by_default' => 4, 'created_at' => 5, 'updated_at' => 6, ),
self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, )
self::TYPE_PHPNAME => array('Id' => 0, 'Code' => 1, 'Symbol' => 2, 'Rate' => 3, 'Position' => 4, 'ByDefault' => 5, 'CreatedAt' => 6, 'UpdatedAt' => 7, ),
self::TYPE_STUDLYPHPNAME => array('id' => 0, 'code' => 1, 'symbol' => 2, 'rate' => 3, 'position' => 4, 'byDefault' => 5, 'createdAt' => 6, 'updatedAt' => 7, ),
self::TYPE_COLNAME => array(CurrencyTableMap::ID => 0, CurrencyTableMap::CODE => 1, CurrencyTableMap::SYMBOL => 2, CurrencyTableMap::RATE => 3, CurrencyTableMap::POSITION => 4, CurrencyTableMap::BY_DEFAULT => 5, CurrencyTableMap::CREATED_AT => 6, CurrencyTableMap::UPDATED_AT => 7, ),
self::TYPE_RAW_COLNAME => array('ID' => 0, 'CODE' => 1, 'SYMBOL' => 2, 'RATE' => 3, 'POSITION' => 4, 'BY_DEFAULT' => 5, 'CREATED_AT' => 6, 'UPDATED_AT' => 7, ),
self::TYPE_FIELDNAME => array('id' => 0, 'code' => 1, 'symbol' => 2, 'rate' => 3, 'position' => 4, 'by_default' => 5, 'created_at' => 6, 'updated_at' => 7, ),
self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, 7, )
);
/**
@@ -168,6 +173,7 @@ class CurrencyTableMap extends TableMap
$this->addColumn('CODE', 'Code', 'VARCHAR', false, 45, null);
$this->addColumn('SYMBOL', 'Symbol', 'VARCHAR', false, 45, null);
$this->addColumn('RATE', 'Rate', 'FLOAT', false, null, null);
$this->addColumn('POSITION', 'Position', 'INTEGER', false, null, null);
$this->addColumn('BY_DEFAULT', 'ByDefault', 'TINYINT', false, null, null);
$this->addColumn('CREATED_AT', 'CreatedAt', 'TIMESTAMP', false, null, null);
$this->addColumn('UPDATED_AT', 'UpdatedAt', 'TIMESTAMP', false, null, null);
@@ -351,6 +357,7 @@ class CurrencyTableMap extends TableMap
$criteria->addSelectColumn(CurrencyTableMap::CODE);
$criteria->addSelectColumn(CurrencyTableMap::SYMBOL);
$criteria->addSelectColumn(CurrencyTableMap::RATE);
$criteria->addSelectColumn(CurrencyTableMap::POSITION);
$criteria->addSelectColumn(CurrencyTableMap::BY_DEFAULT);
$criteria->addSelectColumn(CurrencyTableMap::CREATED_AT);
$criteria->addSelectColumn(CurrencyTableMap::UPDATED_AT);
@@ -359,6 +366,7 @@ class CurrencyTableMap extends TableMap
$criteria->addSelectColumn($alias . '.CODE');
$criteria->addSelectColumn($alias . '.SYMBOL');
$criteria->addSelectColumn($alias . '.RATE');
$criteria->addSelectColumn($alias . '.POSITION');
$criteria->addSelectColumn($alias . '.BY_DEFAULT');
$criteria->addSelectColumn($alias . '.CREATED_AT');
$criteria->addSelectColumn($alias . '.UPDATED_AT');

View File

@@ -57,7 +57,7 @@ class LangTableMap extends TableMap
/**
* The total number of columns
*/
const NUM_COLUMNS = 8;
const NUM_COLUMNS = 9;
/**
* The number of lazy-loaded columns
@@ -67,7 +67,7 @@ class LangTableMap extends TableMap
/**
* The number of columns to hydrate (NUM_COLUMNS - NUM_LAZY_LOAD_COLUMNS)
*/
const NUM_HYDRATE_COLUMNS = 8;
const NUM_HYDRATE_COLUMNS = 9;
/**
* the column name for the ID field
@@ -94,6 +94,11 @@ class LangTableMap extends TableMap
*/
const URL = 'lang.URL';
/**
* the column name for the POSITION field
*/
const POSITION = 'lang.POSITION';
/**
* the column name for the BY_DEFAULT field
*/
@@ -121,12 +126,12 @@ class LangTableMap extends TableMap
* e.g. self::$fieldNames[self::TYPE_PHPNAME][0] = 'Id'
*/
protected static $fieldNames = array (
self::TYPE_PHPNAME => array('Id', 'Title', 'Code', 'Locale', 'Url', 'ByDefault', 'CreatedAt', 'UpdatedAt', ),
self::TYPE_STUDLYPHPNAME => array('id', 'title', 'code', 'locale', 'url', 'byDefault', 'createdAt', 'updatedAt', ),
self::TYPE_COLNAME => array(LangTableMap::ID, LangTableMap::TITLE, LangTableMap::CODE, LangTableMap::LOCALE, LangTableMap::URL, LangTableMap::BY_DEFAULT, LangTableMap::CREATED_AT, LangTableMap::UPDATED_AT, ),
self::TYPE_RAW_COLNAME => array('ID', 'TITLE', 'CODE', 'LOCALE', 'URL', 'BY_DEFAULT', 'CREATED_AT', 'UPDATED_AT', ),
self::TYPE_FIELDNAME => array('id', 'title', 'code', 'locale', 'url', 'by_default', 'created_at', 'updated_at', ),
self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, 7, )
self::TYPE_PHPNAME => array('Id', 'Title', 'Code', 'Locale', 'Url', 'Position', 'ByDefault', 'CreatedAt', 'UpdatedAt', ),
self::TYPE_STUDLYPHPNAME => array('id', 'title', 'code', 'locale', 'url', 'position', 'byDefault', 'createdAt', 'updatedAt', ),
self::TYPE_COLNAME => array(LangTableMap::ID, LangTableMap::TITLE, LangTableMap::CODE, LangTableMap::LOCALE, LangTableMap::URL, LangTableMap::POSITION, LangTableMap::BY_DEFAULT, LangTableMap::CREATED_AT, LangTableMap::UPDATED_AT, ),
self::TYPE_RAW_COLNAME => array('ID', 'TITLE', 'CODE', 'LOCALE', 'URL', 'POSITION', 'BY_DEFAULT', 'CREATED_AT', 'UPDATED_AT', ),
self::TYPE_FIELDNAME => array('id', 'title', 'code', 'locale', 'url', 'position', 'by_default', 'created_at', 'updated_at', ),
self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, 7, 8, )
);
/**
@@ -136,12 +141,12 @@ class LangTableMap extends TableMap
* e.g. self::$fieldKeys[self::TYPE_PHPNAME]['Id'] = 0
*/
protected static $fieldKeys = array (
self::TYPE_PHPNAME => array('Id' => 0, 'Title' => 1, 'Code' => 2, 'Locale' => 3, 'Url' => 4, 'ByDefault' => 5, 'CreatedAt' => 6, 'UpdatedAt' => 7, ),
self::TYPE_STUDLYPHPNAME => array('id' => 0, 'title' => 1, 'code' => 2, 'locale' => 3, 'url' => 4, 'byDefault' => 5, 'createdAt' => 6, 'updatedAt' => 7, ),
self::TYPE_COLNAME => array(LangTableMap::ID => 0, LangTableMap::TITLE => 1, LangTableMap::CODE => 2, LangTableMap::LOCALE => 3, LangTableMap::URL => 4, LangTableMap::BY_DEFAULT => 5, LangTableMap::CREATED_AT => 6, LangTableMap::UPDATED_AT => 7, ),
self::TYPE_RAW_COLNAME => array('ID' => 0, 'TITLE' => 1, 'CODE' => 2, 'LOCALE' => 3, 'URL' => 4, 'BY_DEFAULT' => 5, 'CREATED_AT' => 6, 'UPDATED_AT' => 7, ),
self::TYPE_FIELDNAME => array('id' => 0, 'title' => 1, 'code' => 2, 'locale' => 3, 'url' => 4, 'by_default' => 5, 'created_at' => 6, 'updated_at' => 7, ),
self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, 7, )
self::TYPE_PHPNAME => array('Id' => 0, 'Title' => 1, 'Code' => 2, 'Locale' => 3, 'Url' => 4, 'Position' => 5, 'ByDefault' => 6, 'CreatedAt' => 7, 'UpdatedAt' => 8, ),
self::TYPE_STUDLYPHPNAME => array('id' => 0, 'title' => 1, 'code' => 2, 'locale' => 3, 'url' => 4, 'position' => 5, 'byDefault' => 6, 'createdAt' => 7, 'updatedAt' => 8, ),
self::TYPE_COLNAME => array(LangTableMap::ID => 0, LangTableMap::TITLE => 1, LangTableMap::CODE => 2, LangTableMap::LOCALE => 3, LangTableMap::URL => 4, LangTableMap::POSITION => 5, LangTableMap::BY_DEFAULT => 6, LangTableMap::CREATED_AT => 7, LangTableMap::UPDATED_AT => 8, ),
self::TYPE_RAW_COLNAME => array('ID' => 0, 'TITLE' => 1, 'CODE' => 2, 'LOCALE' => 3, 'URL' => 4, 'POSITION' => 5, 'BY_DEFAULT' => 6, 'CREATED_AT' => 7, 'UPDATED_AT' => 8, ),
self::TYPE_FIELDNAME => array('id' => 0, 'title' => 1, 'code' => 2, 'locale' => 3, 'url' => 4, 'position' => 5, 'by_default' => 6, 'created_at' => 7, 'updated_at' => 8, ),
self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, 7, 8, )
);
/**
@@ -165,6 +170,7 @@ class LangTableMap extends TableMap
$this->addColumn('CODE', 'Code', 'VARCHAR', false, 10, null);
$this->addColumn('LOCALE', 'Locale', 'VARCHAR', false, 45, null);
$this->addColumn('URL', 'Url', 'VARCHAR', false, 255, null);
$this->addColumn('POSITION', 'Position', 'INTEGER', false, null, null);
$this->addColumn('BY_DEFAULT', 'ByDefault', 'TINYINT', false, null, null);
$this->addColumn('CREATED_AT', 'CreatedAt', 'TIMESTAMP', false, null, null);
$this->addColumn('UPDATED_AT', 'UpdatedAt', 'TIMESTAMP', false, null, null);
@@ -333,6 +339,7 @@ class LangTableMap extends TableMap
$criteria->addSelectColumn(LangTableMap::CODE);
$criteria->addSelectColumn(LangTableMap::LOCALE);
$criteria->addSelectColumn(LangTableMap::URL);
$criteria->addSelectColumn(LangTableMap::POSITION);
$criteria->addSelectColumn(LangTableMap::BY_DEFAULT);
$criteria->addSelectColumn(LangTableMap::CREATED_AT);
$criteria->addSelectColumn(LangTableMap::UPDATED_AT);
@@ -342,6 +349,7 @@ class LangTableMap extends TableMap
$criteria->addSelectColumn($alias . '.CODE');
$criteria->addSelectColumn($alias . '.LOCALE');
$criteria->addSelectColumn($alias . '.URL');
$criteria->addSelectColumn($alias . '.POSITION');
$criteria->addSelectColumn($alias . '.BY_DEFAULT');
$criteria->addSelectColumn($alias . '.CREATED_AT');
$criteria->addSelectColumn($alias . '.UPDATED_AT');

View File

@@ -113,7 +113,7 @@ class ImageTest extends \PHPUnit_Framework_TestCase
/**
*
* Tru to process a non-existent file
* Try to process a non-existent file
*
* @expectedException \InvalidArgumentException
*/
@@ -129,6 +129,24 @@ class ImageTest extends \PHPUnit_Framework_TestCase
$image->processImage($event);
}
/**
*
* Try to process a file outside of the cache
*
* @expectedException \InvalidArgumentException
*/
public function testProcessImageOutsideValidPath()
{
$event = new ImageEvent($this->request);
$image = new Image($this->getContainer());
$event->setCacheFilepath("blablabla.png");
$event->setCacheSubdirectory("../../../");
$image->processImage($event);
}
/**
* No operation done on source file -> copie !
*/
@@ -317,4 +335,37 @@ class ImageTest extends \PHPUnit_Framework_TestCase
$image->processImage($event);
}
public function testClearTestsCache() {
$event = new ImageEvent($this->request);
$event->setCacheSubdirectory('tests');
$image = new Image($this->getContainer());
$image->clearCache($event);
}
public function testClearWholeCache() {
$event = new ImageEvent($this->request);
$image = new Image($this->getContainer());
$image->clearCache($event);
}
/**
* Try to clear directory ouside of the cache
*
* @expectedException \InvalidArgumentException
*/
public function testClearUnallowedPathCache() {
$event = new ImageEvent($this->request);
$event->setCacheSubdirectory('../../../..');
$image = new Image($this->getContainer());
$image->clearCache($event);
}
}

View File

@@ -27,6 +27,9 @@ use Thelia\Model\ConfigQuery;
class URL
{
const PATH_TO_FILE = true;
const WITH_INDEX_PAGE = false;
public static function getIndexPage()
{
return ConfigQuery::read('base_url', '/') . "index_dev.php"; // FIXME !
@@ -39,26 +42,29 @@ class URL
*
* @param string $path the relative path
* @param array $parameters An array of parameters
* @param boolean $path_only if true, getIndexPage() will not be added
* @param boolean $path_only if true (PATH_TO_FILE), getIndexPage() will not be added
*
* @return string The generated URL
*/
public static function absoluteUrl($path, array $parameters = array(), $path_only = false)
public static function absoluteUrl($path, array $parameters = null, $path_only = self::WITH_INDEX_PAGE)
{
// Already absolute ?
if (substr($path, 0, 4) != 'http') {
$root = $path_only ? ConfigQuery::read('base_url', '/') : self::getIndexPage();
$root = $path_only == self::PATH_TO_FILE ? ConfigQuery::read('base_url', '/') : self::getIndexPage();
$base = $root . '/' . ltrim($path, '/');
$base = rtrim($root, '/') . '/' . ltrim($path, '/');
} else
$base = $path;
$queryString = '';
if (! is_null($parameters)) {
foreach ($parameters as $name => $value) {
$queryString .= sprintf("%s=%s&", urlencode($name), urlencode($value));
}
}
$sepChar = strstr($base, '?') === false ? '?' : '&';

View File

@@ -21,3 +21,6 @@ Variables Config à initialiser:
- verifyStock : vérification du stock lors du paiement/ajout au panier. Defaut 1
- default_images_quality_percent : qualité par défaut des images générées (0 à 100, défaut: 75).
- original_image_delivery_mode : mode de mise à disposition des images originales (full resolution) dans le cache. 'symlink' pour un lien symbolique, 'copy' pour une copie
- images_library_path : chemin vers le répertoire où sont stockés les images source (defaut: local/media/images)
- image_cache_dir_from_web_root : le repértoire de base où sont cachées les images, relatif à /web (cache/images)
- imagine_graphic_driver : le drivers utilisé par Imagine (gd, imagik, gmagick), defaut: 'gd'

View File

@@ -1,4 +1,9 @@
<?php
use Thelia\Model\ProductImage;
use Propel\Runtime\Exception\PropelException;
use Thelia\Model\CategoryImage;
use Thelia\Model\FolderImage;
use Thelia\Model\ContentImage;
require __DIR__ . '/../core/bootstrap.php';
$thelia = new Thelia\Core\Thelia("dev", true);
@@ -10,8 +15,37 @@ $con->beginTransaction();
$currency = \Thelia\Model\CurrencyQuery::create()->filterByCode('EUR')->findOne();
function generate_image($image, $position, $typeobj, $id) {
global $faker;
$image
->setTitle($faker->text(20))
->setDescription($faker->text(250))
->setChapo($faker->text(40))
->setPostscriptum($faker->text(40))
->setPosition($position)
->setFile(sprintf("sample-image-%s.png", $id))
->save()
;
// Generate images
$image_data = file_get_contents("http://placehold.it/320x200&text=Image+for+$typeobj+ID+".$id);
$image_file = sprintf("%s/../local/media/images/%s/sample-image-%s.png", __DIR__, $typeobj, $id);
if (! is_dir(dirname($image_file))) mkdir(dirname($image_file), 0777, true);
if ($fh = fopen($image_file, "w")) {
fwrite($fh, $image_data);
fclose($fh);
}
}
try {
$stmt = $con->prepare("SET foreign_key_checks = 0");
$stmt->execute();
$category = Thelia\Model\CategoryQuery::create()
->find();
$category->delete();
@@ -50,6 +84,9 @@ try {
->find();
$content->delete();
$stmt = $con->prepare("SET foreign_key_checks = 1");
$stmt->execute();
//first category
$sweet = new Thelia\Model\Category();
$sweet->setParent(0);
@@ -60,6 +97,10 @@ try {
$sweet->save();
$image = new CategoryImage();
$image->setCategoryId($sweet->getId());
generate_image($image, 1, 'category', $sweet->getId());
//second category
$jeans = new Thelia\Model\Category();
$jeans->setParent(0);
@@ -70,6 +111,10 @@ try {
$jeans->save();
$image = new CategoryImage();
$image->setCategoryId($jeans->getId());
generate_image($image, 2, 'category', $jeans->getId());
//third category
$other = new Thelia\Model\Category();
$other->setParent($jeans->getId());
@@ -80,6 +125,10 @@ try {
$other->save();
$image = new CategoryImage();
$image->setCategoryId($other->getId());
generate_image($image, 3, 'category', $other->getId());
for ($i=1; $i <= 5; $i++) {
$product = new \Thelia\Model\Product();
$product->addCategory($sweet);
@@ -102,8 +151,12 @@ try {
$productPrice->setProductSaleElements($stock);
$productPrice->setCurrency($currency);
$productPrice->setPrice($faker->randomFloat(2, 20, 2500));
$productPrice->save();
$image = new ProductImage();
$image->setProductId($product->getId());
generate_image($image, $i, 'product', $product->getId());
}
for ($i=1; $i <= 5; $i++) {
@@ -130,6 +183,10 @@ try {
$productPrice->setPrice($faker->randomFloat(2, 20, 2500));
$productPrice->save();
$image = new ProductImage();
$image->setProductId($product->getId());
generate_image($image, $i, 'product', $product->getId());
}
//folders and contents
@@ -143,6 +200,10 @@ try {
$folder->save();
$image = new FolderImage();
$image->setFolderId($folder->getId());
generate_image($image, $i, 'folder', $folder->getId());
for($j=0; $j<rand(0, 4); $j++) {
$subfolder = new Thelia\Model\Folder();
$subfolder->setParent($folder->getId());
@@ -153,6 +214,10 @@ try {
$subfolder->save();
$image = new FolderImage();
$image->setFolderId($subfolder->getId());
generate_image($image, $j, 'folder', $subfolder->getId());
for($k=0; $k<rand(1, 5); $k++) {
$content = new Thelia\Model\Content();
$content->addFolder($subfolder);
@@ -162,6 +227,11 @@ try {
$content->setDescription($faker->text(255));
$content->save();
$image = new ContentImage();
$image->setContentId($content->getId());
generate_image($image, $k, 'content', $content->getId());
}
}
}
@@ -188,8 +258,13 @@ try {
}
$con->commit();
} catch (Exception $e) {
echo "error : ".$e->getMessage()."\n";
}
catch (PropelException $pe) {
echo "Propel error: ".$pe->getMessage()."\n".$pe->getTraceAsString();
$con->rollBack();
}
catch (Exception $e) {
echo "error occured : ".$e->getMessage()."\n".$e->getTraceAsString();
$con->rollBack();
}

View File

@@ -7,7 +7,7 @@ INSERT INTO `lang`(`id`,`title`,`code`,`locale`,`url`,`by_default`,`position`,`c
INSERT INTO `config` (`name`, `value`, `secured`, `hidden`, `created_at`, `updated_at`) VALUES
('session_config.default', '1', 1, 1, NOW(), NOW()),
('verifyStock', '1', 1, 0, NOW(), NOW());
('imagine_driver', 'gd', 1, 0, NOW(), NOW());
('imagine_graphic_driver', 'gd', 1, 0, NOW(), NOW());
('default_images_quality_percent', '75', 1, 0, NOW(), NOW());
('original_image_delivery_mode', 'symlink', 1, 0, NOW(), NOW());

View File

@@ -521,6 +521,7 @@ CREATE TABLE `lang`
`code` VARCHAR(10),
`locale` VARCHAR(45),
`url` VARCHAR(255),
`position` INTEGER NOT NULL,
`by_default` TINYINT,
`created_at` DATETIME,
`updated_at` DATETIME,
@@ -719,6 +720,7 @@ CREATE TABLE `currency`
`code` VARCHAR(45),
`symbol` VARCHAR(45),
`rate` FLOAT,
`position` INTEGER NOT NULL,
`by_default` TINYINT,
`created_at` DATETIME,
`updated_at` DATETIME,

View File

@@ -386,6 +386,7 @@
<column name="code" size="10" type="VARCHAR" />
<column name="locale" size="45" type="VARCHAR" />
<column name="url" size="255" type="VARCHAR" />
<column name="position" type="INTEGER" />
<column name="by_default" type="TINYINT" />
<behavior name="timestampable" />
</table>
@@ -545,6 +546,7 @@
<column name="code" size="45" type="VARCHAR" />
<column name="symbol" size="45" type="VARCHAR" />
<column name="rate" type="FLOAT" />
<column name="position" type="INTEGER" />
<column name="by_default" type="TINYINT" />
<behavior name="timestampable" />
<behavior name="i18n">

0
local/media/.gitkeep Normal file
View File

View File

@@ -0,0 +1,104 @@
{include file="includes/header.html"}
<div>
<h2>Category Images</h2>
<ul>
{loop type="category" name="jsvdfk"}
<li><p>Category id #ID: #TITLE</p>
<ul>
<li>
{loop type="image" name="image_test" category="#ID" width="200" height="100" resize_mode="borders"}
<p>Processed file URL: #IMAGE_URL</p>
<p>Original file URL: #ORIGINAL_IMAGE_URL</p>
<img src="#IMAGE_URL" />
{/loop}
{loop type="image" name="image_test" category="#ID"}
<p>Full size file URL: #IMAGE_URL</p>
<img src="#IMAGE_URL" />
{/loop}
{loop type="image" name="image_test" source="category" source_id="#ID"}
<p>source="category" source_id="x" argument style: Processed file URL: #IMAGE_URL</p>
{/loop}
</li>
</ul>
</li>
{/loop}
</ul>
</div>
<div>
<h2>Product Images</h2>
<ul>
{loop type="product" name="jsvdfk"}
<li><p>Product id #ID: #TITLE</p>
<ul>
<li>
{loop type="image" name="image_test" product="#ID" width="200" height="100" resize_mode="borders" effects="gamma:0.7" background_color="#cc8000"}
<p>Processed file URL: #IMAGE_URL</p>
<p>Original file URL: #ORIGINAL_IMAGE_URL</p>
<p>Images:</p>
<img src="#IMAGE_URL" />
{/loop}
{loop type="image" name="image_test" product="#ID" width="200" height="100" resize_mode="crop"}
<img src="#IMAGE_URL" />
{/loop}
{loop type="image" name="image_test" product="#ID" width="100" height="200" resize_mode="borders" background_color="#cc8000"}
<img src="#IMAGE_URL" />
{/loop}
{loop type="image" name="image_test" product="#ID" width="100" rotation="-20" background_color="#facabe"}
<img src="#IMAGE_URL" />
{/loop}
{loop type="image" name="image_test" product="#ID" width="200" height="100" resize_mode="borders" background_color="#facabe" effects="negative"}
<img src="#IMAGE_URL" />
{/loop}
</p>
</li>
</ul></li>
{/loop}
</ul>
</div>
<div>
<h2>Folder Images</h2>
<ul>
{loop type="folder" name="jsvdfk"}
<li><p>Folder id #ID: #TITLE</p>
<ul>
<li>
{loop type="image" name="image_test" folder="#ID" width="200" height="100" resize_mode="borders"}
<p>Processed file URL: #IMAGE_URL</p>
<p>Original file URL: #ORIGINAL_IMAGE_URL</p>
<img src="#IMAGE_URL" />
{/loop}
</li>
</ul>
</li>
{/loop}
</ul>
</div>
<div>
<h2>Content Images</h2>
<ul>
{loop type="content" name="jsvdfk"}
<li><p>Content id #ID: #TITLE</p>
<ul>
<li>
{loop type="image" name="image_test" content="#ID" width="200" height="100" resize_mode="borders"}
<p>Processed file URL: #IMAGE_URL</p>
<p>Original file URL: #ORIGINAL_IMAGE_URL</p>
<img src="#IMAGE_URL" />
{/loop}
</li>
</ul>
</li>
{/loop}
</ul>
</div>
{include file="includes/footer.html"}