diff --git a/Readme.md b/Readme.md index 791b61d1e..ac0862dae 100755 --- a/Readme.md +++ b/Readme.md @@ -12,14 +12,33 @@ Here is the most recent developed code for the next major version (v2). You can Most part of the code can possibly change, a large part will be refactor soon, graphical setup does not exist yet. +Requirements +------------ + +* php 5.4 +* apache 2 +* mysql 5 + +If you use Mac OSX, it still doesn't use php 5.4 as default php version... There are many solutions for you : + +* use linux (the best one) +* use last MAMP version and put the php bin directory in your path : + +```bash +export PATH=/Applications/MAMP/bin/php/php5.4.x/bin/:$PATH +``` + +* configure a complete development environment : http://php-osx.liip.ch/ +* use a virtual machine with vagrant and puppet : https://puphpet.com/ + Installation ------------ ``` bash $ git clone --recursive https://github.com/thelia/thelia.git $ cd thelia -$ wget http://getcomposer.org/composer.phar -$ php composer.phar install +$ curl -sS https://getcomposer.org/installer | php +$ php composer.phar install --optimize-autoloader ``` Finish the installation using cli tools : diff --git a/composer.json b/composer.json index 2d315bd3a..4a3798384 100755 --- a/composer.json +++ b/composer.json @@ -36,7 +36,8 @@ "simplepie/simplepie": "dev-master", "imagine/imagine": "dev-master", - "symfony/icu": "1.0" + "symfony/icu": "1.0", + "swiftmailer/swiftmailer": "5.0.*" }, "require-dev" : { "phpunit/phpunit": "3.7.*", @@ -53,9 +54,5 @@ "": "local/modules/", "Thelia" : "core/lib/" } - }, - "scripts" : { - "post-update-cmd": "composer dump-autoload -o", - "post-install-cmd": "composer dump-autoload -o" } } diff --git a/composer.lock b/composer.lock index 61160ea49..b0310c075 100755 --- a/composer.lock +++ b/composer.lock @@ -3,7 +3,7 @@ "This file locks the dependencies of your project to a known state", "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" ], - "hash": "28dfdc7a840f9e70df422581f82a871f", + "hash": "a40be01c82e68ba0c446dc204d2667da", "packages": [ { "name": "imagine/imagine", @@ -445,6 +445,55 @@ ], "time": "2013-07-02 16:38:47" }, + { + "name": "swiftmailer/swiftmailer", + "version": "v5.0.2", + "source": { + "type": "git", + "url": "https://github.com/swiftmailer/swiftmailer.git", + "reference": "f3917ecef35a4e4d98b303eb9fee463bc983f379" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/f3917ecef35a4e4d98b303eb9fee463bc983f379", + "reference": "f3917ecef35a4e4d98b303eb9fee463bc983f379", + "shasum": "" + }, + "require": { + "php": ">=5.2.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.1-dev" + } + }, + "autoload": { + "files": [ + "lib/swift_required.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Chris Corbyn" + } + ], + "description": "Swiftmailer, free feature-rich PHP mailer", + "homepage": "http://swiftmailer.org", + "keywords": [ + "mail", + "mailer" + ], + "time": "2013-08-30 12:35:21" + }, { "name": "symfony-cmf/routing", "version": "1.0.0", diff --git a/core/lib/Thelia/Action/BaseCachedFile.php b/core/lib/Thelia/Action/BaseCachedFile.php new file mode 100644 index 000000000..b66496e07 --- /dev/null +++ b/core/lib/Thelia/Action/BaseCachedFile.php @@ -0,0 +1,178 @@ +. */ +/* */ +/*************************************************************************************/ + +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/), + * and cached in the web space (by default in web/local/). + * + * 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 + * + */ +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; + } +} \ No newline at end of file diff --git a/core/lib/Thelia/Action/Category.php b/core/lib/Thelia/Action/Category.php index 297cd64da..a34f4a85e 100755 --- a/core/lib/Thelia/Action/Category.php +++ b/core/lib/Thelia/Action/Category.php @@ -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) ); } } diff --git a/core/lib/Thelia/Action/Config.php b/core/lib/Thelia/Action/Config.php index 83df28524..f8a7c027c 100644 --- a/core/lib/Thelia/Action/Config.php +++ b/core/lib/Thelia/Action/Config.php @@ -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 + ), ); } } diff --git a/core/lib/Thelia/Action/Currency.php b/core/lib/Thelia/Action/Currency.php index 7908d1f0d..946fee375 100644 --- a/core/lib/Thelia/Action/Currency.php +++ b/core/lib/Thelia/Action/Currency.php @@ -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()) diff --git a/core/lib/Thelia/Action/Document.php b/core/lib/Thelia/Action/Document.php new file mode 100644 index 000000000..86fc51ac5 --- /dev/null +++ b/core/lib/Thelia/Action/Document.php @@ -0,0 +1,139 @@ +. */ +/* */ +/*************************************************************************************/ + +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 + * + */ +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), + ); + } +} diff --git a/core/lib/Thelia/Action/Image.php b/core/lib/Thelia/Action/Image.php index 66baffdbb..4660f93b8 100755 --- a/core/lib/Thelia/Action/Image.php +++ b/core/lib/Thelia/Action/Image.php @@ -71,7 +71,7 @@ use Thelia\Core\Event\TheliaEvents; * @author Franck Allimant * */ -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 * diff --git a/core/lib/Thelia/Action/Message.php b/core/lib/Thelia/Action/Message.php index faac35bf2..8918913fe 100644 --- a/core/lib/Thelia/Action/Message.php +++ b/core/lib/Thelia/Action/Message.php @@ -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()) diff --git a/core/lib/Thelia/Action/Template.php b/core/lib/Thelia/Action/Template.php index a06e10430..18174dd26 100644 --- a/core/lib/Thelia/Action/Template.php +++ b/core/lib/Thelia/Action/Template.php @@ -42,6 +42,14 @@ use Thelia\Core\Event\TemplateEvent; use Thelia\Model\TemplateTemplate; use Thelia\Model\TemplateTemplateQuery; use Thelia\Model\ProductQuery; +use Thelia\Core\Event\TemplateAddAttributeEvent; +use Thelia\Core\Event\TemplateDeleteAttributeEvent; +use Thelia\Model\AttributeTemplateQuery; +use Thelia\Model\AttributeTemplate; +use Thelia\Core\Event\TemplateDeleteFeatureEvent; +use Thelia\Core\Event\TemplateAddFeatureEvent; +use Thelia\Model\FeatureTemplateQuery; +use Thelia\Model\FeatureTemplate; class Template extends BaseAction implements EventSubscriberInterface { @@ -113,6 +121,54 @@ class Template extends BaseAction implements EventSubscriberInterface } } + public function addAttribute(TemplateAddAttributeEvent $event) { + + if (null === AttributeTemplateQuery::create()->filterByAttributeId($event->getAttributeId())->filterByTemplate($event->getTemplate())->findOne()) { + + $attribute_template = new AttributeTemplate(); + + $attribute_template + ->setAttributeId($event->getAttributeId()) + ->setTemplate($event->getTemplate()) + ->save() + ; + } + } + + public function deleteAttribute(TemplateDeleteAttributeEvent $event) { + + $attribute_template = AttributeTemplateQuery::create() + ->filterByAttributeId($event->getAttributeId()) + ->filterByTemplate($event->getTemplate())->findOne() + ; + + if ($attribute_template !== null) $attribute_template->delete(); + } + + public function addFeature(TemplateAddFeatureEvent $event) { + + if (null === FeatureTemplateQuery::create()->filterByFeatureId($event->getFeatureId())->filterByTemplate($event->getTemplate())->findOne()) { + + $feature_template = new FeatureTemplate(); + + $feature_template + ->setFeatureId($event->getFeatureId()) + ->setTemplate($event->getTemplate()) + ->save() + ; + } + } + + public function deleteFeature(TemplateDeleteFeatureEvent $event) { + + $feature_template = FeatureTemplateQuery::create() + ->filterByFeatureId($event->getFeatureId()) + ->filterByTemplate($event->getTemplate())->findOne() + ; + + if ($feature_template !== null) $feature_template->delete(); + } + /** * {@inheritDoc} */ @@ -122,6 +178,13 @@ class Template extends BaseAction implements EventSubscriberInterface TheliaEvents::TEMPLATE_CREATE => array("create", 128), TheliaEvents::TEMPLATE_UPDATE => array("update", 128), TheliaEvents::TEMPLATE_DELETE => array("delete", 128), + + TheliaEvents::TEMPLATE_ADD_ATTRIBUTE => array("addAttribute", 128), + TheliaEvents::TEMPLATE_DELETE_ATTRIBUTE => array("deleteAttribute", 128), + + TheliaEvents::TEMPLATE_ADD_FEATURE => array("addFeature", 128), + TheliaEvents::TEMPLATE_DELETE_FEATURE => array("deleteFeature", 128), + ); } } \ No newline at end of file diff --git a/core/lib/Thelia/Config/Resources/config.xml b/core/lib/Thelia/Config/Resources/config.xml index d8211c6cc..2a344bad9 100755 --- a/core/lib/Thelia/Config/Resources/config.xml +++ b/core/lib/Thelia/Config/Resources/config.xml @@ -51,7 +51,7 @@
- + @@ -82,6 +82,9 @@ + + + @@ -264,6 +267,10 @@ + + + + diff --git a/core/lib/Thelia/Config/Resources/routing/admin.xml b/core/lib/Thelia/Config/Resources/routing/admin.xml index 14ab8d4de..53c137988 100755 --- a/core/lib/Thelia/Config/Resources/routing/admin.xml +++ b/core/lib/Thelia/Config/Resources/routing/admin.xml @@ -85,7 +85,7 @@ - Thelia\Controller\Admin\CategoryController::toggleOnlineAction + Thelia\Controller\Admin\CategoryController::setToggleVisibilityAction @@ -234,6 +234,30 @@ Thelia\Controller\Admin\TemplateController::deleteAction + + Thelia\Controller\Admin\TemplateController::getAjaxFeaturesAction + + + + Thelia\Controller\Admin\TemplateController::addFeatureAction + + + + Thelia\Controller\Admin\TemplateController::deleteFeatureAction + + + + Thelia\Controller\Admin\TemplateController::getAjaxAttributesAction + + + + Thelia\Controller\Admin\TemplateController::addAttributeAction + + + + Thelia\Controller\Admin\TemplateController::deleteAttributeAction + + @@ -292,6 +316,23 @@ + + + + Thelia\Controller\Admin\CountryController::indexAction + + + + Thelia\Controller\Admin\CountryController::createAction + + + + Thelia\Controller\Admin\CountryController::updateAction + \d+ + + + + diff --git a/core/lib/Thelia/Controller/Admin/AbstractCrudController.php b/core/lib/Thelia/Controller/Admin/AbstractCrudController.php index fad774023..5b7f8b60a 100644 --- a/core/lib/Thelia/Controller/Admin/AbstractCrudController.php +++ b/core/lib/Thelia/Controller/Admin/AbstractCrudController.php @@ -240,6 +240,17 @@ abstract class AbstractCrudController extends BaseAdminController return null; } + /** + * Put in this method post object position change processing if required. + * + * @param unknown $deleteEvent the delete event + * @return Response a response, or null to continue normal processing + */ + protected function performAdditionalUpdatePositionAction($positionChangeEvent) + { + return null; + } + /** * Return the current list order identifier, updating it in the same time. */ @@ -309,14 +320,18 @@ abstract class AbstractCrudController extends BaseAdminController $this->adminLogAppend(sprintf("%s %s (ID %s) created", ucfirst($this->objectName), $this->getObjectLabel($createdObject), $this->getObjectId($createdObject))); } - $this->performAdditionalCreateAction($createEvent); + $response = $this->performAdditionalCreateAction($createEvent); - // Substitute _ID_ in the URL with the ID of the created object - $successUrl = str_replace('_ID_', $this->getObjectId($createdObject), $creationForm->getSuccessUrl()); - - // Redirect to the success URL - $this->redirect($successUrl); + if ($response == null) { + // Substitute _ID_ in the URL with the ID of the created object + $successUrl = str_replace('_ID_', $this->getObjectId($createdObject), $creationForm->getSuccessUrl()); + // Redirect to the success URL + $this->redirect($successUrl); + } + else { + return $response; + } } catch (FormValidationException $ex) { // Form cannot be validated @@ -396,16 +411,21 @@ abstract class AbstractCrudController extends BaseAdminController $this->adminLogAppend(sprintf("%s %s (ID %s) modified", ucfirst($this->objectName), $this->getObjectLabel($changedObject), $this->getObjectId($changedObject))); } - $this->performAdditionalUpdateAction($changeEvent); + $response = $this->performAdditionalUpdateAction($changeEvent); - // If we have to stay on the same page, do not redirect to the succesUrl, - // just redirect to the edit page again. - if ($this->getRequest()->get('save_mode') == 'stay') { - $this->redirectToEditionTemplate($this->getRequest()); + if ($response == null) { + // If we have to stay on the same page, do not redirect to the succesUrl, + // just redirect to the edit page again. + if ($this->getRequest()->get('save_mode') == 'stay') { + $this->redirectToEditionTemplate($this->getRequest()); + } + + // Redirect to the success URL + $this->redirect($changeForm->getSuccessUrl()); + } + else { + return $response; } - - // Redirect to the success URL - $this->redirect($changeForm->getSuccessUrl()); } catch (FormValidationException $ex) { // Form cannot be validated @@ -452,7 +472,14 @@ abstract class AbstractCrudController extends BaseAdminController return $this->errorPage($ex); } - $this->redirectToListTemplate(); + $response = $this->performAdditionalUpdatePositionAction($event); + + if ($response == null) { + $this->redirectToListTemplate(); + } + else { + return $response; + } } /** @@ -475,7 +502,7 @@ abstract class AbstractCrudController extends BaseAdminController return $this->errorPage($ex); } - $this->redirectToRoute('admin.categories.default'); + $this->redirectToListTemplate(); } /** diff --git a/core/lib/Thelia/Controller/Admin/AttributeAvController.php b/core/lib/Thelia/Controller/Admin/AttributeAvController.php index b3afa687d..1ab12a081 100644 --- a/core/lib/Thelia/Controller/Admin/AttributeAvController.php +++ b/core/lib/Thelia/Controller/Admin/AttributeAvController.php @@ -33,7 +33,7 @@ use Thelia\Form\AttributeAvCreationForm; use Thelia\Core\Event\UpdatePositionEvent; /** - * Manages attributes-av sent by mail + * Manages attributes-av * * @author Franck Allimant */ diff --git a/core/lib/Thelia/Controller/Admin/AttributeController.php b/core/lib/Thelia/Controller/Admin/AttributeController.php index 247b89632..48a65baa7 100644 --- a/core/lib/Thelia/Controller/Admin/AttributeController.php +++ b/core/lib/Thelia/Controller/Admin/AttributeController.php @@ -37,7 +37,7 @@ use Thelia\Core\Event\AttributeAvUpdateEvent; use Thelia\Core\Event\AttributeEvent; /** - * Manages attributes sent by mail + * Manages attributes * * @author Franck Allimant */ diff --git a/core/lib/Thelia/Controller/Admin/CategoryController.php b/core/lib/Thelia/Controller/Admin/CategoryController.php index fba832ec8..83d90c86e 100755 --- a/core/lib/Thelia/Controller/Admin/CategoryController.php +++ b/core/lib/Thelia/Controller/Admin/CategoryController.php @@ -23,226 +23,160 @@ namespace Thelia\Controller\Admin; -use Thelia\Core\Event\TheliaEvents; -use Thelia\Core\Event\CategoryCreateEvent; -use Thelia\Form\CategoryCreationForm; use Thelia\Core\Event\CategoryDeleteEvent; -use Thelia\Core\Event\CategoryUpdatePositionEvent; +use Thelia\Core\Event\TheliaEvents; +use Thelia\Core\Event\CategoryUpdateEvent; +use Thelia\Core\Event\CategoryCreateEvent; use Thelia\Model\CategoryQuery; use Thelia\Form\CategoryModificationForm; +use Thelia\Form\CategoryCreationForm; +use Thelia\Core\Event\UpdatePositionEvent; +use Thelia\Core\Event\CategoryToggleVisibilityEvent; -class CategoryController extends BaseAdminController +/** + * Manages categories + * + * @author Franck Allimant + */ +class CategoryController extends AbstractCrudController { - /** - * Render the categories list, ensuring the sort order is set. - * - * @return Symfony\Component\HttpFoundation\Response the response - */ - protected function renderList() - { - return $this->render('categories', $this->getTemplateArgs()); + public function __construct() { + parent::__construct( + 'category', + 'manual', + 'category_order', + + 'admin.categories.default', + 'admin.categories.create', + 'admin.categories.update', + 'admin.categories.delete', + + TheliaEvents::CATEGORY_CREATE, + TheliaEvents::CATEGORY_UPDATE, + TheliaEvents::CATEGORY_DELETE, + TheliaEvents::CATEGORY_TOGGLE_VISIBILITY, + TheliaEvents::CATEGORY_UPDATE_POSITION + ); } - protected function getTemplateArgs() - { - // Get the category ID - $category_id = $this->getRequest()->get('category_id', 0); + protected function getCreationForm() { + return new CategoryCreationForm($this->getRequest()); + } - // Find the current category order - $category_order = $this->getRequest()->get( - 'order', - $this->getSession()->get('admin.category_order', 'manual') + protected function getUpdateForm() { + return new CategoryModificationForm($this->getRequest()); + } + + protected function getCreationEvent($formData) { + $createEvent = new CategoryCreateEvent(); + + $createEvent + ->setTitle($formData['title']) + ->setLocale($formData["locale"]) + ->setParent($formData['parent']) + ->setVisible($formData['visible']) + ; + + return $createEvent; + } + + protected function getUpdateEvent($formData) { + $changeEvent = new CategoryUpdateEvent($formData['id']); + + // Create and dispatch the change event + $changeEvent + ->setLocale($formData['locale']) + ->setTitle($formData['title']) + ->setChapo($formData['chapo']) + ->setDescription($formData['description']) + ->setPostscriptum($formData['postscriptum']) + ->setVisible($formData['visible']) + ->setUrl($formData['url']) + ->setParent($formData['parent']) + ; + + return $changeEvent; + } + + protected function createUpdatePositionEvent($positionChangeMode, $positionValue) { + + return new UpdatePositionEvent( + $this->getRequest()->get('category_id', null), + $positionChangeMode, + $positionValue + ); + } + + protected function getDeleteEvent() { + return new CategoryDeleteEvent($this->getRequest()->get('category_id', 0)); + } + + protected function eventContainsObject($event) { + return $event->hasCategory(); + } + + protected function hydrateObjectForm($object) { + + // Prepare the data that will hydrate the form + $data = array( + 'id' => $object->getId(), + 'locale' => $object->getLocale(), + 'title' => $object->getTitle(), + 'chapo' => $object->getChapo(), + 'description' => $object->getDescription(), + 'postscriptum' => $object->getPostscriptum(), + 'visible' => $object->getVisible(), + 'url' => $object->getRewritenUrl($this->getCurrentEditionLocale()), + 'parent' => $object->getParent() ); - $args = array( - 'current_category_id' => $category_id, - 'category_order' => $category_order, + // Setup the object form + return new CategoryModificationForm($this->getRequest(), "form", $data); + } + + protected function getObjectFromEvent($event) { + return $event->hasCategory() ? $event->getCategory() : null; + } + + protected function getExistingObject() { + return CategoryQuery::create() + ->joinWithI18n($this->getCurrentEditionLocale()) + ->findOneById($this->getRequest()->get('category_id', 0)); + } + + protected function getObjectLabel($object) { + return $object->getTitle(); + } + + protected function getObjectId($object) { + return $object->getId(); + } + + protected function renderListTemplate($currentOrder) { + return $this->render('categories', + array( + 'category_order' => $currentOrder, + 'category_id' => $this->getRequest()->get('category_id', 0) + ) + ); + } + + protected function renderEditionTemplate() { + return $this->render('category-edit', array('category_id' => $this->getRequest()->get('category_id', 0))); + } + + protected function redirectToEditionTemplate() { + $this->redirectToRoute( + "admin.categories.update", + array('category_id' => $this->getRequest()->get('category_id', 0)) ); - - // Store the current sort order in session - $this->getSession()->set('admin.category_order', $category_order); - - return $args; } - /** - * The default action is displaying the categories list. - * - * @return Symfony\Component\HttpFoundation\Response the response - */ - public function defaultAction() - { - if (null !== $response = $this->checkAuth("admin.categories.view")) return $response; - return $this->renderList(); - } - - /** - * Create a new category object - * - * @return Symfony\Component\HttpFoundation\Response the response - */ - public function createAction() - { - // Check current user authorization - if (null !== $response = $this->checkAuth("admin.categories.create")) return $response; - - $error_msg = false; - - // Create the Creation Form - $creationForm = new CategoryCreationForm($this->getRequest()); - - try { - - // Validate the form, create the CategoryCreation event and dispatch it. - $form = $this->validateForm($creationForm, "POST"); - - $data = $form->getData(); - - $createEvent = new CategoryCreateEvent( - $data["title"], - $data["parent"], - $data["locale"] - ); - - $this->dispatch(TheliaEvents::CATEGORY_CREATE, $createEvent); - - if (! $createEvent->hasCategory()) throw new \LogicException($this->getTranslator()->trans("No category was created.")); - - $createdObject = $createEvent->getCategory(); - - // Log category creation - $this->adminLogAppend(sprintf("Category %s (ID %s) created", $createdObject->getTitle(), $createdObject->getId())); - - // Substitute _ID_ in the URL with the ID of the created object - $successUrl = str_replace('_ID_', $createdObject->getId(), $creationForm->getSuccessUrl()); - - // Redirect to the success URL - $this->redirect($successUrl); - } catch (FormValidationException $ex) { - // Form cannot be validated - $error_msg = $this->createStandardFormValidationErrorMessage($ex); - } catch (\Exception $ex) { - // Any other error - $error_msg = $ex->getMessage(); - } - - $this->setupFormErrorContext("category creation", $error_msg, $creationForm, $ex); - - // At this point, the form has error, and should be redisplayed. - return $this->renderList(); - } - - /** - * Load a category object for modification, and display the edit template. - * - * @return Symfony\Component\HttpFoundation\Response the response - */ - public function changeAction() - { - // Check current user authorization - if (null !== $response = $this->checkAuth("admin.categories.update")) return $response; - - // Load the category object - $category = CategoryQuery::create() - ->joinWithI18n($this->getCurrentEditionLocale()) - ->findOneById($this->getRequest()->get('category_id')); - - if ($category != null) { - - // Prepare the data that will hydrate the form - $data = array( - 'id' => $category->getId(), - 'locale' => $category->getLocale(), - 'title' => $category->getTitle(), - 'chapo' => $category->getChapo(), - 'description' => $category->getDescription(), - 'postscriptum' => $category->getPostscriptum(), - 'parent' => $category->getParent(), - 'visible' => $category->getVisible() ? true : false, - 'url' => $category->getUrl($this->getCurrentEditionLocale()) - // tbc !!! - ); - - // Setup the object form - $changeForm = new CategoryModificationForm($this->getRequest(), "form", $data); - - // Pass it to the parser - $this->getParserContext()->addForm($changeForm); - } - - // Render the edition template. - return $this->render('category-edit', $this->getTemplateArgs()); - } - - /** - * Save changes on a modified category object, and either go back to the category list, or stay on the edition page. - * - * @return Symfony\Component\HttpFoundation\Response the response - */ - public function saveChangeAction() - { - // Check current user authorization - if (null !== $response = $this->checkAuth("admin.categories.update")) return $response; - - $error_msg = false; - - // Create the form from the request - $changeForm = new CategoryModificationForm($this->getRequest()); - - // Get the category ID - $category_id = $this->getRequest()->get('category_id'); - - try { - - // Check the form against constraints violations - $form = $this->validateForm($changeForm, "POST"); - - // Get the form field values - $data = $form->getData(); - - $changeEvent = new CategoryUpdateEvent($data['id']); - - // Create and dispatch the change event - $changeEvent - ->setCategoryName($data['name']) - ->setLocale($data["locale"]) - ->setSymbol($data['symbol']) - ->setCode($data['code']) - ->setRate($data['rate']) - ; - - $this->dispatch(TheliaEvents::CATEGORY_UPDATE, $changeEvent); - - if (! $createEvent->hasCategory()) throw new \LogicException($this->getTranslator()->trans("No category was updated.")); - - // Log category modification - $changedObject = $changeEvent->getCategory(); - - $this->adminLogAppend(sprintf("Category %s (ID %s) modified", $changedObject->getTitle(), $changedObject->getId())); - - // If we have to stay on the same page, do not redirect to the succesUrl, - // just redirect to the edit page again. - if ($this->getRequest()->get('save_mode') == 'stay') { - $this->redirectToRoute( - "admin.categories.update", - array('category_id' => $category_id) + protected function redirectToListTemplate() { + $this->redirectToRoute( + 'admin.categories.default', + array('category_id' => $this->getRequest()->get('category_id', 0)) ); - } - - // Redirect to the success URL - $this->redirect($changeForm->getSuccessUrl()); - } catch (FormValidationException $ex) { - // Form cannot be validated - $error_msg = $this->createStandardFormValidationErrorMessage($ex); - } catch (\Exception $ex) { - // Any other error - $error_msg = $ex->getMessage(); - } - - $this->setupFormErrorContext("category modification", $error_msg, $changeForm, $ex); - - // At this point, the form has errors, and should be redisplayed. - return $this->render('category-edit', array('category_id' => $category_id)); } /** @@ -253,74 +187,41 @@ class CategoryController extends BaseAdminController // Check current user authorization if (null !== $response = $this->checkAuth("admin.categories.update")) return $response; - $changeEvent = new CategoryUpdateEvent($this->getRequest()->get('category_id', 0)); - - // Create and dispatch the change event - $changeEvent->setIsDefault(true); + $event = new CategoryToggleVisibilityEvent($this->getExistingObject()); try { - $this->dispatch(TheliaEvents::CATEGORY_SET_DEFAULT, $changeEvent); + $this->dispatch(TheliaEvents::CATEGORY_TOGGLE_VISIBILITY, $event); } catch (\Exception $ex) { // Any error return $this->errorPage($ex); } - $this->redirectToRoute('admin.categories.default'); + // Ajax response -> no action + return $this->nullResponse(); } - /** - * Update categoryposition - */ - public function updatePositionAction() + protected function performAdditionalDeleteAction($deleteEvent) { - // Check current user authorization - if (null !== $response = $this->checkAuth("admin.categories.update")) return $response; + // Redirect to parent category list + $this->redirectToRoute( + 'admin.categories.default', + array('category_id' => $deleteEvent->getCategory()->getParent()) + ); + } - try { - $mode = $this->getRequest()->get('mode', null); + protected function performAdditionalUpdatePositionAction($event) + { - if ($mode == 'up') - $mode = CategoryUpdatePositionEvent::POSITION_UP; - else if ($mode == 'down') - $mode = CategoryUpdatePositionEvent::POSITION_DOWN; - else - $mode = CategoryUpdatePositionEvent::POSITION_ABSOLUTE; + $category = CategoryQuery::create()->findPk($event->getObjectId()); - $position = $this->getRequest()->get('position', null); - - $event = new CategoryUpdatePositionEvent( - $this->getRequest()->get('category_id', null), - $mode, - $this->getRequest()->get('position', null) + if ($category != null) { + // Redirect to parent category list + $this->redirectToRoute( + 'admin.categories.default', + array('category_id' => $category->getParent()) ); - - $this->dispatch(TheliaEvents::CATEGORY_UPDATE_POSITION, $event); - } catch (\Exception $ex) { - // Any error - return $this->errorPage($ex); } - $this->redirectToRoute('admin.categories.default'); - } - - /** - * Delete a category object - * - * @return Symfony\Component\HttpFoundation\Response the response - */ - public function deleteAction() - { - // Check current user authorization - if (null !== $response = $this->checkAuth("admin.categories.delete")) return $response; - - // Get the category id, and dispatch the deleted request - $event = new CategoryDeleteEvent($this->getRequest()->get('category_id')); - - $this->dispatch(TheliaEvents::CATEGORY_DELETE, $event); - - if ($event->hasCategory()) - $this->adminLogAppend(sprintf("Category %s (ID %s) deleted", $event->getCategory()->getTitle(), $event->getCategory()->getId())); - - $this->redirectToRoute('admin.categories.default'); + return null; } } diff --git a/core/lib/Thelia/Controller/Admin/ConfigController.php b/core/lib/Thelia/Controller/Admin/ConfigController.php index ff0e4bb39..8701710b0 100644 --- a/core/lib/Thelia/Controller/Admin/ConfigController.php +++ b/core/lib/Thelia/Controller/Admin/ConfigController.php @@ -33,7 +33,7 @@ use Thelia\Form\ConfigCreationForm; use Thelia\Core\Event\UpdatePositionEvent; /** - * Manages variables sent by mail + * Manages variables * * @author Franck Allimant */ diff --git a/core/lib/Thelia/Controller/Admin/CountryController.php b/core/lib/Thelia/Controller/Admin/CountryController.php new file mode 100644 index 000000000..fadca1e92 --- /dev/null +++ b/core/lib/Thelia/Controller/Admin/CountryController.php @@ -0,0 +1,52 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Controller\Admin; + +/** + * Class CustomerController + * @package Thelia\Controller\Admin + * @author Manuel Raynaud + */ +class CountryController extends BaseAdminController +{ + public function indexAction() + { + if (null !== $response = $this->checkAuth("admin.country.view")) return $response; + return $this->render("countries", array("display_country" => 20)); + } + + /** + * update country action + * + * @param $country_id + * @return mixed|\Symfony\Component\HttpFoundation\Response + */ + public function updateAction($country_id) + { + return $this->render("country-edit", array( + "country_id" => $country_id + )); + } + +} \ No newline at end of file diff --git a/core/lib/Thelia/Controller/Admin/CurrencyController.php b/core/lib/Thelia/Controller/Admin/CurrencyController.php index 4f3fdaaea..f0081d698 100644 --- a/core/lib/Thelia/Controller/Admin/CurrencyController.php +++ b/core/lib/Thelia/Controller/Admin/CurrencyController.php @@ -33,7 +33,7 @@ use Thelia\Form\CurrencyCreationForm; use Thelia\Core\Event\UpdatePositionEvent; /** - * Manages currencies sent by mail + * Manages currencies * * @author Franck Allimant */ diff --git a/core/lib/Thelia/Controller/Admin/FeatureAvController.php b/core/lib/Thelia/Controller/Admin/FeatureAvController.php index 25c7a5495..fc6571ccc 100644 --- a/core/lib/Thelia/Controller/Admin/FeatureAvController.php +++ b/core/lib/Thelia/Controller/Admin/FeatureAvController.php @@ -33,7 +33,7 @@ use Thelia\Form\FeatureAvCreationForm; use Thelia\Core\Event\UpdatePositionEvent; /** - * Manages features-av sent by mail + * Manages features-av * * @author Franck Allimant */ diff --git a/core/lib/Thelia/Controller/Admin/FeatureController.php b/core/lib/Thelia/Controller/Admin/FeatureController.php index 92cb89d33..f81f55919 100644 --- a/core/lib/Thelia/Controller/Admin/FeatureController.php +++ b/core/lib/Thelia/Controller/Admin/FeatureController.php @@ -37,7 +37,7 @@ use Thelia\Core\Event\FeatureAvUpdateEvent; use Thelia\Core\Event\FeatureEvent; /** - * Manages features sent by mail + * Manages features * * @author Franck Allimant */ diff --git a/core/lib/Thelia/Controller/Admin/TemplateController.php b/core/lib/Thelia/Controller/Admin/TemplateController.php index aafc56e4b..c9e30612c 100644 --- a/core/lib/Thelia/Controller/Admin/TemplateController.php +++ b/core/lib/Thelia/Controller/Admin/TemplateController.php @@ -35,9 +35,13 @@ use Thelia\Model\TemplateAv; use Thelia\Model\TemplateAvQuery; use Thelia\Core\Event\TemplateAvUpdateEvent; use Thelia\Core\Event\TemplateEvent; +use Thelia\Core\Event\TemplateDeleteAttributeEvent; +use Thelia\Core\Event\TemplateAddAttributeEvent; +use Thelia\Core\Event\TemplateAddFeatureEvent; +use Thelia\Core\Event\TemplateDeleteFeatureEvent; /** - * Manages templates sent by mail + * Manages product templates * * @author Franck Allimant */ @@ -193,4 +197,106 @@ class TemplateController extends AbstractCrudController return null; } + public function getAjaxFeaturesAction() { + return $this->render( + 'ajax/template-feature-list', + array('template_id' => $this->getRequest()->get('template_id')) + ); + } + + public function getAjaxAttributesAction() { + return $this->render( + 'ajax/template-attribute-list', + array('template_id' => $this->getRequest()->get('template_id')) + ); + } + + public function addAttributeAction() { + + // Check current user authorization + if (null !== $response = $this->checkAuth("admin.configuration.template.attribute.add")) return $response; + + $attribute_id = intval($this->getRequest()->get('attribute_id')); + + if ($attribute_id > 0) { + $event = new TemplateAddAttributeEvent( + $this->getExistingObject(), + $attribute_id + ); + + try { + $this->dispatch(TheliaEvents::TEMPLATE_ADD_ATTRIBUTE, $event); + } catch (\Exception $ex) { + // Any error + return $this->errorPage($ex); + } + } + + $this->redirectToEditionTemplate(); + } + + public function deleteAttributeAction() { + + // Check current user authorization + if (null !== $response = $this->checkAuth("admin.configuration.template.attribute.delete")) return $response; + + $event = new TemplateDeleteAttributeEvent( + $this->getExistingObject(), + intval($this->getRequest()->get('attribute_id')) + ); + + try { + $this->dispatch(TheliaEvents::TEMPLATE_DELETE_ATTRIBUTE, $event); + } catch (\Exception $ex) { + // Any error + return $this->errorPage($ex); + } + + $this->redirectToEditionTemplate(); + } + + public function addFeatureAction() { + + // Check current user authorization + if (null !== $response = $this->checkAuth("admin.configuration.template.feature.add")) return $response; + + $feature_id = intval($this->getRequest()->get('feature_id')); + + if ($feature_id > 0) { + $event = new TemplateAddFeatureEvent( + $this->getExistingObject(), + $feature_id + ); + + try { + $this->dispatch(TheliaEvents::TEMPLATE_ADD_FEATURE, $event); + } catch (\Exception $ex) { + // Any error + return $this->errorPage($ex); + } + } + + $this->redirectToEditionTemplate(); + } + + public function deleteFeatureAction() { + + // Check current user authorization + if (null !== $response = $this->checkAuth("admin.configuration.template.feature.delete")) return $response; + + $event = new TemplateDeleteFeatureEvent( + $this->getExistingObject(), + intval($this->getRequest()->get('feature_id')) + ); + + try { + $this->dispatch(TheliaEvents::TEMPLATE_DELETE_FEATURE, $event); + } catch (\Exception $ex) { + // Any error + return $this->errorPage($ex); + } + + $this->redirectToEditionTemplate(); + } + } \ No newline at end of file diff --git a/core/lib/Thelia/Controller/BaseController.php b/core/lib/Thelia/Controller/BaseController.php index 19e62a400..3c4c0a5bc 100755 --- a/core/lib/Thelia/Controller/BaseController.php +++ b/core/lib/Thelia/Controller/BaseController.php @@ -281,4 +281,16 @@ class BaseController extends ContainerAware $this->accessDenied(); } } + + /** + * + * return an instance of \Swift_Mailer with good Transporter configured. + * + * @return \Swift_Mailer + */ + public function getMailer() + { + $mailer = $this->container->get('mailer'); + return $mailer->getSwiftMailer(); + } } diff --git a/core/lib/Thelia/Core/Event/CachedFileEvent.php b/core/lib/Thelia/Core/Event/CachedFileEvent.php new file mode 100644 index 000000000..8f3a026d9 --- /dev/null +++ b/core/lib/Thelia/Core/Event/CachedFileEvent.php @@ -0,0 +1,94 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Core\Event; + +class CachedFileEvent extends ActionEvent +{ + /** + * @var string The complete file name (with path) of the source file + */ + protected $source_filepath = null; + /** + * @var string The target subdirectory in the cache + */ + protected $cache_subdirectory = null; + + /** + * @var string The absolute URL of the cached file (in the web space) + */ + protected $file_url = null; + + /** + * @var string The absolute path of the cached file + */ + protected $cache_filepath = null; + + public function getFileUrl() + { + return $this->file_url; + } + + public function setFileUrl($file_url) + { + $this->file_url = $file_url; + + return $this; + } + + public function getCacheFilepath() + { + return $this->cache_filepath; + } + + public function setCacheFilepath($cache_filepath) + { + $this->cache_filepath = $cache_filepath; + + return $this; + } + + public function getSourceFilepath() + { + return $this->source_filepath; + } + + public function setSourceFilepath($source_filepath) + { + $this->source_filepath = $source_filepath; + + return $this; + } + + public function getCacheSubdirectory() + { + return $this->cache_subdirectory; + } + + public function setCacheSubdirectory($cache_subdirectory) + { + $this->cache_subdirectory = $cache_subdirectory; + + return $this; + } +} diff --git a/core/lib/Thelia/Core/Event/CategoryCreateEvent.php b/core/lib/Thelia/Core/Event/CategoryCreateEvent.php index 5a687217c..41529019c 100644 --- a/core/lib/Thelia/Core/Event/CategoryCreateEvent.php +++ b/core/lib/Thelia/Core/Event/CategoryCreateEvent.php @@ -28,13 +28,7 @@ class CategoryCreateEvent extends CategoryEvent protected $title; protected $parent; protected $locale; - - public function __construct($title, $parent, $locale) - { - $this->title = $title; - $this->parent = $parent; - $this->locale = $locale; - } + protected $visible; public function getTitle() { @@ -71,4 +65,16 @@ class CategoryCreateEvent extends CategoryEvent return $this; } + + public function getVisible() + { + return $this->visible; + } + + public function setVisible($visible) + { + $this->visible = $visible; + + return $this; + } } diff --git a/core/lib/Thelia/Core/Event/CategoryToggleVisibilityEvent.php b/core/lib/Thelia/Core/Event/CategoryToggleVisibilityEvent.php new file mode 100644 index 000000000..f90378e38 --- /dev/null +++ b/core/lib/Thelia/Core/Event/CategoryToggleVisibilityEvent.php @@ -0,0 +1,28 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Core\Event; + +class CategoryToggleVisibilityEvent extends CategoryEvent +{ +} diff --git a/core/lib/Thelia/Core/Event/CategoryUpdateEvent.php b/core/lib/Thelia/Core/Event/CategoryUpdateEvent.php index 44e760549..f5f775a22 100644 --- a/core/lib/Thelia/Core/Event/CategoryUpdateEvent.php +++ b/core/lib/Thelia/Core/Event/CategoryUpdateEvent.php @@ -32,7 +32,6 @@ class CategoryUpdateEvent extends CategoryCreateEvent protected $postscriptum; protected $url; - protected $visibility; protected $parent; public function __construct($category_id) @@ -100,18 +99,6 @@ class CategoryUpdateEvent extends CategoryCreateEvent return $this; } - public function getVisibility() - { - return $this->visibility; - } - - public function setVisibility($visibility) - { - $this->visibility = $visibility; - - return $this; - } - public function getParent() { return $this->parent; diff --git a/core/lib/Thelia/Core/Event/DocumentEvent.php b/core/lib/Thelia/Core/Event/DocumentEvent.php new file mode 100644 index 000000000..f58d51083 --- /dev/null +++ b/core/lib/Thelia/Core/Event/DocumentEvent.php @@ -0,0 +1,67 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Core\Event; + +class DocumentEvent extends CachedFileEvent +{ + protected $document_path; + protected $document_url; + + /** + * @return the document file path + */ + public function getDocumentPath() + { + return $this->document_path; + } + + /** + * @param string $document_path the document file path + */ + public function setDocumentPath($document_path) + { + $this->document_path = $document_path; + + return $this; + } + + /** + * @return the document URL + */ + public function getDocumentUrl() + { + return $this->document_url; + } + + /** + * @param string $document_url the document URL + */ + public function setDocumentUrl($document_url) + { + $this->document_url = $document_url; + + return $this; + } + +} diff --git a/core/lib/Thelia/Core/Event/ImageEvent.php b/core/lib/Thelia/Core/Event/ImageEvent.php index 5ea1581cd..462fa012d 100755 --- a/core/lib/Thelia/Core/Event/ImageEvent.php +++ b/core/lib/Thelia/Core/Event/ImageEvent.php @@ -23,22 +23,8 @@ namespace Thelia\Core\Event; -class ImageEvent extends ActionEvent +class ImageEvent extends CachedFileEvent { - /** - * @var string The complete file name (with path) of the source image - */ - protected $source_filepath = null; - /** - * @var string The target subdirectory in the image cache - */ - protected $cache_subdirectory = null; - - /** - * @var string The absolute URL of the cached image (in the web space) - */ - protected $file_url = null; - /** * @var string The absolute path of the cached image file */ @@ -121,6 +107,8 @@ class ImageEvent extends ActionEvent public function setCategory($category) { $this->category = $category; + + return $this; } public function getWidth() @@ -131,6 +119,8 @@ class ImageEvent extends ActionEvent public function setWidth($width) { $this->width = $width; + + return $this; } public function getHeight() @@ -141,6 +131,8 @@ class ImageEvent extends ActionEvent public function setHeight($height) { $this->height = $height; + + return $this; } public function getResizeMode() @@ -151,6 +143,8 @@ class ImageEvent extends ActionEvent public function setResizeMode($resize_mode) { $this->resize_mode = $resize_mode; + + return $this; } public function getBackgroundColor() @@ -161,6 +155,8 @@ class ImageEvent extends ActionEvent public function setBackgroundColor($background_color) { $this->background_color = $background_color; + + return $this; } public function getEffects() @@ -171,6 +167,8 @@ class ImageEvent extends ActionEvent public function setEffects(array $effects) { $this->effects = $effects; + + return $this; } public function getRotation() @@ -181,46 +179,8 @@ class ImageEvent extends ActionEvent public function setRotation($rotation) { $this->rotation = $rotation; - } - public function getFileUrl() - { - return $this->file_url; - } - - public function setFileUrl($file_url) - { - $this->file_url = $file_url; - } - - public function getCacheFilepath() - { - return $this->cache_filepath; - } - - public function setCacheFilepath($cache_filepath) - { - $this->cache_filepath = $cache_filepath; - } - - public function getSourceFilepath() - { - return $this->source_filepath; - } - - public function setSourceFilepath($source_filepath) - { - $this->source_filepath = $source_filepath; - } - - public function getCacheSubdirectory() - { - return $this->cache_subdirectory; - } - - public function setCacheSubdirectory($cache_subdirectory) - { - $this->cache_subdirectory = $cache_subdirectory; + return $this; } public function getQuality() @@ -231,6 +191,8 @@ class ImageEvent extends ActionEvent public function setQuality($quality) { $this->quality = $quality; + + return $this; } public function getOriginalFileUrl() @@ -241,6 +203,8 @@ class ImageEvent extends ActionEvent public function setOriginalFileUrl($original_file_url) { $this->original_file_url = $original_file_url; + + return $this; } public function getCacheOriginalFilepath() @@ -251,5 +215,7 @@ class ImageEvent extends ActionEvent public function setCacheOriginalFilepath($cache_original_filepath) { $this->cache_original_filepath = $cache_original_filepath; + + return $this; } } diff --git a/core/lib/Thelia/Core/Event/MailTransporterEvent.php b/core/lib/Thelia/Core/Event/MailTransporterEvent.php new file mode 100644 index 000000000..d47ac693f --- /dev/null +++ b/core/lib/Thelia/Core/Event/MailTransporterEvent.php @@ -0,0 +1,52 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Core\Event; + + +/** + * Class MailTransporterEvent + * @package Thelia\Core\Event + * @author Manuel Raynaud + */ +class MailTransporterEvent extends ActionEvent { + /** + * @var \Swift_Transport + */ + protected $transporter; + + public function setMailerTransporter(\Swift_Transport $transporter) + { + $this->transporter = $transporter; + } + + public function getTransporter() + { + return $this->transporter; + } + + public function hasTransporter() + { + return null !== $this->transporter; + } +} \ No newline at end of file diff --git a/core/lib/Thelia/Core/Event/TemplateAddAttributeEvent.php b/core/lib/Thelia/Core/Event/TemplateAddAttributeEvent.php new file mode 100644 index 000000000..6adebf080 --- /dev/null +++ b/core/lib/Thelia/Core/Event/TemplateAddAttributeEvent.php @@ -0,0 +1,51 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Core\Event; + +use Thelia\Model\Template; +class TemplateAddAttributeEvent extends TemplateEvent +{ + protected $attribute_id; + + public function __construct(Template $template, $attribute_id) + { + + parent::__construct($template); + + $this->attribute_id = $attribute_id; + } + + public function getAttributeId() + { + return $this->attribute_id; + } + + public function setAttributeId($attribute_id) + { + $this->attribute_id = $attribute_id; + + return $this; + } + +} diff --git a/core/lib/Thelia/Core/Event/TemplateAddFeatureEvent.php b/core/lib/Thelia/Core/Event/TemplateAddFeatureEvent.php new file mode 100644 index 000000000..ccfecb95a --- /dev/null +++ b/core/lib/Thelia/Core/Event/TemplateAddFeatureEvent.php @@ -0,0 +1,51 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Core\Event; + +use Thelia\Model\Template; +class TemplateAddFeatureEvent extends TemplateEvent +{ + protected $feature_id; + + public function __construct(Template $template, $feature_id) + { + + parent::__construct($template); + + $this->feature_id = $feature_id; + } + + public function getFeatureId() + { + return $this->feature_id; + } + + public function setFeatureId($feature_id) + { + $this->feature_id = $feature_id; + + return $this; + } + +} diff --git a/core/lib/Thelia/Core/Event/TemplateDeleteAttributeEvent.php b/core/lib/Thelia/Core/Event/TemplateDeleteAttributeEvent.php new file mode 100644 index 000000000..3df83422d --- /dev/null +++ b/core/lib/Thelia/Core/Event/TemplateDeleteAttributeEvent.php @@ -0,0 +1,51 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Core\Event; + +use Thelia\Model\Template; + +class TemplateDeleteAttributeEvent extends TemplateEvent +{ + protected $attribute_id; + + public function __construct(Template $template, $attribute_id) + { + + parent::__construct($template); + + $this->attribute_id = $attribute_id; + } + + public function getAttributeId() + { + return $this->attribute_id; + } + + public function setAttributeId($attribute_id) + { + $this->attribute_id = $attribute_id; + + return $this; + } +} diff --git a/core/lib/Thelia/Core/Event/TemplateDeleteFeatureEvent.php b/core/lib/Thelia/Core/Event/TemplateDeleteFeatureEvent.php new file mode 100644 index 000000000..83f73d923 --- /dev/null +++ b/core/lib/Thelia/Core/Event/TemplateDeleteFeatureEvent.php @@ -0,0 +1,51 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Core\Event; + +use Thelia\Model\Template; + +class TemplateDeleteFeatureEvent extends TemplateEvent +{ + protected $feature_id; + + public function __construct(Template $template, $feature_id) + { + + parent::__construct($template); + + $this->feature_id = $feature_id; + } + + public function getFeatureId() + { + return $this->feature_id; + } + + public function setFeatureId($feature_id) + { + $this->feature_id = $feature_id; + + return $this; + } +} diff --git a/core/lib/Thelia/Core/Event/TheliaEvents.php b/core/lib/Thelia/Core/Event/TheliaEvents.php index 566395a20..1fc91dacb 100755 --- a/core/lib/Thelia/Core/Event/TheliaEvents.php +++ b/core/lib/Thelia/Core/Event/TheliaEvents.php @@ -145,50 +145,21 @@ final class TheliaEvents // -- END ADDRESS MANAGEMENT --------------------------------------------------------- - /** - * Sent once the category creation form has been successfully validated, and before category insertion in the database. - */ - const BEFORE_CREATECATEGORY = "action.before_createcategory"; + // -- Categories management ----------------------------------------------- - /** - * Create, change or delete a category - */ - const CATEGORY_CREATE = "action.createCategory"; - const CATEGORY_UPDATE = "action.updateCategory"; - const CATEGORY_DELETE = "action.deleteCategory"; - - /** - * Toggle category visibility - */ + const CATEGORY_CREATE = "action.createCategory"; + const CATEGORY_UPDATE = "action.updateCategory"; + const CATEGORY_DELETE = "action.deleteCategory"; const CATEGORY_TOGGLE_VISIBILITY = "action.toggleCategoryVisibility"; + const CATEGORY_UPDATE_POSITION = "action.updateCategoryPosition"; - /** - * Change category position - */ - const CATEGORY_CHANGE_POSITION = "action.updateCategoryPosition"; - - /** - * Sent just after a successful insert of a new category in the database. - */ + const BEFORE_CREATECATEGORY = "action.before_createcategory"; const AFTER_CREATECATEGORY = "action.after_createcategory"; - /** - * Sent befonre deleting a category - */ - const BEFORE_DELETECATEGORY = "action.before_deletecategory"; - /** - * Sent just after a successful delete of a category from the database. - */ + const BEFORE_DELETECATEGORY = "action.before_deletecategory"; const AFTER_DELETECATEGORY = "action.after_deletecategory"; - /** - * Sent just before a successful change of a category in the database. - */ const BEFORE_UPDATECATEGORY = "action.before_updateCategory"; - - /** - * Sent just after a successful change of a category in the database. - */ const AFTER_UPDATECATEGORY = "action.after_updateCategory"; /** @@ -223,6 +194,11 @@ final class TheliaEvents */ const IMAGE_PROCESS = "action.processImage"; + /** + * Sent on document processing + */ + const DOCUMENT_PROCESS = "action.processDocument"; + /** * Sent on cimage cache clear request */ @@ -344,6 +320,12 @@ final class TheliaEvents const TEMPLATE_UPDATE = "action.updateTemplate"; const TEMPLATE_DELETE = "action.deleteTemplate"; + const TEMPLATE_ADD_ATTRIBUTE = "action.templateAddAttribute"; + const TEMPLATE_DELETE_ATTRIBUTE = "action.templateDeleteAttribute"; + + const TEMPLATE_ADD_FEATURE = "action.templateAddFeature"; + const TEMPLATE_DELETE_FEATURE = "action.templateDeleteFeature"; + const BEFORE_CREATETEMPLATE = "action.before_createTemplate"; const AFTER_CREATETEMPLATE = "action.after_createTemplate"; @@ -424,4 +406,9 @@ final class TheliaEvents const BEFORE_DELETEFEATURE_AV = "action.before_deleteFeatureAv"; const AFTER_DELETEFEATURE_AV = "action.after_deleteFeatureAv"; + /** + * sent when system find a mailer transporter. + */ + const MAILTRANSPORTER_CONFIG = 'action.mailertransporter.config'; + } diff --git a/core/lib/Thelia/Core/Template/Element/LoopResult.php b/core/lib/Thelia/Core/Template/Element/LoopResult.php index f86ab203d..3ca1e91d3 100755 --- a/core/lib/Thelia/Core/Template/Element/LoopResult.php +++ b/core/lib/Thelia/Core/Template/Element/LoopResult.php @@ -37,7 +37,7 @@ class LoopResult implements \Iterator public function __construct($modelCollection = null) { $this->position = 0; - if ($modelCollection instanceof ObjectCollection || $modelCollection instanceof PropelModelPager) { + if ($modelCollection instanceof ObjectCollection || $modelCollection instanceof PropelModelPager || is_array($modelCollection)) { $this->modelCollection = $modelCollection; } } @@ -57,6 +57,17 @@ class LoopResult implements \Iterator return count($this->collection); } + public function getModelCollectionCount() + { + if ($this->modelCollection instanceof ObjectCollection || $this->modelCollection instanceof PropelModelPager) { + return $this->modelCollection->count(); + } elseif (is_array($this->modelCollection)) { + return count($this->modelCollection); + } else { + return 0; + } + } + /** * (PHP 5 >= 5.0.0)
* Return the current element diff --git a/core/lib/Thelia/Core/Template/Element/LoopResultRow.php b/core/lib/Thelia/Core/Template/Element/LoopResultRow.php index 15bb287b1..9c4f93586 100755 --- a/core/lib/Thelia/Core/Template/Element/LoopResultRow.php +++ b/core/lib/Thelia/Core/Template/Element/LoopResultRow.php @@ -107,7 +107,7 @@ class LoopResultRow } if (true === $this->countable) { $this->set('LOOP_COUNT', 1 + $this->loopResult->getCount()); - $this->set('LOOP_TOTAL', $this->loopResult->modelCollection->count()); + $this->set('LOOP_TOTAL', $this->loopResult->getModelCollectionCount()); } } } diff --git a/core/lib/Thelia/Core/Template/Loop/Attribute.php b/core/lib/Thelia/Core/Template/Loop/Attribute.php index db9eb9b8f..e2ea7cf0f 100755 --- a/core/lib/Thelia/Core/Template/Loop/Attribute.php +++ b/core/lib/Thelia/Core/Template/Loop/Attribute.php @@ -64,6 +64,7 @@ class Attribute extends BaseI18nLoop Argument::createIntListTypeArgument('id'), Argument::createIntListTypeArgument('product'), Argument::createIntListTypeArgument('template'), + Argument::createIntListTypeArgument('exclude_template'), Argument::createIntListTypeArgument('exclude'), new Argument( 'order', @@ -115,15 +116,25 @@ class Attribute extends BaseI18nLoop $template = $productObj->getTemplate(); } - // If we have to filter by template, find all attributes assigned to this template, and filter by found IDs if (null !== $template) { $search->filterById( - AttributeTemplateQuery::create()->filterByTemplateId($template)->select('id')->find(), + AttributeTemplateQuery::create()->filterByTemplateId($template)->select('attribute_id')->find(), Criteria::IN ); } + $exclude_template = $this->getExcludeTemplate(); + + // If we have to filter by template, find all attributes assigned to this template, and filter by found IDs + if (null !== $exclude_template) { + // Exclure tous les attribut qui sont attachés aux templates indiqués + $search->filterById( + AttributeTemplateQuery::create()->filterByTemplateId($exclude_template)->select('attribute_id')->find(), + Criteria::NOT_IN + ); + } + $orders = $this->getOrder(); foreach ($orders as $order) { diff --git a/core/lib/Thelia/Core/Template/Loop/Category.php b/core/lib/Thelia/Core/Template/Loop/Category.php index 2b1156b98..bd1c32de2 100755 --- a/core/lib/Thelia/Core/Template/Loop/Category.php +++ b/core/lib/Thelia/Core/Template/Loop/Category.php @@ -173,6 +173,22 @@ class Category extends BaseI18nLoop $loopResult = new LoopResult($categories); foreach ($categories as $category) { + + // Find previous and next category + $previous = CategoryQuery::create() + ->filterByParent($category->getParent()) + ->filterByPosition($category->getPosition(), Criteria::LESS_THAN) + ->orderByPosition(Criteria::DESC) + ->findOne() + ; + + $next = CategoryQuery::create() + ->filterByParent($category->getParent()) + ->filterByPosition($category->getPosition(), Criteria::GREATER_THAN) + ->orderByPosition(Criteria::ASC) + ->findOne() + ; + /* * no cause pagination lost : * if ($this->getNotEmpty() && $category->countAllProducts() == 0) continue; @@ -193,7 +209,13 @@ class Category extends BaseI18nLoop ->set("PRODUCT_COUNT", $category->countChild()) ->set("VISIBLE", $category->getVisible() ? "1" : "0") ->set("POSITION", $category->getPosition()) - ; + + ->set("HAS_PREVIOUS", $previous != null ? 1 : 0) + ->set("HAS_NEXT" , $next != null ? 1 : 0) + + ->set("PREVIOUS", $previous != null ? $previous->getId() : -1) + ->set("NEXT" , $next != null ? $next->getId() : -1) + ; $loopResult->addRow($loopResultRow); } diff --git a/core/lib/Thelia/Core/Template/Loop/CategoryTree.php b/core/lib/Thelia/Core/Template/Loop/CategoryTree.php index afcd0410e..712767954 100755 --- a/core/lib/Thelia/Core/Template/Loop/CategoryTree.php +++ b/core/lib/Thelia/Core/Template/Loop/CategoryTree.php @@ -59,7 +59,7 @@ class CategoryTree extends BaseI18nLoop } // changement de rubrique - protected function buildCategoryTree($parent, $visible, $level, $max_level, array $exclude, LoopResult &$loopResult) + protected function buildCategoryTree($parent, $visible, $level, $max_level, $exclude, LoopResult &$loopResult) { if ($level > $max_level) return; @@ -73,7 +73,7 @@ class CategoryTree extends BaseI18nLoop if ($visible != BooleanOrBothType::ANY) $search->filterByVisible($visible); - $search->filterById($exclude, Criteria::NOT_IN); + if ($exclude != null) $search->filterById($exclude, Criteria::NOT_IN); $search->orderByPosition(Criteria::ASC); diff --git a/core/lib/Thelia/Core/Template/Loop/Document.php b/core/lib/Thelia/Core/Template/Loop/Document.php new file mode 100644 index 000000000..0e7e979c9 --- /dev/null +++ b/core/lib/Thelia/Core/Template/Loop/Document.php @@ -0,0 +1,277 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Core\Template\Loop; +use Thelia\Core\Template\Element\BaseI18nLoop; +use Thelia\Core\Template\Loop\Argument\Argument; +use Thelia\Core\Event\DocumentEvent; +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 document loop + * + * @author Franck Allimant + */ +class Document extends BaseI18nLoop +{ + public $timestampable = true; + + /** + * @var array Possible document sources + */ + protected $possible_sources = array('category', 'product', 'folder', 'content'); + + /** + * @return \Thelia\Core\Template\Loop\Argument\ArgumentCollection + */ + protected function getArgDefinitions() + { + $collection = new ArgumentCollection( + + Argument::createIntListTypeArgument('id'), + Argument::createIntListTypeArgument('exclude'), + new Argument( + 'order', + new TypeCollection( + new EnumListType(array('alpha', 'alpha-reverse', 'manual', 'manual-reverse', 'random')) + ), + 'manual' + ), + Argument::createIntTypeArgument('lang'), + + Argument::createIntTypeArgument('category'), + Argument::createIntTypeArgument('product'), + Argument::createIntTypeArgument('folder'), + Argument::createIntTypeArgument('content'), + + new Argument( + 'source', + new TypeCollection( + new EnumType($this->possible_sources) + ) + ), + Argument::createIntTypeArgument('source_id') + ); + + // Add possible document sources + foreach ($this->possible_sources as $source) { + $collection->addArgument(Argument::createIntTypeArgument($source)); + } + + return $collection; + } + + /** + * 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 createSearchQuery($source, $object_id) + { + $object = ucfirst($source); + + $queryClass = sprintf("\Thelia\Model\%sDocumentQuery", $object); + $filterMethod = sprintf("filterBy%sId", $object); + + // xxxDocumentQuery::create() + $method = new \ReflectionMethod($queryClass, 'create'); + $search = $method->invoke(null); // Static ! + + // $query->filterByXXX(id) + if (! is_null($object_id)) { + $method = new \ReflectionMethod($queryClass, $filterMethod); + $method->invoke($search, $object_id); + } + + $orders = $this->getOrder(); + + // Results ordering + foreach ($orders as $order) { + switch ($order) { + case "alpha": + $search->addAscendingOrderByColumn('i18n_TITLE'); + break; + case "alpha-reverse": + $search->addDescendingOrderByColumn('i18n_TITLE'); + break; + case "manual-reverse": + $search->orderByPosition(Criteria::DESC); + break; + case "manual": + $search->orderByPosition(Criteria::ASC); + break; + case "random": + $search->clearOrderByColumns(); + $search->addAscendingOrderByColumn('RAND()'); + break(2); + break; + } + } + + 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(); + $id = $this->getId(); + + // echo "source = ".$this->getSource().", id=".$source_id." - ".$this->getArg('source_id')->getValue()."
"; + + if (is_null($source_id) && is_null($id)) { + throw new \InvalidArgumentException("If 'source' argument is specified, 'id' or 'source_id' argument should be 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 document source. Valid sources are %s", implode(',', $this->possible_sources))); + + return $search; + } + + /** + * @param unknown $pagination + */ + public function exec(&$pagination) + { + // Select the proper query to use, and get the object type + $object_type = $object_id = null; + + $search = $this->getSearchQuery($object_type, $object_id); + + /* manage translations */ + $locale = $this->configureI18nProcessing($search); + + $id = $this->getId(); + + if (! is_null($id)) { + $search->filterById($id, Criteria::IN); + } + + $exclude = $this->getExclude(); + if (!is_null($exclude)) + $search->filterById($exclude, Criteria::NOT_IN); + + // Create document processing event + $event = new DocumentEvent($this->request); + + // echo "sql=".$search->toString(); + + $results = $this->search($search, $pagination); + + $loopResult = new LoopResult($results); + + foreach ($results as $result) { + + // Create document processing event + $event = new DocumentEvent($this->request); + + // Put source document file path + $source_filepath = sprintf("%s%s/%s/%s", + THELIA_ROOT, + ConfigQuery::read('documents_library_path', 'local/media/documents'), + $object_type, + $result->getFile() + ); + + $event->setSourceFilepath($source_filepath); + $event->setCacheSubdirectory($object_type); + + try { + // Dispatch document processing event + $this->dispatcher->dispatch(TheliaEvents::DOCUMENT_PROCESS, $event); + + $loopResultRow = new LoopResultRow($loopResult, $result, $this->versionable, $this->timestampable, $this->countable); + + $loopResultRow + ->set("ID" , $result->getId()) + ->set("LOCALE" ,$locale) + ->set("DOCUMENT_URL" , $event->getFileUrl()) + ->set("DOCUMENT_PATH" , $event->getCacheFilepath()) + ->set("ORIGINAL_DOCUMENT_PATH", $source_filepath) + ->set("TITLE" , $result->getVirtualColumn('i18n_TITLE')) + ->set("CHAPO" , $result->getVirtualColumn('i18n_CHAPO')) + ->set("DESCRIPTION" , $result->getVirtualColumn('i18n_DESCRIPTION')) + ->set("POSTSCRIPTUM" , $result->getVirtualColumn('i18n_POSTSCRIPTUM')) + ->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 document in document loop: ", $this->args); + } + } + + return $loopResult; + } +} diff --git a/core/lib/Thelia/Core/Template/Loop/Feature.php b/core/lib/Thelia/Core/Template/Loop/Feature.php index 7f412e4b0..f5c66d2e6 100755 --- a/core/lib/Thelia/Core/Template/Loop/Feature.php +++ b/core/lib/Thelia/Core/Template/Loop/Feature.php @@ -38,6 +38,7 @@ use Thelia\Model\Map\ProductCategoryTableMap; use Thelia\Type\TypeCollection; use Thelia\Type; use Thelia\Type\BooleanOrBothType; +use Thelia\Model\FeatureTemplateQuery; /** * @@ -60,7 +61,8 @@ class Feature extends BaseI18nLoop return new ArgumentCollection( Argument::createIntListTypeArgument('id'), Argument::createIntListTypeArgument('product'), - Argument::createIntListTypeArgument('category'), + Argument::createIntListTypeArgument('template'), + Argument::createIntListTypeArgument('exclude_template'), Argument::createBooleanOrBothTypeArgument('visible', 1), Argument::createIntListTypeArgument('exclude'), new Argument( @@ -102,22 +104,33 @@ class Feature extends BaseI18nLoop if ($visible != BooleanOrBothType::ANY) $search->filterByVisible($visible); $product = $this->getProduct(); - $category = $this->getCategory(); + $template = $this->getTemplate(); if (null !== $product) { - $productCategories = ProductCategoryQuery::create()->select(array(ProductCategoryTableMap::CATEGORY_ID))->filterByProductId($product, Criteria::IN)->find()->getData(); + // Find the template assigned to the product. + $productObj = ProductQuery::create()->findPk($product); - if (null === $category) { - $category = $productCategories; - } else { - $category = array_merge($category, $productCategories); - } + // Ignore if the product cannot be found. + if ($productObj !== null) + $template = $productObj->getTemplate(); + } + + // If we have to filter by template, find all features assigned to this template, and filter by found IDs + if (null !== $template) { + $search->filterById( + FeatureTemplateQuery::create()->filterByTemplateId($template)->select('feature_id')->find(), + Criteria::IN + ); } - if (null !== $category) { - $search->filterByCategory( - CategoryQuery::create()->filterById($category)->find(), - Criteria::IN + $exclude_template = $this->getExcludeTemplate(); + + // If we have to filter by template, find all features assigned to this template, and filter by found IDs + if (null !== $exclude_template) { + // Exclure tous les attribut qui sont attachés aux templates indiqués + $search->filterById( + FeatureTemplateQuery::create()->filterByTemplateId($exclude_template)->select('feature_id')->find(), + Criteria::NOT_IN ); } diff --git a/core/lib/Thelia/Core/Template/Loop/Feed.php b/core/lib/Thelia/Core/Template/Loop/Feed.php index 8e155a666..cf29cf3b7 100755 --- a/core/lib/Thelia/Core/Template/Loop/Feed.php +++ b/core/lib/Thelia/Core/Template/Loop/Feed.php @@ -73,9 +73,14 @@ class Feed extends BaseLoop $limit = min(count($items), $this->getLimit()); - $loopResult = new LoopResult(); - + $indexes = array(); for ($idx = 0; $idx < $limit; $idx++) { + $indexes[] = $idx; + } + + $loopResult = new LoopResult($indexes); + + foreach ($indexes as $idx) { $item = $items[$idx]; @@ -87,7 +92,7 @@ class Feed extends BaseLoop $date = $item->get_date('d/m/Y'); - $loopResultRow = new LoopResultRow(); + $loopResultRow = new LoopResultRow($loopResult, null, $this->versionable, $this->timestampable, $this->countable); $loopResultRow->set("URL", $item->get_permalink()); $loopResultRow->set("TITLE", $item->get_title()); diff --git a/core/lib/Thelia/Core/Template/Loop/Image.php b/core/lib/Thelia/Core/Template/Loop/Image.php index c7714731b..c85d41fc7 100755 --- a/core/lib/Thelia/Core/Template/Loop/Image.php +++ b/core/lib/Thelia/Core/Template/Loop/Image.php @@ -123,8 +123,10 @@ class Image extends BaseI18nLoop $search = $method->invoke(null); // Static ! // $query->filterByXXX(id) - $method = new \ReflectionMethod($queryClass, $filterMethod); - $method->invoke($search, $object_id); + if (! is_null($object_id)) { + $method = new \ReflectionMethod($queryClass, $filterMethod); + $method->invoke($search, $object_id); + } $orders = $this->getOrder(); @@ -171,11 +173,12 @@ class Image extends BaseI18nLoop if (! is_null($source)) { $source_id = $this->getSourceId(); + $id = $this->getId(); - // echo "source = ".$this->getSource().", id=".$source_id." - ".$this->getArg('source_id')->getValue()."
"; + //echo "source = ".$this->getSource()."source_id=$source_id, id=$id
"; - if (is_null($source_id)) { - throw new \InvalidArgumentException("'source_id' argument cannot be null if 'source' argument is specified."); + if (is_null($source_id) && is_null($id)) { + throw new \InvalidArgumentException("If 'source' argument is specified, 'id' or 'source_id' argument should be specified"); } $search = $this->createSearchQuery($source, $source_id); @@ -259,14 +262,13 @@ class Image extends BaseI18nLoop } - // echo "sql=".$search->toString(); + //echo "sql=".$search->toString(); $results = $this->search($search, $pagination); $loopResult = new LoopResult($results); foreach ($results as $result) { - // Create image processing event $event = new ImageEvent($this->request); @@ -282,7 +284,7 @@ class Image extends BaseI18nLoop // Put source image file path $source_filepath = sprintf("%s%s/%s/%s", THELIA_ROOT, - ConfigQuery::read('documents_library_path', 'local/media/images'), + ConfigQuery::read('images_library_path', 'local/media/images'), $object_type, $result->getFile() ); diff --git a/core/lib/Thelia/Exception/DocumentException.php b/core/lib/Thelia/Exception/DocumentException.php new file mode 100644 index 000000000..9727a4267 --- /dev/null +++ b/core/lib/Thelia/Exception/DocumentException.php @@ -0,0 +1,36 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Exception; + +use Thelia\Log\Tlog; + +class DocumentException extends \RuntimeException +{ + public function __construct($message, $code = null, $previous = null) + { + Tlog::getInstance()->addError($message); + + parent::__construct($message, $code, $previous); + } +} diff --git a/core/lib/Thelia/Form/AdminLogin.php b/core/lib/Thelia/Form/AdminLogin.php index 88b9964e4..00236161d 100755 --- a/core/lib/Thelia/Form/AdminLogin.php +++ b/core/lib/Thelia/Form/AdminLogin.php @@ -24,6 +24,7 @@ namespace Thelia\Form; use Symfony\Component\Validator\Constraints\Length; use Symfony\Component\Validator\Constraints\NotBlank; +use Thelia\Core\Translation\Translator; class AdminLogin extends BaseForm { @@ -34,15 +35,27 @@ class AdminLogin extends BaseForm "constraints" => array( new NotBlank(), new Length(array("min" => 3)) + ), + "label" => Translator::getInstance()->trans("Username *"), + "label_attr" => array( + "for" => "username" ) )) ->add("password", "password", array( "constraints" => array( new NotBlank() + ), + "label" => Translator::getInstance()->trans("Password *"), + "label_attr" => array( + "for" => "password" ) )) ->add("remember_me", "checkbox", array( - 'value' => 'yes' + 'value' => 'yes', + "label" => Translator::getInstance()->trans("Remember me ?"), + "label_attr" => array( + "for" => "remember_me" + ) )) ; } diff --git a/core/lib/Thelia/Form/CategoryCreationForm.php b/core/lib/Thelia/Form/CategoryCreationForm.php index 5dce6a049..172b09ee6 100755 --- a/core/lib/Thelia/Form/CategoryCreationForm.php +++ b/core/lib/Thelia/Form/CategoryCreationForm.php @@ -39,7 +39,8 @@ class CategoryCreationForm extends BaseForm "for" => "title" ) )) - ->add("parent", "integer", array( + ->add("parent", "text", array( + "label" => Translator::getInstance()->trans("Parent category *"), "constraints" => array( new NotBlank() ) @@ -49,6 +50,9 @@ class CategoryCreationForm extends BaseForm new NotBlank() ) )) + ->add("visible", "integer", array( + "label" => Translator::getInstance()->trans("This category is online on the front office.") + )) ; } diff --git a/core/lib/Thelia/Form/CategoryModificationForm.php b/core/lib/Thelia/Form/CategoryModificationForm.php index d9de36d16..42b5893c1 100644 --- a/core/lib/Thelia/Form/CategoryModificationForm.php +++ b/core/lib/Thelia/Form/CategoryModificationForm.php @@ -24,6 +24,7 @@ namespace Thelia\Form; use Symfony\Component\Validator\Constraints\GreaterThan; use Thelia\Core\Translation\Translator; +use Symfony\Component\Validator\Constraints\NotBlank; class CategoryModificationForm extends CategoryCreationForm { @@ -36,12 +37,13 @@ class CategoryModificationForm extends CategoryCreationForm $this->formBuilder ->add("id", "hidden", array("constraints" => array(new GreaterThan(array('value' => 0))))) - ->add("visible", "checkbox", array( - "label" => Translator::getInstance()->trans("This category is online on the front office.") + ->add("url", "text", array( + "label" => Translator::getInstance()->trans("Rewriten URL *"), + "constraints" => array(new NotBlank()) )) ; - // Add standard description fields + // Add standard description fields, excluding title and locale, which a re defined in parent class $this->addStandardDescFields(array('title', 'locale')); } diff --git a/core/lib/Thelia/Form/CountryCreationForm.php b/core/lib/Thelia/Form/CountryCreationForm.php new file mode 100644 index 000000000..ad6701a64 --- /dev/null +++ b/core/lib/Thelia/Form/CountryCreationForm.php @@ -0,0 +1,85 @@ +. */ +/* */ +/*************************************************************************************/ +namespace Thelia\Form; + +use Symfony\Component\Validator\Constraints\NotBlank; +use Thelia\Core\Translation\Translator; + +class CountryCreationForm extends BaseForm +{ + protected function buildForm() + { + $this->formBuilder + ->add("title", "text", array( + "constraints" => array( + new NotBlank() + ), + "label" => Translator::getInstance()->trans("Country title *"), + "label_attr" => array( + "for" => "title" + ) + )) + ->add("area", "text", array( + "constraints" => array( + new NotBlank() + ), + "label" => Translator::getInstance()->trans("Country area *"), + "label_attr" => array( + "for" => "area" + ) + )) + ->add("isocode", "text", array( + "constraints" => array( + new NotBlank() + ), + "label" => Translator::getInstance()->trans("ISO Code *"), + "label_attr" => array( + "for" => "isocode" + ) + )) + ->add("isoalpha2", "text", array( + "constraints" => array( + new NotBlank() + ), + "label" => Translator::getInstance()->trans("Alpha code 2 *"), + "label_attr" => array( + "for" => "isoalpha2" + ) + )) + ->add("isoalpha3", "text", array( + "constraints" => array( + new NotBlank() + ), + "label" => Translator::getInstance()->trans("Alpha code 3 *"), + "label_attr" => array( + "for" => "isoalpha3" + ) + )) + ; + } + + public function getName() + { + return "thelia_country_creation"; + } +} diff --git a/core/lib/Thelia/Form/CountryModificationForm.php b/core/lib/Thelia/Form/CountryModificationForm.php new file mode 100644 index 000000000..4c1581664 --- /dev/null +++ b/core/lib/Thelia/Form/CountryModificationForm.php @@ -0,0 +1,107 @@ +. */ +/* */ +/*************************************************************************************/ +namespace Thelia\Form; + +use Symfony\Component\Validator\Constraints\GreaterThan; +use Symfony\Component\Validator\Constraints\NotBlank; +use Thelia\Core\Translation\Translator; + +class CountryModificationForm extends CurrencyCreationForm +{ + protected function buildForm() + { + parent::buildForm(true); + + $this->formBuilder + ->add("id", "hidden", array("constraints" => array(new GreaterThan(array('value' => 0))))) + ->add("title", "text", array( + "constraints" => array( + new NotBlank() + ), + "label" => Translator::getInstance()->trans("Country title *"), + "label_attr" => array( + "for" => "title" + ) + )) + ->add("short-description", "text", array( + "constraints" => array( + new NotBlank() + ), + "label" => Translator::getInstance()->trans("Country short description *"), + "label_attr" => array( + "for" => "short-description" + ) + )) + ->add("description", "text", array( + "constraints" => array( + new NotBlank() + ), + "label" => Translator::getInstance()->trans("Country description *"), + "label_attr" => array( + "for" => "description" + ) + )) + ->add("area", "text", array( + "constraints" => array( + new NotBlank() + ), + "label" => Translator::getInstance()->trans("Country area *"), + "label_attr" => array( + "for" => "area" + ) + )) + ->add("isocode", "text", array( + "constraints" => array( + new NotBlank() + ), + "label" => Translator::getInstance()->trans("ISO Code *"), + "label_attr" => array( + "for" => "isocode" + ) + )) + ->add("isoalpha2", "text", array( + "constraints" => array( + new NotBlank() + ), + "label" => Translator::getInstance()->trans("Alpha code 2 *"), + "label_attr" => array( + "for" => "isoalpha2" + ) + )) + ->add("isoalpha3", "text", array( + "constraints" => array( + new NotBlank() + ), + "label" => Translator::getInstance()->trans("Alpha code 3 *"), + "label_attr" => array( + "for" => "isoalpha3" + ) + )) + ; + } + + public function getName() + { + return "thelia_country_modification"; + } +} diff --git a/core/lib/Thelia/Mailer/MailerFactory.php b/core/lib/Thelia/Mailer/MailerFactory.php new file mode 100644 index 000000000..a327a155f --- /dev/null +++ b/core/lib/Thelia/Mailer/MailerFactory.php @@ -0,0 +1,91 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Mailer; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Thelia\Core\Event\MailTransporterEvent; +use Thelia\Core\Event\TheliaEvents; +use Thelia\Model\ConfigQuery; + + +/** + * Class MailerFactory + * @package Thelia\Mailer + * @author Manuel Raynaud + */ +class MailerFactory { + /** + * @var \Swift_Mailer + */ + protected $swiftMailer; + + protected $dispatcher; + + public function __construct(EventDispatcherInterface $dispatcher) + { + + $this->dispatcher = $dispatcher; + + $transporterEvent = new MailTransporterEvent(); + $this->dispatcher->dispatch(TheliaEvents::MAILTRANSPORTER_CONFIG, $transporterEvent); + + if($transporterEvent->hasTransporter()) { + $transporter = $transporterEvent->getTransporter(); + } else { + if (ConfigQuery::read("smtp.enabled")) { + $transporter = $this->configureSmtp(); + } else { + $transporter = \Swift_MailTransport::newInstance(); + } + } + + $this->swiftMailer = new \Swift_Mailer($transporter); + } + + private function configureSmtp() + { + $smtpTransporter = new \Swift_SmtpTransport(); + $smtpTransporter->setHost(Configquery::read('smtp.host', 'localhost')) + ->setPort(ConfigQuery::read('smtp.host')) + ->setEncryption(ConfigQuery::read('smtp.encryption')) + ->setUsername(ConfigQuery::read('smtp.username')) + ->setPassword(ConfigQuery::read('smtp.password')) + ->setAuthMode(ConfigQuery::read('smtp.authmode')) + ->setTimeout(ConfigQuery::read('smtp.timeout', 30)) + ->setSourceIp(ConfigQuery::read('smtp.sourceip')) + ; + return $smtpTransporter; + } + + public function send(\Swift_Mime_Message $message, &$failedRecipients = null) + { + $this->swiftMailer->send($message, $failedRecipients); + } + + public function getSwiftMailer() + { + return $this->swiftMailer; + } + + +} \ No newline at end of file diff --git a/core/lib/Thelia/Model/Base/Country.php b/core/lib/Thelia/Model/Base/Country.php index 90fd48880..86cc8220b 100644 --- a/core/lib/Thelia/Model/Base/Country.php +++ b/core/lib/Thelia/Model/Base/Country.php @@ -93,6 +93,12 @@ abstract class Country implements ActiveRecordInterface */ protected $isoalpha3; + /** + * The value for the by_default field. + * @var int + */ + protected $by_default; + /** * The value for the created_at field. * @var string @@ -477,6 +483,17 @@ abstract class Country implements ActiveRecordInterface return $this->isoalpha3; } + /** + * Get the [by_default] column value. + * + * @return int + */ + public function getByDefault() + { + + return $this->by_default; + } + /** * Get the [optionally formatted] temporal [created_at] column value. * @@ -626,6 +643,27 @@ abstract class Country implements ActiveRecordInterface return $this; } // setIsoalpha3() + /** + * Set the value of [by_default] column. + * + * @param int $v new value + * @return \Thelia\Model\Country The current object (for fluent API support) + */ + public function setByDefault($v) + { + if ($v !== null) { + $v = (int) $v; + } + + if ($this->by_default !== $v) { + $this->by_default = $v; + $this->modifiedColumns[] = CountryTableMap::BY_DEFAULT; + } + + + return $this; + } // setByDefault() + /** * Sets the value of [created_at] column to a normalized version of the date/time value specified. * @@ -720,13 +758,16 @@ abstract class Country implements ActiveRecordInterface $col = $row[TableMap::TYPE_NUM == $indexType ? 4 + $startcol : CountryTableMap::translateFieldName('Isoalpha3', TableMap::TYPE_PHPNAME, $indexType)]; $this->isoalpha3 = (null !== $col) ? (string) $col : null; - $col = $row[TableMap::TYPE_NUM == $indexType ? 5 + $startcol : CountryTableMap::translateFieldName('CreatedAt', TableMap::TYPE_PHPNAME, $indexType)]; + $col = $row[TableMap::TYPE_NUM == $indexType ? 5 + $startcol : CountryTableMap::translateFieldName('ByDefault', TableMap::TYPE_PHPNAME, $indexType)]; + $this->by_default = (null !== $col) ? (int) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 6 + $startcol : CountryTableMap::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 : CountryTableMap::translateFieldName('UpdatedAt', TableMap::TYPE_PHPNAME, $indexType)]; + $col = $row[TableMap::TYPE_NUM == $indexType ? 7 + $startcol : CountryTableMap::translateFieldName('UpdatedAt', TableMap::TYPE_PHPNAME, $indexType)]; if ($col === '0000-00-00 00:00:00') { $col = null; } @@ -739,7 +780,7 @@ abstract class Country implements ActiveRecordInterface $this->ensureConsistency(); } - return $startcol + 7; // 7 = CountryTableMap::NUM_HYDRATE_COLUMNS. + return $startcol + 8; // 8 = CountryTableMap::NUM_HYDRATE_COLUMNS. } catch (Exception $e) { throw new PropelException("Error populating \Thelia\Model\Country object", 0, $e); @@ -1043,6 +1084,9 @@ abstract class Country implements ActiveRecordInterface if ($this->isColumnModified(CountryTableMap::ISOALPHA3)) { $modifiedColumns[':p' . $index++] = 'ISOALPHA3'; } + if ($this->isColumnModified(CountryTableMap::BY_DEFAULT)) { + $modifiedColumns[':p' . $index++] = 'BY_DEFAULT'; + } if ($this->isColumnModified(CountryTableMap::CREATED_AT)) { $modifiedColumns[':p' . $index++] = 'CREATED_AT'; } @@ -1075,6 +1119,9 @@ abstract class Country implements ActiveRecordInterface case 'ISOALPHA3': $stmt->bindValue($identifier, $this->isoalpha3, PDO::PARAM_STR); break; + case 'BY_DEFAULT': + $stmt->bindValue($identifier, $this->by_default, PDO::PARAM_INT); + break; case 'CREATED_AT': $stmt->bindValue($identifier, $this->created_at ? $this->created_at->format("Y-m-d H:i:s") : null, PDO::PARAM_STR); break; @@ -1152,9 +1199,12 @@ abstract class Country implements ActiveRecordInterface return $this->getIsoalpha3(); break; case 5: - return $this->getCreatedAt(); + return $this->getByDefault(); break; case 6: + return $this->getCreatedAt(); + break; + case 7: return $this->getUpdatedAt(); break; default: @@ -1191,8 +1241,9 @@ abstract class Country implements ActiveRecordInterface $keys[2] => $this->getIsocode(), $keys[3] => $this->getIsoalpha2(), $keys[4] => $this->getIsoalpha3(), - $keys[5] => $this->getCreatedAt(), - $keys[6] => $this->getUpdatedAt(), + $keys[5] => $this->getByDefault(), + $keys[6] => $this->getCreatedAt(), + $keys[7] => $this->getUpdatedAt(), ); $virtualColumns = $this->virtualColumns; foreach($virtualColumns as $key => $virtualColumn) @@ -1263,9 +1314,12 @@ abstract class Country implements ActiveRecordInterface $this->setIsoalpha3($value); break; case 5: - $this->setCreatedAt($value); + $this->setByDefault($value); break; case 6: + $this->setCreatedAt($value); + break; + case 7: $this->setUpdatedAt($value); break; } // switch() @@ -1297,8 +1351,9 @@ abstract class Country implements ActiveRecordInterface if (array_key_exists($keys[2], $arr)) $this->setIsocode($arr[$keys[2]]); if (array_key_exists($keys[3], $arr)) $this->setIsoalpha2($arr[$keys[3]]); if (array_key_exists($keys[4], $arr)) $this->setIsoalpha3($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[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]]); } /** @@ -1315,6 +1370,7 @@ abstract class Country implements ActiveRecordInterface if ($this->isColumnModified(CountryTableMap::ISOCODE)) $criteria->add(CountryTableMap::ISOCODE, $this->isocode); if ($this->isColumnModified(CountryTableMap::ISOALPHA2)) $criteria->add(CountryTableMap::ISOALPHA2, $this->isoalpha2); if ($this->isColumnModified(CountryTableMap::ISOALPHA3)) $criteria->add(CountryTableMap::ISOALPHA3, $this->isoalpha3); + if ($this->isColumnModified(CountryTableMap::BY_DEFAULT)) $criteria->add(CountryTableMap::BY_DEFAULT, $this->by_default); if ($this->isColumnModified(CountryTableMap::CREATED_AT)) $criteria->add(CountryTableMap::CREATED_AT, $this->created_at); if ($this->isColumnModified(CountryTableMap::UPDATED_AT)) $criteria->add(CountryTableMap::UPDATED_AT, $this->updated_at); @@ -1385,6 +1441,7 @@ abstract class Country implements ActiveRecordInterface $copyObj->setIsocode($this->getIsocode()); $copyObj->setIsoalpha2($this->getIsoalpha2()); $copyObj->setIsoalpha3($this->getIsoalpha3()); + $copyObj->setByDefault($this->getByDefault()); $copyObj->setCreatedAt($this->getCreatedAt()); $copyObj->setUpdatedAt($this->getUpdatedAt()); @@ -2287,6 +2344,7 @@ abstract class Country implements ActiveRecordInterface $this->isocode = null; $this->isoalpha2 = null; $this->isoalpha3 = null; + $this->by_default = null; $this->created_at = null; $this->updated_at = null; $this->alreadyInSave = false; diff --git a/core/lib/Thelia/Model/Base/CountryQuery.php b/core/lib/Thelia/Model/Base/CountryQuery.php index 1e565e9c0..5e60f1821 100644 --- a/core/lib/Thelia/Model/Base/CountryQuery.php +++ b/core/lib/Thelia/Model/Base/CountryQuery.php @@ -27,6 +27,7 @@ use Thelia\Model\Map\CountryTableMap; * @method ChildCountryQuery orderByIsocode($order = Criteria::ASC) Order by the isocode column * @method ChildCountryQuery orderByIsoalpha2($order = Criteria::ASC) Order by the isoalpha2 column * @method ChildCountryQuery orderByIsoalpha3($order = Criteria::ASC) Order by the isoalpha3 column + * @method ChildCountryQuery orderByByDefault($order = Criteria::ASC) Order by the by_default column * @method ChildCountryQuery orderByCreatedAt($order = Criteria::ASC) Order by the created_at column * @method ChildCountryQuery orderByUpdatedAt($order = Criteria::ASC) Order by the updated_at column * @@ -35,6 +36,7 @@ use Thelia\Model\Map\CountryTableMap; * @method ChildCountryQuery groupByIsocode() Group by the isocode column * @method ChildCountryQuery groupByIsoalpha2() Group by the isoalpha2 column * @method ChildCountryQuery groupByIsoalpha3() Group by the isoalpha3 column + * @method ChildCountryQuery groupByByDefault() Group by the by_default column * @method ChildCountryQuery groupByCreatedAt() Group by the created_at column * @method ChildCountryQuery groupByUpdatedAt() Group by the updated_at column * @@ -66,6 +68,7 @@ use Thelia\Model\Map\CountryTableMap; * @method ChildCountry findOneByIsocode(string $isocode) Return the first ChildCountry filtered by the isocode column * @method ChildCountry findOneByIsoalpha2(string $isoalpha2) Return the first ChildCountry filtered by the isoalpha2 column * @method ChildCountry findOneByIsoalpha3(string $isoalpha3) Return the first ChildCountry filtered by the isoalpha3 column + * @method ChildCountry findOneByByDefault(int $by_default) Return the first ChildCountry filtered by the by_default column * @method ChildCountry findOneByCreatedAt(string $created_at) Return the first ChildCountry filtered by the created_at column * @method ChildCountry findOneByUpdatedAt(string $updated_at) Return the first ChildCountry filtered by the updated_at column * @@ -74,6 +77,7 @@ use Thelia\Model\Map\CountryTableMap; * @method array findByIsocode(string $isocode) Return ChildCountry objects filtered by the isocode column * @method array findByIsoalpha2(string $isoalpha2) Return ChildCountry objects filtered by the isoalpha2 column * @method array findByIsoalpha3(string $isoalpha3) Return ChildCountry objects filtered by the isoalpha3 column + * @method array findByByDefault(int $by_default) Return ChildCountry objects filtered by the by_default column * @method array findByCreatedAt(string $created_at) Return ChildCountry objects filtered by the created_at column * @method array findByUpdatedAt(string $updated_at) Return ChildCountry objects filtered by the updated_at column * @@ -164,7 +168,7 @@ abstract class CountryQuery extends ModelCriteria */ protected function findPkSimple($key, $con) { - $sql = 'SELECT ID, AREA_ID, ISOCODE, ISOALPHA2, ISOALPHA3, CREATED_AT, UPDATED_AT FROM country WHERE ID = :p0'; + $sql = 'SELECT ID, AREA_ID, ISOCODE, ISOALPHA2, ISOALPHA3, BY_DEFAULT, CREATED_AT, UPDATED_AT FROM country WHERE ID = :p0'; try { $stmt = $con->prepare($sql); $stmt->bindValue(':p0', $key, PDO::PARAM_INT); @@ -424,6 +428,47 @@ abstract class CountryQuery extends ModelCriteria return $this->addUsingAlias(CountryTableMap::ISOALPHA3, $isoalpha3, $comparison); } + /** + * Filter the query on the by_default column + * + * Example usage: + * + * $query->filterByByDefault(1234); // WHERE by_default = 1234 + * $query->filterByByDefault(array(12, 34)); // WHERE by_default IN (12, 34) + * $query->filterByByDefault(array('min' => 12)); // WHERE by_default > 12 + * + * + * @param mixed $byDefault 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 ChildCountryQuery The current query, for fluid interface + */ + public function filterByByDefault($byDefault = null, $comparison = null) + { + if (is_array($byDefault)) { + $useMinMax = false; + if (isset($byDefault['min'])) { + $this->addUsingAlias(CountryTableMap::BY_DEFAULT, $byDefault['min'], Criteria::GREATER_EQUAL); + $useMinMax = true; + } + if (isset($byDefault['max'])) { + $this->addUsingAlias(CountryTableMap::BY_DEFAULT, $byDefault['max'], Criteria::LESS_EQUAL); + $useMinMax = true; + } + if ($useMinMax) { + return $this; + } + if (null === $comparison) { + $comparison = Criteria::IN; + } + } + + return $this->addUsingAlias(CountryTableMap::BY_DEFAULT, $byDefault, $comparison); + } + /** * Filter the query on the created_at column * diff --git a/core/lib/Thelia/Model/Category.php b/core/lib/Thelia/Model/Category.php index ced10c94b..042864de0 100755 --- a/core/lib/Thelia/Model/Category.php +++ b/core/lib/Thelia/Model/Category.php @@ -15,6 +15,8 @@ class Category extends BaseCategory use \Thelia\Model\Tools\PositionManagementTrait; + use \Thelia\Model\Tools\UrlRewritingTrait; + /** * @return int number of child for the current category */ @@ -23,30 +25,12 @@ class Category extends BaseCategory return CategoryQuery::countChild($this->getId()); } - public function getUrl($locale) - { - return URL::getInstance()->retrieve('category', $this->getId(), $locale)->toString(); - } - /** - * Create a new category. - * - * @param string $title the category title - * @param int $parent the ID of the parent category - * @param string $locale the locale of the title + * {@inheritDoc} */ - public function create($title, $parent, $locale) - { - $this - ->setLocale($locale) - ->setTitle($title) - ->setParent($parent) - ->setVisible(1) - ->setPosition($this->getNextPosition($parent)) - ; - - $this->save(); - } + protected function getRewritenUrlViewName() { + return 'category'; + } /** * @@ -71,18 +55,38 @@ class Category extends BaseCategory return $countProduct; } + /** + * Calculate next position relative to our parent + */ + protected function addCriteriaToPositionQuery($query) { + $query->filterByParent($this->getParent()); + } + + /** + * {@inheritDoc} + */ public function preInsert(ConnectionInterface $con = null) { + $this->setPosition($this->getNextPosition()); + + $this->generateRewritenUrl($this->getLocale()); + $this->dispatchEvent(TheliaEvents::BEFORE_CREATECATEGORY, new CategoryEvent($this)); return true; } + /** + * {@inheritDoc} + */ public function postInsert(ConnectionInterface $con = null) { $this->dispatchEvent(TheliaEvents::AFTER_CREATECATEGORY, new CategoryEvent($this)); } + /** + * {@inheritDoc} + */ public function preUpdate(ConnectionInterface $con = null) { $this->dispatchEvent(TheliaEvents::BEFORE_UPDATECATEGORY, new CategoryEvent($this)); @@ -90,16 +94,27 @@ class Category extends BaseCategory return true; } + /** + * {@inheritDoc} + */ public function postUpdate(ConnectionInterface $con = null) { $this->dispatchEvent(TheliaEvents::AFTER_UPDATECATEGORY, new CategoryEvent($this)); } + /** + * {@inheritDoc} + */ public function preDelete(ConnectionInterface $con = null) { $this->dispatchEvent(TheliaEvents::BEFORE_DELETECATEGORY, new CategoryEvent($this)); + + return true; } + /** + * {@inheritDoc} + */ public function postDelete(ConnectionInterface $con = null) { $this->dispatchEvent(TheliaEvents::AFTER_DELETECATEGORY, new CategoryEvent($this)); diff --git a/core/lib/Thelia/Model/CategoryDocument.php b/core/lib/Thelia/Model/CategoryDocument.php index bd86f1d1e..73d99f591 100755 --- a/core/lib/Thelia/Model/CategoryDocument.php +++ b/core/lib/Thelia/Model/CategoryDocument.php @@ -3,8 +3,26 @@ namespace Thelia\Model; use Thelia\Model\Base\CategoryDocument as BaseCategoryDocument; +use Propel\Runtime\Connection\ConnectionInterface; - class CategoryDocument extends BaseCategoryDocument +class CategoryDocument extends BaseCategoryDocument { + use \Thelia\Model\Tools\PositionManagementTrait; + /** + * Calculate next position relative to our parent + */ + protected function addCriteriaToPositionQuery($query) { + $query->filterByCategory($this->getCategory()); + } + + /** + * {@inheritDoc} + */ + public function preInsert(ConnectionInterface $con = null) + { + $this->setPosition($this->getNextPosition()); + + return true; + } } diff --git a/core/lib/Thelia/Model/CategoryImage.php b/core/lib/Thelia/Model/CategoryImage.php index ef555f83e..5bf964e10 100755 --- a/core/lib/Thelia/Model/CategoryImage.php +++ b/core/lib/Thelia/Model/CategoryImage.php @@ -3,8 +3,26 @@ namespace Thelia\Model; use Thelia\Model\Base\CategoryImage as BaseCategoryImage; +use Propel\Runtime\Connection\ConnectionInterface; - class CategoryImage extends BaseCategoryImage +class CategoryImage extends BaseCategoryImage { + use \Thelia\Model\Tools\PositionManagementTrait; + /** + * Calculate next position relative to our parent + */ + protected function addCriteriaToPositionQuery($query) { + $query->filterByCategory($this->getCategory()); + } + + /** + * {@inheritDoc} + */ + public function preInsert(ConnectionInterface $con = null) + { + $this->setPosition($this->getNextPosition()); + + return true; + } } diff --git a/core/lib/Thelia/Model/Content.php b/core/lib/Thelia/Model/Content.php index 5bc0ba6b2..79660f93a 100755 --- a/core/lib/Thelia/Model/Content.php +++ b/core/lib/Thelia/Model/Content.php @@ -4,11 +4,41 @@ namespace Thelia\Model; use Thelia\Model\Base\Content as BaseContent; use Thelia\Tools\URL; +use Propel\Runtime\Connection\ConnectionInterface; class Content extends BaseContent { - public function getUrl($locale) + use \Thelia\Model\Tools\ModelEventDispatcherTrait; + + use \Thelia\Model\Tools\PositionManagementTrait; + + use \Thelia\Model\Tools\UrlRewritingTrait; + + /** + * {@inheritDoc} + */ + protected function getRewritenUrlViewName() { + return 'content'; + } + + /** + * Calculate next position relative to our parent + */ + protected function addCriteriaToPositionQuery($query) { + + // TODO: Find the default folder for this content, + // and generate the position relative to this folder + } + + /** + * {@inheritDoc} + */ + public function preInsert(ConnectionInterface $con = null) { - return URL::getInstance()->retrieve('content', $this->getId(), $locale)->toString(); + $this->setPosition($this->getNextPosition()); + + $this->generateRewritenUrl($this->getLocale()); + + return true; } } diff --git a/core/lib/Thelia/Model/ContentDocument.php b/core/lib/Thelia/Model/ContentDocument.php index 933a089cb..8ecf3a3a9 100755 --- a/core/lib/Thelia/Model/ContentDocument.php +++ b/core/lib/Thelia/Model/ContentDocument.php @@ -3,8 +3,26 @@ namespace Thelia\Model; use Thelia\Model\Base\ContentDocument as BaseContentDocument; +use Propel\Runtime\Connection\ConnectionInterface; - class ContentDocument extends BaseContentDocument +class ContentDocument extends BaseContentDocument { + use \Thelia\Model\Tools\PositionManagementTrait; + /** + * Calculate next position relative to our parent + */ + protected function addCriteriaToPositionQuery($query) { + $query->filterByContent($this->getContent()); + } + + /** + * {@inheritDoc} + */ + public function preInsert(ConnectionInterface $con = null) + { + $this->setPosition($this->getNextPosition()); + + return true; + } } diff --git a/core/lib/Thelia/Model/ContentImage.php b/core/lib/Thelia/Model/ContentImage.php index 3020e48f3..ac1dcf755 100755 --- a/core/lib/Thelia/Model/ContentImage.php +++ b/core/lib/Thelia/Model/ContentImage.php @@ -3,8 +3,26 @@ namespace Thelia\Model; use Thelia\Model\Base\ContentImage as BaseContentImage; +use Propel\Runtime\Connection\ConnectionInterface; - class ContentImage extends BaseContentImage +class ContentImage extends BaseContentImage { + use \Thelia\Model\Tools\PositionManagementTrait; -} + /** + * Calculate next position relative to our parent + */ + protected function addCriteriaToPositionQuery($query) { + $query->filterByContent($this->getContent()); + } + + /** + * {@inheritDoc} + */ + public function preInsert(ConnectionInterface $con = null) + { + $this->setPosition($this->getNextPosition()); + + return true; + } +} \ No newline at end of file diff --git a/core/lib/Thelia/Model/Folder.php b/core/lib/Thelia/Model/Folder.php index 8151dae0e..1e73e7e23 100755 --- a/core/lib/Thelia/Model/Folder.php +++ b/core/lib/Thelia/Model/Folder.php @@ -4,9 +4,23 @@ namespace Thelia\Model; use Thelia\Model\Base\Folder as BaseFolder; use Thelia\Tools\URL; +use Propel\Runtime\Connection\ConnectionInterface; class Folder extends BaseFolder { + use \Thelia\Model\Tools\ModelEventDispatcherTrait; + + use \Thelia\Model\Tools\PositionManagementTrait; + + use \Thelia\Model\Tools\UrlRewritingTrait; + + /** + * {@inheritDoc} + */ + protected function getRewritenUrlViewName() { + return 'folder'; + } + /** * @return int number of contents for the folder */ @@ -15,11 +29,6 @@ class Folder extends BaseFolder return FolderQuery::countChild($this->getId()); } - public function getUrl($locale) - { - return URL::getInstance()->retrieve('folder', $this->getId(), $locale)->toString(); - } - /** * * count all products for current category and sub categories @@ -43,4 +52,23 @@ class Folder extends BaseFolder return $contentsCount; } + + /** + * Calculate next position relative to our parent + */ + protected function addCriteriaToPositionQuery($query) { + $query->filterByParent($this->getParent()); + } + + /** + * {@inheritDoc} + */ + public function preInsert(ConnectionInterface $con = null) + { + $this->setPosition($this->getNextPosition()); + + $this->generateRewritenUrl($this->getLocale()); + + return true; + } } diff --git a/core/lib/Thelia/Model/FolderDocument.php b/core/lib/Thelia/Model/FolderDocument.php index c9644835e..0a86995d2 100755 --- a/core/lib/Thelia/Model/FolderDocument.php +++ b/core/lib/Thelia/Model/FolderDocument.php @@ -3,8 +3,26 @@ namespace Thelia\Model; use Thelia\Model\Base\FolderDocument as BaseFolderDocument; +use Propel\Runtime\Connection\ConnectionInterface; - class FolderDocument extends BaseFolderDocument +class FolderDocument extends BaseFolderDocument { + use \Thelia\Model\Tools\PositionManagementTrait; + /** + * Calculate next position relative to our parent + */ + protected function addCriteriaToPositionQuery($query) { + $query->filterByFolder($this->getFolder()); + } + + /** + * {@inheritDoc} + */ + public function preInsert(ConnectionInterface $con = null) + { + $this->setPosition($this->getNextPosition()); + + return true; + } } diff --git a/core/lib/Thelia/Model/FolderImage.php b/core/lib/Thelia/Model/FolderImage.php index 4e6d285f8..58d8f928e 100755 --- a/core/lib/Thelia/Model/FolderImage.php +++ b/core/lib/Thelia/Model/FolderImage.php @@ -3,8 +3,26 @@ namespace Thelia\Model; use Thelia\Model\Base\FolderImage as BaseFolderImage; +use Propel\Runtime\Connection\ConnectionInterface; - class FolderImage extends BaseFolderImage +class FolderImage extends BaseFolderImage { + use \Thelia\Model\Tools\PositionManagementTrait; + /** + * Calculate next position relative to our parent + */ + protected function addCriteriaToPositionQuery($query) { + $query->filterByFolder($this->getFolder()); + } + + /** + * {@inheritDoc} + */ + public function preInsert(ConnectionInterface $con = null) + { + $this->setPosition($this->getNextPosition()); + + return true; + } } diff --git a/core/lib/Thelia/Model/Map/CountryTableMap.php b/core/lib/Thelia/Model/Map/CountryTableMap.php index e7c356f08..519af7176 100644 --- a/core/lib/Thelia/Model/Map/CountryTableMap.php +++ b/core/lib/Thelia/Model/Map/CountryTableMap.php @@ -57,7 +57,7 @@ class CountryTableMap 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 CountryTableMap 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 @@ -94,6 +94,11 @@ class CountryTableMap extends TableMap */ const ISOALPHA3 = 'country.ISOALPHA3'; + /** + * the column name for the BY_DEFAULT field + */ + const BY_DEFAULT = 'country.BY_DEFAULT'; + /** * the column name for the CREATED_AT field */ @@ -125,12 +130,12 @@ class CountryTableMap extends TableMap * e.g. self::$fieldNames[self::TYPE_PHPNAME][0] = 'Id' */ protected static $fieldNames = array ( - self::TYPE_PHPNAME => array('Id', 'AreaId', 'Isocode', 'Isoalpha2', 'Isoalpha3', 'CreatedAt', 'UpdatedAt', ), - self::TYPE_STUDLYPHPNAME => array('id', 'areaId', 'isocode', 'isoalpha2', 'isoalpha3', 'createdAt', 'updatedAt', ), - self::TYPE_COLNAME => array(CountryTableMap::ID, CountryTableMap::AREA_ID, CountryTableMap::ISOCODE, CountryTableMap::ISOALPHA2, CountryTableMap::ISOALPHA3, CountryTableMap::CREATED_AT, CountryTableMap::UPDATED_AT, ), - self::TYPE_RAW_COLNAME => array('ID', 'AREA_ID', 'ISOCODE', 'ISOALPHA2', 'ISOALPHA3', 'CREATED_AT', 'UPDATED_AT', ), - self::TYPE_FIELDNAME => array('id', 'area_id', 'isocode', 'isoalpha2', 'isoalpha3', 'created_at', 'updated_at', ), - self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, ) + self::TYPE_PHPNAME => array('Id', 'AreaId', 'Isocode', 'Isoalpha2', 'Isoalpha3', 'ByDefault', 'CreatedAt', 'UpdatedAt', ), + self::TYPE_STUDLYPHPNAME => array('id', 'areaId', 'isocode', 'isoalpha2', 'isoalpha3', 'byDefault', 'createdAt', 'updatedAt', ), + self::TYPE_COLNAME => array(CountryTableMap::ID, CountryTableMap::AREA_ID, CountryTableMap::ISOCODE, CountryTableMap::ISOALPHA2, CountryTableMap::ISOALPHA3, CountryTableMap::BY_DEFAULT, CountryTableMap::CREATED_AT, CountryTableMap::UPDATED_AT, ), + self::TYPE_RAW_COLNAME => array('ID', 'AREA_ID', 'ISOCODE', 'ISOALPHA2', 'ISOALPHA3', 'BY_DEFAULT', 'CREATED_AT', 'UPDATED_AT', ), + self::TYPE_FIELDNAME => array('id', 'area_id', 'isocode', 'isoalpha2', 'isoalpha3', 'by_default', 'created_at', 'updated_at', ), + self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, 7, ) ); /** @@ -140,12 +145,12 @@ class CountryTableMap extends TableMap * e.g. self::$fieldKeys[self::TYPE_PHPNAME]['Id'] = 0 */ protected static $fieldKeys = array ( - self::TYPE_PHPNAME => array('Id' => 0, 'AreaId' => 1, 'Isocode' => 2, 'Isoalpha2' => 3, 'Isoalpha3' => 4, 'CreatedAt' => 5, 'UpdatedAt' => 6, ), - self::TYPE_STUDLYPHPNAME => array('id' => 0, 'areaId' => 1, 'isocode' => 2, 'isoalpha2' => 3, 'isoalpha3' => 4, 'createdAt' => 5, 'updatedAt' => 6, ), - self::TYPE_COLNAME => array(CountryTableMap::ID => 0, CountryTableMap::AREA_ID => 1, CountryTableMap::ISOCODE => 2, CountryTableMap::ISOALPHA2 => 3, CountryTableMap::ISOALPHA3 => 4, CountryTableMap::CREATED_AT => 5, CountryTableMap::UPDATED_AT => 6, ), - self::TYPE_RAW_COLNAME => array('ID' => 0, 'AREA_ID' => 1, 'ISOCODE' => 2, 'ISOALPHA2' => 3, 'ISOALPHA3' => 4, 'CREATED_AT' => 5, 'UPDATED_AT' => 6, ), - self::TYPE_FIELDNAME => array('id' => 0, 'area_id' => 1, 'isocode' => 2, 'isoalpha2' => 3, 'isoalpha3' => 4, 'created_at' => 5, 'updated_at' => 6, ), - self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, ) + self::TYPE_PHPNAME => array('Id' => 0, 'AreaId' => 1, 'Isocode' => 2, 'Isoalpha2' => 3, 'Isoalpha3' => 4, 'ByDefault' => 5, 'CreatedAt' => 6, 'UpdatedAt' => 7, ), + self::TYPE_STUDLYPHPNAME => array('id' => 0, 'areaId' => 1, 'isocode' => 2, 'isoalpha2' => 3, 'isoalpha3' => 4, 'byDefault' => 5, 'createdAt' => 6, 'updatedAt' => 7, ), + self::TYPE_COLNAME => array(CountryTableMap::ID => 0, CountryTableMap::AREA_ID => 1, CountryTableMap::ISOCODE => 2, CountryTableMap::ISOALPHA2 => 3, CountryTableMap::ISOALPHA3 => 4, CountryTableMap::BY_DEFAULT => 5, CountryTableMap::CREATED_AT => 6, CountryTableMap::UPDATED_AT => 7, ), + self::TYPE_RAW_COLNAME => array('ID' => 0, 'AREA_ID' => 1, 'ISOCODE' => 2, 'ISOALPHA2' => 3, 'ISOALPHA3' => 4, 'BY_DEFAULT' => 5, 'CREATED_AT' => 6, 'UPDATED_AT' => 7, ), + self::TYPE_FIELDNAME => array('id' => 0, 'area_id' => 1, 'isocode' => 2, 'isoalpha2' => 3, 'isoalpha3' => 4, 'by_default' => 5, 'created_at' => 6, 'updated_at' => 7, ), + self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, 7, ) ); /** @@ -169,6 +174,7 @@ class CountryTableMap extends TableMap $this->addColumn('ISOCODE', 'Isocode', 'VARCHAR', true, 4, null); $this->addColumn('ISOALPHA2', 'Isoalpha2', 'VARCHAR', false, 2, null); $this->addColumn('ISOALPHA3', 'Isoalpha3', 'VARCHAR', false, 4, 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); } // initialize() @@ -351,6 +357,7 @@ class CountryTableMap extends TableMap $criteria->addSelectColumn(CountryTableMap::ISOCODE); $criteria->addSelectColumn(CountryTableMap::ISOALPHA2); $criteria->addSelectColumn(CountryTableMap::ISOALPHA3); + $criteria->addSelectColumn(CountryTableMap::BY_DEFAULT); $criteria->addSelectColumn(CountryTableMap::CREATED_AT); $criteria->addSelectColumn(CountryTableMap::UPDATED_AT); } else { @@ -359,6 +366,7 @@ class CountryTableMap extends TableMap $criteria->addSelectColumn($alias . '.ISOCODE'); $criteria->addSelectColumn($alias . '.ISOALPHA2'); $criteria->addSelectColumn($alias . '.ISOALPHA3'); + $criteria->addSelectColumn($alias . '.BY_DEFAULT'); $criteria->addSelectColumn($alias . '.CREATED_AT'); $criteria->addSelectColumn($alias . '.UPDATED_AT'); } diff --git a/core/lib/Thelia/Model/Product.php b/core/lib/Thelia/Model/Product.php index 06c4640d0..cc082e691 100755 --- a/core/lib/Thelia/Model/Product.php +++ b/core/lib/Thelia/Model/Product.php @@ -6,19 +6,29 @@ use Propel\Runtime\Exception\PropelException; use Thelia\Model\Base\Product as BaseProduct; use Thelia\Tools\URL; use Thelia\TaxEngine\Calculator; +use Propel\Runtime\Connection\ConnectionInterface; class Product extends BaseProduct { - public function getUrl($locale) - { - return URL::getInstance()->retrieve('product', $this->getId(), $locale)->toString(); + use \Thelia\Model\Tools\ModelEventDispatcherTrait; + + use \Thelia\Model\Tools\PositionManagementTrait; + + use \Thelia\Model\Tools\UrlRewritingTrait; + + /** + * {@inheritDoc} + */ + protected function getRewritenUrlViewName() { + return 'product'; } public function getRealLowestPrice($virtualColumnName = 'real_lowest_price') { try { $amount = $this->getVirtualColumn($virtualColumnName); - } catch(PropelException $e) { + } + catch(PropelException $e) { throw new PropelException("Virtual column `$virtualColumnName` does not exist in Product::getRealLowestPrice"); } @@ -30,4 +40,26 @@ class Product extends BaseProduct $taxCalculator = new Calculator(); return $taxCalculator->load($this, $country)->getTaxedPrice($this->getRealLowestPrice()); } + + /** + * Calculate next position relative to our default category + */ + protected function addCriteriaToPositionQuery($query) { + + // TODO: Find the default category for this product, + // and generate the position relative to this category + + } + + /** + * {@inheritDoc} + */ + public function preInsert(ConnectionInterface $con = null) + { + $this->setPosition($this->getNextPosition()); + + $this->generateRewritenUrl($this->getLocale()); + + return true; + } } diff --git a/core/lib/Thelia/Model/ProductDocument.php b/core/lib/Thelia/Model/ProductDocument.php index a49c4f11e..53515ff3c 100755 --- a/core/lib/Thelia/Model/ProductDocument.php +++ b/core/lib/Thelia/Model/ProductDocument.php @@ -3,8 +3,27 @@ namespace Thelia\Model; use Thelia\Model\Base\ProductDocument as BaseProductDocument; +use Propel\Runtime\Connection\ConnectionInterface; - class ProductDocument extends BaseProductDocument +class ProductDocument extends BaseProductDocument { + use \Thelia\Model\Tools\PositionManagementTrait; + + /** + * Calculate next position relative to our parent + */ + protected function addCriteriaToPositionQuery($query) { + $query->filterByProduct($this->getProduct()); + } + + /** + * {@inheritDoc} + */ + public function preInsert(ConnectionInterface $con = null) + { + $this->setPosition($this->getNextPosition()); + + return true; + } } diff --git a/core/lib/Thelia/Model/ProductImage.php b/core/lib/Thelia/Model/ProductImage.php index 9fe5b78e0..4bf0c40a6 100755 --- a/core/lib/Thelia/Model/ProductImage.php +++ b/core/lib/Thelia/Model/ProductImage.php @@ -3,8 +3,26 @@ namespace Thelia\Model; use Thelia\Model\Base\ProductImage as BaseProductImage; +use Propel\Runtime\Connection\ConnectionInterface; - class ProductImage extends BaseProductImage +class ProductImage extends BaseProductImage { + use \Thelia\Model\Tools\PositionManagementTrait; + /** + * Calculate next position relative to our parent + */ + protected function addCriteriaToPositionQuery($query) { + $query->filterByProduct($this->getProduct()); + } + + /** + * {@inheritDoc} + */ + public function preInsert(ConnectionInterface $con = null) + { + $this->setPosition($this->getNextPosition()); + + return true; + } } diff --git a/core/lib/Thelia/Model/Tools/UrlRewritingTrait.php b/core/lib/Thelia/Model/Tools/UrlRewritingTrait.php new file mode 100644 index 000000000..6ab24fbc4 --- /dev/null +++ b/core/lib/Thelia/Model/Tools/UrlRewritingTrait.php @@ -0,0 +1,78 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Model\Tools; + +use Thelia\Tools\URL; +/** + * A trait for managing Rewriten URLs from model classes + */ +trait UrlRewritingTrait { + + /** + * @returns string the view name of the rewriten object (e.g., 'category', 'product') + */ + protected abstract function getRewritenUrlViewName(); + + /** + * Get the object URL for the given locale, rewriten if rewriting is enabled. + * + * @param string $locale a valid locale (e.g. en_US) + */ + public function getUrl($locale) + { + return URL::getInstance()->retrieve($this->getRewritenUrlViewName(), $this->getId(), $locale)->toString(); + } + + /** + * Generate a rewriten URL from the object title, and store it in the rewriting table + * + * @param string $locale a valid locale (e.g. en_US) + */ + public function generateRewritenUrl($locale) + { + URL::getInstance()->generateRewritenUrl($this->getRewritenUrlViewName(), $this->getId(), $locale, $this->getTitle()); + } + + /** + * return the rewriten URL for the given locale + * + * @param string $locale a valid locale (e.g. en_US) + */ + public function getRewritenUrl($locale) + { + return "fake url - TODO"; + } + + /** + * Set the rewriten URL for the given locale + * + * @param string $locale a valid locale (e.g. en_US) + */ + public function setRewritenUrl($locale, $url) + { + // TODO - code me ! + + return $this; + } +} \ No newline at end of file diff --git a/core/lib/Thelia/Tests/Action/DocumentTest.php b/core/lib/Thelia/Tests/Action/DocumentTest.php new file mode 100644 index 000000000..39aece1f4 --- /dev/null +++ b/core/lib/Thelia/Tests/Action/DocumentTest.php @@ -0,0 +1,248 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Tests\Action\DocumentTest; + +use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage; +use Thelia\Core\HttpFoundation\Request; +use Thelia\Core\HttpFoundation\Session\Session; + +use Thelia\Action\Document; +use Thelia\Core\Event\DocumentEvent; +use Thelia\Model\ConfigQuery; + +/** + * Class DocumentTest + * + * @package Thelia\Tests\Action\DocumentTest + */ +class DocumentTest extends \Thelia\Tests\TestCaseWithURLToolSetup +{ + protected $request; + + protected $session; + + public function getContainer() + { + $container = new \Symfony\Component\DependencyInjection\ContainerBuilder(); + + $dispatcher = $this->getMock("Symfony\Component\EventDispatcher\EventDispatcherInterface"); + + $container->set("event_dispatcher", $dispatcher); + + $request = new Request(); + $request->setSession($this->session); + + $container->set("request", $request); + + return $container; + } + + public function setUp() + { + $this->session = new Session(new MockArraySessionStorage()); + $this->request = new Request(); + + $this->request->setSession($this->session); + + // mock cache configuration. + $config = ConfigQuery::create()->filterByName('document_cache_dir_from_web_root')->findOne(); + + if ($config != null) { + $this->cache_dir_from_web_root = $config->getValue(); + + $config->setValue(__DIR__."/assets/documents/cache"); + + $config->setValue($this->cache_dir_from_web_root)->save(); + } + } + + public static function setUpBeforeClass() + { + $dir = THELIA_WEB_DIR."/cache/tests"; + if ($dh = @opendir($dir)) { + while ($file = readdir($dh)) { + if ($file == '.' || $file == '..') continue; + + unlink(sprintf("%s/%s", $dir, $file)); + } + + closedir($dh); + } + } + + public function tearDown() + { + // restore cache configuration. + $config = ConfigQuery::create()->filterByName('document_cache_dir_from_web_root')->findOne(); + + if ($config != null) { + $config->setValue($this->cache_dir_from_web_root)->save(); + } + } + + /** + * + * Documentevent is empty, mandatory parameters not specified. + * + * @expectedException \InvalidArgumentException + */ + public function testProcessEmptyDocumentEvent() + { + $event = new DocumentEvent($this->request); + + $document = new Document($this->getContainer()); + + $document->processDocument($event); + } + + /** + * + * Try to process a non-existent file + * + * @expectedException \InvalidArgumentException + */ + public function testProcessNonExistentDocument() + { + $event = new DocumentEvent($this->request); + + $document = new Document($this->getContainer()); + + $event->setCacheFilepath("blablabla.txt"); + $event->setCacheSubdirectory("tests"); + + $document->processDocument($event); + } + + /** + * + * Try to process a file outside of the cache + * + * @expectedException \InvalidArgumentException + */ + public function testProcessDocumentOutsideValidPath() + { + $event = new DocumentEvent($this->request); + + $document = new Document($this->getContainer()); + + $event->setCacheFilepath("blablabla.pdf"); + $event->setCacheSubdirectory("../../../"); + + $document->processDocument($event); + } + + /** + * No operation done on source file -> copie ! + */ + public function testProcessDocumentCopy() + { + $event = new DocumentEvent($this->request); + + $event->setSourceFilepath(__DIR__."/assets/documents/sources/test-document-1.txt"); + $event->setCacheSubdirectory("tests"); + + $document = new Document($this->getContainer()); + + // mock cache configuration. + $config = ConfigQuery::create()->filterByName('original_document_delivery_mode')->findOne(); + + if ($config != null) { + $oldval = $config->getValue(); + $config->setValue('copy')->save(); + } + + $document->processDocument($event); + + if ($config != null) $config->setValue($oldval)->save(); + + $imgdir = ConfigQuery::read('document_cache_dir_from_web_root'); + + $this->assertFileExists(THELIA_WEB_DIR."/$imgdir/tests/test-document-1.txt"); + } + + /** + * No operation done on source file -> link ! + */ + public function testProcessDocumentSymlink() + { + $event = new DocumentEvent($this->request); + + $event->setSourceFilepath(__DIR__."/assets/documents/sources/test-document-2.txt"); + $event->setCacheSubdirectory("tests"); + + $document = new Document($this->getContainer()); + + // mock cache configuration. + $config = ConfigQuery::create()->filterByName('original_document_delivery_mode')->findOne(); + + if ($config != null) { + $oldval = $config->getValue(); + $config->setValue('symlink')->save(); + } + + $document->processDocument($event); + + if ($config != null) $config->setValue($oldval)->save(); + + $imgdir = ConfigQuery::read('document_cache_dir_from_web_root'); + + $this->assertFileExists(THELIA_WEB_DIR."/$imgdir/tests/test-document-2.txt"); + } + + public function testClearTestsCache() + { + $event = new DocumentEvent($this->request); + + $event->setCacheSubdirectory('tests'); + + $document = new Document($this->getContainer()); + + $document->clearCache($event); + } + + public function testClearWholeCache() + { + $event = new DocumentEvent($this->request); + + $document = new Document($this->getContainer()); + + $document->clearCache($event); + } + + /** + * Try to clear directory ouside of the cache + * + * @expectedException \InvalidArgumentException + */ + public function testClearUnallowedPathCache() + { + $event = new DocumentEvent($this->request); + + $event->setCacheSubdirectory('../../../..'); + + $document = new Document($this->getContainer()); + + $document->clearCache($event); + } +} diff --git a/core/lib/Thelia/Tests/Action/assets/documents/sources/test-document-1.txt b/core/lib/Thelia/Tests/Action/assets/documents/sources/test-document-1.txt new file mode 100644 index 000000000..82537f32d --- /dev/null +++ b/core/lib/Thelia/Tests/Action/assets/documents/sources/test-document-1.txt @@ -0,0 +1 @@ +This is a text document. \ No newline at end of file diff --git a/core/lib/Thelia/Tests/Action/assets/documents/sources/test-document-2.txt b/core/lib/Thelia/Tests/Action/assets/documents/sources/test-document-2.txt new file mode 100644 index 000000000..82537f32d --- /dev/null +++ b/core/lib/Thelia/Tests/Action/assets/documents/sources/test-document-2.txt @@ -0,0 +1 @@ +This is a text document. \ No newline at end of file diff --git a/core/lib/Thelia/Tests/Core/Template/Loop/DocumentTest.php b/core/lib/Thelia/Tests/Core/Template/Loop/DocumentTest.php new file mode 100644 index 000000000..04e41b6f8 --- /dev/null +++ b/core/lib/Thelia/Tests/Core/Template/Loop/DocumentTest.php @@ -0,0 +1,89 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Tests\Core\Template\Loop; + +use Thelia\Model\DocumentQuery; +use Thelia\Tests\Core\Template\Element\BaseLoopTestor; + +use Thelia\Core\Template\Loop\Document; +use Thelia\Model\ProductDocumentQuery; +use Thelia\Model\CategoryDocumentQuery; +use Thelia\Model\ContentDocumentQuery; +use Thelia\Model\FolderDocumentQuery; + +/** + * + * @author Etienne Roudeix + * + */ +class DocumentTest extends BaseLoopTestor +{ + public function getTestedClassName() + { + return 'Thelia\Core\Template\Loop\Document'; + } + + public function getTestedInstance() + { + return new Document($this->container); + } + + public function getMandatoryArguments() + { + return array('source' => 'product', 'id' => 1); + } + + public function testSearchByProductId() + { + $document = ProductDocumentQuery::create()->findOne(); + + $this->baseTestSearchById($document->getId()); + } + + public function testSearchByFolderId() + { + $document = FolderDocumentQuery::create()->findOne(); + + $this->baseTestSearchById($document->getId()); + } + + public function testSearchByContentId() + { + $document = ContentDocumentQuery::create()->findOne(); + + $this->baseTestSearchById($document->getId()); + } + + public function testSearchByCategoryId() + { + $document = CategoryDocumentQuery::create()->findOne(); + + $this->baseTestSearchById($document->getId()); + } + + public function testSearchLimit() + { + $this->baseTestSearchWithLimit(1); + } +} diff --git a/core/lib/Thelia/Tests/Core/Template/Loop/ImageTest.php b/core/lib/Thelia/Tests/Core/Template/Loop/ImageTest.php new file mode 100644 index 000000000..3d2517c0a --- /dev/null +++ b/core/lib/Thelia/Tests/Core/Template/Loop/ImageTest.php @@ -0,0 +1,89 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Tests\Core\Template\Loop; + +use Thelia\Model\ImageQuery; +use Thelia\Tests\Core\Template\Element\BaseLoopTestor; + +use Thelia\Core\Template\Loop\Image; +use Thelia\Model\ProductImageQuery; +use Thelia\Model\CategoryImageQuery; +use Thelia\Model\ContentImageQuery; +use Thelia\Model\FolderImageQuery; + +/** + * + * @author Etienne Roudeix + * + */ +class ImageTest extends BaseLoopTestor +{ + public function getTestedClassName() + { + return 'Thelia\Core\Template\Loop\Image'; + } + + public function getTestedInstance() + { + return new Image($this->container); + } + + public function getMandatoryArguments() + { + return array('source' => 'product', 'id' => 1); + } + + public function testSearchByProductId() + { + $image = ProductImageQuery::create()->findOne(); + + $this->baseTestSearchById($image->getId()); + } + + public function testSearchByFolderId() + { + $image = FolderImageQuery::create()->findOne(); + + $this->baseTestSearchById($image->getId()); + } + + public function testSearchByContentId() + { + $image = ContentImageQuery::create()->findOne(); + + $this->baseTestSearchById($image->getId()); + } + + public function testSearchByCategoryId() + { + $image = CategoryImageQuery::create()->findOne(); + + $this->baseTestSearchById($image->getId()); + } + + public function testSearchLimit() + { + $this->baseTestSearchWithLimit(1); + } +} diff --git a/core/lib/Thelia/Tools/URL.php b/core/lib/Thelia/Tools/URL.php index 32c1aadb5..363860064 100755 --- a/core/lib/Thelia/Tools/URL.php +++ b/core/lib/Thelia/Tools/URL.php @@ -43,14 +43,15 @@ class URL protected static $instance = null; - public function __construct(ContainerInterface $container) + public function __construct(ContainerInterface $container = null) { // Allow singleton style calls once intanciated. // For this to work, the URL service has to be instanciated very early. This is done manually // in TheliaHttpKernel, by calling $this->container->get('thelia.url.manager'); self::$instance = $this; - $this->requestContext = $container->get('router.admin')->getContext(); + if ($container !== null) + $this->requestContext = $container->get('router.admin')->getContext(); $this->retriever = new RewritingRetriever(); $this->resolver = new RewritingResolver(); @@ -183,6 +184,7 @@ class URL return $this->absoluteUrl($path, $parameters); } + /** * Retrieve a rewritten URL from a view, a view id and a locale * @@ -261,4 +263,50 @@ class URL return $this->resolver; } + + protected function sanitize($string, $force_lowercase = true, $alphabetic_only = false) + { + static $strip = array("~", "`", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "=", "+", "[", "{", "]", + "}", "\\", "|", ";", ":", "\"", "'", "‘", "’", "“", "”", "–", "—", + "—", "–", ",", "<", ".", ">", "/", "?"); + + $clean = trim(str_replace($strip, "", strip_tags($string))); + + $clean = preg_replace('/\s+/', "-", $clean); + + $clean = ($alphabetic_only) ? preg_replace("/[^a-zA-Z0-9]/", "", $clean) : $clean ; + + return ($force_lowercase) ? + (function_exists('mb_strtolower')) ? + mb_strtolower($clean, 'UTF-8') : + strtolower($clean) : + $clean; + } + + /** + * Genenerate the file part of a rewriten URL from a given baseString, using a view, a view id and a locale + * + * @param $view + * @param $viewId + * @param $viewLocale + * @param $baseString the string to be converted in a valid URL + * + * @return A valid file part URL. + */ + public function generateRewritenUrl($view, $viewId, $viewLocale, $baseString) + { + // Borrowed from http://stackoverflow.com/questions/2668854/sanitizing-strings-to-make-them-url-and-filename-safe + + // Replace all weird characters with dashes + $string = preg_replace('/[^\w\-~_\.]+/u', '-', $baseString); + + // Only allow one dash separator at a time (and make string lowercase) + $cleanString = mb_strtolower(preg_replace('/--+/u', '-', $string), 'UTF-8'); + + $urlFilePart = $cleanString . ".html"; + + // TODO : + // check if URL url already exists, and add a numeric suffix, or the like + // insert the URL in the rewriting table + } } diff --git a/install/faker.php b/install/faker.php index 6ad32ef4b..aadfc8759 100755 --- a/install/faker.php +++ b/install/faker.php @@ -4,12 +4,7 @@ use Thelia\Constraint\Rule\AvailableForTotalAmountManager; use Thelia\Constraint\Rule\AvailableForXArticlesManager; use Thelia\Constraint\Rule\Operators; use Thelia\Coupon\CouponRuleCollection; -use Thelia\Model\ProductImage; -use Thelia\Model\CategoryImage; -use Thelia\Model\FolderImage; -use Thelia\Model\ContentImage; -use Imagine\Image\Color; -use Imagine\Image\Point; + require __DIR__ . '/../core/bootstrap.php'; @@ -23,12 +18,17 @@ $con = \Propel\Runtime\Propel::getConnection( ); $con->beginTransaction(); +// Intialize URL management +$url = new Thelia\Tools\URL(); + $currency = \Thelia\Model\CurrencyQuery::create()->filterByCode('EUR')->findOne(); try { $stmt = $con->prepare("SET foreign_key_checks = 0"); $stmt->execute(); + echo "Clearing tables\n"; + $productAssociatedContent = Thelia\Model\ProductAssociatedContentQuery::create() ->find(); $productAssociatedContent->delete(); @@ -37,14 +37,6 @@ try { ->find(); $categoryAssociatedContent->delete(); - $attributeCategory = Thelia\Model\AttributeCategoryQuery::create() - ->find(); - $attributeCategory->delete(); - - $featureCategory = Thelia\Model\FeatureCategoryQuery::create() - ->find(); - $featureCategory->delete(); - $featureProduct = Thelia\Model\FeatureProductQuery::create() ->find(); $featureProduct->delete(); @@ -133,9 +125,22 @@ try { ->find(); $productPrice->delete(); + \Thelia\Model\ProductImageQuery::create()->find()->delete(); + \Thelia\Model\CategoryImageQuery::create()->find()->delete(); + \Thelia\Model\FolderImageQuery::create()->find()->delete(); + \Thelia\Model\ContentImageQuery::create()->find()->delete(); + + \Thelia\Model\ProductDocumentQuery::create()->find()->delete(); + \Thelia\Model\CategoryDocumentQuery::create()->find()->delete(); + \Thelia\Model\FolderDocumentQuery::create()->find()->delete(); + \Thelia\Model\ContentDocumentQuery::create()->find()->delete(); + $stmt = $con->prepare("SET foreign_key_checks = 1"); + $stmt->execute(); + echo "Creating customer\n"; + //customer $customer = new Thelia\Model\Customer(); $customer->createOrUpdate( @@ -193,6 +198,8 @@ try { } } + echo "Creating features\n"; + //features and features_av $featureList = array(); for($i=0; $i<4; $i++) { @@ -216,6 +223,8 @@ try { } } + echo "Creating attributes\n"; + //attributes and attributes_av $attributeList = array(); for($i=0; $i<4; $i++) { @@ -238,6 +247,8 @@ try { } } + echo "Creating templates\n"; + $template = new Thelia\Model\Template(); setI18n($faker, $template, array("Name" => 20)); $template->save(); @@ -260,6 +271,8 @@ try { ->save(); } + echo "Creating folders and content\n"; + //folders and contents $contentIdList = array(); for($i=0; $i<4; $i++) { @@ -271,10 +284,14 @@ try { $folder->save(); - $image = new FolderImage(); + $image = new \Thelia\Model\FolderImage(); $image->setFolderId($folder->getId()); generate_image($image, 1, 'folder', $folder->getId()); + $document = new \Thelia\Model\FolderDocument(); + $document->setFolderId($folder->getId()); + generate_document($document, 1, 'folder', $folder->getId()); + for($j=1; $jsetParent($folder->getId()); @@ -284,10 +301,14 @@ try { $subfolder->save(); - $image = new FolderImage(); + $image = new \Thelia\Model\FolderImage(); $image->setFolderId($subfolder->getId()); generate_image($image, 1, 'folder', $subfolder->getId()); + $document = new \Thelia\Model\FolderDocument(); + $document->setFolderId($folder->getId()); + generate_document($document, 1, 'folder', $subfolder->getId()); + for($k=0; $kaddFolder($subfolder); @@ -299,13 +320,20 @@ try { $contentId = $content->getId(); $contentIdList[] = $contentId; - $image = new ContentImage(); - $image->setContentId($content->getId()); + $image = new \Thelia\Model\ContentImage(); + $image->setContentId($contentId); generate_image($image, 1, 'content', $contentId); + + $document = new \Thelia\Model\ContentDocument(); + $document->setContentId($contentId); + generate_document($document, 1, 'content', $contentId); + } } } + echo "Creating categories and products\n"; + //categories and products $productIdList = array(); $categoryIdList = array(); @@ -325,22 +353,6 @@ try { } } - //attribute_category and feature_category (all categories got all features/attributes) - foreach($categoryIdList as $categoryId) { - foreach($attributeList as $attributeId => $attributeAvId) { - $attributeCategory = new Thelia\Model\AttributeCategory(); - $attributeCategory->setCategoryId($categoryId) - ->setAttributeId($attributeId) - ->save(); - } - foreach($featureList as $featureId => $featureAvId) { - $featureCategory = new Thelia\Model\FeatureCategory(); - $featureCategory->setCategoryId($categoryId) - ->setFeatureId($featureId) - ->save(); - } - } - foreach($productIdList as $productId) { //add random accessories - or not $alreadyPicked = array(); @@ -364,6 +376,7 @@ try { $productAssociatedContent = new Thelia\Model\ProductAssociatedContent(); do { $pick = array_rand($contentIdList, 1); + \Thelia\Log\Tlog::getInstance()->debug("pick : $pick"); } while(in_array($pick, $alreadyPicked)); $alreadyPicked[] = $pick; @@ -428,6 +441,8 @@ try { } } + echo "Generating coupns fixtures\n"; + generateCouponFixtures($thelia); $con->commit(); @@ -452,10 +467,14 @@ function createProduct($faker, $category, $position, $template, &$productIdList) $productId = $product->getId(); $productIdList[] = $productId; - $image = new ProductImage(); + $image = new \Thelia\Model\ProductImage(); $image->setProductId($productId); generate_image($image, 1, 'product', $productId); + $document = new \Thelia\Model\ProductDocument(); + $document->setProductId($productId); + generate_document($document, 1, 'product', $productId); + return $product; } @@ -487,10 +506,14 @@ function createCategory($faker, $parent, $position, &$categoryIdList, $contentId ->save(); } - $image = new CategoryImage(); + $image = new \Thelia\Model\CategoryImage(); $image->setCategoryId($categoryId); generate_image($image, 1, 'category', $categoryId); + $document = new \Thelia\Model\CategoryDocument(); + $document->setCategoryId($categoryId); + generate_document($document, 1, 'category', $categoryId); + return $category; } @@ -503,37 +526,36 @@ function generate_image($image, $position, $typeobj, $id) { ->setDescription($faker->text(250)) ->setChapo($faker->text(40)) ->setPostscriptum($faker->text(40)) - ->setPosition($position) ->setFile(sprintf("sample-image-%s.png", $id)) ->save() ; // Generate images $imagine = new Imagine\Gd\Imagine(); - $image = $imagine->create(new Imagine\Image\Box(320,240), new Color('#E9730F')); + $image = $imagine->create(new Imagine\Image\Box(320,240), new Imagine\Image\Color('#E9730F')); - $white = new Color('#FFF'); + $white = new Imagine\Image\Color('#FFF'); $font = $imagine->font(__DIR__.'/faker-assets/FreeSans.ttf', 14, $white); $tbox = $font->box("THELIA"); - $image->draw()->text("THELIA", $font, new Point((320 - $tbox->getWidth()) / 2, 30)); + $image->draw()->text("THELIA", $font, new Imagine\Image\Point((320 - $tbox->getWidth()) / 2, 30)); $str = sprintf("%s sample image", ucfirst($typeobj)); $tbox = $font->box($str); - $image->draw()->text($str, $font, new Point((320 - $tbox->getWidth()) / 2, 80)); + $image->draw()->text($str, $font, new Imagine\Image\Point((320 - $tbox->getWidth()) / 2, 80)); $font = $imagine->font(__DIR__.'/faker-assets/FreeSans.ttf', 18, $white); $str = sprintf("%s ID %d", strtoupper($typeobj), $id); $tbox = $font->box($str); - $image->draw()->text($str, $font, new Point((320 - $tbox->getWidth()) / 2, 180)); + $image->draw()->text($str, $font, new Imagine\Image\Point((320 - $tbox->getWidth()) / 2, 180)); $image->draw() - ->line(new Point(0, 0), new Point(319, 0), $white) - ->line(new Point(319, 0), new Point(319, 239), $white) - ->line(new Point(319, 239), new Point(0,239), $white) - ->line(new Point(0, 239), new Point(0, 0), $white) + ->line(new Imagine\Image\Point(0, 0), new Imagine\Image\Point(319, 0), $white) + ->line(new Imagine\Image\Point(319, 0), new Imagine\Image\Point(319, 239), $white) + ->line(new Imagine\Image\Point(319, 239), new Imagine\Image\Point(0,239), $white) + ->line(new Imagine\Image\Point(0, 239), new Imagine\Image\Point(0, 0), $white) ; $image_file = sprintf("%s/../local/media/images/%s/sample-image-%s.png", __DIR__, $typeobj, $id); @@ -543,6 +565,26 @@ function generate_image($image, $position, $typeobj, $id) { $image->save($image_file); } +function generate_document($document, $position, $typeobj, $id) { + + global $faker; + + $document + ->setTitle($faker->text(20)) + ->setDescription($faker->text(250)) + ->setChapo($faker->text(40)) + ->setPostscriptum($faker->text(40)) + ->setFile(sprintf("sample-document-%s.txt", $id)) + ->save() + ; + + $document_file = sprintf("%s/../local/media/documents/%s/sample-document-%s.txt", __DIR__, $typeobj, $id); + + if (! is_dir(dirname($document_file))) mkdir(dirname($document_file), 0777, true); + + file_put_contents($document_file, $faker->text(256)); +} + function setI18n($faker, &$object, $fields = array('Title' => 20, 'Description' => 50) ) { $localeList = $localeList = array('fr_FR', 'en_US', 'es_ES', 'it_IT'); diff --git a/install/insert.sql b/install/insert.sql index 03fbc690c..fbb09889b 100755 --- a/install/insert.sql +++ b/install/insert.sql @@ -13,8 +13,11 @@ INSERT INTO `config` (`name`, `value`, `secured`, `hidden`, `created_at`, `updat ('imagine_graphic_driver', 'gd', 0, 0, NOW(), NOW()), ('default_images_quality_percent', '75', 0, 0, NOW(), NOW()), ('original_image_delivery_mode', 'symlink', 0, 0, NOW(), NOW()), +('original_document_delivery_mode', 'symlink', 0, 0, NOW(), NOW()), ('images_library_path', 'local/media/images', 0, 0, NOW(), NOW()), +('documents_library_path', 'local/media/documents', 0, 0, NOW(), NOW()), ('image_cache_dir_from_web_root', 'cache/images', 0, 0, NOW(), NOW()), +('document_cache_dir_from_web_root', 'cache/documents', 0, 0, NOW(), NOW()), ('currency_rate_update_url', 'http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml', 0, 0, NOW(), NOW()), ('page_not_found_view', '404.html', 0, 0, NOW(), NOW()), ('use_tax_free_amounts', 0, 0, 0, NOW(), NOW()), @@ -59,271 +62,271 @@ VALUES (3, 'en_US', 'UK Pound'); -INSERT INTO `country` (`id`, `area_id`, `isocode`, `isoalpha2`, `isoalpha3`, `created_at`, `updated_at`) VALUES -(1, NULL, '4', 'AF', 'AFG', NOW(), NOW()), -(2, NULL, '710', 'ZA', 'ZAF', NOW(), NOW()), -(3, NULL, '8', 'AL', 'ALB', NOW(), NOW()), -(4, NULL, '12', 'DZ', 'DZA', NOW(), NOW()), -(5, NULL, '276', 'DE', 'DEU', NOW(), NOW()), -(6, NULL, '20', 'AD', 'AND', NOW(), NOW()), -(7, NULL, '24', 'AO', 'AGO', NOW(), NOW()), -(8, NULL, '28', 'AG', 'ATG', NOW(), NOW()), -(9, NULL, '682', 'SA', 'SAU', NOW(), NOW()), -(10, NULL, '32', 'AR', 'ARG', NOW(), NOW()), -(11, NULL, '51', 'AM', 'ARM', NOW(), NOW()), -(12, NULL, '36', 'AU', 'AUS', NOW(), NOW()), -(13, NULL, '40', 'AT', 'AUT', NOW(), NOW()), -(14, NULL, '31', 'AZ', 'AZE', NOW(), NOW()), -(15, NULL, '44', 'BS', 'BHS', NOW(), NOW()), -(16, NULL, '48', 'BR', 'BHR', NOW(), NOW()), -(17, NULL, '50', 'BD', 'BGD', NOW(), NOW()), -(18, NULL, '52', 'BB', 'BRB', NOW(), NOW()), -(19, NULL, '585', 'PW', 'PLW', NOW(), NOW()), -(20, NULL, '56', 'BE', 'BEL', NOW(), NOW()), -(21, NULL, '84', 'BL', 'BLZ', NOW(), NOW()), -(22, NULL, '204', 'BJ', 'BEN', NOW(), NOW()), -(23, NULL, '64', 'BT', 'BTN', NOW(), NOW()), -(24, NULL, '112', 'BY', 'BLR', NOW(), NOW()), -(25, NULL, '104', 'MM', 'MMR', NOW(), NOW()), -(26, NULL, '68', 'BO', 'BOL', NOW(), NOW()), -(27, NULL, '70', 'BA', 'BIH', NOW(), NOW()), -(28, NULL, '72', 'BW', 'BWA', NOW(), NOW()), -(29, NULL, '76', 'BR', 'BRA', NOW(), NOW()), -(30, NULL, '96', 'BN', 'BRN', NOW(), NOW()), -(31, NULL, '100', 'BG', 'BGR', NOW(), NOW()), -(32, NULL, '854', 'BF', 'BFA', NOW(), NOW()), -(33, NULL, '108', 'BI', 'BDI', NOW(), NOW()), -(34, NULL, '116', 'KH', 'KHM', NOW(), NOW()), -(35, NULL, '120', 'CM', 'CMR', NOW(), NOW()), -(37, NULL, '132', 'CV', 'CPV', NOW(), NOW()), -(38, NULL, '152', 'CL', 'CHL', NOW(), NOW()), -(39, NULL, '156', 'CN', 'CHN', NOW(), NOW()), -(40, NULL, '196', 'CY', 'CYP', NOW(), NOW()), -(41, NULL, '170', 'CO', 'COL', NOW(), NOW()), -(42, NULL, '174', 'KM', 'COM', NOW(), NOW()), -(43, NULL, '178', 'CG', 'COG', NOW(), NOW()), -(44, NULL, '184', 'CK', 'COK', NOW(), NOW()), -(45, NULL, '408', 'KP', 'PRK', NOW(), NOW()), -(46, NULL, '410', 'KR', 'KOR', NOW(), NOW()), -(47, NULL, '188', 'CR', 'CRI', NOW(), NOW()), -(48, NULL, '384', 'CI', 'CIV', NOW(), NOW()), -(49, NULL, '191', 'HR', 'HRV', NOW(), NOW()), -(50, NULL, '192', 'CU', 'CUB', NOW(), NOW()), -(51, NULL, '208', 'DK', 'DNK', NOW(), NOW()), -(52, NULL, '262', 'DJ', 'DJI', NOW(), NOW()), -(53, NULL, '212', 'DM', 'DMA', NOW(), NOW()), -(54, NULL, '818', 'EG', 'EGY', NOW(), NOW()), -(55, NULL, '784', 'AE', 'ARE', NOW(), NOW()), -(56, NULL, '218', 'EC', 'ECU', NOW(), NOW()), -(57, NULL, '232', 'ER', 'ERI', NOW(), NOW()), -(58, NULL, '724', 'ES', 'ESP', NOW(), NOW()), -(59, NULL, '233', 'EE', 'EST', NOW(), NOW()), -(61, NULL, '231', 'ET', 'ETH', NOW(), NOW()), -(62, NULL, '242', 'FJ', 'FJI', NOW(), NOW()), -(63, NULL, '246', 'FI', 'FIN', NOW(), NOW()), -(64, NULL, '250', 'FR', 'FRA', NOW(), NOW()), -(65, NULL, '266', 'GA', 'GAB', NOW(), NOW()), -(66, NULL, '270', 'GM', 'GMB', NOW(), NOW()), -(67, NULL, '268', 'GE', 'GEO', NOW(), NOW()), -(68, NULL, '288', 'GH', 'GHA', NOW(), NOW()), -(69, NULL, '300', 'GR', 'GRC', NOW(), NOW()), -(70, NULL, '308', 'GD', 'GRD', NOW(), NOW()), -(71, NULL, '320', 'GT', 'GTM', NOW(), NOW()), -(72, NULL, '324', 'GN', 'GIN', NOW(), NOW()), -(73, NULL, '624', 'GW', 'GNB', NOW(), NOW()), -(74, NULL, '226', 'GQ', 'GNQ', NOW(), NOW()), -(75, NULL, '328', 'GY', 'GUY', NOW(), NOW()), -(76, NULL, '332', 'HT', 'HTI', NOW(), NOW()), -(77, NULL, '340', 'HN', 'HND', NOW(), NOW()), -(78, NULL, '348', 'HU', 'HUN', NOW(), NOW()), -(79, NULL, '356', 'IN', 'IND', NOW(), NOW()), -(80, NULL, '360', 'ID', 'IDN', NOW(), NOW()), -(81, NULL, '364', 'IR', 'IRN', NOW(), NOW()), -(82, NULL, '368', 'IQ', 'IRQ', NOW(), NOW()), -(83, NULL, '372', 'IE', 'IRL', NOW(), NOW()), -(84, NULL, '352', 'IS', 'ISL', NOW(), NOW()), -(85, NULL, '376', 'IL', 'ISR', NOW(), NOW()), -(86, NULL, '380', 'IT', 'ITA', NOW(), NOW()), -(87, NULL, '388', 'JM', 'JAM', NOW(), NOW()), -(88, NULL, '392', 'JP', 'JPN', NOW(), NOW()), -(89, NULL, '400', 'JO', 'JOR', NOW(), NOW()), -(90, NULL, '398', 'KZ', 'KAZ', NOW(), NOW()), -(91, NULL, '404', 'KE', 'KEN', NOW(), NOW()), -(92, NULL, '417', 'KG', 'KGZ', NOW(), NOW()), -(93, NULL, '296', 'KI', 'KIR', NOW(), NOW()), -(94, NULL, '414', 'KW', 'KWT', NOW(), NOW()), -(95, NULL, '418', 'LA', 'LAO', NOW(), NOW()), -(96, NULL, '426', 'LS', 'LSO', NOW(), NOW()), -(97, NULL, '428', 'LV', 'LVA', NOW(), NOW()), -(98, NULL, '422', 'LB', 'LBN', NOW(), NOW()), -(99, NULL, '430', 'LR', 'LBR', NOW(), NOW()), -(100, NULL, '343', 'LY', 'LBY', NOW(), NOW()), -(101, NULL, '438', 'LI', 'LIE', NOW(), NOW()), -(102, NULL, '440', 'LT', 'LTU', NOW(), NOW()), -(103, NULL, '442', 'LU', 'LUX', NOW(), NOW()), -(104, NULL, '807', 'MK', 'MKD', NOW(), NOW()), -(105, NULL, '450', 'MD', 'MDG', NOW(), NOW()), -(106, NULL, '458', 'MY', 'MYS', NOW(), NOW()), -(107, NULL, '454', 'MW', 'MWI', NOW(), NOW()), -(108, NULL, '462', 'MV', 'MDV', NOW(), NOW()), -(109, NULL, '466', 'ML', 'MLI', NOW(), NOW()), -(110, NULL, '470', 'MT', 'MLT', NOW(), NOW()), -(111, NULL, '504', 'MA', 'MAR', NOW(), NOW()), -(112, NULL, '584', 'MH', 'MHL', NOW(), NOW()), -(113, NULL, '480', 'MU', 'MUS', NOW(), NOW()), -(114, NULL, '478', 'MR', 'MRT', NOW(), NOW()), -(115, NULL, '484', 'MX', 'MEX', NOW(), NOW()), -(116, NULL, '583', 'FM', 'FSM', NOW(), NOW()), -(117, NULL, '498', 'MD', 'MDA', NOW(), NOW()), -(118, NULL, '492', 'MC', 'MCO', NOW(), NOW()), -(119, NULL, '496', 'MN', 'MNG', NOW(), NOW()), -(120, NULL, '508', 'MZ', 'MOZ', NOW(), NOW()), -(121, NULL, '516', 'NA', 'NAM', NOW(), NOW()), -(122, NULL, '520', 'NR', 'NRU', NOW(), NOW()), -(123, NULL, '524', 'NP', 'NPL', NOW(), NOW()), -(124, NULL, '558', 'NI', 'NIC', NOW(), NOW()), -(125, NULL, '562', 'NE', 'NER', NOW(), NOW()), -(126, NULL, '566', 'NG', 'NGA', NOW(), NOW()), -(127, NULL, '570', 'NU', 'NIU', NOW(), NOW()), -(128, NULL, '578', 'NO', 'NOR', NOW(), NOW()), -(129, NULL, '554', 'NZ', 'NZL', NOW(), NOW()), -(130, NULL, '512', 'OM', 'OMN', NOW(), NOW()), -(131, NULL, '800', 'UG', 'UGA', NOW(), NOW()), -(132, NULL, '860', 'UZ', 'UZB', NOW(), NOW()), -(133, NULL, '586', 'PK', 'PAK', NOW(), NOW()), -(134, NULL, '591', 'PA', 'PAN', NOW(), NOW()), -(135, NULL, '598', 'PG', 'PNG', NOW(), NOW()), -(136, NULL, '600', 'PY', 'PRY', NOW(), NOW()), -(137, NULL, '528', 'NL', 'NLD', NOW(), NOW()), -(138, NULL, '604', 'PE', 'PER', NOW(), NOW()), -(139, NULL, '608', 'PH', 'PHL', NOW(), NOW()), -(140, NULL, '616', 'PL', 'POL', NOW(), NOW()), -(141, NULL, '620', 'PT', 'PRT', NOW(), NOW()), -(142, NULL, '634', 'QA', 'QAT', NOW(), NOW()), -(143, NULL, '140', 'CF', 'CAF', NOW(), NOW()), -(144, NULL, '214', 'DO', 'DOM', NOW(), NOW()), -(145, NULL, '203', 'CZ', 'CZE', NOW(), NOW()), -(146, NULL, '642', 'RO', 'ROU', NOW(), NOW()), -(147, NULL, '826', 'GB', 'GBR', NOW(), NOW()), -(148, NULL, '643', 'RU', 'RUS', NOW(), NOW()), -(149, NULL, '646', 'RW', 'RWA', NOW(), NOW()), -(150, NULL, '659', 'KN', 'KNA', NOW(), NOW()), -(151, NULL, '662', 'LC', 'LCA', NOW(), NOW()), -(152, NULL, '674', 'SM', 'SMR', NOW(), NOW()), -(153, NULL, '670', 'VC', 'VCT', NOW(), NOW()), -(154, NULL, '90', 'SB', 'SLB', NOW(), NOW()), -(155, NULL, '222', 'SV', 'SLV', NOW(), NOW()), -(156, NULL, '882', 'WS', 'WSM', NOW(), NOW()), -(157, NULL, '678', 'ST', 'STP', NOW(), NOW()), -(158, NULL, '686', 'SN', 'SEN', NOW(), NOW()), -(159, NULL, '690', 'SC', 'SYC', NOW(), NOW()), -(160, NULL, '694', 'SL', 'SLE', NOW(), NOW()), -(161, NULL, '702', 'SG', 'SGP', NOW(), NOW()), -(162, NULL, '703', 'SK', 'SVK', NOW(), NOW()), -(163, NULL, '705', 'SI', 'SVN', NOW(), NOW()), -(164, NULL, '706', 'SO', 'SOM', NOW(), NOW()), -(165, NULL, '729', 'SD', 'SDN', NOW(), NOW()), -(166, NULL, '144', 'LK', 'LKA', NOW(), NOW()), -(167, NULL, '752', 'SE', 'SWE', NOW(), NOW()), -(168, NULL, '756', 'CH', 'CHE', NOW(), NOW()), -(169, NULL, '740', 'SR', 'SUR', NOW(), NOW()), -(170, NULL, '748', 'SZ', 'SWZ', NOW(), NOW()), -(171, NULL, '760', 'SY', 'SYR', NOW(), NOW()), -(172, NULL, '762', 'TJ', 'TJK', NOW(), NOW()), -(173, NULL, '834', 'TZ', 'TZA', NOW(), NOW()), -(174, NULL, '148', 'TD', 'TCD', NOW(), NOW()), -(175, NULL, '764', 'TH', 'THA', NOW(), NOW()), -(176, NULL, '768', 'TG', 'TGO', NOW(), NOW()), -(177, NULL, '776', 'TO', 'TON', NOW(), NOW()), -(178, NULL, '780', 'TT', 'TTO', NOW(), NOW()), -(179, NULL, '788', 'TN', 'TUN', NOW(), NOW()), -(180, NULL, '795', 'TM', 'TKM', NOW(), NOW()), -(181, NULL, '792', 'TR', 'TUR', NOW(), NOW()), -(182, NULL, '798', 'TV', 'TUV', NOW(), NOW()), -(183, NULL, '804', 'UA', 'UKR', NOW(), NOW()), -(184, NULL, '858', 'UY', 'URY', NOW(), NOW()), -(185, NULL, '336', 'VA', 'VAT', NOW(), NOW()), -(186, NULL, '548', 'VU', 'VUT', NOW(), NOW()), -(187, NULL, '862', 'VE', 'VEN', NOW(), NOW()), -(188, NULL, '704', 'VN', 'VNM', NOW(), NOW()), -(189, NULL, '887', 'YE', 'YEM', NOW(), NOW()), -(190, NULL, '807', 'MK', 'MKD', NOW(), NOW()), -(191, NULL, '180', 'CD', 'COD', NOW(), NOW()), -(192, NULL, '894', 'ZM', 'ZMB', NOW(), NOW()), -(193, NULL, '716', 'ZW', 'ZWE', NOW(), NOW()), -(196, NULL, '840', 'US', 'USA', NOW(), NOW()), -(197, NULL, '840', 'US', 'USA', NOW(), NOW()), -(198, NULL, '840', 'US', 'USA', NOW(), NOW()), -(199, NULL, '840', 'US', 'USA', NOW(), NOW()), -(200, NULL, '840', 'US', 'USA', NOW(), NOW()), -(201, NULL, '840', 'US', 'USA', NOW(), NOW()), -(202, NULL, '840', 'US', 'USA', NOW(), NOW()), -(203, NULL, '840', 'US', 'USA', NOW(), NOW()), -(204, NULL, '840', 'US', 'USA', NOW(), NOW()), -(205, NULL, '840', 'US', 'USA', NOW(), NOW()), -(206, NULL, '840', 'US', 'USA', NOW(), NOW()), -(207, NULL, '840', 'US', 'USA', NOW(), NOW()), -(208, NULL, '840', 'US', 'USA', NOW(), NOW()), -(209, NULL, '840', 'US', 'USA', NOW(), NOW()), -(210, NULL, '840', 'US', 'USA', NOW(), NOW()), -(211, NULL, '840', 'US', 'USA', NOW(), NOW()), -(212, NULL, '840', 'US', 'USA', NOW(), NOW()), -(213, NULL, '840', 'US', 'USA', NOW(), NOW()), -(214, NULL, '840', 'US', 'USA', NOW(), NOW()), -(215, NULL, '840', 'US', 'USA', NOW(), NOW()), -(216, NULL, '840', 'US', 'USA', NOW(), NOW()), -(217, NULL, '840', 'US', 'USA', NOW(), NOW()), -(218, NULL, '840', 'US', 'USA', NOW(), NOW()), -(219, NULL, '840', 'US', 'USA', NOW(), NOW()), -(220, NULL, '840', 'US', 'USA', NOW(), NOW()), -(221, NULL, '840', 'US', 'USA', NOW(), NOW()), -(222, NULL, '840', 'US', 'USA', NOW(), NOW()), -(223, NULL, '840', 'US', 'USA', NOW(), NOW()), -(224, NULL, '840', 'US', 'USA', NOW(), NOW()), -(225, NULL, '840', 'US', 'USA', NOW(), NOW()), -(226, NULL, '840', 'US', 'USA', NOW(), NOW()), -(227, NULL, '840', 'US', 'USA', NOW(), NOW()), -(228, NULL, '840', 'US', 'USA', NOW(), NOW()), -(229, NULL, '840', 'US', 'USA', NOW(), NOW()), -(230, NULL, '840', 'US', 'USA', NOW(), NOW()), -(231, NULL, '840', 'US', 'USA', NOW(), NOW()), -(232, NULL, '840', 'US', 'USA', NOW(), NOW()), -(233, NULL, '840', 'US', 'USA', NOW(), NOW()), -(234, NULL, '840', 'US', 'USA', NOW(), NOW()), -(235, NULL, '840', 'US', 'USA', NOW(), NOW()), -(236, NULL, '840', 'US', 'USA', NOW(), NOW()), -(237, NULL, '840', 'US', 'USA', NOW(), NOW()), -(238, NULL, '840', 'US', 'USA', NOW(), NOW()), -(239, NULL, '840', 'US', 'USA', NOW(), NOW()), -(240, NULL, '840', 'US', 'USA', NOW(), NOW()), -(241, NULL, '840', 'US', 'USA', NOW(), NOW()), -(242, NULL, '840', 'US', 'USA', NOW(), NOW()), -(243, NULL, '840', 'US', 'USA', NOW(), NOW()), -(244, NULL, '840', 'US', 'USA', NOW(), NOW()), -(245, NULL, '840', 'US', 'USA', NOW(), NOW()), -(246, NULL, '124', 'CA', 'CAN', NOW(), NOW()), -(247, NULL, '124', 'CA', 'CAN', NOW(), NOW()), -(248, NULL, '124', 'CA', 'CAN', NOW(), NOW()), -(249, NULL, '124', 'CA', 'CAN', NOW(), NOW()), -(250, NULL, '124', 'CA', 'CAN', NOW(), NOW()), -(251, NULL, '124', 'CA', 'CAN', NOW(), NOW()), -(252, NULL, '124', 'CA', 'CAN', NOW(), NOW()), -(253, NULL, '124', 'CA', 'CAN', NOW(), NOW()), -(254, NULL, '124', 'CA', 'CAN', NOW(), NOW()), -(255, NULL, '124', 'CA', 'CAN', NOW(), NOW()), -(256, NULL, '124', 'CA', 'CAN', NOW(), NOW()), -(257, NULL, '124', 'CA', 'CAN', NOW(), NOW()), -(258, NULL, '124', 'CA', 'CAN', NOW(), NOW()), -(259, NULL, '312', 'GP', 'GLP', NOW(), NOW()), -(260, NULL, '254', 'GF', 'GUF', NOW(), NOW()), -(261, NULL, '474', 'MQ', 'MTQ', NOW(), NOW()), -(262, NULL, '175', 'YT', 'MYT', NOW(), NOW()), -(263, NULL, '638', 'RE', 'REU', NOW(), NOW()), -(264, NULL, '666', 'PM', 'SPM', NOW(), NOW()), -(265, NULL, '540', 'NC', 'NCL', NOW(), NOW()), -(266, NULL, '258', 'PF', 'PYF', NOW(), NOW()), -(267, NULL, '876', 'WF', 'WLF', NOW(), NOW()), -(268, NULL, '840', 'US', 'USA', NOW(), NOW()); +INSERT INTO `country` (`id`, `area_id`, `isocode`, `isoalpha2`, `isoalpha3`, `by_default`, `created_at`, `updated_at`) VALUES +(1, NULL, '4', 'AF', 'AFG', 0, NOW(), NOW()), +(2, NULL, '710', 'ZA', 'ZAF', 0, NOW(), NOW()), +(3, NULL, '8', 'AL', 'ALB', 0, NOW(), NOW()), +(4, NULL, '12', 'DZ', 'DZA', 0, NOW(), NOW()), +(5, NULL, '276', 'DE', 'DEU', 0, NOW(), NOW()), +(6, NULL, '20', 'AD', 'AND', 0, NOW(), NOW()), +(7, NULL, '24', 'AO', 'AGO', 0, NOW(), NOW()), +(8, NULL, '28', 'AG', 'ATG', 0, NOW(), NOW()), +(9, NULL, '682', 'SA', 'SAU', 0, NOW(), NOW()), +(10, NULL, '32', 'AR', 'ARG', 0, NOW(), NOW()), +(11, NULL, '51', 'AM', 'ARM', 0, NOW(), NOW()), +(12, NULL, '36', 'AU', 'AUS', 0, NOW(), NOW()), +(13, NULL, '40', 'AT', 'AUT', 0, NOW(), NOW()), +(14, NULL, '31', 'AZ', 'AZE', 0, NOW(), NOW()), +(15, NULL, '44', 'BS', 'BHS', 0, NOW(), NOW()), +(16, NULL, '48', 'BR', 'BHR', 0, NOW(), NOW()), +(17, NULL, '50', 'BD', 'BGD', 0, NOW(), NOW()), +(18, NULL, '52', 'BB', 'BRB', 0, NOW(), NOW()), +(19, NULL, '585', 'PW', 'PLW', 0, NOW(), NOW()), +(20, NULL, '56', 'BE', 'BEL', 0, NOW(), NOW()), +(21, NULL, '84', 'BL', 'BLZ', 0, NOW(), NOW()), +(22, NULL, '204', 'BJ', 'BEN', 0, NOW(), NOW()), +(23, NULL, '64', 'BT', 'BTN', 0, NOW(), NOW()), +(24, NULL, '112', 'BY', 'BLR', 0, NOW(), NOW()), +(25, NULL, '104', 'MM', 'MMR', 0, NOW(), NOW()), +(26, NULL, '68', 'BO', 'BOL', 0, NOW(), NOW()), +(27, NULL, '70', 'BA', 'BIH', 0, NOW(), NOW()), +(28, NULL, '72', 'BW', 'BWA', 0, NOW(), NOW()), +(29, NULL, '76', 'BR', 'BRA', 0, NOW(), NOW()), +(30, NULL, '96', 'BN', 'BRN', 0, NOW(), NOW()), +(31, NULL, '100', 'BG', 'BGR', 0, NOW(), NOW()), +(32, NULL, '854', 'BF', 'BFA', 0, NOW(), NOW()), +(33, NULL, '108', 'BI', 'BDI', 0, NOW(), NOW()), +(34, NULL, '116', 'KH', 'KHM', 0, NOW(), NOW()), +(35, NULL, '120', 'CM', 'CMR', 0, NOW(), NOW()), +(37, NULL, '132', 'CV', 'CPV', 0, NOW(), NOW()), +(38, NULL, '152', 'CL', 'CHL', 0, NOW(), NOW()), +(39, NULL, '156', 'CN', 'CHN', 0, NOW(), NOW()), +(40, NULL, '196', 'CY', 'CYP', 0, NOW(), NOW()), +(41, NULL, '170', 'CO', 'COL', 0, NOW(), NOW()), +(42, NULL, '174', 'KM', 'COM', 0, NOW(), NOW()), +(43, NULL, '178', 'CG', 'COG', 0, NOW(), NOW()), +(44, NULL, '184', 'CK', 'COK', 0, NOW(), NOW()), +(45, NULL, '408', 'KP', 'PRK', 0, NOW(), NOW()), +(46, NULL, '410', 'KR', 'KOR', 0, NOW(), NOW()), +(47, NULL, '188', 'CR', 'CRI', 0, NOW(), NOW()), +(48, NULL, '384', 'CI', 'CIV', 0, NOW(), NOW()), +(49, NULL, '191', 'HR', 'HRV', 0, NOW(), NOW()), +(50, NULL, '192', 'CU', 'CUB', 0, NOW(), NOW()), +(51, NULL, '208', 'DK', 'DNK', 0, NOW(), NOW()), +(52, NULL, '262', 'DJ', 'DJI', 0, NOW(), NOW()), +(53, NULL, '212', 'DM', 'DMA', 0, NOW(), NOW()), +(54, NULL, '818', 'EG', 'EGY', 0, NOW(), NOW()), +(55, NULL, '784', 'AE', 'ARE', 0, NOW(), NOW()), +(56, NULL, '218', 'EC', 'ECU', 0, NOW(), NOW()), +(57, NULL, '232', 'ER', 'ERI', 0, NOW(), NOW()), +(58, NULL, '724', 'ES', 'ESP', 0, NOW(), NOW()), +(59, NULL, '233', 'EE', 'EST', 0, NOW(), NOW()), +(61, NULL, '231', 'ET', 'ETH', 0, NOW(), NOW()), +(62, NULL, '242', 'FJ', 'FJI', 0, NOW(), NOW()), +(63, NULL, '246', 'FI', 'FIN', 0, NOW(), NOW()), +(64, NULL, '250', 'FR', 'FRA', 1, NOW(), NOW()), +(65, NULL, '266', 'GA', 'GAB', 0, NOW(), NOW()), +(66, NULL, '270', 'GM', 'GMB', 0, NOW(), NOW()), +(67, NULL, '268', 'GE', 'GEO', 0, NOW(), NOW()), +(68, NULL, '288', 'GH', 'GHA', 0, NOW(), NOW()), +(69, NULL, '300', 'GR', 'GRC', 0, NOW(), NOW()), +(70, NULL, '308', 'GD', 'GRD', 0, NOW(), NOW()), +(71, NULL, '320', 'GT', 'GTM', 0, NOW(), NOW()), +(72, NULL, '324', 'GN', 'GIN', 0, NOW(), NOW()), +(73, NULL, '624', 'GW', 'GNB', 0, NOW(), NOW()), +(74, NULL, '226', 'GQ', 'GNQ', 0, NOW(), NOW()), +(75, NULL, '328', 'GY', 'GUY', 0, NOW(), NOW()), +(76, NULL, '332', 'HT', 'HTI', 0, NOW(), NOW()), +(77, NULL, '340', 'HN', 'HND', 0, NOW(), NOW()), +(78, NULL, '348', 'HU', 'HUN', 0, NOW(), NOW()), +(79, NULL, '356', 'IN', 'IND', 0, NOW(), NOW()), +(80, NULL, '360', 'ID', 'IDN', 0, NOW(), NOW()), +(81, NULL, '364', 'IR', 'IRN', 0, NOW(), NOW()), +(82, NULL, '368', 'IQ', 'IRQ', 0, NOW(), NOW()), +(83, NULL, '372', 'IE', 'IRL', 0, NOW(), NOW()), +(84, NULL, '352', 'IS', 'ISL', 0, NOW(), NOW()), +(85, NULL, '376', 'IL', 'ISR', 0, NOW(), NOW()), +(86, NULL, '380', 'IT', 'ITA', 0, NOW(), NOW()), +(87, NULL, '388', 'JM', 'JAM', 0, NOW(), NOW()), +(88, NULL, '392', 'JP', 'JPN', 0, NOW(), NOW()), +(89, NULL, '400', 'JO', 'JOR', 0, NOW(), NOW()), +(90, NULL, '398', 'KZ', 'KAZ', 0, NOW(), NOW()), +(91, NULL, '404', 'KE', 'KEN', 0, NOW(), NOW()), +(92, NULL, '417', 'KG', 'KGZ', 0, NOW(), NOW()), +(93, NULL, '296', 'KI', 'KIR', 0, NOW(), NOW()), +(94, NULL, '414', 'KW', 'KWT', 0, NOW(), NOW()), +(95, NULL, '418', 'LA', 'LAO', 0, NOW(), NOW()), +(96, NULL, '426', 'LS', 'LSO', 0, NOW(), NOW()), +(97, NULL, '428', 'LV', 'LVA', 0, NOW(), NOW()), +(98, NULL, '422', 'LB', 'LBN', 0, NOW(), NOW()), +(99, NULL, '430', 'LR', 'LBR', 0, NOW(), NOW()), +(100, NULL, '343', 'LY', 'LBY', 0, NOW(), NOW()), +(101, NULL, '438', 'LI', 'LIE', 0, NOW(), NOW()), +(102, NULL, '440', 'LT', 'LTU', 0, NOW(), NOW()), +(103, NULL, '442', 'LU', 'LUX', 0, NOW(), NOW()), +(104, NULL, '807', 'MK', 'MKD', 0, NOW(), NOW()), +(105, NULL, '450', 'MD', 'MDG', 0, NOW(), NOW()), +(106, NULL, '458', 'MY', 'MYS', 0, NOW(), NOW()), +(107, NULL, '454', 'MW', 'MWI', 0, NOW(), NOW()), +(108, NULL, '462', 'MV', 'MDV', 0, NOW(), NOW()), +(109, NULL, '466', 'ML', 'MLI', 0, NOW(), NOW()), +(110, NULL, '470', 'MT', 'MLT', 0, NOW(), NOW()), +(111, NULL, '504', 'MA', 'MAR', 0, NOW(), NOW()), +(112, NULL, '584', 'MH', 'MHL', 0, NOW(), NOW()), +(113, NULL, '480', 'MU', 'MUS', 0, NOW(), NOW()), +(114, NULL, '478', 'MR', 'MRT', 0, NOW(), NOW()), +(115, NULL, '484', 'MX', 'MEX', 0, NOW(), NOW()), +(116, NULL, '583', 'FM', 'FSM', 0, NOW(), NOW()), +(117, NULL, '498', 'MD', 'MDA', 0, NOW(), NOW()), +(118, NULL, '492', 'MC', 'MCO', 0, NOW(), NOW()), +(119, NULL, '496', 'MN', 'MNG', 0, NOW(), NOW()), +(120, NULL, '508', 'MZ', 'MOZ', 0, NOW(), NOW()), +(121, NULL, '516', 'NA', 'NAM', 0, NOW(), NOW()), +(122, NULL, '520', 'NR', 'NRU', 0, NOW(), NOW()), +(123, NULL, '524', 'NP', 'NPL', 0, NOW(), NOW()), +(124, NULL, '558', 'NI', 'NIC', 0, NOW(), NOW()), +(125, NULL, '562', 'NE', 'NER', 0, NOW(), NOW()), +(126, NULL, '566', 'NG', 'NGA', 0, NOW(), NOW()), +(127, NULL, '570', 'NU', 'NIU', 0, NOW(), NOW()), +(128, NULL, '578', 'NO', 'NOR', 0, NOW(), NOW()), +(129, NULL, '554', 'NZ', 'NZL', 0, NOW(), NOW()), +(130, NULL, '512', 'OM', 'OMN', 0, NOW(), NOW()), +(131, NULL, '800', 'UG', 'UGA', 0, NOW(), NOW()), +(132, NULL, '860', 'UZ', 'UZB', 0, NOW(), NOW()), +(133, NULL, '586', 'PK', 'PAK', 0, NOW(), NOW()), +(134, NULL, '591', 'PA', 'PAN', 0, NOW(), NOW()), +(135, NULL, '598', 'PG', 'PNG', 0, NOW(), NOW()), +(136, NULL, '600', 'PY', 'PRY', 0, NOW(), NOW()), +(137, NULL, '528', 'NL', 'NLD', 0, NOW(), NOW()), +(138, NULL, '604', 'PE', 'PER', 0, NOW(), NOW()), +(139, NULL, '608', 'PH', 'PHL', 0, NOW(), NOW()), +(140, NULL, '616', 'PL', 'POL', 0, NOW(), NOW()), +(141, NULL, '620', 'PT', 'PRT', 0, NOW(), NOW()), +(142, NULL, '634', 'QA', 'QAT', 0, NOW(), NOW()), +(143, NULL, '140', 'CF', 'CAF', 0, NOW(), NOW()), +(144, NULL, '214', 'DO', 'DOM', 0, NOW(), NOW()), +(145, NULL, '203', 'CZ', 'CZE', 0, NOW(), NOW()), +(146, NULL, '642', 'RO', 'ROU', 0, NOW(), NOW()), +(147, NULL, '826', 'GB', 'GBR', 0, NOW(), NOW()), +(148, NULL, '643', 'RU', 'RUS', 0, NOW(), NOW()), +(149, NULL, '646', 'RW', 'RWA', 0, NOW(), NOW()), +(150, NULL, '659', 'KN', 'KNA', 0, NOW(), NOW()), +(151, NULL, '662', 'LC', 'LCA', 0, NOW(), NOW()), +(152, NULL, '674', 'SM', 'SMR', 0, NOW(), NOW()), +(153, NULL, '670', 'VC', 'VCT', 0, NOW(), NOW()), +(154, NULL, '90', 'SB', 'SLB', 0, NOW(), NOW()), +(155, NULL, '222', 'SV', 'SLV', 0, NOW(), NOW()), +(156, NULL, '882', 'WS', 'WSM', 0, NOW(), NOW()), +(157, NULL, '678', 'ST', 'STP', 0, NOW(), NOW()), +(158, NULL, '686', 'SN', 'SEN', 0, NOW(), NOW()), +(159, NULL, '690', 'SC', 'SYC', 0, NOW(), NOW()), +(160, NULL, '694', 'SL', 'SLE', 0, NOW(), NOW()), +(161, NULL, '702', 'SG', 'SGP', 0, NOW(), NOW()), +(162, NULL, '703', 'SK', 'SVK', 0, NOW(), NOW()), +(163, NULL, '705', 'SI', 'SVN', 0, NOW(), NOW()), +(164, NULL, '706', 'SO', 'SOM', 0, NOW(), NOW()), +(165, NULL, '729', 'SD', 'SDN', 0, NOW(), NOW()), +(166, NULL, '144', 'LK', 'LKA', 0, NOW(), NOW()), +(167, NULL, '752', 'SE', 'SWE', 0, NOW(), NOW()), +(168, NULL, '756', 'CH', 'CHE', 0, NOW(), NOW()), +(169, NULL, '740', 'SR', 'SUR', 0, NOW(), NOW()), +(170, NULL, '748', 'SZ', 'SWZ', 0, NOW(), NOW()), +(171, NULL, '760', 'SY', 'SYR', 0, NOW(), NOW()), +(172, NULL, '762', 'TJ', 'TJK', 0, NOW(), NOW()), +(173, NULL, '834', 'TZ', 'TZA', 0, NOW(), NOW()), +(174, NULL, '148', 'TD', 'TCD', 0, NOW(), NOW()), +(175, NULL, '764', 'TH', 'THA', 0, NOW(), NOW()), +(176, NULL, '768', 'TG', 'TGO', 0, NOW(), NOW()), +(177, NULL, '776', 'TO', 'TON', 0, NOW(), NOW()), +(178, NULL, '780', 'TT', 'TTO', 0, NOW(), NOW()), +(179, NULL, '788', 'TN', 'TUN', 0, NOW(), NOW()), +(180, NULL, '795', 'TM', 'TKM', 0, NOW(), NOW()), +(181, NULL, '792', 'TR', 'TUR', 0, NOW(), NOW()), +(182, NULL, '798', 'TV', 'TUV', 0, NOW(), NOW()), +(183, NULL, '804', 'UA', 'UKR', 0, NOW(), NOW()), +(184, NULL, '858', 'UY', 'URY', 0, NOW(), NOW()), +(185, NULL, '336', 'VA', 'VAT', 0, NOW(), NOW()), +(186, NULL, '548', 'VU', 'VUT', 0, NOW(), NOW()), +(187, NULL, '862', 'VE', 'VEN', 0, NOW(), NOW()), +(188, NULL, '704', 'VN', 'VNM', 0, NOW(), NOW()), +(189, NULL, '887', 'YE', 'YEM', 0, NOW(), NOW()), +(190, NULL, '807', 'MK', 'MKD', 0, NOW(), NOW()), +(191, NULL, '180', 'CD', 'COD', 0, NOW(), NOW()), +(192, NULL, '894', 'ZM', 'ZMB', 0, NOW(), NOW()), +(193, NULL, '716', 'ZW', 'ZWE', 0, NOW(), NOW()), +(196, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(197, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(198, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(199, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(200, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(201, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(202, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(203, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(204, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(205, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(206, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(207, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(208, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(209, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(210, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(211, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(212, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(213, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(214, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(215, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(216, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(217, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(218, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(219, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(220, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(221, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(222, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(223, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(224, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(225, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(226, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(227, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(228, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(229, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(230, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(231, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(232, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(233, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(234, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(235, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(236, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(237, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(238, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(239, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(240, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(241, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(242, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(243, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(244, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(245, NULL, '840', 'US', 'USA', 0, NOW(), NOW()), +(246, NULL, '124', 'CA', 'CAN', 0, NOW(), NOW()), +(247, NULL, '124', 'CA', 'CAN', 0, NOW(), NOW()), +(248, NULL, '124', 'CA', 'CAN', 0, NOW(), NOW()), +(249, NULL, '124', 'CA', 'CAN', 0, NOW(), NOW()), +(250, NULL, '124', 'CA', 'CAN', 0, NOW(), NOW()), +(251, NULL, '124', 'CA', 'CAN', 0, NOW(), NOW()), +(252, NULL, '124', 'CA', 'CAN', 0, NOW(), NOW()), +(253, NULL, '124', 'CA', 'CAN', 0, NOW(), NOW()), +(254, NULL, '124', 'CA', 'CAN', 0, NOW(), NOW()), +(255, NULL, '124', 'CA', 'CAN', 0, NOW(), NOW()), +(256, NULL, '124', 'CA', 'CAN', 0, NOW(), NOW()), +(257, NULL, '124', 'CA', 'CAN', 0, NOW(), NOW()), +(258, NULL, '124', 'CA', 'CAN', 0, NOW(), NOW()), +(259, NULL, '312', 'GP', 'GLP', 0, NOW(), NOW()), +(260, NULL, '254', 'GF', 'GUF', 0, NOW(), NOW()), +(261, NULL, '474', 'MQ', 'MTQ', 0, NOW(), NOW()), +(262, NULL, '175', 'YT', 'MYT', 0, NOW(), NOW()), +(263, NULL, '638', 'RE', 'REU', 0, NOW(), NOW()), +(264, NULL, '666', 'PM', 'SPM', 0, NOW(), NOW()), +(265, NULL, '540', 'NC', 'NCL', 0, NOW(), NOW()), +(266, NULL, '258', 'PF', 'PYF', 0, NOW(), NOW()), +(267, NULL, '876', 'WF', 'WLF', 0, NOW(), NOW()), +(268, NULL, '840', 'US', 'USA', 0, NOW(), NOW()); INSERT INTO `country_i18n` (`id`, `locale`, `title`, `description`, `chapo`, `postscriptum`) VALUES (1, 'en_US', 'Afghanistan', '', '', ''), diff --git a/install/thelia.sql b/install/thelia.sql index 26f371a6b..f178467a1 100755 --- a/install/thelia.sql +++ b/install/thelia.sql @@ -21,7 +21,7 @@ CREATE TABLE `category` `version_created_at` DATETIME, `version_created_by` VARCHAR(100), PRIMARY KEY (`id`) -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- product @@ -54,7 +54,7 @@ CREATE TABLE `product` CONSTRAINT `fk_product_template1` FOREIGN KEY (`template_id`) REFERENCES `template` (`id`) -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- product_category @@ -81,7 +81,7 @@ CREATE TABLE `product_category` REFERENCES `category` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- country @@ -96,6 +96,7 @@ CREATE TABLE `country` `isocode` VARCHAR(4) NOT NULL, `isoalpha2` VARCHAR(2), `isoalpha3` VARCHAR(4), + `by_default` TINYINT, `created_at` DATETIME, `updated_at` DATETIME, PRIMARY KEY (`id`), @@ -105,7 +106,7 @@ CREATE TABLE `country` REFERENCES `area` (`id`) ON UPDATE RESTRICT ON DELETE SET NULL -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- tax @@ -121,7 +122,7 @@ CREATE TABLE `tax` `created_at` DATETIME, `updated_at` DATETIME, PRIMARY KEY (`id`) -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- tax_rule @@ -135,7 +136,7 @@ CREATE TABLE `tax_rule` `created_at` DATETIME, `updated_at` DATETIME, PRIMARY KEY (`id`) -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- tax_rule_country @@ -170,7 +171,7 @@ CREATE TABLE `tax_rule_country` REFERENCES `country` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- feature @@ -186,7 +187,7 @@ CREATE TABLE `feature` `created_at` DATETIME, `updated_at` DATETIME, PRIMARY KEY (`id`) -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- feature_av @@ -208,7 +209,7 @@ CREATE TABLE `feature_av` REFERENCES `feature` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- feature_product @@ -245,7 +246,7 @@ CREATE TABLE `feature_product` REFERENCES `feature_av` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- feature_template @@ -271,7 +272,7 @@ CREATE TABLE `feature_template` CONSTRAINT `fk_feature_template` FOREIGN KEY (`template_id`) REFERENCES `template` (`id`) -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- attribute @@ -286,7 +287,7 @@ CREATE TABLE `attribute` `created_at` DATETIME, `updated_at` DATETIME, PRIMARY KEY (`id`) -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- attribute_av @@ -308,7 +309,7 @@ CREATE TABLE `attribute_av` REFERENCES `attribute` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- attribute_combination @@ -340,7 +341,7 @@ CREATE TABLE `attribute_combination` CONSTRAINT `fk_attribute_combination_product_sale_elements_id` FOREIGN KEY (`product_sale_elements_id`) REFERENCES `product_sale_elements` (`id`) -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- product_sale_elements @@ -367,7 +368,7 @@ CREATE TABLE `product_sale_elements` REFERENCES `product` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- attribute_template @@ -393,7 +394,7 @@ CREATE TABLE `attribute_template` CONSTRAINT `fk_attribute_template` FOREIGN KEY (`template_id`) REFERENCES `template` (`id`) -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- config @@ -412,7 +413,7 @@ CREATE TABLE `config` `updated_at` DATETIME, PRIMARY KEY (`id`), UNIQUE INDEX `name_UNIQUE` (`name`) -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- customer @@ -446,7 +447,7 @@ CREATE TABLE `customer` REFERENCES `customer_title` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- address @@ -493,7 +494,7 @@ CREATE TABLE `address` REFERENCES `country` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- customer_title @@ -509,7 +510,7 @@ CREATE TABLE `customer_title` `created_at` DATETIME, `updated_at` DATETIME, PRIMARY KEY (`id`) -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- lang @@ -535,7 +536,7 @@ CREATE TABLE `lang` `created_at` DATETIME, `updated_at` DATETIME, PRIMARY KEY (`id`) -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- folder @@ -555,7 +556,7 @@ CREATE TABLE `folder` `version_created_at` DATETIME, `version_created_by` VARCHAR(100), PRIMARY KEY (`id`) -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- content @@ -574,7 +575,7 @@ CREATE TABLE `content` `version_created_at` DATETIME, `version_created_by` VARCHAR(100), PRIMARY KEY (`id`) -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- product_image @@ -597,7 +598,7 @@ CREATE TABLE `product_image` REFERENCES `product` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- product_document @@ -620,7 +621,7 @@ CREATE TABLE `product_document` REFERENCES `product` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- order @@ -679,7 +680,7 @@ CREATE TABLE `order` REFERENCES `order_status` (`id`) ON UPDATE RESTRICT ON DELETE SET NULL -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- currency @@ -698,7 +699,7 @@ CREATE TABLE `currency` `created_at` DATETIME, `updated_at` DATETIME, PRIMARY KEY (`id`) -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- order_address @@ -723,7 +724,7 @@ CREATE TABLE `order_address` `created_at` DATETIME, `updated_at` DATETIME, PRIMARY KEY (`id`) -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- order_product @@ -752,7 +753,7 @@ CREATE TABLE `order_product` REFERENCES `order` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- order_status @@ -767,7 +768,7 @@ CREATE TABLE `order_status` `created_at` DATETIME, `updated_at` DATETIME, PRIMARY KEY (`id`) -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- order_feature @@ -790,7 +791,7 @@ CREATE TABLE `order_feature` REFERENCES `order_product` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- module @@ -810,7 +811,7 @@ CREATE TABLE `module` `updated_at` DATETIME, PRIMARY KEY (`id`), UNIQUE INDEX `code_UNIQUE` (`code`) -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- accessory @@ -839,7 +840,7 @@ CREATE TABLE `accessory` REFERENCES `product` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- area @@ -855,7 +856,7 @@ CREATE TABLE `area` `created_at` DATETIME, `updated_at` DATETIME, PRIMARY KEY (`id`) -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- delivzone @@ -877,7 +878,7 @@ CREATE TABLE `delivzone` REFERENCES `area` (`id`) ON UPDATE RESTRICT ON DELETE SET NULL -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- group @@ -893,7 +894,7 @@ CREATE TABLE `group` `updated_at` DATETIME, PRIMARY KEY (`id`), UNIQUE INDEX `code_UNIQUE` (`code`) -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- resource @@ -909,7 +910,7 @@ CREATE TABLE `resource` `updated_at` DATETIME, PRIMARY KEY (`id`), UNIQUE INDEX `code_UNIQUE` (`code`) -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- admin @@ -931,7 +932,7 @@ CREATE TABLE `admin` `created_at` DATETIME, `updated_at` DATETIME, PRIMARY KEY (`id`) -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- admin_group @@ -959,7 +960,7 @@ CREATE TABLE `admin_group` REFERENCES `admin` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- group_resource @@ -989,7 +990,7 @@ CREATE TABLE `group_resource` REFERENCES `resource` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- group_module @@ -1018,7 +1019,7 @@ CREATE TABLE `group_module` REFERENCES `module` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- message @@ -1038,7 +1039,7 @@ CREATE TABLE `message` `version_created_by` VARCHAR(100), PRIMARY KEY (`id`), UNIQUE INDEX `name_UNIQUE` (`name`) -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- coupon @@ -1074,7 +1075,7 @@ CREATE TABLE `coupon` INDEX `idx_is_removing_postage` (`is_removing_postage`), INDEX `idx_max_usage` (`max_usage`), INDEX `idx_is_available_on_special_offers` (`is_available_on_special_offers`) -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- coupon_order @@ -1096,7 +1097,7 @@ CREATE TABLE `coupon_order` REFERENCES `order` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- admin_log @@ -1115,7 +1116,7 @@ CREATE TABLE `admin_log` `created_at` DATETIME, `updated_at` DATETIME, PRIMARY KEY (`id`) -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- content_folder @@ -1142,7 +1143,7 @@ CREATE TABLE `content_folder` REFERENCES `folder` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- cart @@ -1179,7 +1180,7 @@ CREATE TABLE `cart` CONSTRAINT `fk_cart_currency_id` FOREIGN KEY (`currency_id`) REFERENCES `currency` (`id`) -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- cart_item @@ -1214,7 +1215,7 @@ CREATE TABLE `cart_item` CONSTRAINT `fk_cart_item_product_sale_elements_id` FOREIGN KEY (`product_sale_elements_id`) REFERENCES `product_sale_elements` (`id`) -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- product_price @@ -1241,7 +1242,7 @@ CREATE TABLE `product_price` FOREIGN KEY (`currency_id`) REFERENCES `currency` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- category_image @@ -1264,7 +1265,7 @@ CREATE TABLE `category_image` REFERENCES `category` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- folder_image @@ -1287,7 +1288,7 @@ CREATE TABLE `folder_image` REFERENCES `folder` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- content_image @@ -1310,7 +1311,7 @@ CREATE TABLE `content_image` REFERENCES `content` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- category_document @@ -1333,7 +1334,7 @@ CREATE TABLE `category_document` REFERENCES `category` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- content_document @@ -1356,7 +1357,7 @@ CREATE TABLE `content_document` REFERENCES `content` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- folder_document @@ -1379,7 +1380,7 @@ CREATE TABLE `folder_document` REFERENCES `folder` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- product_associated_content @@ -1408,7 +1409,7 @@ CREATE TABLE `product_associated_content` REFERENCES `content` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- category_associated_content @@ -1437,7 +1438,7 @@ CREATE TABLE `category_associated_content` REFERENCES `content` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- rewriting_url @@ -1464,7 +1465,7 @@ CREATE TABLE `rewriting_url` REFERENCES `rewriting_url` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- rewriting_argument @@ -1486,7 +1487,7 @@ CREATE TABLE `rewriting_argument` REFERENCES `rewriting_url` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- template @@ -1500,7 +1501,7 @@ CREATE TABLE `template` `created_at` DATETIME, `updated_at` DATETIME, PRIMARY KEY (`id`) -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- category_i18n @@ -1521,7 +1522,7 @@ CREATE TABLE `category_i18n` FOREIGN KEY (`id`) REFERENCES `category` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- product_i18n @@ -1542,7 +1543,7 @@ CREATE TABLE `product_i18n` FOREIGN KEY (`id`) REFERENCES `product` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- country_i18n @@ -1563,7 +1564,7 @@ CREATE TABLE `country_i18n` FOREIGN KEY (`id`) REFERENCES `country` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- tax_i18n @@ -1582,7 +1583,7 @@ CREATE TABLE `tax_i18n` FOREIGN KEY (`id`) REFERENCES `tax` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- tax_rule_i18n @@ -1601,7 +1602,7 @@ CREATE TABLE `tax_rule_i18n` FOREIGN KEY (`id`) REFERENCES `tax_rule` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- feature_i18n @@ -1622,7 +1623,7 @@ CREATE TABLE `feature_i18n` FOREIGN KEY (`id`) REFERENCES `feature` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- feature_av_i18n @@ -1643,7 +1644,7 @@ CREATE TABLE `feature_av_i18n` FOREIGN KEY (`id`) REFERENCES `feature_av` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- attribute_i18n @@ -1664,7 +1665,7 @@ CREATE TABLE `attribute_i18n` FOREIGN KEY (`id`) REFERENCES `attribute` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- attribute_av_i18n @@ -1685,7 +1686,7 @@ CREATE TABLE `attribute_av_i18n` FOREIGN KEY (`id`) REFERENCES `attribute_av` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- config_i18n @@ -1706,7 +1707,7 @@ CREATE TABLE `config_i18n` FOREIGN KEY (`id`) REFERENCES `config` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- customer_title_i18n @@ -1725,7 +1726,7 @@ CREATE TABLE `customer_title_i18n` FOREIGN KEY (`id`) REFERENCES `customer_title` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- folder_i18n @@ -1746,7 +1747,7 @@ CREATE TABLE `folder_i18n` FOREIGN KEY (`id`) REFERENCES `folder` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- content_i18n @@ -1767,7 +1768,7 @@ CREATE TABLE `content_i18n` FOREIGN KEY (`id`) REFERENCES `content` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- product_image_i18n @@ -1788,7 +1789,7 @@ CREATE TABLE `product_image_i18n` FOREIGN KEY (`id`) REFERENCES `product_image` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- product_document_i18n @@ -1809,7 +1810,7 @@ CREATE TABLE `product_document_i18n` FOREIGN KEY (`id`) REFERENCES `product_document` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- currency_i18n @@ -1827,7 +1828,7 @@ CREATE TABLE `currency_i18n` FOREIGN KEY (`id`) REFERENCES `currency` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- order_status_i18n @@ -1848,7 +1849,7 @@ CREATE TABLE `order_status_i18n` FOREIGN KEY (`id`) REFERENCES `order_status` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- module_i18n @@ -1869,7 +1870,7 @@ CREATE TABLE `module_i18n` FOREIGN KEY (`id`) REFERENCES `module` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- group_i18n @@ -1890,7 +1891,7 @@ CREATE TABLE `group_i18n` FOREIGN KEY (`id`) REFERENCES `group` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- resource_i18n @@ -1911,7 +1912,7 @@ CREATE TABLE `resource_i18n` FOREIGN KEY (`id`) REFERENCES `resource` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- message_i18n @@ -1932,7 +1933,7 @@ CREATE TABLE `message_i18n` FOREIGN KEY (`id`) REFERENCES `message` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- coupon_i18n @@ -1952,7 +1953,7 @@ CREATE TABLE `coupon_i18n` FOREIGN KEY (`id`) REFERENCES `coupon` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- category_image_i18n @@ -1973,7 +1974,7 @@ CREATE TABLE `category_image_i18n` FOREIGN KEY (`id`) REFERENCES `category_image` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- folder_image_i18n @@ -1994,7 +1995,7 @@ CREATE TABLE `folder_image_i18n` FOREIGN KEY (`id`) REFERENCES `folder_image` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- content_image_i18n @@ -2015,7 +2016,7 @@ CREATE TABLE `content_image_i18n` FOREIGN KEY (`id`) REFERENCES `content_image` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- category_document_i18n @@ -2036,7 +2037,7 @@ CREATE TABLE `category_document_i18n` FOREIGN KEY (`id`) REFERENCES `category_document` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- content_document_i18n @@ -2057,7 +2058,7 @@ CREATE TABLE `content_document_i18n` FOREIGN KEY (`id`) REFERENCES `content_document` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- folder_document_i18n @@ -2078,7 +2079,7 @@ CREATE TABLE `folder_document_i18n` FOREIGN KEY (`id`) REFERENCES `folder_document` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- template_i18n @@ -2096,7 +2097,7 @@ CREATE TABLE `template_i18n` FOREIGN KEY (`id`) REFERENCES `template` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- category_version @@ -2120,7 +2121,7 @@ CREATE TABLE `category_version` FOREIGN KEY (`id`) REFERENCES `category` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- product_version @@ -2146,7 +2147,7 @@ CREATE TABLE `product_version` FOREIGN KEY (`id`) REFERENCES `product` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- folder_version @@ -2170,7 +2171,7 @@ CREATE TABLE `folder_version` FOREIGN KEY (`id`) REFERENCES `folder` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- content_version @@ -2193,7 +2194,7 @@ CREATE TABLE `content_version` FOREIGN KEY (`id`) REFERENCES `content` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- message_version @@ -2216,7 +2217,7 @@ CREATE TABLE `message_version` FOREIGN KEY (`id`) REFERENCES `message` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; -- --------------------------------------------------------------------- -- coupon_version @@ -2246,7 +2247,7 @@ CREATE TABLE `coupon_version` FOREIGN KEY (`id`) REFERENCES `coupon` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB CHARACTER SET='utf8'; +) ENGINE=InnoDB; # This restores the fkey checks, after having unset them earlier SET FOREIGN_KEY_CHECKS = 1; diff --git a/local/config/schema.xml b/local/config/schema.xml index d5cccb9da..186bdbfd6 100755 --- a/local/config/schema.xml +++ b/local/config/schema.xml @@ -1,9 +1,5 @@ - + - - - - @@ -84,6 +80,7 @@ + diff --git a/local/modules/DebugBar/DataCollector/PropelCollector.php b/local/modules/DebugBar/DataCollector/PropelCollector.php index dff0e6871..c0ce87746 100644 --- a/local/modules/DebugBar/DataCollector/PropelCollector.php +++ b/local/modules/DebugBar/DataCollector/PropelCollector.php @@ -124,7 +124,7 @@ class PropelCollector extends DataCollector implements Renderable, LoggerInterfa $message = "$sql ($duration_str)"; if ($this->alternativeLogger) { - $this->alternativeLogger->info($message); + $this->alternativeLogger->log($level, $message); } } @@ -180,7 +180,7 @@ class PropelCollector extends DataCollector implements Renderable, LoggerInterfa */ public function emergency($message, array $context = array()) { - $this->log(null, $message, $context); + $this->log(\Thelia\Log\Tlog::EMERGENCY, $message, $context); } /** @@ -195,7 +195,7 @@ class PropelCollector extends DataCollector implements Renderable, LoggerInterfa */ public function alert($message, array $context = array()) { - $this->log(null, $message, $context); + $this->log(\Thelia\Log\Tlog::ALERT, $message, $context); } /** @@ -209,7 +209,7 @@ class PropelCollector extends DataCollector implements Renderable, LoggerInterfa */ public function critical($message, array $context = array()) { - $this->log(null, $message, $context); + $this->log(\Thelia\Log\Tlog::CRITICAL, $message, $context); } /** @@ -222,7 +222,7 @@ class PropelCollector extends DataCollector implements Renderable, LoggerInterfa */ public function error($message, array $context = array()) { - $this->log(null, $message, $context); + $this->log(\Thelia\Log\Tlog::ERROR, $message, $context); } /** @@ -237,7 +237,7 @@ class PropelCollector extends DataCollector implements Renderable, LoggerInterfa */ public function warning($message, array $context = array()) { - $this->log(null, $message, $context); + $this->log(\Thelia\Log\Tlog::WARNING, $message, $context); } /** @@ -249,7 +249,7 @@ class PropelCollector extends DataCollector implements Renderable, LoggerInterfa */ public function notice($message, array $context = array()) { - $this->log(null, $message, $context); + $this->log(\Thelia\Log\Tlog::NOTICE, $message, $context); } /** @@ -263,7 +263,7 @@ class PropelCollector extends DataCollector implements Renderable, LoggerInterfa */ public function info($message, array $context = array()) { - $this->log(null, $message, $context); + $this->log(\Thelia\Log\Tlog::INFO, $message, $context); } /** @@ -275,7 +275,7 @@ class PropelCollector extends DataCollector implements Renderable, LoggerInterfa */ public function debug($message, array $context = array()) { - $this->log(null, $message, $context); + $this->log(\Thelia\Log\Tlog::DEBUG, $message, $context); } diff --git a/reset_install.sh b/reset_install.sh index 399156b67..380a80a5f 100755 --- a/reset_install.sh +++ b/reset_install.sh @@ -8,7 +8,7 @@ echo -e "\n\e[01;34m[INFO] Clearing caches\e[00m\n" php Thelia cache:clear echo -e "\n\e[01;34m[INFO] Downloading vendors\e[00m\n" -composer install --prefer-dist +composer install --prefer-dist --optimize-autoloader cd local/config/ diff --git a/templates/admin/default/admin-layout.tpl b/templates/admin/default/admin-layout.tpl index 3b97c069b..4cad798fb 100644 --- a/templates/admin/default/admin-layout.tpl +++ b/templates/admin/default/admin-layout.tpl @@ -206,7 +206,6 @@ - {intl l='Édité par OpenStudio'} - {intl l='Forum Thelia'} - {intl l='Contributions Thelia'} - {intl l='interface par Steaw-Webdesign'}

{module_include location='in_footer'} diff --git a/templates/admin/default/ajax/template-attribute-list.html b/templates/admin/default/ajax/template-attribute-list.html index b6379672a..772ed5883 100644 --- a/templates/admin/default/ajax/template-attribute-list.html +++ b/templates/admin/default/ajax/template-attribute-list.html @@ -1,15 +1,102 @@
{ifloop rel="free_attributes"} - - {intl l='Select an attribute and click (+) to add it to this template'} + + + + +
+ + + + +
+ + {intl l='Select an attribute and click (+) to add it to this template'} + + {/ifloop} {elseloop rel="free_attributes"}
There is currently no available attributes.
{/elseloop}
+
+ + + + + + + {module_include location='template_attributes_table_header'} + + + + + + + {loop name="assigned_attributes" type="attribute" template="$template_id" backend_context="1" lang="$edit_language_id"} + + + + + + {module_include location='template_attributes_table_row'} + + + + {/loop} + + {elseloop rel="assigned_attributes"} + + + + {/elseloop} + +
{intl l='ID'}{intl l='Attribute title'}{intl l="Actions"}
{$ID} + {$TITLE} + +
+ {loop type="auth" name="can_create" roles="ADMIN" permissions="admin.configuration.template.attribute.delete"} + + + + {/loop} +
+
+
+ {intl l="This template contains no attributes"} +
+
+ +{* Delete value confirmation dialog *} + +{capture "delete_attribute_dialog"} + + +{/capture} + +{include + file = "includes/generic-confirm-dialog.html" + + dialog_id = "delete_attribute_dialog" + dialog_title = {intl l="Remove attribute"} + dialog_message = {intl l="Do you really want to remove this attribute from the template ?"} + + form_action = {url path='/admin/configuration/templates/attributes/delete'} + form_content = {$smarty.capture.delete_attribute_dialog nofilter} +} + + diff --git a/templates/admin/default/ajax/template-feature-list.html b/templates/admin/default/ajax/template-feature-list.html new file mode 100644 index 000000000..a20ff7125 --- /dev/null +++ b/templates/admin/default/ajax/template-feature-list.html @@ -0,0 +1,102 @@ +
+ {ifloop rel="free_features"} +
+ + + +
+ + + + +
+ + {intl l='Select an feature and click (+) to add it to this template'} +
+ + {/ifloop} + {elseloop rel="free_features"} +
There is currently no available features.
+ {/elseloop} +
+ + + + + + + + + {module_include location='template_features_table_header'} + + + + + + + {loop name="assigned_features" type="feature" template="$template_id" backend_context="1" lang="$edit_language_id"} + + + + + + {module_include location='template_features_table_row'} + + + + {/loop} + + {elseloop rel="assigned_features"} + + + + {/elseloop} + +
{intl l='ID'}{intl l='Feature title'}{intl l="Actions"}
{$ID} + {$TITLE} + +
+ {loop type="auth" name="can_create" roles="ADMIN" permissions="admin.configuration.template.feature.delete"} + + + + {/loop} +
+
+
+ {intl l="This template contains no features"} +
+
+ +{* Delete value confirmation dialog *} + +{capture "delete_feature_dialog"} + + +{/capture} + +{include + file = "includes/generic-confirm-dialog.html" + + dialog_id = "delete_feature_dialog" + dialog_title = {intl l="Remove feature"} + dialog_message = {intl l="Do you really want to remove this feature from the template ?"} + + form_action = {url path='/admin/configuration/templates/features/delete'} + form_content = {$smarty.capture.delete_feature_dialog nofilter} +} + + diff --git a/templates/admin/default/ajax/thelia_news_feed.html b/templates/admin/default/ajax/thelia_news_feed.html index 09b3af020..f1b7e3133 100755 --- a/templates/admin/default/ajax/thelia_news_feed.html +++ b/templates/admin/default/ajax/thelia_news_feed.html @@ -1,11 +1,26 @@ {* this temlate is loaded via Ajax in the login page, to prevent login page slowdown *} -{loop type="feed" name="thelia_feeds" url="http://thelia.net/Flux-rss.html?id_rubrique=8" limit="3"} -
-

{$DATE}

-

{$TITLE|strip_tags nofilter}

- {* we use unescape:"htmlall" to unescape var before truncate, to prevent a cut in the middel of an HTML entity, eg &ea... *} -

{$DESCRIPTION|strip_tags|unescape:"htmlall"|truncate:250:"...":true nofilter}

-

{intl l='Lire la suite »'}

-
-{/loop} +
+ {loop type="feed" name="thelia_feeds" url="http://thelia.net/Flux-rss.html?id_rubrique=8" limit="3"} + +
+ +
+
+ {* we use unescape:"htmlall" to unescape var before truncate, to prevent a cut in the middel of an HTML entity, eg &ea... *} +

{$DESCRIPTION|strip_tags|unescape:"htmlall"|truncate:250:"...":true nofilter}

+
+ +
+
+ + {/loop} +
\ No newline at end of file diff --git a/templates/admin/default/assets/less/thelia/thelia.less b/templates/admin/default/assets/less/thelia/thelia.less index 50cd9bde6..6dc130918 100644 --- a/templates/admin/default/assets/less/thelia/thelia.less +++ b/templates/admin/default/assets/less/thelia/thelia.less @@ -34,7 +34,7 @@ .topbar { - background: url("@{imgDir}/top.jpg") repeat-x; + background: url("@{imgDir}/top.jpg") repeat-x; font-weight: bold; .version-info { @@ -202,7 +202,7 @@ border-bottom: 2px solid #A5CED8; margin-bottom: 0.5em; } - + // The action bar on the right .actions { text-align: right; @@ -217,6 +217,10 @@ text-transform: none; } } + + .inner-actions { + margin-top: 0.5em; + } } // The overall form container diff --git a/templates/admin/default/categories.html b/templates/admin/default/categories.html index 6fe06f8bc..32b9e6cba 100755 --- a/templates/admin/default/categories.html +++ b/templates/admin/default/categories.html @@ -1,396 +1,260 @@ {extends file="admin-layout.tpl"} -{block name="page-title"}{intl l='Catalog'}{/block} +{block name="page-title"}{intl l='Categories'}{/block} -{block name="check-permissions"}admin.catalog.view{/block} +{block name="check-permissions"}admin.categories.view{/block} {block name="main-content"} -
-
+
- {include file="includes/catalog-breadcrumb.html"} +
- {module_include location='catalog_top'} + {include file="includes/catalog-breadcrumb.html"} -
-
-
- - - {module_include location='catalog_bottom'} - - + {module_include location='category_list_row'} - {* Adding a new Category *} + + + + + + + {/loop} + + {/ifloop} + + {elseloop rel="category_list"} + + + + + + {/elseloop} +
- {* display parent category name, and get current cat ID *} - {loop name="category_title" type="category" visible="*" id=$current_category_id} - {intl l="Categories in %cat" cat=$TITLE} - {$cat_id = $ID} - {/loop} - {elseloop rel="category_title"} - {intl l="Top level categories"} - {/elseloop} + {module_include location='categories_top'} - {module_include location='category_list_caption'} +
+
+
+ + + {module_include location='category_list_caption'} - {ifloop rel="category_list"} - - - + {loop type="auth" name="can_create" roles="ADMIN" permissions="admin.categories.create"} + + + + {/loop} + - + {ifloop rel="category_list"} + + + - + - {module_include location='category_list_header'} + - + {module_include location='category_list_header'} - + - - - + - - {loop name="category_list" type="category" visible="*" parent=$current_category_id order=$category_order backend_context="1" lang=$lang_id} - - + + + - + + {loop name="category_list" type="category" visible="*" parent=$category_id order=$category_order backend_context="1" lang=$lang_id} + + - - - {module_include location='category_list_row'} - - - - - - - - {/loop} - - {/ifloop} - - {elseloop rel="category_list"} - - - - - - {/elseloop} -
+ {* display parent category name, and get current cat ID *} + {loop name="category_title" type="category" visible="*" id=$category_id} + {intl l="Categories in %cat" cat=$TITLE} + {$cat_id = $ID} + {/loop} + {elseloop rel="category_title"} + {intl l="Top level categories"} + {/elseloop} - {loop type="auth" name="can_create" roles="ADMIN" permissions="admin.categories.create"} - - - - {/loop} -
- {admin_sortable_header - current_order=$category_order - order='id' - reverse_order='id_reverse' - path={url path='/admin/catalog' id_category=$current_category_id} - label="{intl l='ID'}" - } -  
+ {admin_sortable_header + current_order=$category_order + order='id' + reverse_order='id_reverse' + path={url path='/admin/categories' id_category=$category_id} + request_parameter_name='category_order' + label="{intl l='ID'}" + } + - {admin_sortable_header - current_order=$category_order - order='alpha' - reverse_order='alpha_reverse' - path={url path='/admin/catalog' id_category=$current_category_id} - label="{intl l='Category title'}" - } -   + {admin_sortable_header + current_order=$category_order + order='alpha' + reverse_order='alpha_reverse' + path={url path='/admin/categories' id_category=$category_id} + request_parameter_name='category_order' + label="{intl l='Category title'}" + } + - {admin_sortable_header - current_order=$category_order - order='visible' - reverse_order='visible_reverse' - path={url path='/admin/catalog' id_category=$current_category_id} - label="{intl l='Online'}" - } - - {admin_sortable_header - current_order=$category_order - order='manual' - reverse_order='manual_reverse' - path={url path='/admin/catalog' id_category=$current_category_id} - label="{intl l='Position'}" - } - + {admin_sortable_header + current_order=$category_order + order='visible' + reverse_order='visible_reverse' + path={url path='/admin/categories' id_category=$category_id} + request_parameter_name='category_order' + label="{intl l='Online'}" + } + {intl l='Actions'}
+ {admin_sortable_header + current_order=$category_order + order='manual' + reverse_order='manual_reverse' + path={url path='/admin/categories' id_category=$category_id} + request_parameter_name='category_order' + label="{intl l='Position'}" + } +
{$ID}{intl l='Actions'}
- {loop type="image" name="cat_image" source="category" source_id="$ID" limit="1" width="50" height="50" resize_mode="crop" backend_context="1"} - {$TITLE} - {/loop} -
{$ID} - - {$TITLE} - - - {loop type="auth" name="can_change" roles="ADMIN" permissions="admin.categories.edit"} -
- -
- {/loop} - - {elseloop rel="can_change"} -
- -
- {/elseloop} -
- {admin_position_block - permission="admin.categories.edit" - path={url path='admin/category/update-position' category_id=$ID} - url_parameter="category_id" - in_place_edit_class="categoryPositionChange" - position=$POSITION - id=$ID - } - -
- - - {loop type="auth" name="can_change" roles="ADMIN" permissions="admin.categories.edit"} - - {/loop} - - {loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.categories.delete"} - - {/loop} -
-
-
- {loop type="auth" name="can_create" roles="ADMIN" permissions="admin.categories.create"} - {intl l="This category has no sub-categories. To create a new one, click the + button above."} - {/loop} - - {elseloop rel="can_create"} - {intl l="This category has no sub-categories."} - {/elseloop} -
-
-
-
-
- -
-
-
- - - - {ifloop rel="product_list"} - - - - - - - - - - - - - - - - {loop name="product_list" type="product" category=$current_category_id order="manual"} - - - - - - - - {module_include location='product_list_row'} - - - - - - - - {/loop} - - {/ifloop} + - {elseloop rel="product_list"} - - - - - - {/elseloop} -
- {* display parent category name *} - {loop name="category_title" type="category" visible="*" id=$current_category_id} - {intl l="Products in %cat" cat=$TITLE} - {/loop} - - {elseloop rel="category_title"} - {intl l="Top level Products"} - {/elseloop} - - {module_include location='product_list_caption'} - - - - -
- {admin_sortable_header - current_order=$product_order - order='id' - reverse_order='id_reverse' - path={url path='/admin/product' category_id=$current_category_id} - label="{intl l='ID'}" - } - -   - {admin_sortable_header - current_order=$product_order - order='ref' - reverse_order='ref_reverse' - path={url path='/admin/product' category_id=$current_category_id} - label="{intl l='Reference'}" - } - - {admin_sortable_header - current_order=$product_order - order='alpha' - reverse_order='alpha_reverse' - path={url path='/admin/product' category_id=$current_category_id} - label="{intl l='Product title'}" - } - - {module_include location='product_list_header'} - - - {admin_sortable_header - current_order=$product_order - order='visible' - reverse_order='visible_reverse' - path={url path='/admin/product' category_id=$current_category_id} - label="{intl l='Online'}" - } - - {admin_sortable_header - current_order=$product_order - order='manual' - reverse_order='manual_reverse' - path={url path='/admin/product' category_id=$current_category_id} - label="{intl l='Position'}" - } -  
{$ID} - {loop type="image" name="cat_image" source="product" source_id="$ID" limit="1" width="50" height="50" resize_mode="crop" backend_context="1"} - - {$TITLE} - - {/loop} - - {$REF}{$TITLE} - {loop type="auth" name="can_change" roles="ADMIN" permissions="admin.products.edit"} -
- -
- {/loop} - - {elseloop rel="can_change"} -
- -
- {/elseloop} -
- {admin_position_block - permission="admin.product.edit" - path={url path='admin/product' category_id=$ID} - url_parameter="product_id" - in_place_edit_class="productPositionChange" - position=$POSITION - id=$ID - } - -
- {loop type="auth" name="can_change" roles="ADMIN" permissions="admin.product.edit"} - - {/loop} - - {loop type="auth" name="can_change" roles="ADMIN" permissions="admin.product.delete"} - +
+ {loop type="image" name="cat_image" source="category" source_id="$ID" limit="1" width="50" height="50" resize_mode="crop" backend_context="1"} + {$TITLE} {/loop} - -
{intl l="This category doesn't have any products. To add a new product, click the + button above."}
-
-
-
+
+ + {$TITLE} + + + {loop type="auth" name="can_change" roles="ADMIN" permissions="admin.categories.edit"} +
+ +
+ {/loop} - {form name="thelia.admin.category.creation"} + {elseloop rel="can_change"} +
+ +
+ {/elseloop} +
+ {admin_position_block + permission="admin.categories.edit" + path={url path='admin/categories/update-position' category_id=$ID} + url_parameter="category_id" + in_place_edit_class="categoryPositionChange" + position=$POSITION + id=$ID + } + +
+ + + {loop type="auth" name="can_change" roles="ADMIN" permissions="admin.categories.edit"} + + {/loop} + + {loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.categories.delete"} + + {/loop} +
+
+
+ {loop type="auth" name="can_create" roles="ADMIN" permissions="admin.categories.create"} + {intl l="This category has no sub-categories. To create a new one, click the + button above."} + {/loop} + + {elseloop rel="can_create"} + {intl l="This category has no sub-categories."} + {/elseloop} +
+
+
+
+
+ + {module_include location='categories_bottom'} + +
+
+ + + {* Adding a new category *} + + {form name="thelia.admin.category.creation"} {* Capture the dialog body, to pass it to the generic dialog *} {capture "category_creation_dialog"} {form_hidden_fields form=$form} - {form_field form=$form field='success_url'} - {* on success, redirect to the edition page, _ID_ is replaced with the created object ID, see controller *} - - {/form_field} + {form_field form=$form field='success_url'} + {* on success, redirect to the edition page, _ID_ is replaced with the created object ID, see controller *} + + {/form_field} - {form_field form=$form field='parent'} - - {/form_field} + {form_field form=$form field='parent'} + + {/form_field} - {form_field form=$form field='title'} -
- + {form_field form=$form field='title'} +
+ + {loop type="lang" name="default-lang" default_only="1"} +
+ + $TITLE +
- {loop type="lang" name="default-lang" default_only="1"} +
{intl l='Enter here the category name in the default language (%title)' title="$TITLE"}
-
- - $TITLE -
+ {* Switch edition to the current locale *} + -
{intl l='Enter here the category name in the default language (%title)' title="$TITLE"}
+ {form_field form=$form field='locale'} + + {/form_field} + {/loop} +
+ {/form_field} - {* Switch edition to the current locale *} - - - {form_field form=$form field='locale'} - - {/form_field} - {/loop} -
- {/form_field} + {form_field form=$form field='visible'} +
+
+ +
+
+ {/form_field} {module_include location='category_create_form'} - {/capture} + {/capture} - {include - file = "includes/generic-create-dialog.html" + {include + file = "includes/generic-create-dialog.html" - dialog_id = "add_category_dialog" - dialog_title = {intl l="Create a new category"} - dialog_body = {$smarty.capture.category_creation_dialog nofilter} + dialog_id = "category_creation_dialog" + dialog_title = {intl l="Create a new category"} + dialog_body = {$smarty.capture.category_creation_dialog nofilter} - dialog_ok_label = {intl l="Create this category"} - dialog_cancel_label = {intl l="Cancel"} + dialog_ok_label = {intl l="Create this category"} - form_action = {url path='/admin/categories/create'} - form_enctype = {form_enctype form=$form} - form_error_message = $form_error_message - } + form_action = {url path='/admin/categories/create'} + form_enctype = {form_enctype form=$form} + form_error_message = $form_error_message + } {/form} - {* Delete category confirmation dialog *} + + {* Delete confirmation dialog *} {capture "category_delete_dialog"} - - + {module_include location='category_delete_form'} @@ -399,9 +263,9 @@ {include file = "includes/generic-confirm-dialog.html" - dialog_id = "delete_category_dialog" - dialog_title = {intl l="Delete a category"} - dialog_message = {intl l="Do you really want to delete this category, and all its contents ?"} + dialog_id = "category_delete_dialog" + dialog_title = {intl l="Delete category"} + dialog_message = {intl l="Do you really want to delete this category and all its content ?"} form_action = {url path='/admin/categories/delete'} form_content = {$smarty.capture.category_delete_dialog nofilter} @@ -410,108 +274,76 @@ {block name="javascript-initialization"} - {javascripts file='assets/js/bootstrap-switch/bootstrap-switch.js'} - - {/javascripts} + {javascripts file='assets/js/bootstrap-switch/bootstrap-switch.js'} + + {/javascripts} - {javascripts file='assets/js/bootstrap-editable/bootstrap-editable.js'} - - {/javascripts} + {javascripts file='assets/js/bootstrap-editable/bootstrap-editable.js'} + + {/javascripts} - + {/block} \ No newline at end of file diff --git a/templates/admin/default/category-edit.html b/templates/admin/default/category-edit.html index e01849475..626114d2a 100755 --- a/templates/admin/default/category-edit.html +++ b/templates/admin/default/category-edit.html @@ -8,206 +8,154 @@
- {include file="includes/catalog-breadcrumb.html"} + {include file="includes/catalog-breadcrumb.html" editing_category="true"}
- {loop name="category_edit" type="category" visible="*" id="{$current_category_id}" backend_context="1" lang="$edit_language_id"} + {loop name="category_edit" type="category" visible="*" id="{$category_id}" backend_context="1" lang="$edit_language_id"}
- {intl l='Edit category'} + {intl l='Edit category %title' title=$TITLE}
- - - + + {if $HAS_PREVIOUS != 0} + + {else} + + {/if} + + + + {if $HAS_NEXT != 0} + + {else} + + {/if}
-
+
+
-
- -
+
-
-
-
+
- {include file="includes/inner-form-toolbar.html" close_url="{url path='admin/catalog/category/edit' category_id=$current_category_id}"} +
-
-
-
- + {form name="thelia.admin.category.modification"} + -
- -
-
+ {include file="includes/inner-form-toolbar.html" close_url="{url path='/admin/categories' category_id=$category_id}"} -
- + {* Be sure to get the category ID, even if the form could not be validated *} + -
- -
-
+ {form_hidden_fields form=$form} -
- + {form_field form=$form field='success_url'} + + {/form_field} -
- + {form_field form=$form field='locale'} + + {/form_field} -
-
+ {if $form_error}
{$form_error_message}
{/if} -
- + {include file="includes/standard-description-form-fields.html"} -
- -
-
+ {form_field form=$form field='url'} +
+ -
- + +
+ {/form_field} -
- -
{intl l="The rewritten URL to the category page. Click \"Use Default\" button to use the default URL. Use only digits, letters, - and _ characters."}
-
-
+
+
+ {form_field form=$form field='parent'} +
-
-
+ -
-
-
-   -
-

{intl l='Category created on %date_create. Last modification: %date_change' date_create="{format_date date=$CREATE_DATE}" date_change="{format_date date=$UPDATE_DATE}"}}

-
-
-
-
+ +
+ {/form_field} +
+ +
+ {form_field form=$form field='visible'} +
+ +
+ +
+
+ {/form_field} +
+
-
-
- - -
- -
-
-
- -
-
- - -
- -
-
-
-
- -
- - -
- +   +
+

{intl l='Category created on %date_create. Last modification: %date_change' date_create="{format_date date=$CREATE_DATE}" date_change="{format_date date=$UPDATE_DATE}"}

-
+
-
-
-
+ + {/form} +
+
-
-

Images

-
+
+ klljkmk +
-
-

Documents

-
+
+
-
-

Modules

-
+
+
-
-
- - {/loop} +
+
+
+
+
+ {/loop}
@@ -217,10 +165,6 @@ + + + {/javascripts} + +{/block} \ No newline at end of file diff --git a/templates/admin/default/country-edit.html b/templates/admin/default/country-edit.html new file mode 100644 index 000000000..fe1a0f240 --- /dev/null +++ b/templates/admin/default/country-edit.html @@ -0,0 +1,147 @@ +{extends file="admin-layout.tpl"} + +{block name="page-title"}{intl l='Edit a country'}{/block} + +{block name="check-permissions"}admin.configuration.countries.edit{/block} + +{block name="main-content"} +
+ +
+ + {loop name="country_edit" type="country" id="$country_id" backend_context="1" lang="$edit_language_id"} + + + +
+
+
+ +
+ {intl l="Edit country $TITLE"} +
+ +
+
+ + {form name="thelia.admin.country.modification"} +
+ +
+
+ {* Be sure to get the country ID, even if the form could not be validated *} + + + {form_hidden_fields form=$form} + + {form_field form=$form field='success_url'} + + {/form_field} + + {if $form_error}
{$form_error_message}
{/if} + + {form_field form=$form field='area'} +
+ + +
+ {/form_field} + + {form_field form=$form field='isocode'} +
+ + +
+ {/form_field} + + {form_field form=$form field='isoalpha2'} +
+ + +
+ {/form_field} + + {form_field form=$form field='isoalpha3'} +
+ + +
+ {/form_field} +
+ +
+ {intl l="Translations"} +
+ + {loop type="lang" name="lang"} +
+
+
+

+ {intl l=$TITLE} {$TITLE} +

+
+
+ {form_field form=$form field='title'} +
+ + +
+ {/form_field} + {form_field form=$form field='short-description'} +
+ + +
+ {/form_field} + {form_field form=$form field='description'} +
+ + +
+ {/form_field} +
+
+
+ {/loop} + +
+ +
+
+
+ {/form} + +
+
+ +
+
+ +
+ + {/loop} + + {elseloop rel="country_edit"} +
+
+
+ {intl l="Sorry, country ID=$country_id was not found."} +
+
+
+ {/elseloop} + +
+
+{/block} \ No newline at end of file diff --git a/templates/admin/default/currency-edit.html b/templates/admin/default/currency-edit.html index cc7ac16ac..57b511903 100644 --- a/templates/admin/default/currency-edit.html +++ b/templates/admin/default/currency-edit.html @@ -54,7 +54,7 @@ {form_field form=$form field='name'}
- +  
{/form_field} @@ -64,7 +64,7 @@ - + List of ISO 4217 code @@ -80,7 +80,7 @@ - + {intl l='The symbol, such as $, £, €...'} {/form_field} @@ -90,7 +90,7 @@ - + The rate from Euro: Price in Euro x rate = Price in this currency {/form_field} diff --git a/templates/admin/default/general_error.html b/templates/admin/default/general_error.html index 2c40f4038..eae6614c9 100755 --- a/templates/admin/default/general_error.html +++ b/templates/admin/default/general_error.html @@ -10,11 +10,13 @@
-

{intl l="Oops! An Error Occurred"}

+
+

{intl l="Oops! An Error Occurred"}

- {block name="error-message"}
{$error_message}
{/block} - -

{intl l="Go to administration home"}

+ {block name="error-message"}

{$error_message}

{/block} + + {intl l="Go to administration home"} +
diff --git a/templates/admin/default/includes/catalog-breadcrumb.html b/templates/admin/default/includes/catalog-breadcrumb.html index b9312f0dd..8bbe69088 100644 --- a/templates/admin/default/includes/catalog-breadcrumb.html +++ b/templates/admin/default/includes/catalog-breadcrumb.html @@ -5,17 +5,17 @@
  • Catalog {ifloop rel="category_path"}
  • - {loop name="category_path" type="category-path" visible="*" category=$current_category_id} - {if $ID == $current_category_id} + {loop name="category_path" type="category-path" visible="*" category=$category_id} + {if $ID == $category_id}
  • - {if $action == 'edit'} - {intl l='Editing %cat' cat="{$TITLE}"} + {if $editing_category == true} + {intl l='Editing %cat' cat="{$TITLE}"} {else} - {$TITLE} {intl l="(edit)"} + {$TITLE} {intl l="(edit)"} {/if}
  • {else} -
  • {$TITLE}
  • +
  • {$TITLE}
  • {/if} {/loop} {/ifloop} diff --git a/templates/admin/default/login.html b/templates/admin/default/login.html index 682d2b954..c30eae514 100755 --- a/templates/admin/default/login.html +++ b/templates/admin/default/login.html @@ -6,52 +6,74 @@ {block name="page-title"}{intl l='Welcome'}{/block} {block name="main-content"} -
    +
    +
    + +
    +
    +
    + +

    {intl l='Thelia Back Office'}

    -
    +
    + {module_include location='index_top'} + + {form name="thelia.admin.login"} +
    - {module_include location='index_top'} + {if $form_error}
    {$form_error_message}
    {/if} -
    -

    {intl l='Thelia Back Office'}

    +
    + {intl l='Login'} + + {form_hidden_fields form=$form} - {form name="thelia.admin.login"} - + {form_field form=$form field='success_url'} + {* on success, redirect to /admin *} + {/form_field} + + {form_field form=$form field='username'} +
    + +
    + + +
    +
    + {/form_field} + {form_field form=$form field='password'} +
    + +
    + + +
    +
    + {/form_field} - {if $form_error}
    {$form_error_message}
    {/if} + {form_field form=$form field='remember_me'} +
    + +
    + {/form_field} - {form_hidden_fields form=$form} + +
    + + {/form} - {form_field form=$form field='success_url'} - {* on success, redirect to /admin *} - {/form_field} + {module_include location='index_middle'} +
    - {form_field form=$form field='username'} - - - - {/form_field} - - {form_field form=$form field='password'} - - - - {/form_field} - - {form_field form=$form field='remember_me'} - - {/form_field} - - - - {/form} -
    - - {module_include location='index_middle'} - -
    -
    -
    {intl l="Loading Thelia lastest news..."}
    +
    +
    +
    +
    {intl l="Loading Thelia lastest news..."}
    +
    +
    +
    @@ -59,6 +81,7 @@ {module_include location='index_bottom'}
    +
    {/block} {block name="javascript-initialization"} diff --git a/templates/admin/default/message-edit.html b/templates/admin/default/message-edit.html index db6118c05..51e97d61d 100644 --- a/templates/admin/default/message-edit.html +++ b/templates/admin/default/message-edit.html @@ -43,7 +43,7 @@ {/form_field} {form_field form=$form field='id'} - + {/form_field} {form_field form=$form field='locale'} @@ -55,7 +55,7 @@ {form_field form=$form field='name'}
    - +
    {/form_field} @@ -71,14 +71,14 @@ {form_field form=$form field='title'}
    - +
    {/form_field} {form_field form=$form field='subject'}
    - +
    {/form_field} @@ -88,7 +88,7 @@ {intl l="{$label}"} : {intl l="The mailing template in HTML format."} - +
    {/form_field} @@ -98,7 +98,7 @@ {intl l="{$label}"} : {intl l="The mailing template in text-only format."} - +
    {/form_field} diff --git a/templates/admin/default/orders.html b/templates/admin/default/orders.html index 4f9c6ecf8..dcf9ef7e3 100644 --- a/templates/admin/default/orders.html +++ b/templates/admin/default/orders.html @@ -59,7 +59,7 @@
    {loop type="auth" name="can_change" roles="ADMIN" permissions="admin.orders.edit"} - + {/loop} {loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.orders.delete"} @@ -83,7 +83,7 @@
    {loop type="auth" name="can_change" roles="ADMIN" permissions="admin.orders.edit"} - + {/loop} {loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.orders.delete"} @@ -107,7 +107,7 @@
    {loop type="auth" name="can_change" roles="ADMIN" permissions="admin.orders.edit"} - + {/loop} {loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.orders.delete"} diff --git a/templates/admin/default/template-edit.html b/templates/admin/default/template-edit.html index 0a073b719..7b9ddd4aa 100644 --- a/templates/admin/default/template-edit.html +++ b/templates/admin/default/template-edit.html @@ -108,8 +108,8 @@ {/block} \ No newline at end of file diff --git a/templates/admin/default/variable-edit.html b/templates/admin/default/variable-edit.html index 7e634b92a..30d9ea7c5 100644 --- a/templates/admin/default/variable-edit.html +++ b/templates/admin/default/variable-edit.html @@ -45,7 +45,7 @@ {* We do not allow creation of hidden variables *} {form_field form=$form field='id'} - + {/form_field} {form_field form=$form field='hidden'} @@ -61,14 +61,14 @@ {form_field form=$form field='name'}
    - +
    {/form_field} {form_field form=$form field='value'}
    - +
    {/form_field} diff --git a/templates/admin/default/variables.html b/templates/admin/default/variables.html index 3f1e90a09..6100466bd 100644 --- a/templates/admin/default/variables.html +++ b/templates/admin/default/variables.html @@ -95,7 +95,7 @@ {if $SECURED} {$VALUE} {else} - + {/if}