# By Manuel Raynaud (10) and others
# Via franck (4) and others
* 'master' of https://github.com/thelia/thelia: (24 commits)
  Added documents action and loop
  Typo
  Added UrlRewritingTrait to manage URLs from model classes
  fix typo
  Started category management
  add some php doc
  integrate swiftMailer as mailer solution
  add swiftmailer in composer
  use dump autoloader in all compser scripts
  remove script part of composer.json file
  fix typo
  add some information for OSX requirements
  No alert bloc
  default country
  Autofocus on username field for better use
  Beautiful login page
  feed loop is now countable
  Change error page design
  Add validation button on form
  - Edit country view creation - Delete and edit modalbox creation - Countries routes management
  ...
This commit is contained in:
gmorel
2013-09-17 11:41:53 +02:00
98 changed files with 4723 additions and 1963 deletions

View File

@@ -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 :

View File

@@ -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"
}
}

51
composer.lock generated
View File

@@ -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",

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -71,7 +71,7 @@ use Thelia\Core\Event\TheliaEvents;
* @author Franck Allimant <franck@cqfdev.fr>
*
*/
class Image extends BaseAction implements EventSubscriberInterface
class Image extends BaseCachedFile implements EventSubscriberInterface
{
// Resize mode constants
const EXACT_RATIO_WITH_BORDERS = 1;
@@ -79,38 +79,10 @@ class Image extends BaseAction implements EventSubscriberInterface
const KEEP_IMAGE_RATIO = 3;
/**
* Clear the image cache. Is a subdirectory is specified, only this directory is cleared.
* If no directory is specified, the whole cache is cleared.
* Only files are deleted, directories will remain.
*
* @param ImageEvent $event
* @return string root of the image cache directory in web space
*/
public function clearCache(ImageEvent $event)
{
$path = $this->getCachePath($event->getCacheSubdirectory(), false);
$this->clearDirectory($path);
}
/**
* Recursively clears the specified directory.
*
* @param string $path the directory path
*/
protected function clearDirectory($path)
{
$iterator = new \DirectoryIterator($path);
foreach ($iterator as $fileinfo) {
if ($fileinfo->isDot()) continue;
if ($fileinfo->isFile() || $fileinfo->isLink()) {
@unlink($fileinfo->getPathname());
} elseif ($fileinfo->isDir()) {
$this->clearDirectory($fileinfo->getPathname());
}
}
protected function getCacheDirFromWebRoot() {
return ConfigQuery::read('image_cache_dir_from_web_root', 'cache');
}
/**
@@ -138,9 +110,9 @@ class Image extends BaseAction implements EventSubscriberInterface
// echo basename($source_file).": ";
// Find cached file path
$cacheFilePath = $this->getCacheFilePath($subdir, $source_file, $event);
$cacheFilePath = $this->getCacheFilePath($subdir, $source_file, $event->isOriginalImage(), $event->getOptionsHash());
$originalImagePathInCache = $this->getCacheFilePath($subdir, $source_file, $event, true);
$originalImagePathInCache = $this->getCacheFilePath($subdir, $source_file, true);
if (! file_exists($cacheFilePath)) {
@@ -359,94 +331,6 @@ class Image extends BaseAction implements EventSubscriberInterface
return $image;
}
/**
* Return the absolute URL to the cached image
*
* @param string $subdir the subdirectory related to cache base
* @param string $filename the safe filename, as returned by getCacheFilePath()
* @return string the absolute URL to the cached image
*/
protected function getCacheFileURL($subdir, $safe_filename)
{
$path = $this->getCachePathFromWebRoot($subdir);
return URL::getInstance()->absoluteUrl(sprintf("%s/%s", $path, $safe_filename), null, URL::PATH_TO_FILE);
}
/**
* Return the full path of the cached file
*
* @param string $subdir the subdirectory related to cache base
* @param string $filename the filename
* @param boolean $forceOriginalImage if true, the origiunal image path in the cache dir is returned.
* @return string the cache directory path relative to Web Root
*/
protected function getCacheFilePath($subdir, $filename, ImageEvent $event, $forceOriginalImage = false)
{
$path = $this->getCachePath($subdir);
$safe_filename = preg_replace("[^:alnum:\-\._]", "-", strtolower(basename($filename)));
// Keep original safe name if no tranformations are applied
if ($forceOriginalImage || $event->isOriginalImage())
return sprintf("%s/%s", $path, $safe_filename);
else
return sprintf("%s/%s-%s", $path, $event->getOptionsHash(), $safe_filename);
}
/**
* Return the cache directory path relative to Web Root
*
* @param string $subdir the subdirectory related to cache base, or null to get the cache directory only.
* @return string the cache directory path relative to Web Root
*/
protected function getCachePathFromWebRoot($subdir = null)
{
$cache_dir_from_web_root = ConfigQuery::read('image_cache_dir_from_web_root', 'cache');
if ($subdir != null) {
$safe_subdir = basename($subdir);
$path = sprintf("%s/%s", $cache_dir_from_web_root, $safe_subdir);
} else
$path = $cache_dir_from_web_root;
// Check if path is valid, e.g. in the cache dir
return $path;
}
/**
* Return the absolute cache directory path
*
* @param string $subdir the subdirectory related to cache base, or null to get the cache base directory.
* @throws \RuntimeException if cache directory cannot be created
* @return string the absolute cache directory path
*/
protected function getCachePath($subdir = null, $create_if_not_exists = true)
{
$cache_base = $this->getCachePathFromWebRoot($subdir);
$web_root = rtrim(THELIA_WEB_DIR, '/');
$path = sprintf("%s/%s", $web_root, $cache_base);
// Create directory (recursively) if it does not exists.
if ($create_if_not_exists && !is_dir($path)) {
if (!@mkdir($path, 0777, true)) {
throw new ImageException(sprintf("Failed to create %s/%s image cache directory", $cache_base));
}
}
// Check if path is valid, e.g. in the cache dir
$cache_base = realpath(sprintf("%s/%s", $web_root, $this->getCachePathFromWebRoot()));
if (strpos(realpath($path), $cache_base) !== 0) {
throw new \InvalidArgumentException(sprintf("Invalid cache path %s, with subdirectory %s", $path, $subdir));
}
return $path;
}
/**
* Create a new Imagine object using current driver configuration
*

View File

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

View File

@@ -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),
);
}
}

View File

@@ -51,7 +51,7 @@
<form name="thelia.address.update" class="Thelia\Form\AddressUpdateForm" />
<form name="thelia.admin.category.creation" class="Thelia\Form\CategoryCreationForm"/>
<form name="thelia.admin.category.deletion" class="Thelia\Form\CategoryModificationForm"/>
<form name="thelia.admin.category.modification" class="Thelia\Form\CategoryModificationForm"/>
<form name="thelia.admin.product.creation" class="Thelia\Form\ProductCreationForm"/>
<form name="thelia.admin.product.deletion" class="Thelia\Form\ProductModificationForm"/>
@@ -82,6 +82,9 @@
<form name="thelia.admin.template.creation" class="Thelia\Form\TemplateCreationForm"/>
<form name="thelia.admin.template.modification" class="Thelia\Form\TemplateModificationForm"/>
<form name="thelia.admin.country.creation" class="Thelia\Form\CountryCreationForm"/>
<form name="thelia.admin.country.modification" class="Thelia\Form\CountryModificationForm"/>
</forms>
@@ -264,6 +267,10 @@
<tag name="thelia.coupon.addCoupon"/>
</service>
<service id="mailer" class="Thelia\Mailer\MailerFactory">
<argument type="service" id="event_dispatcher"/>
</service>
</services>

View File

@@ -85,7 +85,7 @@
</route>
<route id="admin.categories.set-default" path="/admin/categories/toggle-online">
<default key="_controller">Thelia\Controller\Admin\CategoryController::toggleOnlineAction</default>
<default key="_controller">Thelia\Controller\Admin\CategoryController::setToggleVisibilityAction</default>
</route>
<route id="admin.categories.delete" path="/admin/categories/delete">
@@ -234,6 +234,30 @@
<default key="_controller">Thelia\Controller\Admin\TemplateController::deleteAction</default>
</route>
<route id="admin.configuration.templates.features.list" path="/admin/configuration/templates/features/list">
<default key="_controller">Thelia\Controller\Admin\TemplateController::getAjaxFeaturesAction</default>
</route>
<route id="admin.configuration.templates.features.add" path="/admin/configuration/templates/features/add">
<default key="_controller">Thelia\Controller\Admin\TemplateController::addFeatureAction</default>
</route>
<route id="admin.configuration.templates.features.delete" path="/admin/configuration/templates/features/delete">
<default key="_controller">Thelia\Controller\Admin\TemplateController::deleteFeatureAction</default>
</route>
<route id="admin.configuration.templates.attributes.list" path="/admin/configuration/templates/attributes/list">
<default key="_controller">Thelia\Controller\Admin\TemplateController::getAjaxAttributesAction</default>
</route>
<route id="admin.configuration.templates.attributes.add" path="/admin/configuration/templates/attributes/add">
<default key="_controller">Thelia\Controller\Admin\TemplateController::addAttributeAction</default>
</route>
<route id="admin.configuration.templates.attributes.delete" path="/admin/configuration/templates/attributes/delete">
<default key="_controller">Thelia\Controller\Admin\TemplateController::deleteAttributeAction</default>
</route>
<!-- attribute and attributes value management -->
@@ -292,6 +316,23 @@
<!-- end attribute and feature routes management -->
<!-- Countries routes management -->
<route id="admin.configuration.countries.default" path="/admin/configuration/countries">
<default key="_controller">Thelia\Controller\Admin\CountryController::indexAction</default>
</route>
<route id="admin.configuration.countries.create" path="/admin/configuration/countries/create">
<default key="_controller">Thelia\Controller\Admin\CountryController::createAction</default>
</route>
<route id="admin.configuration.countries.update.view" path="/admin/configuration/countries/update/{country_id}" methods="get">
<default key="_controller">Thelia\Controller\Admin\CountryController::updateAction</default>
<requirement key="country_id">\d+</requirement>
</route>
<!-- end countries routes management -->
<!-- feature and features value management -->
<route id="admin.configuration.features.default" path="/admin/configuration/features">

View File

@@ -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();
}
/**

View File

@@ -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 <franck@cqfdev.fr>
*/

View File

@@ -37,7 +37,7 @@ use Thelia\Core\Event\AttributeAvUpdateEvent;
use Thelia\Core\Event\AttributeEvent;
/**
* Manages attributes sent by mail
* Manages attributes
*
* @author Franck Allimant <franck@cqfdev.fr>
*/

View File

@@ -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 <franck@cqfdev.fr>
*/
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;
}
}

View File

@@ -33,7 +33,7 @@ use Thelia\Form\ConfigCreationForm;
use Thelia\Core\Event\UpdatePositionEvent;
/**
* Manages variables sent by mail
* Manages variables
*
* @author Franck Allimant <franck@cqfdev.fr>
*/

View File

@@ -0,0 +1,52 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Controller\Admin;
/**
* Class CustomerController
* @package Thelia\Controller\Admin
* @author Manuel Raynaud <mraynaud@openstudio.fr>
*/
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
));
}
}

View File

@@ -33,7 +33,7 @@ use Thelia\Form\CurrencyCreationForm;
use Thelia\Core\Event\UpdatePositionEvent;
/**
* Manages currencies sent by mail
* Manages currencies
*
* @author Franck Allimant <franck@cqfdev.fr>
*/

View File

@@ -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 <franck@cqfdev.fr>
*/

View File

@@ -37,7 +37,7 @@ use Thelia\Core\Event\FeatureAvUpdateEvent;
use Thelia\Core\Event\FeatureEvent;
/**
* Manages features sent by mail
* Manages features
*
* @author Franck Allimant <franck@cqfdev.fr>
*/

View File

@@ -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 <franck@cqfdev.fr>
*/
@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -0,0 +1,94 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\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;
}
}

View File

@@ -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;
}
}

View File

@@ -0,0 +1,28 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Core\Event;
class CategoryToggleVisibilityEvent extends CategoryEvent
{
}

View File

@@ -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;

View File

@@ -0,0 +1,67 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\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;
}
}

View File

@@ -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;
}
}

View File

@@ -0,0 +1,52 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Core\Event;
/**
* Class MailTransporterEvent
* @package Thelia\Core\Event
* @author Manuel Raynaud <mraynaud@openstudio.fr>
*/
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;
}
}

View File

@@ -0,0 +1,51 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\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;
}
}

View File

@@ -0,0 +1,51 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\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;
}
}

View File

@@ -0,0 +1,51 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\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;
}
}

View File

@@ -0,0 +1,51 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\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;
}
}

View File

@@ -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';
}

View File

@@ -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 &gt;= 5.0.0)<br/>
* Return the current element

View File

@@ -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());
}
}
}

View File

@@ -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) {

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -0,0 +1,277 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\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 <franck@cqfdev.fr>
*/
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()."<br />";
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;
}
}

View File

@@ -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
);
}

View File

@@ -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());

View File

@@ -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()."<br />";
//echo "source = ".$this->getSource()."source_id=$source_id, id=$id<br />";
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()
);

View File

@@ -0,0 +1,36 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\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);
}
}

View File

@@ -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"
)
))
;
}

View File

@@ -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.")
))
;
}

View File

@@ -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'));
}

View File

@@ -0,0 +1,85 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\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";
}
}

View File

@@ -0,0 +1,107 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\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";
}
}

View File

@@ -0,0 +1,91 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\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 <mraynaud@openstudio.fr>
*/
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;
}
}

View File

@@ -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;

View File

@@ -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:
* <code>
* $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
* </code>
*
* @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
*

View File

@@ -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));

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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');
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -0,0 +1,78 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\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;
}
}

View File

@@ -0,0 +1,248 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\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);
}
}

View File

@@ -0,0 +1 @@
This is a text document.

View File

@@ -0,0 +1 @@
This is a text document.

View File

@@ -0,0 +1,89 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\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 <eroudeix@openstudio.fr>
*
*/
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);
}
}

View File

@@ -0,0 +1,89 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\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 <eroudeix@openstudio.fr>
*
*/
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);
}
}

View File

@@ -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("~", "`", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "=", "+", "[", "{", "]",
"}", "\\", "|", ";", ":", "\"", "'", "&#8216;", "&#8217;", "&#8220;", "&#8221;", "&#8211;", "&#8212;",
"—", "–", ",", "<", ".", ">", "/", "?");
$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
}
}

View File

@@ -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; $j<rand(0, 5); $j++) {
$subfolder = new Thelia\Model\Folder();
$subfolder->setParent($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; $k<rand(0, 5); $k++) {
$content = new Thelia\Model\Content();
$content->addFolder($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');

View File

@@ -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', '', '', ''),

View File

@@ -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;

View File

@@ -1,9 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8"?>
<database defaultIdMethod="native" name="thelia">
<vendor type="mysql">
<parameter name="Engine" value="InnoDB"/>
<parameter name="Charset" value="utf8"/>
</vendor>
<table name="category" namespace="Thelia\Model">
<column autoIncrement="true" name="id" primaryKey="true" required="true" type="INTEGER" />
<column name="parent" type="INTEGER" />
@@ -84,6 +80,7 @@
<column name="description" type="CLOB" />
<column name="chapo" type="LONGVARCHAR" />
<column name="postscriptum" type="LONGVARCHAR" />
<column name="by_default" type="TINYINT" />
<foreign-key foreignTable="area" name="fk_country_area_id" onDelete="SET NULL" onUpdate="RESTRICT">
<reference foreign="id" local="area_id" />
</foreign-key>

View File

@@ -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);
}

View File

@@ -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/

View File

@@ -206,7 +206,6 @@
- <a href="http://www.openstudio.fr/" target="_blank">{intl l='Édité par OpenStudio'}</a>
- <a href="http://forum.thelia.net/" target="_blank">{intl l='Forum Thelia'}</a>
- <a href="http://contrib.thelia.net/" target="_blank">{intl l='Contributions Thelia'}</a>
<span class="pull-right">{intl l='interface par <a target="_blank" href="http://www.steaw-webdesign.com/">Steaw-Webdesign</a>'}</span>
</p>
{module_include location='in_footer'}

View File

@@ -1,15 +1,102 @@
<div class="form-group">
{ifloop rel="free_attributes"}
<select name="free_attributes" id="free_attributes" class="form-control">
<option value="">Select an attribute...</option>
{loop name="free_attributes" type="attribute" template="$template_id" backend_context="1" lang="$edit_language_id"}
<option value="{$ID}">{$TITLE}</option>
{/loop}
</select>
<span class="help-block">{intl l='Select an attribute and click (+) to add it to this template'}</span>
<form action="{url path='/admin/configuration/templates/attributes/add'}">
<input type="hidden" name="template_id" value="{$template_id}" />
<div class="input-group">
<select required="required" name="attribute_id" id="attribute_id" class="form-control">
<option value="">Select an attribute...</option>
{loop name="free_attributes" type="attribute" exclude_template="$template_id" backend_context="1" lang="$edit_language_id"}
<option value="{$ID}">{$TITLE}</option>
{/loop}
</select>
<span class="input-group-btn">
<button class="btn btn-default btn-primary action-btn" type="submit"><span class="glyphicon glyphicon-plus-sign"></span></button>
</span>
</div>
<span class="help-block">{intl l='Select an attribute and click (+) to add it to this template'}</span>
</form>
{/ifloop}
{elseloop rel="free_attributes"}
<div class="alert alert-info">There is currently no available attributes.</div>
{/elseloop}
</div>
<table class="table table-striped table-condensed table-left-aligned">
<thead>
<tr>
<th>{intl l='ID'}</th>
<th>{intl l='Attribute title'}</th>
{module_include location='template_attributes_table_header'}
<th class="actions">{intl l="Actions"}</th>
</tr>
</thead>
<tbody>
{loop name="assigned_attributes" type="attribute" template="$template_id" backend_context="1" lang="$edit_language_id"}
<tr>
<td>{$ID}</td>
<td>
{$TITLE}
</td>
{module_include location='template_attributes_table_row'}
<td class="actions">
<div class="btn-group">
{loop type="auth" name="can_create" roles="ADMIN" permissions="admin.configuration.template.attribute.delete"}
<a class="btn btn-default btn-xs delete-attribute" title="{intl l='Delete this attribute'}" href="#delete_attribute_dialog" data-id="{$ID}" data-toggle="modal">
<span class="glyphicon glyphicon-trash"></span>
</a>
{/loop}
</div>
</td>
</tr>
{/loop}
{elseloop rel="assigned_attributes"}
<tr>
<td colspan="3">
<div class="alert alert-info">
{intl l="This template contains no attributes"}
</div>
</td>
</tr>
{/elseloop}
</tbody>
</table>
{* Delete value confirmation dialog *}
{capture "delete_attribute_dialog"}
<input type="hidden" name="template_id" value="{$template_id}" />
<input type="hidden" name="attribute_id" id="attribute_delete_id" value="" />
{/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}
}
<script>
$(function() {
// Set proper attribute ID in delete attribute from
$('a.delete-attribute').click(function(ev) {
$('#attribute_delete_id').val($(this).data('id'));
});
});
</script>

View File

@@ -0,0 +1,102 @@
<div class="form-group">
{ifloop rel="free_features"}
<form action="{url path='/admin/configuration/templates/features/add'}">
<input type="hidden" name="template_id" value="{$template_id}" />
<div class="input-group">
<select required="required" name="feature_id" id="feature_id" class="form-control">
<option value="">Select an feature...</option>
{loop name="free_features" type="feature" exclude_template="$template_id" backend_context="1" lang="$edit_language_id"}
<option value="{$ID}">{$TITLE}</option>
{/loop}
</select>
<span class="input-group-btn">
<button class="btn btn-default btn-primary action-btn" type="submit"><span class="glyphicon glyphicon-plus-sign"></span></button>
</span>
</div>
<span class="help-block">{intl l='Select an feature and click (+) to add it to this template'}</span>
</form>
{/ifloop}
{elseloop rel="free_features"}
<div class="alert alert-info">There is currently no available features.</div>
{/elseloop}
</div>
<table class="table table-striped table-condensed table-left-aligned">
<thead>
<tr>
<th>{intl l='ID'}</th>
<th>{intl l='Feature title'}</th>
{module_include location='template_features_table_header'}
<th class="actions">{intl l="Actions"}</th>
</tr>
</thead>
<tbody>
{loop name="assigned_features" type="feature" template="$template_id" backend_context="1" lang="$edit_language_id"}
<tr>
<td>{$ID}</td>
<td>
{$TITLE}
</td>
{module_include location='template_features_table_row'}
<td class="actions">
<div class="btn-group">
{loop type="auth" name="can_create" roles="ADMIN" permissions="admin.configuration.template.feature.delete"}
<a class="btn btn-default btn-xs delete-feature" title="{intl l='Delete this feature'}" href="#delete_feature_dialog" data-id="{$ID}" data-toggle="modal">
<span class="glyphicon glyphicon-trash"></span>
</a>
{/loop}
</div>
</td>
</tr>
{/loop}
{elseloop rel="assigned_features"}
<tr>
<td colspan="3">
<div class="alert alert-info">
{intl l="This template contains no features"}
</div>
</td>
</tr>
{/elseloop}
</tbody>
</table>
{* Delete value confirmation dialog *}
{capture "delete_feature_dialog"}
<input type="hidden" name="template_id" value="{$template_id}" />
<input type="hidden" name="feature_id" id="feature_delete_id" value="" />
{/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}
}
<script>
$(function() {
// Set proper feature ID in delete feature from
$('a.delete-feature').click(function(ev) {
$('#feature_delete_id').val($(this).data('id'));
});
});
</script>

View File

@@ -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"}
<div class="span4 feed-list-item">
<h3>{$DATE}</h3>
<h2><a href="{$URL}" target="_blank" title="{intl l='Lire la suite'}">{$TITLE|strip_tags nofilter}</a></h2>
{* we use unescape:"htmlall" to unescape var before truncate, to prevent a cut in the middel of an HTML entity, eg &ea... *}
<p>{$DESCRIPTION|strip_tags|unescape:"htmlall"|truncate:250:"...":true nofilter}</p>
<p><a class="btn" href="{$URL}" target="_blank">{intl l='Lire la suite »'}</a></p>
</div>
{/loop}
<div class="panel-group" id="accordion">
{loop type="feed" name="thelia_feeds" url="http://thelia.net/Flux-rss.html?id_rubrique=8" limit="3"}
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">
<a class="accordion-toggle" data-toggle="collapse" data-parent="#accordion" href="#collapse-{$LOOP_COUNT}">
{$TITLE|strip_tags nofilter} - {$DATE}
</a>
</h3>
</div>
<div id="collapse-{$LOOP_COUNT}" class="panel-collapse collapse {if $LOOP_COUNT == 1}in{/if}">
<div class="panel-body">
{* we use unescape:"htmlall" to unescape var before truncate, to prevent a cut in the middel of an HTML entity, eg &ea... *}
<p>{$DESCRIPTION|strip_tags|unescape:"htmlall"|truncate:250:"...":true nofilter}</p>
</div>
<div class="panel-footer">
<a href="{$URL}" target="_blank" class="btn btn-defaut btn-primary"><span class="glyphicon glyphicon-book"></span> {intl l='Lire la suite'}</a>
</div>
</div>
</div>
{/loop}
</div>

View File

@@ -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

View File

@@ -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"}
<div class="catalog">
<div id="wrapper" class="container">
<div class="categories">
{include file="includes/catalog-breadcrumb.html"}
<div id="wrapper" class="container">
{module_include location='catalog_top'}
{include file="includes/catalog-breadcrumb.html"}
<div class="row">
<div class="col-md-12">
<div class="general-block-decorator">
<table class="table table-striped table-condensed" id="category_list">
<caption>
{* 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'}
<div class="row">
<div class="col-md-12">
<div class="general-block-decorator">
<table class="table table-striped table-condensed" id="category_list">
<caption>
{* 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"}
<a class="btn btn-default btn-primary action-btn" title="{intl l='Add a new category'}" href="#add_category_dialog" data-toggle="modal">
<span class="glyphicon glyphicon-plus-sign"></span>
</a>
{/loop}
</caption>
{module_include location='category_list_caption'}
{ifloop rel="category_list"}
<thead>
<tr>
<th class="object-title">
{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'}"
}
</th>
{loop type="auth" name="can_create" roles="ADMIN" permissions="admin.categories.create"}
<a class="btn btn-default btn-primary action-btn" title="{intl l='Add a new category'}" href="#category_creation_dialog" data-toggle="modal">
<span class="glyphicon glyphicon-plus-sign"></span>
</a>
{/loop}
</caption>
<th class="object-image">&nbsp;</th>
{ifloop rel="category_list"}
<thead>
<tr>
<th class="object-title">
{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'}"
}
</th>
<th class="object-title">
{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'}"
}
</th>
<th class="object-image">&nbsp;</th>
{module_include location='category_list_header'}
<th class="object-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'}"
}
</th>
<th>
{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'}"
}
</th>
{module_include location='category_list_header'}
<th>
{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'}"
}
</th>
<th>
{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'}"
}
</th>
<th class="actions">{intl l='Actions'}</th>
</tr>
</thead>
<th>
{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'}"
}
</th>
<tbody>
{loop name="category_list" type="category" visible="*" parent=$current_category_id order=$category_order backend_context="1" lang=$lang_id}
<tr>
<td>{$ID}</td>
<th class="actions">{intl l='Actions'}</th>
</tr>
</thead>
<td>
{loop type="image" name="cat_image" source="category" source_id="$ID" limit="1" width="50" height="50" resize_mode="crop" backend_context="1"}
<a href="{url path='admin/catalog' category_id=$ID}" title="{intl l='Browse this category'}"><img class="img-thumbnail" src="{$IMAGE_URL}" alt="{$TITLE}" /></a>
{/loop}
</td>
<tbody>
{loop name="category_list" type="category" visible="*" parent=$category_id order=$category_order backend_context="1" lang=$lang_id}
<tr>
<td>{$ID}</td>
<td class="object-title">
<a href="{url path='admin/catalog' category_id=$ID}" title="{intl l='Browse this category'}">
{$TITLE}
</a>
</td>
{module_include location='category_list_row'}
<td>
{loop type="auth" name="can_change" roles="ADMIN" permissions="admin.categories.edit"}
<div class="make-switch switch-small" data-on="success" data-off="danger" data-on-label="<i class='glyphicon glyphicon-ok'></i>" data-off-label="<i class='glyphicon glyphicon-remove'></i>">
<input type="checkbox" data-id="{$ID}" class="categoryVisibleToggle" {if $VISIBLE == 1}checked="checked"{/if}>
</div>
{/loop}
{elseloop rel="can_change"}
<div class="make-switch switch-small" data-on="success" data-off="danger" data-on-label="<i class='glyphicon glyphicon-ok'></i>" data-off-label="<i class='glyphicon glyphicon-remove'></i>">
<input type="checkbox" class="disabled" disabled="disabled" {if $VISIBLE == 1}checked="checked"{/if}>
</div>
{/elseloop}
</td>
<td>
{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
}
</td>
<td>
<div class="btn-group">
<a class="btn btn-default btn-xs" title="{intl l='Browse this category'}" href="{url path='admin/category' category_id=$ID}"><i class="glyphicon glyphicon-folder-open"></i></a>
{loop type="auth" name="can_change" roles="ADMIN" permissions="admin.categories.edit"}
<a class="btn btn-default btn-xs" title="{intl l='Edit this category'}" href="{url path='/admin/categories/update' category_id=$ID}"><i class="glyphicon glyphicon-edit"></i></a>
{/loop}
{loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.categories.delete"}
<a class="btn btn-default btn-xs category-delete" title="{intl l='Delete this category and all its contents'}" href="#delete_category_dialog" data-id="{$ID}" data-toggle="modal"><i class="glyphicon glyphicon-trash"></i></a>
{/loop}
</div>
</td>
</tr>
{/loop}
</tbody>
{/ifloop}
{elseloop rel="category_list"}
<thead>
<tr>
<td class="message">
<div class="alert alert-info">
{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}
</div>
</td>
</tr>
</thead>
{/elseloop}
</table>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="general-block-decorator">
<table class="table table-striped table-condensed">
<caption>
{* 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'}
<a class="btn btn-default btn-primary action-btn" title="{intl l='Add a new product'}" href="#productAddModal" data-toggle="modal">
<span class="glyphicon glyphicon-plus-sign"></span>
</a>
</caption>
{ifloop rel="product_list"}
<thead>
<tr>
<th class="object-title">
{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'}"
}
<th>&nbsp;</th>
<th class="object-title">
{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'}"
}
</th>
<th class="object-title">
{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'}
<th>
{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'}"
}
</th>
<th>
{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'}"
}
</th>
<th>&nbsp;</th>
</tr>
</thead>
<tbody>
{loop name="product_list" type="product" category=$current_category_id order="manual"}
<tr>
<td>{$ID}</td>
<td>
{loop type="image" name="cat_image" source="product" source_id="$ID" limit="1" width="50" height="50" resize_mode="crop" backend_context="1"}
<a href="{url path='admin/product/edit' id=$ID}" title="{intl l='Edit this product'}">
<img src="{$IMAGE_URL}" alt="{$TITLE}" />
</a>
{/loop}
<td class="object-title"><a href="{url path='admin/product/edit' id=$ID}" title="{intl l='Edit this product'}">{$REF}</a></td>
<td class="object-title"><a href="{url path='admin/product/edit' id=$ID}" title="{intl l='Edit this product'}">{$TITLE}</a></td>
{module_include location='product_list_row'}
<td>
{loop type="auth" name="can_change" roles="ADMIN" permissions="admin.products.edit"}
<div class="make-switch switch-small" data-on="success" data-off="danger" data-on-label="<i class='glyphicon glyphicon-ok'></i>" data-off-label="<i class='glyphicon glyphicon-remove'></i>">
<input type="checkbox" data-id="{$ID}" class="productVisibleToggle" {if $VISIBLE == 1}checked="checked"{/if}>
</div>
{/loop}
{elseloop rel="can_change"}
<div class="make-switch switch-small" data-on="success" data-off="danger" data-on-label="<i class='glyphicon glyphicon-ok'></i>" data-off-label="<i class='glyphicon glyphicon-remove'></i>">
<input type="checkbox" data-id="{$ID}" class="displayToggle" {if $VISIBLE == 1}checked="checked"{/if}>
</div>
{/elseloop}
</td>
<td>
{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
}
</td>
<td>
<div class="btn-group">
{loop type="auth" name="can_change" roles="ADMIN" permissions="admin.product.edit"}
<a class="btn btn-default btn-xs" title="{intl l='Edit this product'}" href="{url path='admin/product/edit' product_id=$ID}"><i class="glyphicon glyphicon-edit"></i></a>
{/loop}
{loop type="auth" name="can_change" roles="ADMIN" permissions="admin.product.delete"}
<a class="btn btn-default btn-xs product-delete" title="{intl l='Delete this product'}" href="{url path='admin/product/delete' id=$ID}"><i class="glyphicon glyphicon-trash"></i></a>
<td>
{loop type="image" name="cat_image" source="category" source_id="$ID" limit="1" width="50" height="50" resize_mode="crop" backend_context="1"}
<a href="{url path='admin/catalog' category_id=$ID}" title="{intl l='Browse this category'}"><img class="img-thumbnail" src="{$IMAGE_URL}" alt="{$TITLE}" /></a>
{/loop}
</div>
</td>
</tr>
{/loop}
</tbody>
{/ifloop}
</td>
{elseloop rel="product_list"}
<thead>
<tr>
<td class="message"><div class="alert alert-info">{intl l="This category doesn't have any products. To add a new product, <strong>click the + button</strong> above."}</div></td>
</tr>
</thead>
{/elseloop}
</table>
</div>
</div>
</div>
<td class="object-title">
<a href="{url path='admin/catalog' category_id=$ID}" title="{intl l='Browse this category'}">
{$TITLE}
</a>
</td>
{module_include location='catalog_bottom'}
</div>
</div>
{module_include location='category_list_row'}
{* Adding a new Category *}
<td>
{loop type="auth" name="can_change" roles="ADMIN" permissions="admin.categories.edit"}
<div class="make-switch switch-small categoryVisibleToggle" data-id="{$ID}" data-on="success" data-off="danger" data-on-label="<i class='glyphicon glyphicon-ok'></i>" data-off-label="<i class='glyphicon glyphicon-remove'></i>">
<input type="checkbox" class="categoryVisibleToggle" {if $VISIBLE == 1}checked="checked"{/if}>
</div>
{/loop}
{form name="thelia.admin.category.creation"}
{elseloop rel="can_change"}
<div class="make-switch switch-small" data-on="success" data-off="danger" data-on-label="<i class='glyphicon glyphicon-ok'></i>" data-off-label="<i class='glyphicon glyphicon-remove'></i>">
<input type="checkbox" class="disabled" disabled="disabled" {if $VISIBLE == 1}checked="checked"{/if}>
</div>
{/elseloop}
</td>
<td>
{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
}
</td>
<td class="actions">
<div class="btn-group">
<a class="btn btn-default btn-xs" title="{intl l='Browse this category'}" href="{url path='admin/categories' category_id=$ID}"><i class="glyphicon glyphicon-folder-open"></i></a>
{loop type="auth" name="can_change" roles="ADMIN" permissions="admin.categories.edit"}
<a class="btn btn-default btn-xs" title="{intl l='Edit this category'}" href="{url path='/admin/categories/update' category_id=$ID}"><i class="glyphicon glyphicon-edit"></i></a>
{/loop}
{loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.categories.delete"}
<a class="btn btn-default btn-xs category-delete" title="{intl l='Delete this category and all its contents'}" href="#category_delete_dialog" data-id="{$ID}" data-toggle="modal"><i class="glyphicon glyphicon-trash"></i></a>
{/loop}
</div>
</td>
</tr>
{/loop}
</tbody>
{/ifloop}
{elseloop rel="category_list"}
<thead>
<tr>
<td class="message">
<div class="alert alert-info">
{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}
</div>
</td>
</tr>
</thead>
{/elseloop}
</table>
</div>
</div>
</div>
{module_include location='categories_bottom'}
</div>
</div>
{* 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 *}
<input type="hidden" name="{$name}" value="{url path='/admin/categories/update' category_id='_ID_'}" />
{/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 *}
<input type="hidden" name="{$name}" value="{url path='/admin/categories/update' category_id='_ID_'}" />
{/form_field}
{form_field form=$form field='parent'}
<input type="hidden" name="{$name}" value="{$current_category_id}" />
{/form_field}
{form_field form=$form field='parent'}
<input type="hidden" name="{$name}" value="{$category_id}" />
{/form_field}
{form_field form=$form field='title'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{$label} : </label>
{form_field form=$form field='title'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{$label} : </label>
{loop type="lang" name="default-lang" default_only="1"}
<div class="input-group">
<input type="text" id="{$label_attr.for}" required="required" name="{$name}" class="form-control" value="{$value}" title="{intl l='Currency name'}" placeholder="{intl l='Name'}">
<span class="input-group-addon"><img src="{image file="assets/img/flags/{$CODE}.gif"}" alt="$TITLE" /></span>
</div>
{loop type="lang" name="default-lang" default_only="1"}
<div class="help-block">{intl l='Enter here the category name in the default language (%title)' title="$TITLE"}</div>
<div class="input-group">
<input type="text" id="{$label_attr.for}" required="required" name="{$name}" class="form-control" value="{$value}" title="{intl l='Currency name'}" placeholder="{intl l='Name'}">
<span class="input-group-addon"><img src="{image file="assets/img/flags/{$CODE}.gif"}" alt="$TITLE" /></span>
</div>
{* Switch edition to the current locale *}
<input type="hidden" name="edit_language_id" value="{$ID}" />
<div class="help-block">{intl l='Enter here the category name in the default language (%title)' title="$TITLE"}</div>
{form_field form=$form field='locale'}
<input type="hidden" name="{$name}" value="{$LOCALE}" />
{/form_field}
{/loop}
</div>
{/form_field}
{* Switch edition to the current locale *}
<input type="hidden" name="edit_language_id" value="{$ID}" />
{form_field form=$form field='locale'}
<input type="hidden" name="{$name}" value="{$LOCALE}" />
{/form_field}
{/loop}
</div>
{/form_field}
{form_field form=$form field='visible'}
<div class="form-group {if $error}has-error{/if}">
<div class="checkbox">
<label>
<input type="checkbox" id="{$label_attr.for}" name="{$name}" value="1" checked="checked">
{$label}
</label>
</div>
</div>
{/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"}
<input type="hidden" name="current_category_id" value="{$current_category_id}" />
<input type="hidden" name="category_id" id="delete_category_id" value"" />
<input type="hidden" name="category_id" id="category_delete_id" value="" />
{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 <strong>all</strong> 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'}
<script src="{$asset_url}"></script>
{/javascripts}
{javascripts file='assets/js/bootstrap-switch/bootstrap-switch.js'}
<script src="{$asset_url}"></script>
{/javascripts}
{javascripts file='assets/js/bootstrap-editable/bootstrap-editable.js'}
<script src="{$asset_url}"></script>
{/javascripts}
{javascripts file='assets/js/bootstrap-editable/bootstrap-editable.js'}
<script src="{$asset_url}"></script>
{/javascripts}
<script>
$(function() {
<script>
$(function() {
// JS stuff for category creation form
{include
file = "includes/generic-js-dialog.html"
// Set proper category ID in delete from
$('a.category-delete').click(function(ev) {
$('#category_delete_id').val($(this).data('id'));
});
dialog_id = "add_category_dialog"
form_name = "thelia.admin.category.creation"
}
// JS stuff for creation form
{include
file = "includes/generic-js-dialog.html"
dialog_id = "category_creation_dialog"
form_name = "thelia.admin.category.creation"
}
// JS stuff for product creation form
{include
file = "includes/generic-js-dialog.html"
dialog_id = "add_product_dialog"
form_name = "thelia.admin.product.creation"
}
{* Toggle object visibility *}
{* Set the proper ID in the delete confirmation dialog *}
$(".categoryVisibleToggle").on('switch-change', function(event, data) {
console.log("yaya");
$.ajax({
url : "{url path='admin/categories/toggle-online'}",
data : {
category_id : $(this).data('id'),
action : 'visibilityToggle'
}
});
});
$('a.category-delete').click(function(ev) {
$('#delete_category_id').val($(this).data('id'));
});
{* Inline editing of object position using bootstrap-editable *}
$('a.product-delete').click(function(ev) {
$('#delete_product_id').val($(this).data('id'));
});
$('.categoryPositionChange').editable({
type : 'text',
title : '{intl l="Enter new category position"}',
mode : 'popup',
inputclass : 'input-mini',
placement : 'left',
success : function(response, newValue) {
// The URL template
var url = "{url path='/admin/categories/update-position' category_id='__ID__' position='__POS__'}";
// Perform subtitutions
url = url.replace('__ID__', $(this).data('id'))
.replace('__POS__', newValue);
{* Toggle object visibility *}
// Reload the page
location.href = url;
}
});
{* Change default status *}
$('.change-default').change(function(ev) {
var url = "{url path='/admin/categories/set-default' category_id='__ID__'}";
// Perform ID subtitutions
url = url.replace('__ID__', $(this).val());
// Reload the page
location.href = url;
});
$(".categoryVisibleToggle").click(function() {
$.ajax({
url : "{url path='admin/categories/toggle-online'}",
data : {
category_id : $(this).data('id'),
action : 'visibilityToggle'
}
});
});
$(".productVisibleToggle").click(function() {
$.ajax({
url : "{url path='admin/products/toggle-online'}",
data : {
category_id : $(this).data('id'),
action : 'visibilityToggle'
}
});
});
{* Inline editing of object position using bootstrap-editable *}
$('.categoryPositionChange').editable({
type : 'text',
title : '{intl l="Enter new category position"}',
mode : 'popup',
inputclass : 'input-mini',
placement : 'left',
success : function(response, newValue) {
// The URL template
var url = "{url path='/admin/categories/update-position' category_id='__ID__' position='__POS__'}";
// Perform subtitutions
url = url.replace('__ID__', $(this).data('id'))
.replace('__POS__', newValue);
// Reload the page
location.href = url;
}
});
$('.productPositionChange').editable({
type : 'text',
title : '{intl l="Enter new product position"}',
mode : 'popup',
inputclass : 'input-mini',
placement : 'left',
success : function(response, newValue) {
// The URL template
var url = "{url path='/admin/products/update-position' product_id='__ID__' position='__POS__'}";
// Perform subtitutions
url = url.replace('__ID__', $(this).data('id'))
.replace('__POS__', newValue);
// Reload the page
location.href = url;
}
});
})
</script>
</script>
{/block}

View File

@@ -8,206 +8,154 @@
<div class="catalog edit-category">
<div id="wrapper" class="container">
{include file="includes/catalog-breadcrumb.html"}
{include file="includes/catalog-breadcrumb.html" editing_category="true"}
<div class="row">
{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"}
<div class="col-md-12 general-block-decorator">
<div class="row">
<div class="col-md-7 title">
{intl l='Edit category'}
{intl l='Edit category %title' title=$TITLE}
</div>
<div class="col-md-5 actions">
<button class="btn btn-default" title="{intl l='Edit previous category'}"><i class="glyphicon glyphicon-arrow-left"></i></button>
<button class="btn btn-default" title="{intl l='Preview category page'}"><i class="glyphicon glyphicon-eye-open"></i></button>
<button class="btn btn-default" title="{intl l='Edit next category'}"><i class="glyphicon glyphicon-arrow-right"></i></button>
{if $HAS_PREVIOUS != 0}
<a href="{url path='/admin/categories/update' category_id=$PREVIOUS}" class="btn btn-default" title="{intl l='Edit previous category'}"><span class="glyphicon glyphicon-arrow-left"></span></a>
{else}
<a href="#" disabled="disabled" class="btn btn-default"><span class="glyphicon glyphicon-arrow-left"></span></a>
{/if}
<a href="{$URL}" target="_blank" class="btn btn-default" title="{intl l='Preview category page'}"><span class="glyphicon glyphicon-eye-open"></span></a>
{if $HAS_NEXT != 0}
<a href="{url path='/admin/categories/update' category_id=$NEXT}" class="btn btn-default" title="{intl l='Edit next category'}"><span class="glyphicon glyphicon-arrow-right"></span></a>
{else}
<a href="#" disabled="disabled" class="btn btn-default"><span class="glyphicon glyphicon-arrow-right"></span></a>
{/if}
</div>
</div>
<form method="post">
<div class="row">
<div class="col-md-12">
<div class="tabbable">
<ul class="nav nav-tabs admin-tabs" id="tabbed_menu">
<li class="active">
<a href="#general_description">{intl l="General description"}</a>
</li>
<ul class="nav nav-tabs">
<li class="active"><a href="#general_description" data-toggle="tab">{intl l="General description"}</a></li>
<li>
<a href="#details">{intl l="Details"}</a>
</li>
<li>
<a href="#images">{intl l="Images"}</a>
</li>
<li>
<a href="#documents">{intl l="Documents"}</a>
</li>
<li>
<a href="#modules">{intl l="Modules"}</a>
</li>
</ul>
<li><a href="#details" data-toggle="tab">{intl l="Details"}</a></li>
<li><a href="#images" data-toggle="tab">{intl l="Images"}</a></li>
<li><a href="#documents" data-toggle="tab">{intl l="Documents"}</a></li>
<li><a href="#modules" data-toggle="tab">{intl l="Modules"}</a></li>
</ul>
<div class="tab-content">
<div class="tab-content">
<div class="tab-pane active form-container" id="general_description">
<div class="form-horizontal col-md-12">
<fieldset>
<div class="tab-pane fade active in" id="general_description">
{include file="includes/inner-form-toolbar.html" close_url="{url path='admin/catalog/category/edit' category_id=$current_category_id}"}
<div class="form-container">
<div class="row">
<div class="col-md-12">
<div class="control-group">
<label class="control-label">
{intl l='Title *'}
</label>
{form name="thelia.admin.category.modification"}
<form method="POST" action="{url path='/admin/categories/save'}" {form_enctype form=$form} class="clearfix">
<div class="controls">
<input type="text" required="required" title="{intl l='Category title'}" placeholder="{intl l='Category title'}" class="input-block-level" value="{$TITLE|htmlspecialchars}">
</div>
</div>
{include file="includes/inner-form-toolbar.html" close_url="{url path='/admin/categories' category_id=$category_id}"}
<div class="control-group">
<label class="control-label">
{intl l='Summary'}
<span class="label-help-block">{intl l="A short category description, used when a summary or an introduction is required"}</span>
</label>
{* Be sure to get the category ID, even if the form could not be validated *}
<input type="hidden" name="category_id" value="{$category_id}" />
<div class="controls">
<textarea name="summary" rows="3" title="{intl l='Short category description'}" placeholder="{intl l='Short category description'}" class="input-block-level">{$CHAPO|htmlspecialchars}</textarea>
</div>
</div>
{form_hidden_fields form=$form}
<div class="control-group">
<label class="control-label">
{intl l='Detailed description'}
<span class="label-help-block">{intl l="The détailed category description."}</span>
</label>
{form_field form=$form field='success_url'}
<input type="hidden" name="{$name}" value="{url path='/admin/category' category_id={$category_d}}" />
{/form_field}
<div class="controls">
<textarea name="summary" rows="10" class="input-block-level">{$DESCRIPTION|htmlspecialchars}</textarea>
{form_field form=$form field='locale'}
<input type="hidden" name="{$name}" value="{$edit_language_locale}" />
{/form_field}
</div>
</div>
{if $form_error}<div class="alert alert-danger">{$form_error_message}</div>{/if}
<div class="control-group">
<label class="control-label">
{intl l='Conclusion'}
<span class="label-help-block">{intl l="A short post-description information"}</span>
</label>
{include file="includes/standard-description-form-fields.html"}
<div class="controls">
<textarea name="summary" rows="3" title="{intl l='Short category description'}" placeholder="{intl l='Short category description'}" class="input-block-level">{$POSTSCRIPTUM|htmlspecialchars}</textarea>
</div>
</div>
{form_field form=$form field='url'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">
{intl l="{$label}"} :
</label>
<div class="control-group">
<label class="control-label">
{intl l='Rewriten URL'}
</label>
<input type="text" id="{$label_attr.for}" required="required" name="{$name}" value="{$value}" title="{intl l='Rewritten URL'}" placeholder="{intl l='Rewriten URL'}" class="form-control">
</div>
{/form_field}
<div class="controls">
<div class="input-group input-block-level">
<input type="text" required="required" title="{intl l='Rewriten URL'}" placeholder="{intl l='Rewriten URL'}" class="input-block-level" value="{$URL|htmlspecialchars}">
<a class="btn btn-default input-group-addon use_default_rewriten_url" href="#">{intl l='Use default'}</a>
</div>
<div class="help-block">{intl l="The rewritten URL to the category page. Click \"Use Default\" button to use the default URL. Use only digits, letters, - and _ characters."}</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
{form_field form=$form field='parent'}
<div class="form-group {if $error}has-error{/if}">
</div>
</div>
<label for="{$label_attr.for}" class="control-label">
{intl l="{$label}"} :
</label>
<div class="row">
<div class="col-md-12">
<div class="control-group">
<lablel>&nbsp;</lablel>
<div class="controls">
<p>{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}"}}</p>
</div>
</div>
</div>
</div>
<select id="{$label_attr.for}" required="required" name="{$name}" class="form-control">
<option value="0">{intl l="Top level"}</option>
</fieldset>
</div>
</div>
{$myparent=$PARENT}
{loop name="cat-parent" type="category-tree" visible="*" category="0"}
<option value="{$ID}" style="padding-left: {3 + $LEVEL * 20}px" {if $myparent == $ID}selected="selected"{/if} {if $category_id == $ID}disabled="disabled"{/if}>{$TITLE}</option>
{/loop}
<div class="tab-pane form-container" id="details">
<div class="form-horizontal col-md-12">
<fieldset>
{include file="includes/inner-form-toolbar.html" close_url="{url path='admin/catalog/category/edit' category_id=$current_category_id}"}
</select>
</div>
{/form_field}
</div>
<div class="col-md-6">
{form_field form=$form field='visible'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{intl l='Visibility'}</label>
<div class="checkbox">
<label>
<input type="checkbox" id="{$label_attr.for}" name="{$name}" value="1" {if $value != 0}checked="checked"{/if}>
{$label}
</label>
</div>
</div>
{/form_field}
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="control-group">
<label class="control-label">
{intl l='Category ID'}
</label>
<div class="controls">
<input type="text" name="id" disabled="disabled" value="{$ID}" />
</div>
</div>
</div>
<div class="col-md-6">
<div class="control-group">
<label class="control-label">
{intl l='Parent category *'}
</label>
<div class="controls">
<select required="required" name="parent">
<option value="0">{intl l="Top level"}</option>
{loop name="cat-parent" type="category-tree" visible="*" category="0" exclude="{$current_category_id}"}
<option value="{$ID}" style="padding-left: {3 + $LEVEL * 20}px" {if $parent_category_id == $ID}selected="selected"{/if}>{$TITLE}</option>
{/loop}
</select>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="control-group">
<label class="control-label">
{intl l='Visibility'}
</label>
<div class="controls">
<label class="checkbox">
<input type="checkbox" name="visible" {if $VISIBLE}checked="checked"{/if}> {intl l="Display this category on front-office"}
</label>
<lablel>&nbsp;</lablel>
<div class="controls">
<p>{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}"}</p>
</div>
</div>
</div>
</div>
</div>
</fieldset>
</div>
</div>
</form>
{/form}
</div>
</div>
<div class="tab-pane" id="images">
<p>Images</p>
</div>
<div class="tab-pane fade" id="details">
klljkmk
</div>
<div class="tab-pane" id="documents">
<p>Documents</p>
</div>
<div class="tab-pane fade" id="images">
</div>
<div class="tab-pane" id="modules">
<p>Modules</p>
</div>
<div class="tab-pane fade" id="documents">
</div>
</div>
</div>
</form>
{/loop}
<div class="tab-pane fade" id="modules">
</div>
</div>
</div>
</div>
</div>
{/loop}
</div>
</div>
</div>
@@ -217,10 +165,6 @@
<script>
$(function() {
$('#tabbed_menu a').click(function (e) {
e.preventDefault();
$(this).tab('show');
});
$('.use_default_rewriten_url').click(function(ev) {
alert("Not functionnal");

View File

@@ -0,0 +1,220 @@
{extends file="admin-layout.tpl"}
{block name="page-title"}{intl l='Countries'}{/block}
{block name="check-permissions"}admin.configuration.countries.view{/block}
{block name="main-content"}
<div class="countries">
<div id="wrapper" class="container">
<ul class="breadcrumb">
<li><a href="{url path='/admin/home'}">{intl l="Home"}</a></li>
<li><a href="{url path='/admin/configuration'}">{intl l="Configuration"}</a></li>
<li><a href="{url path='/admin/configuration/countries'}">{intl l="Countries"}</a></li>
</ul>
{module_include location='countries_top'}
<div class="row">
<div class="col-md-12">
<form action="" method="post">
<div class="general-block-decorator">
<table class="table table-striped table-condensed">
<caption class="clearfix">
{intl l='Countries'}
{loop type="auth" name="can_create" roles="ADMIN" permissions="admin.configuration.countries.create"}
<a class="btn btn-default btn-primary action-btn" title="{intl l='Add a new country'}" href="#add_country_dialog" data-toggle="modal">
<span class="glyphicon glyphicon-plus-sign"></span>
</a>
{/loop}
</caption>
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Default</th>
<th>Shop</th>
<th>N° ISO</th>
<th>ISO Code</th>
{module_include location='countries_table_header'}
<th class="actions">{intl l='Actions'}</th>
</tr>
</thead>
<tbody>
{loop name="countries" type="country" backend_context="1" lang=$lang_id order=$order}
<tr>
<td>{$ID}</td>
<td>{$TITLE}</td>
<td>
<div class="make-switch switch-small switch-radio" data-on="success" data-off="danger" data-on-label="<i class='glyphicon glyphicon-ok'></i>" data-off-label="<i class='glyphicon glyphicon-remove'></i>">
<input class="change-default" type="radio" name="" value="{$ID}" {if $IS_DEFAULT}selected="selected"{/if}/>
</div>
</td>
<td>
<div class="make-switch switch-small switch-radio" data-on="success" data-off="danger" data-on-label="<i class='glyphicon glyphicon-ok'></i>" data-off-label="<i class='glyphicon glyphicon-remove'></i>">
<input class="change-default" type="radio" name="" value="{$ID}" {if $IS_DEFAULT}selected="selected"{/if}/>
</div>
</td>
<td>{$ISOCODE}</td>
<td>{$ISOALPHA3}</td>
{module_include location='countries_table_row'}
<td class="actions">
<div class="btn-group">
{loop type="auth" name="can_change" roles="ADMIN" permissions="admin.configuration.countries.change"}
<a class="btn btn-default btn-xs country-change" title="{intl l='Change this country'}" href="{url path="/admin/configuration/countries/update/{$ID}"}">
<span class="glyphicon glyphicon-edit"></span>
</a>
{/loop}
{loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.configuration.countries.delete"}
<a class="btn btn-default btn-xs country-delete" title="{intl l='Delete this country'}" href="#delete_dialog" data-id="{$ID}" data-toggle="modal">
<span class="glyphicon glyphicon-trash"></span>
</a>
{/loop}
</div>
</td>
</tr>
{/loop}
{elseloop rel="countries"}
<tr>
<td colspan="8">
<div class="alert alert-info">
{intl l="No country has been created yet. Click the + button to create one."}
</div>
</td>
</tr>
{/elseloop}
</tbody>
</table>
</div>
</form>
</div>
</div>
{module_include location='countries_bottom'}
</div>
</div>
{* Adding a new Country *}
{form name="thelia.admin.country.creation"}
{* Capture the dialog body, to pass it to the generic dialog *}
{capture "country_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 *}
<input type="hidden" name="{$name}" value="{url path='/admin/country/update' country_id='_ID_'}" />
{/form_field}
{form_field form=$form field='title'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
<input type="text" id="{$label_attr.for}" name="{$name}" class="form-control" value="{$value}" title="{intl l="{$label}"}" placeholder="{intl l='Country title'}">
</div>
{/form_field}
{form_field form=$form field='area'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
<select name="{$name}" id="{$label_attr.for}" class="form-control">
<option value="{$ID}">{$TITLE}</option>
</select>
</div>
{/form_field}
{form_field form=$form field='isocode'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
<input type="text" id="{$label_attr.for}" name="{$name}" class="form-control" value="{$value}" title="{intl l="{$label}"}" placeholder="{intl l='ISO Code'}">
</div>
{/form_field}
{form_field form=$form field='isoalpha2'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
<input type="text" id="{$label_attr.for}" name="{$name}" class="form-control" value="{$value}" title="{intl l="{$label}"}" placeholder="{intl l='Alpha code 2'}">
</div>
{/form_field}
{form_field form=$form field='isoalpha3'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
<input type="text" id="{$label_attr.for}" name="{$name}" class="form-control" value="{$value}" title="{intl l="{$label}"}" placeholder="{intl l='Alpha code 3'}">
</div>
{/form_field}
{module_include location='country_create_form'}
{/capture}
{include
file = "includes/generic-create-dialog.html"
dialog_id = "add_country_dialog"
dialog_title = {intl l="Create a new country"}
dialog_body = {$smarty.capture.country_creation_dialog nofilter}
dialog_ok_label = {intl l="Create this country"}
dialog_cancel_label = {intl l="Cancel"}
form_action = {url path='/admin/configuration/countries/create'}
form_enctype = {form_enctype form=$form}
form_error_message = $form_error_message
}
{/form}
{* Delete confirmation dialog *}
{capture "delete_dialog"}
<input type="hidden" name="country_id" id="country_delete_id" value="" />
{module_include location='country_delete_form'}
{/capture}
{include
file = "includes/generic-confirm-dialog.html"
dialog_id = "delete_dialog"
dialog_title = {intl l="Delete country"}
dialog_message = {intl l="Do you really want to delete this country ?"}
form_action = {url path='/admin/configuration/countries/delete'}
form_content = {$smarty.capture.delete_dialog nofilter}
}
{/block}
{block name="javascript-initialization"}
{javascripts file='assets/js/bootstrap-switch/bootstrap-switch.js'}
<script src="{$asset_url}"></script>
<script>
// Toogle switch on input radio
$('.switch-radio').on('switch-change', function () {
$('.switch-radio').bootstrapSwitch('toggleRadioState');
});
</script>
{/javascripts}
{/block}

View File

@@ -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"}
<div class="countries edit-country">
<div id="wrapper" class="container">
{loop name="country_edit" type="country" id="$country_id" backend_context="1" lang="$edit_language_id"}
<ul class="breadcrumb">
<li><a href="{url path='/admin/home'}">{intl l="Home"}</a></li>
<li><a href="{url path='/admin/configuration'}">{intl l="Configuration"}</a></li>
<li><a href="{url path='/admin/configuration/countries'}">{intl l="Countries"}</a></li>
<li>{intl l='Editing country "%name"' name="{$TITLE}"}</li>
</ul>
<div class="row">
<div class="col-md-12 general-block-decorator">
<div class="row">
<div class="col-md-12 title title-without-tabs">
{intl l="Edit country $TITLE"}
</div>
<div class="form-container">
<div class="col-md-12">
{form name="thelia.admin.country.modification"}
<form method="POST" action="{url path='/admin/configuration/countries/save'}" {form_enctype form=$form} class="clearfix">
<div class="row">
<div class="col-md-12">
{* Be sure to get the country ID, even if the form could not be validated *}
<input type="hidden" name="country_id" value="{$country_id}" />
{form_hidden_fields form=$form}
{form_field form=$form field='success_url'}
<input type="hidden" name="{$name}" value="{url path='/admin/configuration/countries'}" />
{/form_field}
{if $form_error}<div class="alert alert-danger">{$form_error_message}</div>{/if}
{form_field form=$form field='area'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
<select name="{$name}" id="{$label_attr.for}" class="form-control">
<option value="{$ID}">{$TITLE}</option>
</select>
</div>
{/form_field}
{form_field form=$form field='isocode'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
<input type="text" id="{$label_attr.for}" name="{$name}" class="form-control" value="{$value}" title="{intl l="{$label}"}" placeholder="{intl l='ISO Code'}">
</div>
{/form_field}
{form_field form=$form field='isoalpha2'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
<input type="text" id="{$label_attr.for}" name="{$name}" class="form-control" value="{$value}" title="{intl l="{$label}"}" placeholder="{intl l='Alpha code 2'}">
</div>
{/form_field}
{form_field form=$form field='isoalpha3'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
<input type="text" id="{$label_attr.for}" name="{$name}" class="form-control" value="{$value}" title="{intl l="{$label}"}" placeholder="{intl l='Alpha code 3'}">
</div>
{/form_field}
</div>
<div class="col-md-12 title title-without-tabs">
{intl l="Translations"}
</div>
{loop type="lang" name="lang"}
<div class="col-md-3">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">
<img src="{image file="assets/img/flags/{$CODE}.gif"}" alt="{intl l=$TITLE}"> {$TITLE}
</h3>
</div>
<div class="panel-body">
{form_field form=$form field='title'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
<input type="text" id="{$label_attr.for}" name="{$name}" class="form-control" value="{$value}" title="{intl l="{$label}"}" placeholder="{intl l='Country title'}">
</div>
{/form_field}
{form_field form=$form field='short-description'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
<textarea id="{$label_attr.for}" name="{$name}" class="form-control" title="{intl l="{$label}"}" placeholder="{intl l='Country short description'}"></textarea>
</div>
{/form_field}
{form_field form=$form field='description'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
<textarea id="{$label_attr.for}" name="{$name}" class="form-control" title="{intl l="{$label}"}" placeholder="{intl l='Country description'}"></textarea>
</div>
{/form_field}
</div>
</div>
</div>
{/loop}
<div class="col-md-12 text-right">
<button type="submit" class="btn btn-default btn-primary" title="{intl l='Add a new country'}">
{intl l="Save"}
<span class="glyphicon glyphicon-ok"></span>
</button>
</div>
</div>
</form>
{/form}
</div>
</div>
</div>
</div>
</div>
{/loop}
{elseloop rel="country_edit"}
<div class="row">
<div class="col-md-12">
<div class="alert alert-error">
{intl l="Sorry, country ID=$country_id was not found."}
</div>
</div>
</div>
{/elseloop}
</div>
</div>
{/block}

View File

@@ -54,7 +54,7 @@
{form_field form=$form field='name'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
<input type="text" id="{$label_attr.for}" required="required" name="{$name}" value="{$value|htmlspecialchars}" title="{intl l='Currency name'}" placeholder="{intl l='Currency name'}" class="form-control">
<input type="text" id="{$label_attr.for}" required="required" name="{$name}" value="{$value}" title="{intl l='Currency name'}" placeholder="{intl l='Currency name'}" class="form-control">
<span class="help-block">&nbsp;</span>
</div>
{/form_field}
@@ -64,7 +64,7 @@
<label for="{$label_attr.for}" class="control-label">
{intl l="{$label}"} :
</label>
<input type="text" id="{$label_attr.for}" required="required" name="{$name}" value="{$value|htmlspecialchars}" title="{intl l='Currency ISO 4217 Code'}" placeholder="{intl l='Code'}" class="form-control">
<input type="text" id="{$label_attr.for}" required="required" name="{$name}" value="{$value}" title="{intl l='Currency ISO 4217 Code'}" placeholder="{intl l='Code'}" class="form-control">
<span class="help-block">
<a title="{intl l='More information about ISO 4217'}" href="http://fr.wikipedia.org/wiki/ISO_4217" target="_blank">List of ISO 4217 code</a>
</span>
@@ -80,7 +80,7 @@
<label for="{$label_attr.for}" class="control-label">
{intl l="{$label}"} :
</label>
<input type="text" id="{$label_attr.for}" required="required" name="{$name}" value="{$value|htmlspecialchars}" title="{intl l='Currency symbol'}" placeholder="{intl l='Symbol'}" class="form-control">
<input type="text" id="{$label_attr.for}" required="required" name="{$name}" value="{$value}" title="{intl l='Currency symbol'}" placeholder="{intl l='Symbol'}" class="form-control">
<span class="help-block">{intl l='The symbol, such as $, £, &euro;...'}</span>
</div>
{/form_field}
@@ -90,7 +90,7 @@
<label for="{$label_attr.for}" class="control-label">
{intl l="{$label}"} :
</label>
<input type="text" id="{$label_attr.for}" required="required" name="{$name}" value="{$value|htmlspecialchars}" title="{intl l='Rate from Euro'}" placeholder="{intl l='Rate'}" class="form-control">
<input type="text" id="{$label_attr.for}" required="required" name="{$name}" value="{$value}" title="{intl l='Rate from Euro'}" placeholder="{intl l='Rate'}" class="form-control">
<span class="help-block">The rate from Euro: Price in Euro x rate = Price in this currency</span>
</div>
{/form_field}

View File

@@ -10,11 +10,13 @@
<div class="row">
<div class="col-md-12">
<h1>{intl l="Oops! An Error Occurred"}</h1>
<div class="general-block-decorator text-center">
<h1>{intl l="Oops! An Error Occurred"}</h1>
{block name="error-message"}<div class="alert alert-error">{$error_message}</div>{/block}
<p><i class="glyphicon glyphicon-backward"></i> <a href="{url path='/admin/home'}">{intl l="Go to administration home"}</a></p>
{block name="error-message"}<p>{$error_message}</p>{/block}
<a href="{url path='/admin/home'}" class="btn btn-default btn-info btn-lg"><span class="glyphicon glyphicon-home"></span> {intl l="Go to administration home"}</a>
</div>
</div>
</div>

View File

@@ -5,17 +5,17 @@
<li><a href="{url path='admin/catalog'}">Catalog</a>
{ifloop rel="category_path"}</li>
{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}
<li class="active">
{if $action == 'edit'}
{intl l='Editing %cat' cat="{$TITLE}"}
{if $editing_category == true}
{intl l='Editing %cat' cat="{$TITLE}"}
{else}
{$TITLE} <a href="{url path='admin/catalog/category/edit' category_id=$ID}" title="{intl l='Edit this category'}">{intl l="(edit)"}</a>
{$TITLE} <a href="{url path='/admin/categories/update' category_id=$ID}" title="{intl l='Edit this category'}">{intl l="(edit)"}</a>
{/if}
</li>
{else}
<li><a href="{url path='admin/catalog/category' id=" $ID" action='browse'}">{$TITLE}</a></li>
<li><a href="{url path='/admin/categories' category_id=" $ID" action='browse'}">{$TITLE}</a></li>
{/if}
{/loop}
{/ifloop}

View File

@@ -6,52 +6,74 @@
{block name="page-title"}{intl l='Welcome'}{/block}
{block name="main-content"}
<div class="loginpage">
<div class="loginpage">
<div id="wrapper" class="container">
<div class="row">
<div class="col-md-12">
<div class="general-block-decorator clearfix">
<h1 class="title title-without-tabs">{intl l='Thelia Back Office'}</h1>
<div id="wrapper" class="container">
<div class="col-md-6">
{module_include location='index_top'}
{form name="thelia.admin.login"}
<form action="{url path='/admin/checklogin'}" method="post" {form_enctype form=$form}>
{module_include location='index_top'}
{if $form_error}<div class="alert alert-danger">{$form_error_message}</div>{/if}
<div class="jumbotron">
<h1>{intl l='Thelia Back Office'}</h1>
<fieldset>
<legend>{intl l='Login'}</legend>
{form_hidden_fields form=$form}
{form name="thelia.admin.login"}
<form action="{url path='/admin/checklogin'}" method="post" class="well form-inline" {form_enctype form=$form}>
{form_field form=$form field='success_url'}
<input type="hidden" name="{$name}" value="{url path='/admin'}" /> {* on success, redirect to /admin *}
{/form_field}
{form_field form=$form field='username'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span>
<input type="text" id="{$label_attr.for}" name="{$name}" class="form-control" title="{intl l="{$label}"}" placeholder="{intl l='Username'}" autofocus>
</div>
</div>
{/form_field}
{form_field form=$form field='password'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-lock"></span></span>
<input type="password" id="{$label_attr.for}" name="{$name}" class="form-control" title="{intl l="{$label}"}" placeholder="{intl l='Password'}">
</div>
</div>
{/form_field}
{if $form_error}<div class="alert alert-error">{$form_error_message}</div>{/if}
{form_field form=$form field='remember_me'}
<div class="checkbox">
<label for="{$label_attr.for}">
<input type="checkbox" name="{$name}" id="{$label_attr.for}" value="{$value}" {$attr} {if $options.checked}checked="checked"{/if}/> {intl l="{$label}"}
</label>
</div>
{/form_field}
{form_hidden_fields form=$form}
<button type="submit" class="btn btn-default btn-primary pull-right"><span class="glyphicon glyphicon-off"></span> {intl l='Login'}</button>
</fieldset>
</form>
{/form}
{form_field form=$form field='success_url'}
<input type="hidden" name="{$name}" value="{url path='/admin'}" /> {* on success, redirect to /admin *}
{/form_field}
{module_include location='index_middle'}
</div>
{form_field form=$form field='username'}
<span {if $error}class="error"{/if}>
<input type="text" id="username" class="input" placeholder="{intl l='User name'}" name="{$name}" value="{$value}" {$attr} />
</span>
{/form_field}
{form_field form=$form field='password'}
<span {if $error}class="error"{/if}>
<input type="password" id="password" class="input" placeholder="{intl l='Password'}" name="{$name}" {$attr} />
</span>
{/form_field}
{form_field form=$form field='remember_me'}
<label class="checkbox"> <input type="checkbox" name="{$name}" value="{$value}" {$attr} {if $options.checked}checked="checked"{/if}/> {intl l='Remember me'}</label>
{/form_field}
<span class="pull-right"><button type="submit" class="btn btn-default btn-primary">{intl l='Login'} <span class="glyphicon glyphicon-play"></span></button></span>
</form>
{/form}
</div>
{module_include location='index_middle'}
<div class="row feed-list">
<div class="col-md-6 col-md-offset-3">
<div class="alert alert-info">{intl l="Loading Thelia lastest news..."}</div>
<div class="col-md-6">
<div class="row feed-list">
<div class="col-md-6 col-md-offset-3">
<div class="alert alert-info">{intl l="Loading Thelia lastest news..."}</div>
</div>
</div>
</div>
</div>
</div>
</div>
@@ -59,6 +81,7 @@
{module_include location='index_bottom'}
</div>
</div>
{/block}
{block name="javascript-initialization"}

View File

@@ -43,7 +43,7 @@
{/form_field}
{form_field form=$form field='id'}
<input type="hidden" name="{$name}" value="{$value|htmlspecialchars}" />
<input type="hidden" name="{$name}" value="{$value}" />
{/form_field}
{form_field form=$form field='locale'}
@@ -55,7 +55,7 @@
{form_field form=$form field='name'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
<input type="text" id="{$label_attr.for}" required="required" name="{$name}" value="{$value|htmlspecialchars}" title="{intl l='Variable name'}" placeholder="{intl l='Variable name'}" class="form-control">
<input type="text" id="{$label_attr.for}" required="required" name="{$name}" value="{$value}" title="{intl l='Variable name'}" placeholder="{intl l='Variable name'}" class="form-control">
</div>
{/form_field}
@@ -71,14 +71,14 @@
{form_field form=$form field='title'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
<input type="text" id="{$label_attr.for}" name="{$name}" required="required" title="{intl l='Title'}" placeholder="{intl l='Title'}" class="form-control" value="{$value|htmlspecialchars}">
<input type="text" id="{$label_attr.for}" name="{$name}" required="required" title="{intl l='Title'}" placeholder="{intl l='Title'}" class="form-control" value="{$value}">
</div>
{/form_field}
{form_field form=$form field='subject'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
<input type="text" id="{$label_attr.for}" name="{$name}" required="required" title="{intl l='Subject'}" placeholder="{intl l='Subject'}" class="form-control" value="{$value|htmlspecialchars}">
<input type="text" id="{$label_attr.for}" name="{$name}" required="required" title="{intl l='Subject'}" placeholder="{intl l='Subject'}" class="form-control" value="{$value}">
</div>
{/form_field}
@@ -88,7 +88,7 @@
{intl l="{$label}"} :
<span class="label-help-block">{intl l="The mailing template in HTML format."}</span>
</label>
<textarea name="{$name}" id="{$label_attr.for}" rows="10" class="form-control">{$value|htmlspecialchars}</textarea>
<textarea name="{$name}" id="{$label_attr.for}" rows="10" class="form-control">{$value}</textarea>
</div>
{/form_field}
@@ -98,7 +98,7 @@
{intl l="{$label}"} :
<span class="label-help-block">{intl l="The mailing template in text-only format."}</span>
</label>
<textarea name="{$name}" id="{$label_attr.for}" rows="10" class="form-control">{$value|htmlspecialchars}</textarea>
<textarea name="{$name}" id="{$label_attr.for}" rows="10" class="form-control">{$value}</textarea>
</div>
{/form_field}

View File

@@ -59,7 +59,7 @@
<div class="btn-group">
{loop type="auth" name="can_change" roles="ADMIN" permissions="admin.orders.edit"}
<a class="btn btn-default btn-xs" title="{intl l='Edit this order'}" href="{url path='/admin/order/update/$ID'}"><span class="glyphicon glyphicon-edit"></span></a>
<a class="btn btn-default btn-xs" title="{intl l='Edit this order'}" href="{url path="/admin/order/update/$ID"}"><span class="glyphicon glyphicon-edit"></span></a>
{/loop}
{loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.orders.delete"}
@@ -83,7 +83,7 @@
<div class="btn-group">
{loop type="auth" name="can_change" roles="ADMIN" permissions="admin.orders.edit"}
<a class="btn btn-default btn-xs" title="{intl l='Edit this order'}" href="{url path='/admin/order/update/$ID'}"><span class="glyphicon glyphicon-edit"></span></a>
<a class="btn btn-default btn-xs" title="{intl l='Edit this order'}" href="{url path="/admin/order/update/$ID"}"><span class="glyphicon glyphicon-edit"></span></a>
{/loop}
{loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.orders.delete"}
@@ -107,7 +107,7 @@
<div class="btn-group">
{loop type="auth" name="can_change" roles="ADMIN" permissions="admin.orders.edit"}
<a class="btn btn-default btn-xs" title="{intl l='Edit this order'}" href="{url path='/admin/order/update/$ID'}"><span class="glyphicon glyphicon-edit"></span></a>
<a class="btn btn-default btn-xs" title="{intl l='Edit this order'}" href="{url path="/admin/order/update/$ID"}"><span class="glyphicon glyphicon-edit"></span></a>
{/loop}
{loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.orders.delete"}

View File

@@ -108,8 +108,8 @@
<script>
$(function() {
$('#attribute_list_management').load("{admin_viewurl view='ajax/template-attribute-list' template_id=$template_id}");
$('#feature_list_management').load("{admin_viewurl view='ajax/template-feature-list' template_id=$template_id}");
$('#feature_list_management').load("{url path='/admin/configuration/templates/features/list' template_id=$template_id}");
$('#attribute_list_management').load("{url path='/admin/configuration/templates/attributes/list' template_id=$template_id}");
});
</script>
{/block}

View File

@@ -45,7 +45,7 @@
{* We do not allow creation of hidden variables *}
{form_field form=$form field='id'}
<input type="hidden" name="{$name}" value="{$value|htmlspecialchars}" />
<input type="hidden" name="{$name}" value="{$value}" />
{/form_field}
{form_field form=$form field='hidden'}
@@ -61,14 +61,14 @@
{form_field form=$form field='name'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
<input type="text" id="{$label_attr.for}" required="required" name="{$name}" value="{$value|htmlspecialchars}" title="{intl l='Variable name'}" placeholder="{intl l='Variable name'}" class="form-control">
<input type="text" id="{$label_attr.for}" required="required" name="{$name}" value="{$value}" title="{intl l='Variable name'}" placeholder="{intl l='Variable name'}" class="form-control">
</div>
{/form_field}
{form_field form=$form field='value'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
<input type="text" id="{$label_attr.for}" name="{$name}" value="{$value|htmlspecialchars}" title="{intl l='Variable value'}" placeholder="{intl l='Variable value'}" class="form-control">
<input type="text" id="{$label_attr.for}" name="{$name}" value="{$value}" title="{intl l='Variable value'}" placeholder="{intl l='Variable value'}" class="form-control">
</div>
{/form_field}

View File

@@ -95,7 +95,7 @@
{if $SECURED}
{$VALUE}
{else}
<input id="cancelable_edit_{$ID}" class="js-edit form-control" data-id="{$ID}" type="text" name="variable[{$ID}]" value="{$VALUE|htmlspecialchars}" />
<input id="cancelable_edit_{$ID}" class="js-edit form-control" data-id="{$ID}" type="text" name="variable[{$ID}]" value="{$VALUE}" />
{/if}
</td>