Merge branch 'master' into template

Conflicts:
	core/lib/Thelia/Core/Event/TheliaEvents.php
	core/lib/Thelia/Model/Base/Module.php
	core/lib/Thelia/Model/Base/ModuleQuery.php
	core/lib/Thelia/Model/Map/ModuleTableMap.php
	install/thelia.sql
	local/config/schema.xml
This commit is contained in:
Etienne Roudeix
2013-09-17 12:44:34 +02:00
70 changed files with 2822 additions and 1461 deletions

View File

@@ -0,0 +1,178 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Action;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Thelia\Core\Event\CachedFileEvent;
use Thelia\Model\ConfigQuery;
use Thelia\Tools\URL;
/**
*
* Cached file management actions. This class handles file caching in the web space
*
* Basically, files are stored outside the web space (by default in local/media/<dirname>),
* and cached in the web space (by default in web/local/<dirname>).
*
* In the file cache directory, a subdirectory for files categories (eg. product, category, folder, etc.) is
* automatically created, and the cached file is created here. Plugin may use their own subdirectory as required.
*
* A copy (or symbolic link, by default) of the original file is created in the cache.
*
* @package Thelia\Action
* @author Franck Allimant <franck@cqfdev.fr>
*
*/
abstract class BaseCachedFile extends BaseAction
{
/**
* @return string root of the file cache directory in web space
*/
protected abstract function getCacheDirFromWebRoot();
/**
* Clear the file 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 CachedFileEvent $event
*/
public function clearCache(CachedFileEvent $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());
} elseif ($fileinfo->isDir()) {
$this->clearDirectory($fileinfo->getPathname());
}
}
}
/**
* Return the absolute URL to the cached file
*
* @param string $subdir the subdirectory related to cache base
* @param string $filename the safe filename, as returned by getCacheFilePath()
* @return string the absolute URL to the cached file
*/
protected function getCacheFileURL($subdir, $safe_filename)
{
$path = $this->getCachePathFromWebRoot($subdir);
return URL::getInstance()->absoluteUrl(sprintf("%s/%s", $path, $safe_filename), null, URL::PATH_TO_FILE);
}
/**
* Return the full path of the cached file
*
* @param string $subdir the subdirectory related to cache base
* @param string $filename the filename
* @param string $hashed_options a hash of transformation options, or null if no transformations have been applied
* @param boolean $forceOriginalDocument if true, the original file path in the cache dir is returned.
* @return string the cache directory path relative to Web Root
*/
protected function getCacheFilePath($subdir, $filename, $forceOriginalFile = false, $hashed_options = null)
{
$path = $this->getCachePath($subdir);
$safe_filename = preg_replace("[^:alnum:\-\._]", "-", strtolower(basename($filename)));
// Keep original safe name if no tranformations are applied
if ($forceOriginalFile || $hashed_options == null)
return sprintf("%s/%s", $path, $safe_filename);
else
return sprintf("%s/%s-%s", $path, $hashed_options, $safe_filename);
}
/**
* Return the cache directory path relative to Web Root
*
* @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 = null)
{
$cache_dir_from_web_root = $this->getCacheDirFromWebRoot();
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;
}
/**
* Return the absolute cache directory path
*
* @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 = null, $create_if_not_exists = true)
{
$cache_base = $this->getCachePathFromWebRoot($subdir);
$web_root = rtrim(THELIA_WEB_DIR, '/');
$path = sprintf("%s/%s", $web_root, $cache_base);
// Create directory (recursively) if it does not exists.
if ($create_if_not_exists && !is_dir($path)) {
if (!@mkdir($path, 0777, true)) {
throw new \RuntimeException(sprintf("Failed to create %s/%s file in 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;
}
}

View File

@@ -24,52 +24,88 @@
namespace Thelia\Action;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Model\Category as CategoryModel;
use Thelia\Model\CategoryQuery;
use Thelia\Model\Category as CategoryModel;
use Propel\Runtime\ActiveQuery\Criteria;
use Propel\Runtime\Propel;
use Thelia\Model\Map\CategoryTableMap;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Core\Event\CategoryUpdateEvent;
use Thelia\Core\Event\CategoryCreateEvent;
use Thelia\Core\Event\CategoryDeleteEvent;
use Thelia\Model\ConfigQuery;
use Thelia\Core\Event\UpdatePositionEvent;
use Thelia\Core\Event\CategoryToggleVisibilityEvent;
use Thelia\Core\Event\CategoryChangePositionEvent;
class Category extends BaseAction implements EventSubscriberInterface
{
/**
* Create a new category entry
*
* @param CategoryCreateEvent $event
*/
public function create(CategoryCreateEvent $event)
{
$category = new CategoryModel();
$category
->setDispatcher($this->getDispatcher())
->create(
$event->getTitle(),
$event->getParent(),
$event->getLocale()
);
->setLocale($event->getLocale())
->setTitle($event->getTitle())
->setParent($event->getParent())
->setVisible($event->getVisible())
->save()
;
$event->setCategory($category);
}
public function update(CategoryChangeEvent $event)
/**
* Change a category
*
* @param CategoryUpdateEvent $event
*/
public function update(CategoryUpdateEvent $event)
{
$search = CategoryQuery::create();
if (null !== $category = CategoryQuery::create()->findPk($event->getCategoryId())) {
$category
->setDispatcher($this->getDispatcher())
->setLocale($event->getLocale())
->setTitle($event->getTitle())
->setDescription($event->getDescription())
->setChapo($event->getChapo())
->setPostscriptum($event->getPostscriptum())
->setParent($event->getParent())
->setVisible($event->getVisible())
->save();
$event->setCategory($category);
}
}
/**
* Delete a category
* Delete a category entry
*
* @param ActionEvent $event
* @param CategoryDeleteEvent $event
*/
public function delete(CategoryDeleteEvent $event)
{
$category = CategoryQuery::create()->findPk($event->getCategoryId());
if (null !== $category = CategoryQuery::create()->findPk($event->getCategoryId())) {
if ($category !== null) {
$category
->setDispatcher($this->getDispatcher())
->delete()
;
$category->setDispatcher($this->getDispatcher())->delete();
$event->setCategory($category);
}
}
@@ -80,178 +116,48 @@ class Category extends BaseAction implements EventSubscriberInterface
*/
public function toggleVisibility(CategoryToggleVisibilityEvent $event)
{
$category = CategoryQuery::create()->findPk($event->getCategoryId());
$category = $event->getCategory();
if ($category !== null) {
$category
->setDispatcher($this->getDispatcher())
->setVisible($category->getVisible() ? false : true)
->save()
$category
->setDispatcher($this->getDispatcher())
->setVisible($category->getVisible() ? false : true)
->save()
;
}
/**
* Changes position, selecting absolute ou relative change.
*
* @param CategoryChangePositionEvent $event
*/
public function updatePosition(UpdatePositionEvent $event)
{
if (null !== $category = CategoryQuery::create()->findPk($event->getObjectId())) {
$category->setDispatcher($this->getDispatcher());
$mode = $event->getMode();
if ($mode == UpdatePositionEvent::POSITION_ABSOLUTE)
return $category->changeAbsolutePosition($event->getPosition());
else if ($mode == UpdatePositionEvent::POSITION_UP)
return $category->movePositionUp();
else if ($mode == UpdatePositionEvent::POSITION_DOWN)
return $category->movePositionDown();
}
}
/**
* Changes category position, selecting absolute ou relative change.
*
* @param CategoryChangePositionEvent $event
*/
public function changePosition(CategoryChangePositionEvent $event)
{
if ($event->getMode() == CategoryChangePositionEvent::POSITION_ABSOLUTE)
return $this->changeAbsolutePosition($event);
else
return $this->exchangePosition($event);
}
/**
* Move up or down a category
*
* @param CategoryChangePositionEvent $event
*/
protected function exchangePosition(CategoryChangePositionEvent $event)
{
$category = CategoryQuery::create()->findPk($event->getCategoryId());
if ($category !== null) {
// The current position of the category
$my_position = $category->getPosition();
// Find category to exchange position with
$search = CategoryQuery::create()
->filterByParent($category->getParent());
// Up or down ?
if ($event->getMode() == CategoryChangePositionEvent::POSITION_UP) {
// Find the category immediately before me
$search->filterByPosition(array('max' => $my_position-1))->orderByPosition(Criteria::DESC);
} elseif ($event->getMode() == CategoryChangePositionEvent::POSITION_DOWN) {
// Find the category immediately after me
$search->filterByPosition(array('min' => $my_position+1))->orderByPosition(Criteria::ASC);
} else
return;
$result = $search->findOne();
// If we found the proper category, exchange their positions
if ($result) {
$cnx = Propel::getWriteConnection(CategoryTableMap::DATABASE_NAME);
$cnx->beginTransaction();
try {
$category
->setDispatcher($this->getDispatcher())
->setPosition($result->getPosition())
->save()
;
$result->setPosition($my_position)->save();
$cnx->commit();
} catch (Exception $e) {
$cnx->rollback();
}
}
}
}
/**
* Changes category position
*
* @param CategoryChangePositionEvent $event
*/
protected function changeAbsolutePosition(CategoryChangePositionEvent $event)
{
$category = CategoryQuery::create()->findPk($event->getCategoryId());
if ($category !== null) {
// The required position
$new_position = $event->getPosition();
// The current position
$current_position = $category->getPosition();
if ($new_position != null && $new_position > 0 && $new_position != $current_position) {
// Find categories to offset
$search = CategoryQuery::create()->filterByParent($category->getParent());
if ($new_position > $current_position) {
// The new position is after the current position -> we will offset + 1 all categories located between us and the new position
$search->filterByPosition(array('min' => 1+$current_position, 'max' => $new_position));
$delta = -1;
} else {
// The new position is brefore the current position -> we will offset - 1 all categories located between us and the new position
$search->filterByPosition(array('min' => $new_position, 'max' => $current_position - 1));
$delta = 1;
}
$results = $search->find();
$cnx = Propel::getWriteConnection(CategoryTableMap::DATABASE_NAME);
$cnx->beginTransaction();
try {
foreach ($results as $result) {
$result->setPosition($result->getPosition() + $delta)->save($cnx);
}
$category
->setDispatcher($this->getDispatcher())
->setPosition($new_position)
->save($cnx)
;
$cnx->commit();
} catch (Exception $e) {
$cnx->rollback();
}
}
}
}
/**
* Returns an array of event names this subscriber listens to.
*
* The array keys are event names and the value can be:
*
* * The method name to call (priority defaults to 0)
* * An array composed of the method name to call and the priority
* * An array of arrays composed of the method names to call and respective
* priorities, or 0 if unset
*
* For instance:
*
* * array('eventName' => 'methodName')
* * array('eventName' => array('methodName', $priority))
* * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
*
* @return array The event names to listen to
*
* @api
* {@inheritDoc}
*/
public static function getSubscribedEvents()
{
return array(
TheliaEvents::CATEGORY_CREATE => array("create", 128),
TheliaEvents::CATEGORY_UPDATE => array("update", 128),
TheliaEvents::CATEGORY_DELETE => array("delete", 128),
TheliaEvents::CATEGORY_CREATE => array("create", 128),
TheliaEvents::CATEGORY_UPDATE => array("update", 128),
TheliaEvents::CATEGORY_DELETE => array("delete", 128),
TheliaEvents::CATEGORY_TOGGLE_VISIBILITY => array("toggleVisibility", 128),
TheliaEvents::CATEGORY_CHANGE_POSITION => array("changePosition", 128),
"action.updateCategoryPositionU" => array("changePositionUp", 128),
"action.updateCategoryPositionDown" => array("changePositionDown", 128),
"action.updateCategoryPosition" => array("changePosition", 128),
TheliaEvents::CATEGORY_UPDATE_POSITION => array("updatePosition", 128)
);
}
}

View File

@@ -22,7 +22,6 @@
/*************************************************************************************/
namespace Thelia\Action;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Thelia\Model\ConfigQuery;
@@ -45,18 +44,9 @@ class Config extends BaseAction implements EventSubscriberInterface
{
$config = new ConfigModel();
$config
->setDispatcher($this->getDispatcher())
->setName($event->getEventName())
->setValue($event->getValue())
->setLocale($event->getLocale())
->setTitle($event->getTitle())
->setHidden($event->getHidden())
->setSecured($event->getSecured())
->save()
;
$config->setDispatcher($this->getDispatcher())->setName($event->getEventName())->setValue($event->getValue())
->setLocale($event->getLocale())->setTitle($event->getTitle())->setHidden($event->getHidden())
->setSecured($event->getSecured())->save();
$event->setConfig($config);
}
@@ -70,18 +60,13 @@ class Config extends BaseAction implements EventSubscriberInterface
{
$search = ConfigQuery::create();
if (null !== $config = $search->findOneById($event->getConfigId())) {
if (null !== $config = $search->findPk($event->getConfigId())) {
if ($event->getValue() !== $config->getValue()) {
$config
->setDispatcher($this->getDispatcher())
$config->setDispatcher($this->getDispatcher())->setValue($event->getValue())->save();
->setValue($event->getValue())
->save()
;
$event->setConfig($config);
$event->setConfig($config);
}
}
}
@@ -95,23 +80,12 @@ class Config extends BaseAction implements EventSubscriberInterface
{
$search = ConfigQuery::create();
if (null !== $config = ConfigQuery::create()->findOneById($event->getConfigId())) {
if (null !== $config = ConfigQuery::create()->findPk($event->getConfigId())) {
$config
->setDispatcher($this->getDispatcher())
->setName($event->getEventName())
->setValue($event->getValue())
->setHidden($event->getHidden())
->setSecured($event->getSecured())
->setLocale($event->getLocale())
->setTitle($event->getTitle())
->setDescription($event->getDescription())
->setChapo($event->getChapo())
->setPostscriptum($event->getPostscriptum())
->save();
$config->setDispatcher($this->getDispatcher())->setName($event->getEventName())->setValue($event->getValue())
->setHidden($event->getHidden())->setSecured($event->getSecured())->setLocale($event->getLocale())
->setTitle($event->getTitle())->setDescription($event->getDescription())->setChapo($event->getChapo())
->setPostscriptum($event->getPostscriptum())->save();
$event->setConfig($config);
}
@@ -125,14 +99,11 @@ class Config extends BaseAction implements EventSubscriberInterface
public function delete(ConfigDeleteEvent $event)
{
if (null !== ($config = ConfigQuery::create()->findOneById($event->getConfigId()))) {
if (null !== ($config = ConfigQuery::create()->findPk($event->getConfigId()))) {
if (! $config->getSecured()) {
if (!$config->getSecured()) {
$config
->setDispatcher($this->getDispatcher())
->delete()
;
$config->setDispatcher($this->getDispatcher())->delete();
$event->setConfig($config);
}
@@ -145,10 +116,15 @@ class Config extends BaseAction implements EventSubscriberInterface
public static function getSubscribedEvents()
{
return array(
TheliaEvents::CONFIG_CREATE => array("create", 128),
TheliaEvents::CONFIG_SETVALUE => array("setValue", 128),
TheliaEvents::CONFIG_UPDATE => array("modify", 128),
TheliaEvents::CONFIG_DELETE => array("delete", 128),
TheliaEvents::CONFIG_CREATE => array(
"create", 128
), TheliaEvents::CONFIG_SETVALUE => array(
"setValue", 128
), TheliaEvents::CONFIG_UPDATE => array(
"modify", 128
), TheliaEvents::CONFIG_DELETE => array(
"delete", 128
),
);
}
}

View File

@@ -71,7 +71,7 @@ class Currency extends BaseAction implements EventSubscriberInterface
{
$search = CurrencyQuery::create();
if (null !== $currency = CurrencyQuery::create()->findOneById($event->getCurrencyId())) {
if (null !== $currency = CurrencyQuery::create()->findPk($event->getCurrencyId())) {
$currency
->setDispatcher($this->getDispatcher())
@@ -97,7 +97,7 @@ class Currency extends BaseAction implements EventSubscriberInterface
{
$search = CurrencyQuery::create();
if (null !== $currency = CurrencyQuery::create()->findOneById($event->getCurrencyId())) {
if (null !== $currency = CurrencyQuery::create()->findPk($event->getCurrencyId())) {
if ($currency->getByDefault() != $event->getIsDefault()) {
@@ -123,7 +123,7 @@ class Currency extends BaseAction implements EventSubscriberInterface
public function delete(CurrencyDeleteEvent $event)
{
if (null !== ($currency = CurrencyQuery::create()->findOneById($event->getCurrencyId()))) {
if (null !== ($currency = CurrencyQuery::create()->findPk($event->getCurrencyId()))) {
$currency
->setDispatcher($this->getDispatcher())

View File

@@ -0,0 +1,139 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Action;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Thelia\Core\Event\DocumentEvent;
use Thelia\Model\ConfigQuery;
use Thelia\Tools\URL;
use Imagine\Document\ImagineInterface;
use Imagine\Document\DocumentInterface;
use Imagine\Document\Box;
use Imagine\Document\Color;
use Imagine\Document\Point;
use Thelia\Exception\DocumentException;
use Thelia\Core\Event\TheliaEvents;
/**
*
* Document management actions. This class handles document processing an caching.
*
* Basically, documents are stored outside the web space (by default in local/media/documents),
* and cached in the web space (by default in web/local/documents).
*
* In the documents caches directory, a subdirectory for documents categories (eg. product, category, folder, etc.) is
* automatically created, and the cached document is created here. Plugin may use their own subdirectory as required.
*
* The cached document name contains a hash of the processing options, and the original (normalized) name of the document.
*
* A copy (or symbolic link, by default) of the original document is always created in the cache, so that the full
* resolution document is always available.
*
* Various document processing options are available :
*
* - resizing, with border, crop, or by keeping document 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 document Gamma to the specified value. Example: gamma:0.7
* - grayscale or greyscale: switch document to grayscale
* - colorize:color : apply a color mask to the document. Exemple: colorize:#ff2244
* - negative : transform the document in its negative equivalent
* - vflip or vertical_flip : vertical flip
* - hflip or horizontal_flip : horizontal flip
*
* If a problem occurs, an DocumentException may be thrown.
*
* @package Thelia\Action
* @author Franck Allimant <franck@cqfdev.fr>
*
*/
class Document extends BaseCachedFile implements EventSubscriberInterface
{
/**
* @return string root of the document cache directory in web space
*/
protected function getCacheDirFromWebRoot() {
return ConfigQuery::read('document_cache_dir_from_web_root', 'cache');
}
/**
* Process document and write the result in the document cache.
*
* When the original document is required, create either a symbolic link with the
* original document in the cache dir, or copy it in the cache dir if it's not already done.
*
* This method updates the cache_file_path and file_url attributes of the event
*
* @param DocumentEvent $event
* @throws \InvalidArgumentException, DocumentException
*/
public function processDocument(DocumentEvent $event)
{
$subdir = $event->getCacheSubdirectory();
$source_file = $event->getSourceFilepath();
if (null == $subdir || null == $source_file) {
throw new \InvalidArgumentException("Cache sub-directory and source file path cannot be null");
}
$originalDocumentPathInCache = $this->getCacheFilePath($subdir, $source_file, true);
if (! file_exists($originalDocumentPathInCache)) {
if (! file_exists($source_file)) {
throw new DocumentException(sprintf("Source document file %s does not exists.", $source_file));
}
$mode = ConfigQuery::read('original_document_delivery_mode', 'symlink');
if ($mode == 'symlink') {
if (false == symlink($source_file, $originalDocumentPathInCache)) {
throw new DocumentException(sprintf("Failed to create symbolic link for %s in %s document cache directory", basename($source_file), $subdir));
}
} else {// mode = 'copy'
if (false == @copy($source_file, $originalDocumentPathInCache)) {
throw new DocumentException(sprintf("Failed to copy %s in %s document cache directory", basename($source_file), $subdir));
}
}
}
// Compute the document URL
$document_url = $this->getCacheFileURL($subdir, basename($originalDocumentPathInCache));
// Update the event with file path and file URL
$event->setDocumentPath($originalDocumentPathInCache);
$event->setDocumentUrl(URL::getInstance()->absoluteUrl($document_url, null, URL::PATH_TO_FILE));
}
public static function getSubscribedEvents()
{
return array(
TheliaEvents::DOCUMENT_PROCESS => array("processDocument", 128),
TheliaEvents::DOCUMENT_CLEAR_CACHE => array("clearCache", 128),
);
}
}

View File

@@ -71,7 +71,7 @@ use Thelia\Core\Event\TheliaEvents;
* @author Franck Allimant <franck@cqfdev.fr>
*
*/
class Image extends BaseAction implements EventSubscriberInterface
class Image extends BaseCachedFile implements EventSubscriberInterface
{
// Resize mode constants
const EXACT_RATIO_WITH_BORDERS = 1;
@@ -79,38 +79,10 @@ class Image extends BaseAction implements EventSubscriberInterface
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
* @return string root of the image cache directory in web space
*/
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());
} elseif ($fileinfo->isDir()) {
$this->clearDirectory($fileinfo->getPathname());
}
}
protected function getCacheDirFromWebRoot() {
return ConfigQuery::read('image_cache_dir_from_web_root', 'cache');
}
/**
@@ -138,9 +110,9 @@ class Image extends BaseAction implements EventSubscriberInterface
// echo basename($source_file).": ";
// Find cached file path
$cacheFilePath = $this->getCacheFilePath($subdir, $source_file, $event);
$cacheFilePath = $this->getCacheFilePath($subdir, $source_file, $event->isOriginalImage(), $event->getOptionsHash());
$originalImagePathInCache = $this->getCacheFilePath($subdir, $source_file, $event, true);
$originalImagePathInCache = $this->getCacheFilePath($subdir, $source_file, true);
if (! file_exists($cacheFilePath)) {
@@ -359,94 +331,6 @@ class Image extends BaseAction implements EventSubscriberInterface
return $image;
}
/**
* Return the absolute URL to the cached image
*
* @param string $subdir the subdirectory related to cache base
* @param string $filename the safe filename, as returned by getCacheFilePath()
* @return string the absolute URL to the cached image
*/
protected function getCacheFileURL($subdir, $safe_filename)
{
$path = $this->getCachePathFromWebRoot($subdir);
return URL::getInstance()->absoluteUrl(sprintf("%s/%s", $path, $safe_filename), null, URL::PATH_TO_FILE);
}
/**
* Return the full path of the cached file
*
* @param string $subdir the subdirectory related to cache base
* @param string $filename the filename
* @param boolean $forceOriginalImage if true, the origiunal image path in the cache dir is returned.
* @return string the cache directory path relative to Web Root
*/
protected function getCacheFilePath($subdir, $filename, ImageEvent $event, $forceOriginalImage = false)
{
$path = $this->getCachePath($subdir);
$safe_filename = preg_replace("[^:alnum:\-\._]", "-", strtolower(basename($filename)));
// Keep original safe name if no tranformations are applied
if ($forceOriginalImage || $event->isOriginalImage())
return sprintf("%s/%s", $path, $safe_filename);
else
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, or null to get the cache directory only.
* @return string the cache directory path relative to Web Root
*/
protected function getCachePathFromWebRoot($subdir = null)
{
$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;
}
/**
* Return the absolute cache directory path
*
* @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 = null, $create_if_not_exists = true)
{
$cache_base = $this->getCachePathFromWebRoot($subdir);
$web_root = rtrim(THELIA_WEB_DIR, '/');
$path = sprintf("%s/%s", $web_root, $cache_base);
// Create directory (recursively) if it does not exists.
if ($create_if_not_exists && !is_dir($path)) {
if (!@mkdir($path, 0777, true)) {
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;
}
/**
* Create a new Imagine object using current driver configuration
*

View File

@@ -70,7 +70,7 @@ class Message extends BaseAction implements EventSubscriberInterface
{
$search = MessageQuery::create();
if (null !== $message = MessageQuery::create()->findOneById($event->getMessageId())) {
if (null !== $message = MessageQuery::create()->findPk($event->getMessageId())) {
$message
->setDispatcher($this->getDispatcher())
@@ -99,7 +99,7 @@ class Message extends BaseAction implements EventSubscriberInterface
public function delete(MessageDeleteEvent $event)
{
if (null !== ($message = MessageQuery::create()->findOneById($event->getMessageId()))) {
if (null !== ($message = MessageQuery::create()->findPk($event->getMessageId()))) {
$message
->setDispatcher($this->getDispatcher())