Merge branch 'master' of https://github.com/thelia/thelia into coupon

# By gmorel (24) and others
# Via gmorel (12) and others
* 'master' of https://github.com/thelia/thelia: (43 commits)
  Working : upload file/image : fix sanitizeFileName
  Working : images : enhance display
  Working : Fix : Unit test
  Working : Fix : Unit test
  Working : Fix : Image Management + Document Management
  Working : FileManager :Add some more unit tests
  Working : Add a link on documents
  Working : fix url document + refactor : naming conventions
  Working : refactor : naming conventions
  Working : upload : fix unit test
  WIP : upload documents : add action, ctrl, event
  Finished product combination basic function
  WIP : upload document : add forms
  Working : upload image : fix return URL to images tab
  Working : upload image : fix fallback and delete links on refresh
  Formatted combination table
  Impemented combination creation
  Working : Upload image : Fix upload validation
  - Image format allowed - manual-reverse order on image loop
  Upload allow only for images
  ...

Conflicts:
	core/lib/Thelia/Model/Base/AttributeTemplate.php
	core/lib/Thelia/Model/Base/AttributeTemplateQuery.php
	core/lib/Thelia/Model/Map/AttributeTemplateTableMap.php
	install/faker.php
	install/thelia.sql
	local/config/schema.xml
	templates/admin/default/assets/js/coupon.js
	tests/functionnal/casperjs/exe/00_parameters.js
	tests/functionnal/casperjs/exe/31_coupons_rule.js
This commit is contained in:
gmorel
2013-09-27 10:37:09 +02:00
127 changed files with 11206 additions and 1128 deletions

View File

@@ -37,7 +37,8 @@
"imagine/imagine": "dev-master",
"symfony/icu": "1.0",
"swiftmailer/swiftmailer": "5.0.*"
"swiftmailer/swiftmailer": "5.0.*",
"symfony/serializer": "2.3.*"
},
"require-dev" : {
"phpunit/phpunit": "3.7.*",

67
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": "a40be01c82e68ba0c446dc204d2667da",
"hash": "097481390dc87b3482d895b3b6a65479",
"packages": [
{
"name": "imagine/imagine",
@@ -1456,6 +1456,53 @@
"homepage": "http://symfony.com",
"time": "2013-08-23 14:06:02"
},
{
"name": "symfony/serializer",
"version": "v2.3.4",
"target-dir": "Symfony/Component/Serializer",
"source": {
"type": "git",
"url": "https://github.com/symfony/Serializer.git",
"reference": "457ba76395955926a67ea692957b0872dead5278"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Serializer/zipball/457ba76395955926a67ea692957b0872dead5278",
"reference": "457ba76395955926a67ea692957b0872dead5278",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.3-dev"
}
},
"autoload": {
"psr-0": {
"Symfony\\Component\\Serializer\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "http://symfony.com/contributors"
}
],
"description": "Symfony Serializer Component",
"homepage": "http://symfony.com",
"time": "2013-07-21 12:12:18"
},
{
"name": "symfony/translation",
"version": "v2.2.6",
@@ -1722,12 +1769,12 @@
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "1.2.12"
"reference": "0e9958c459d675fb497d8dc5001c91d335734e48"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/1.2.12",
"reference": "1.2.12",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/0e9958c459d675fb497d8dc5001c91d335734e48",
"reference": "0e9958c459d675fb497d8dc5001c91d335734e48",
"shasum": ""
},
"require": {
@@ -1916,12 +1963,12 @@
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-token-stream.git",
"reference": "1.2.0"
"reference": "31babf400e5b5868573bf49a000a3519d3978233"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/1.2.0",
"reference": "1.2.0",
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/31babf400e5b5868573bf49a000a3519d3978233",
"reference": "31babf400e5b5868573bf49a000a3519d3978233",
"shasum": ""
},
"require": {
@@ -1966,12 +2013,12 @@
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "3.7.24"
"reference": "af7b77ccb5c64458bdfca95665d29558d1df7d08"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3.7.24",
"reference": "3.7.24",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/af7b77ccb5c64458bdfca95665d29558d1df7d08",
"reference": "af7b77ccb5c64458bdfca95665d29558d1df7d08",
"shasum": ""
},
"require": {

View File

@@ -123,19 +123,7 @@ class Attribute extends BaseAction implements EventSubscriberInterface
*/
public function updatePosition(UpdatePositionEvent $event)
{
if (null !== $attribute = AttributeQuery::create()->findPk($event->getObjectId())) {
$attribute->setDispatcher($this->getDispatcher());
$mode = $event->getMode();
if ($mode == UpdatePositionEvent::POSITION_ABSOLUTE)
return $attribute->changeAbsolutePosition($event->getPosition());
else if ($mode == UpdatePositionEvent::POSITION_UP)
return $attribute->movePositionUp();
else if ($mode == UpdatePositionEvent::POSITION_DOWN)
return $attribute->movePositionDown();
}
return $this->genericUpdatePosition(AttributeQuery::create(), $event);
}
protected function doAddToAllTemplates(AttributeModel $attribute)

View File

@@ -112,19 +112,7 @@ class AttributeAv extends BaseAction implements EventSubscriberInterface
*/
public function updatePosition(UpdatePositionEvent $event)
{
if (null !== $attribute = AttributeAvQuery::create()->findPk($event->getObjectId())) {
$attribute->setDispatcher($this->getDispatcher());
$mode = $event->getMode();
if ($mode == UpdatePositionEvent::POSITION_ABSOLUTE)
return $attribute->changeAbsolutePosition($event->getPosition());
else if ($mode == UpdatePositionEvent::POSITION_UP)
return $attribute->movePositionUp();
else if ($mode == UpdatePositionEvent::POSITION_DOWN)
return $attribute->movePositionDown();
}
return $this->genericUpdatePosition(AttributeAvQuery::create(), $event);
}

View File

@@ -23,6 +23,10 @@
namespace Thelia\Action;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Thelia\Model\AdminLog;
use Propel\Runtime\ActiveQuery\PropelQuery;
use Propel\Runtime\ActiveQuery\ModelCriteria;
use Thelia\Core\Event\UpdatePositionEvent;
class BaseAction
{
@@ -45,4 +49,42 @@ class BaseAction
{
return $this->container->get('event_dispatcher');
}
/**
* Changes object position, selecting absolute ou relative change.
*
* @param $query the query to retrieve the object to move
* @param UpdatePositionEvent $event
*/
protected function genericUpdatePosition(ModelCriteria $query, UpdatePositionEvent $event)
{
if (null !== $object = $query->findPk($event->getObjectId())) {
$object->setDispatcher($this->getDispatcher());
$mode = $event->getMode();
if ($mode == UpdatePositionEvent::POSITION_ABSOLUTE)
return $object->changeAbsolutePosition($event->getPosition());
else if ($mode == UpdatePositionEvent::POSITION_UP)
return $object->movePositionUp();
else if ($mode == UpdatePositionEvent::POSITION_DOWN)
return $object->movePositionDown();
}
}
/**
* Helper to append a message to the admin log.
*
* @param string $message
*/
public function adminLogAppend($message)
{
AdminLog::append(
$message,
$this->container->get('request'),
$this->container->get('thelia.securityContext')->getAdminUser()
);
}
}

View File

@@ -136,19 +136,7 @@ class Category extends BaseAction implements EventSubscriberInterface
*/
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();
}
return $this->genericUpdatePosition(CategoryQuery::create(), $event);
}
public function addContent(CategoryAddContentEvent $event) {

View File

@@ -166,20 +166,7 @@ class Currency extends BaseAction implements EventSubscriberInterface
*/
public function updatePosition(UpdatePositionEvent $event)
{
if (null !== $currency = CurrencyQuery::create()->findPk($event->getObjectId())) {
$currency->setDispatcher($this->getDispatcher());
$mode = $event->getMode();
echo "loaded $mode !";
if ($mode == UpdatePositionEvent::POSITION_ABSOLUTE)
return $currency->changeAbsolutePosition($event->getPosition());
else if ($mode == UpdatePositionEvent::POSITION_UP)
return $currency->movePositionUp();
else if ($mode == UpdatePositionEvent::POSITION_DOWN)
return $currency->movePositionDown();
}
return $this->genericUpdatePosition(CurrencyQuery::create(), $event);
}
/**

View File

@@ -25,8 +25,12 @@ namespace Thelia\Action;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Thelia\Core\Event\DocumentCreateOrUpdateEvent;
use Thelia\Core\Event\DocumentDeleteEvent;
use Thelia\Core\Event\DocumentEvent;
use Thelia\Exception\ImageException;
use Thelia\Model\ConfigQuery;
use Thelia\Tools\FileManager;
use Thelia\Tools\URL;
use Imagine\Document\ImagineInterface;
@@ -88,45 +92,175 @@ class Document extends BaseCachedFile implements EventSubscriberInterface
*
* This method updates the cache_file_path and file_url attributes of the event
*
* @param DocumentEvent $event
* @throws \InvalidArgumentException, DocumentException
* @param DocumentEvent $event Event
*
* @throws \Thelia\Exception\DocumentException
* @throws \InvalidArgumentException , DocumentException
*/
public function processDocument(DocumentEvent $event)
{
$subdir = $event->getCacheSubdirectory();
$source_file = $event->getSourceFilepath();
$sourceFile = $event->getSourceFilepath();
if (null == $subdir || null == $source_file) {
if (null == $subdir || null == $sourceFile) {
throw new \InvalidArgumentException("Cache sub-directory and source file path cannot be null");
}
$originalDocumentPathInCache = $this->getCacheFilePath($subdir, $source_file, true);
$originalDocumentPathInCache = $this->getCacheFilePath($subdir, $sourceFile, true);
if (! file_exists($originalDocumentPathInCache)) {
if (! file_exists($source_file)) {
throw new DocumentException(sprintf("Source document file %s does not exists.", $source_file));
if (! file_exists($sourceFile)) {
throw new DocumentException(sprintf("Source document file %s does not exists.", $sourceFile));
}
$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));
if (false == symlink($sourceFile, $originalDocumentPathInCache)) {
throw new DocumentException(sprintf("Failed to create symbolic link for %s in %s document cache directory", basename($sourceFile), $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));
} else {
// mode = 'copy'
if (false == @copy($sourceFile, $originalDocumentPathInCache)) {
throw new DocumentException(sprintf("Failed to copy %s in %s document cache directory", basename($sourceFile), $subdir));
}
}
}
// Compute the document URL
$document_url = $this->getCacheFileURL($subdir, basename($originalDocumentPathInCache));
$documentUrl = $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));
$event->setDocumentPath($documentUrl);
$event->setDocumentUrl(URL::getInstance()->absoluteUrl($documentUrl, null, URL::PATH_TO_FILE));
}
/**
* Take care of saving document in the database and file storage
*
* @param DocumentCreateOrUpdateEvent $event Document event
*
* @throws \Thelia\Exception\ImageException
* @todo refactor make all documents using propel inheritance and factorise image behaviour into one single clean action
*/
public function saveDocument(DocumentCreateOrUpdateEvent $event)
{
$this->adminLogAppend(
$this->container->get('thelia.translator')->trans(
'Saving documents for %parentName% parent id %parentId% (%parentType%)',
array(
'%parentName%' => $event->getParentName(),
'%parentId%' => $event->getParentId(),
'%parentType%' => $event->getDocumentType()
),
'document'
)
);
$fileManager = new FileManager($this->container);
$model = $event->getModelDocument();
$nbModifiedLines = $model->save();
$event->setModelDocument($model);
if (!$nbModifiedLines) {
throw new ImageException(
sprintf(
'Document "%s" with parent id %s (%s) failed to be saved',
$event->getParentName(),
$event->getParentId(),
$event->getDocumentType()
)
);
}
$newUploadedFile = $fileManager->copyUploadedFile($event->getParentId(), $event->getDocumentType(), $event->getModelDocument(), $event->getUploadedFile(), FileManager::FILE_TYPE_DOCUMENTS);
$event->setUploadedFile($newUploadedFile);
}
/**
* Take care of updating document in the database and file storage
*
* @param DocumentCreateOrUpdateEvent $event Document event
*
* @throws \Thelia\Exception\ImageException
* @todo refactor make all documents using propel inheritance and factorise image behaviour into one single clean action
*/
public function updateDocument(DocumentCreateOrUpdateEvent $event)
{
$this->adminLogAppend(
$this->container->get('thelia.translator')->trans(
'Updating documents for %parentName% parent id %parentId% (%parentType%)',
array(
'%parentName%' => $event->getParentName(),
'%parentId%' => $event->getParentId(),
'%parentType%' => $event->getDocumentType()
),
'image'
)
);
if (null !== $event->getUploadedFile()) {
$event->getModelDocument()->setTitle($event->getUploadedFile()->getClientOriginalName());
}
$fileManager = new FileManager($this->container);
// Copy and save file
if ($event->getUploadedFile()) {
// Remove old picture file from file storage
$url = $fileManager->getUploadDir($event->getDocumentType(), FileManager::FILE_TYPE_DOCUMENTS) . '/' . $event->getOldModelDocument()->getFile();
unlink(str_replace('..', '', $url));
$newUploadedFile = $fileManager->copyUploadedFile($event->getParentId(), $event->getDocumentType(), $event->getModelDocument(), $event->getUploadedFile(), FileManager::FILE_TYPE_DOCUMENTS);
$event->setUploadedFile($newUploadedFile);
}
// Update document modifications
$event->getModelDocument()->save();
$event->setModelDocument($event->getModelDocument());
}
/**
* Take care of deleting document in the database and file storage
*
* @param DocumentDeleteEvent $event Image event
*
* @throws \Exception
* @todo refactor make all documents using propel inheritance and factorise image behaviour into one single clean action
*/
public function deleteDocument(DocumentDeleteEvent $event)
{
$fileManager = new FileManager($this->container);
try {
$fileManager->deleteFile($event->getDocumentToDelete(), $event->getDocumentType(), FileManager::FILE_TYPE_DOCUMENTS);
$this->adminLogAppend(
$this->container->get('thelia.translator')->trans(
'Deleting document for %id% with parent id %parentId%',
array(
'%id%' => $event->getDocumentToDelete()->getId(),
'%parentId%' => $event->getDocumentToDelete()->getParentId(),
),
'document'
)
);
} catch(\Exception $e) {
$this->adminLogAppend(
$this->container->get('thelia.translator')->trans(
'Fail to delete document for %id% with parent id %parentId% (Exception : %e%)',
array(
'%id%' => $event->getDocumentToDelete()->getId(),
'%parentId%' => $event->getDocumentToDelete()->getParentId(),
'%e%' => $e->getMessage()
),
'document'
)
);
throw $e;
}
}
public static function getSubscribedEvents()
@@ -134,6 +268,9 @@ class Document extends BaseCachedFile implements EventSubscriberInterface
return array(
TheliaEvents::DOCUMENT_PROCESS => array("processDocument", 128),
TheliaEvents::DOCUMENT_CLEAR_CACHE => array("clearCache", 128),
TheliaEvents::DOCUMENT_DELETE => array("deleteDocument", 128),
TheliaEvents::DOCUMENT_SAVE => array("saveDocument", 128),
TheliaEvents::DOCUMENT_UPDATE => array("updateDocument", 128),
);
}
}

View File

@@ -123,19 +123,7 @@ class Feature extends BaseAction implements EventSubscriberInterface
*/
public function updatePosition(UpdatePositionEvent $event)
{
if (null !== $feature = FeatureQuery::create()->findPk($event->getObjectId())) {
$feature->setDispatcher($this->getDispatcher());
$mode = $event->getMode();
if ($mode == UpdatePositionEvent::POSITION_ABSOLUTE)
return $feature->changeAbsolutePosition($event->getPosition());
else if ($mode == UpdatePositionEvent::POSITION_UP)
return $feature->movePositionUp();
else if ($mode == UpdatePositionEvent::POSITION_DOWN)
return $feature->movePositionDown();
}
return $this->genericUpdatePosition(FeatureQuery::create(), $event);
}
protected function doAddToAllTemplates(FeatureModel $feature)

View File

@@ -112,19 +112,7 @@ class FeatureAv extends BaseAction implements EventSubscriberInterface
*/
public function updatePosition(UpdatePositionEvent $event)
{
if (null !== $feature = FeatureAvQuery::create()->findPk($event->getObjectId())) {
$feature->setDispatcher($this->getDispatcher());
$mode = $event->getMode();
if ($mode == UpdatePositionEvent::POSITION_ABSOLUTE)
return $feature->changeAbsolutePosition($event->getPosition());
else if ($mode == UpdatePositionEvent::POSITION_UP)
return $feature->movePositionUp();
else if ($mode == UpdatePositionEvent::POSITION_DOWN)
return $feature->movePositionDown();
}
return $this->genericUpdatePosition(FeatureAvQuery::create(), $event);
}

View File

@@ -23,10 +23,20 @@
namespace Thelia\Action;
use Propel\Runtime\ActiveRecord\ActiveRecordInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Thelia\Core\Event\ImageCreateOrUpdateEvent;
use Thelia\Core\Event\ImagesCreateOrUpdateEvent;
use Thelia\Core\Event\ImageDeleteEvent;
use Thelia\Core\Event\ImageEvent;
use Thelia\Model\CategoryImage;
use Thelia\Model\ConfigQuery;
use Thelia\Model\ContentImage;
use Thelia\Model\FolderImage;
use Thelia\Model\ProductImage;
use Thelia\Tools\FileManager;
use Thelia\Tools\URL;
use Imagine\Image\ImagineInterface;
@@ -39,10 +49,10 @@ use Thelia\Core\Event\TheliaEvents;
/**
*
* Image management actions. This class handles image processing an caching.
* Image management actions. This class handles image processing and caching.
*
* Basically, images are stored outside the web space (by default in local/media/images),
* and cached in the web space (by default in web/local/images).
* Basically, images are stored outside of the web space (by default in local/media/images),
* and cached inside the web space (by default in web/local/images).
*
* In the images caches directory, a subdirectory for images categories (eg. product, category, folder, etc.) is
* automatically created, and the cached image is created here. Plugin may use their own subdirectory as required.
@@ -78,6 +88,8 @@ class Image extends BaseCachedFile implements EventSubscriberInterface
const EXACT_RATIO_WITH_CROP = 2;
const KEEP_IMAGE_RATIO = 3;
/**
* @return string root of the image cache directory in web space
*/
@@ -240,6 +252,128 @@ class Image extends BaseCachedFile implements EventSubscriberInterface
$event->setOriginalFileUrl(URL::getInstance()->absoluteUrl($original_image_url, null, URL::PATH_TO_FILE));
}
/**
* Take care of saving image in the database and file storage
*
* @param ImageCreateOrUpdateEvent $event Image event
*
* @throws \Thelia\Exception\ImageException
* @todo refactor make all pictures using propel inheritance and factorise image behaviour into one single clean action
*/
public function saveImage(ImageCreateOrUpdateEvent $event)
{
$this->adminLogAppend(
$this->container->get('thelia.translator')->trans(
'Saving images for %parentName% parent id %parentId% (%parentType%)',
array(
'%parentName%' => $event->getParentName(),
'%parentId%' => $event->getParentId(),
'%parentType%' => $event->getImageType()
),
'image'
)
);
$fileManager = new FileManager($this->container);
$model = $event->getModelImage();
$nbModifiedLines = $model->save();
$event->setModelImage($model);
if (!$nbModifiedLines) {
throw new ImageException(
sprintf(
'Image "%s" with parent id %s (%s) failed to be saved',
$event->getParentName(),
$event->getParentId(),
$event->getImageType()
)
);
}
$newUploadedFile = $fileManager->copyUploadedFile($event->getParentId(), $event->getImageType(), $event->getModelImage(), $event->getUploadedFile(), FileManager::FILE_TYPE_IMAGES);
$event->setUploadedFile($newUploadedFile);
}
/**
* Take care of updating image in the database and file storage
*
* @param ImageCreateOrUpdateEvent $event Image event
*
* @throws \Thelia\Exception\ImageException
* @todo refactor make all pictures using propel inheritance and factorise image behaviour into one single clean action
*/
public function updateImage(ImageCreateOrUpdateEvent $event)
{
$this->adminLogAppend(
$this->container->get('thelia.translator')->trans(
'Updating images for %parentName% parent id %parentId% (%parentType%)',
array(
'%parentName%' => $event->getParentName(),
'%parentId%' => $event->getParentId(),
'%parentType%' => $event->getImageType()
),
'image'
)
);
$fileManager = new FileManager($this->container);
// Copy and save file
if ($event->getUploadedFile()) {
// Remove old picture file from file storage
$url = $fileManager->getUploadDir($event->getImageType(), FileManager::FILE_TYPE_IMAGES) . '/' . $event->getOldModelImage()->getFile();
unlink(str_replace('..', '', $url));
$newUploadedFile = $fileManager->copyUploadedFile($event->getParentId(), $event->getImageType(), $event->getModelImage(), $event->getUploadedFile(), FileManager::FILE_TYPE_IMAGES);
$event->setUploadedFile($newUploadedFile);
}
// Update image modifications
$event->getModelImage()->save();
$event->setModelImage($event->getModelImage());
}
/**
* Take care of deleting image in the database and file storage
*
* @param ImageDeleteEvent $event Image event
*
* @throws \Exception
* @todo refactor make all pictures using propel inheritance and factorise image behaviour into one single clean action
*/
public function deleteImage(ImageDeleteEvent $event)
{
$fileManager = new FileManager($this->container);
try {
$fileManager->deleteFile($event->getImageToDelete(), $event->getImageType(), FileManager::FILE_TYPE_IMAGES);
$this->adminLogAppend(
$this->container->get('thelia.translator')->trans(
'Deleting image for %id% with parent id %parentId%',
array(
'%id%' => $event->getImageToDelete()->getId(),
'%parentId%' => $event->getImageToDelete()->getParentId(),
),
'image'
)
);
} catch(\Exception $e){
$this->adminLogAppend(
$this->container->get('thelia.translator')->trans(
'Fail to delete image for %id% with parent id %parentId% (Exception : %e%)',
array(
'%id%' => $event->getImageToDelete()->getId(),
'%parentId%' => $event->getImageToDelete()->getParentId(),
'%e%' => $e->getMessage()
),
'image'
)
);
throw $e;
}
}
/**
* Process image resizing, with borders or cropping. If $dest_width and $dest_height
* are both null, no resize is performed.
@@ -362,6 +496,9 @@ class Image extends BaseCachedFile implements EventSubscriberInterface
return array(
TheliaEvents::IMAGE_PROCESS => array("processImage", 128),
TheliaEvents::IMAGE_CLEAR_CACHE => array("clearCache", 128),
TheliaEvents::IMAGE_DELETE => array("deleteImage", 128),
TheliaEvents::IMAGE_SAVE => array("saveImage", 128),
TheliaEvents::IMAGE_UPDATE => array("updateImage", 128),
);
}
}

View File

@@ -48,6 +48,26 @@ use Thelia\Model\AccessoryQuery;
use Thelia\Model\Accessory;
use Thelia\Core\Event\ProductAddAccessoryEvent;
use Thelia\Core\Event\ProductDeleteAccessoryEvent;
use Thelia\Core\Event\FeatureProductUpdateEvent;
use Thelia\Model\FeatureProduct;
use Thelia\Model\FeatureQuery;
use Thelia\Core\Event\FeatureProductDeleteEvent;
use Thelia\Model\FeatureProductQuery;
use Thelia\Model\ProductCategoryQuery;
use Thelia\Core\Event\ProductSetTemplateEvent;
use Thelia\Model\AttributeCombinationQuery;
use Thelia\Model\ProductSaleElementsQuery;
use Propel\Runtime\ActiveQuery\PropelQuery;
use Thelia\Core\Event\ProductDeleteCategoryEvent;
use Thelia\Core\Event\ProductAddCategoryEvent;
use Thelia\Model\AttributeAvQuery;
use Thelia\Model\AttributeCombination;
use Thelia\Core\Event\ProductCreateCombinationEvent;
use Propel\Runtime\Propel;
use Thelia\Model\Map\ProductTableMap;
use Thelia\Core\Event\ProductDeleteCombinationEvent;
use Thelia\Model\ProductPrice;
use Thelia\Model\ProductSaleElements;
class Product extends BaseAction implements EventSubscriberInterface
{
@@ -71,7 +91,15 @@ class Product extends BaseAction implements EventSubscriberInterface
// Set the default tax rule to this product
->setTaxRule(TaxRuleQuery::create()->findOneByIsDefault(true))
->create($event->getDefaultCategory())
//public function create($defaultCategoryId, $basePrice, $priceCurrencyId, $taxRuleId, $baseWeight) {
->create(
$event->getDefaultCategory(),
$event->getBasePrice(),
$event->getCurrencyId(),
$event->getTaxRuleId(),
$event->getBaseWeight()
);
;
$event->setProduct($product);
@@ -84,8 +112,6 @@ class Product extends BaseAction implements EventSubscriberInterface
*/
public function update(ProductUpdateEvent $event)
{
$search = ProductQuery::create();
if (null !== $product = ProductQuery::create()->findPk($event->getProductId())) {
$product
@@ -96,11 +122,16 @@ class Product extends BaseAction implements EventSubscriberInterface
->setDescription($event->getDescription())
->setChapo($event->getChapo())
->setPostscriptum($event->getPostscriptum())
->setParent($event->getParent())
->setVisible($event->getVisible())
->save();
->save()
;
// Update the rewriten URL, if required
$product->setRewrittenUrl($event->getLocale(), $event->getUrl());
// Update default category (ifd required)
$product->updateDefaultCategory($event->getDefaultCategory());
$event->setProduct($product);
}
@@ -147,19 +178,7 @@ class Product extends BaseAction implements EventSubscriberInterface
*/
public function updatePosition(UpdatePositionEvent $event)
{
if (null !== $product = ProductQuery::create()->findPk($event->getObjectId())) {
$product->setDispatcher($this->getDispatcher());
$mode = $event->getMode();
if ($mode == UpdatePositionEvent::POSITION_ABSOLUTE)
return $product->changeAbsolutePosition($event->getPosition());
else if ($mode == UpdatePositionEvent::POSITION_UP)
return $product->movePositionUp();
else if ($mode == UpdatePositionEvent::POSITION_DOWN)
return $product->movePositionDown();
}
return $this->genericUpdatePosition(ProductQuery::create(), $event);
}
public function addContent(ProductAddContentEvent $event) {
@@ -193,6 +212,34 @@ class Product extends BaseAction implements EventSubscriberInterface
;
}
public function addCategory(ProductAddCategoryEvent $event) {
if (ProductCategoryQuery::create()
->filterByProduct($event->getProduct())
->filterByCategoryId($event->getCategoryId())
->count() <= 0) {
$productCategory = new ProductCategory();
$productCategory
->setProduct($event->getProduct())
->setCategoryId($event->getCategoryId())
->setDefaultCategory(false)
->save()
;
}
}
public function removeCategory(ProductDeleteCategoryEvent $event) {
$productCategory = ProductCategoryQuery::create()
->filterByProduct($event->getProduct())
->filterByCategoryId($event->getCategoryId())
->findOne();
if ($productCategory != null) $productCategory->delete();
}
public function addAccessory(ProductAddAccessoryEvent $event) {
if (AccessoryQuery::create()
@@ -224,26 +271,165 @@ class Product extends BaseAction implements EventSubscriberInterface
;
}
public function setProductTemplate(ProductSetTemplateEvent $event) {
$product = $event->getProduct();
// Delete all product feature relations
FeatureProductQuery::create()->filterByProduct($product)->delete();
// Delete all product attributes sale elements
ProductSaleElementsQuery::create()->filterByProduct($product)->delete();
// Update the product template
$template_id = $event->getTemplateId();
// Set it to null if it's zero.
if ($template_id <= 0) $template_id = NULL;
$product->setTemplateId($template_id)->save();
}
/**
* Changes accessry position, selecting absolute ou relative change.
*
* @param ProductChangePositionEvent $event
*/
public function updateAccessoryPosition(UpdatePositionEvent $event)
{
return $this->genericUpdatePosition(AccessoryQuery::create(), $event);
}
/**
* Changes position, selecting absolute ou relative change.
*
* @param ProductChangePositionEvent $event
*/
public function updateAccessoryPosition(UpdatePositionEvent $event)
public function updateContentPosition(UpdatePositionEvent $event)
{
if (null !== $accessory = AccessoryQuery::create()->findPk($event->getObjectId())) {
return $this->genericUpdatePosition(ProductAssociatedContentQuery::create(), $event);
}
$accessory->setDispatcher($this->getDispatcher());
public function updateFeatureProductValue(FeatureProductUpdateEvent $event) {
$mode = $event->getMode();
// If the feature is not free text, it may have one ore more values.
// If the value exists, we do not change it
// If the value does not exists, we create it.
//
// If the feature is free text, it has only a single value.
// Etiher create or update it.
if ($mode == UpdatePositionEvent::POSITION_ABSOLUTE)
return $accessory->changeAbsolutePosition($event->getPosition());
else if ($mode == UpdatePositionEvent::POSITION_UP)
return $accessory->movePositionUp();
else if ($mode == UpdatePositionEvent::POSITION_DOWN)
return $accessory->movePositionDown();
$featureProductQuery = FeatureProductQuery::create()
->filterByFeatureId($event->getFeatureId())
->filterByProductId($event->getProductId())
;
if ($event->getIsTextValue() !== true) {
$featureProductQuery->filterByFeatureAvId($event->getFeatureValue());
}
$featureProduct = $featureProductQuery->findOne();
if ($featureProduct == null) {
$featureProduct = new FeatureProduct();
$featureProduct
->setDispatcher($this->getDispatcher())
->setProductId($event->getProductId())
->setFeatureId($event->getFeatureId())
;
}
if ($event->getIsTextValue() == true) {
$featureProduct->setFreeTextValue($event->getFeatureValue());
}
else {
$featureProduct->setFeatureAvId($event->getFeatureValue());
}
$featureProduct->save();
$event->setFeatureProduct($featureProduct);
}
public function deleteFeatureProductValue(FeatureProductDeleteEvent $event) {
$featureProduct = FeatureProductQuery::create()
->filterByProductId($event->getProductId())
->filterByFeatureId($event->getFeatureId())
->delete()
;
}
public function createProductCombination(ProductCreateCombinationEvent $event) {
$con = Propel::getWriteConnection(ProductTableMap::DATABASE_NAME);
$con->beginTransaction();
try {
$product = $event->getProduct();
// Create an empty product sale element
$salesElement = new ProductSaleElements();
$salesElement
->setProduct($product)
->setRef($product->getRef())
->setPromo(0)
->setNewness(0)
->setWeight(0)
->setIsDefault(false)
->save($con)
;
// Create an empty product price in the default currency
$product_price = new ProductPrice();
$product_price
->setProductSaleElements($salesElement)
->setPromoPrice(0)
->setPrice(0)
->setCurrencyId($event->getCurrencyId())
->save($con)
;
$combinationAttributes = $event->getAttributeAvList();
if (count($combinationAttributes) > 0) {
foreach($combinationAttributes as $attributeAvId) {
$attributeAv = AttributeAvQuery::create()->findPk($attributeAvId);
if ($attributeAv !== null) {
$attributeCombination = new AttributeCombination();
$attributeCombination
->setAttributeAvId($attributeAvId)
->setAttribute($attributeAv->getAttribute())
->setProductSaleElements($salesElement)
->save();
}
}
}
// Store all the stuff !
$con->commit();
}
catch(\Exception $ex) {
$con->rollback();
throw $ex;
}
}
public function deleteProductCombination(ProductDeleteCombinationEvent $event) {
if (null !== $pse = ProductSaleElementsQuery::create()->findPk($event->getProductSaleElementId())) {
$pse->delete();
}
}
@@ -263,9 +449,22 @@ class Product extends BaseAction implements EventSubscriberInterface
TheliaEvents::PRODUCT_ADD_CONTENT => array("addContent", 128),
TheliaEvents::PRODUCT_REMOVE_CONTENT => array("removeContent", 128),
TheliaEvents::PRODUCT_UPDATE_ACCESSORY_POSITION => array("updateAccessoryPosition", 128),
TheliaEvents::PRODUCT_UPDATE_CONTENT_POSITION => array("updateContentPosition", 128),
TheliaEvents::PRODUCT_ADD_COMBINATION => array("createProductCombination", 128),
TheliaEvents::PRODUCT_DELETE_COMBINATION => array("deleteProductCombination", 128),
TheliaEvents::PRODUCT_ADD_ACCESSORY => array("addAccessory", 128),
TheliaEvents::PRODUCT_REMOVE_ACCESSORY => array("removeAccessory", 128),
TheliaEvents::PRODUCT_ADD_CATEGORY => array("addCategory", 128),
TheliaEvents::PRODUCT_REMOVE_CATEGORY => array("removeCategory", 128),
TheliaEvents::PRODUCT_SET_TEMPLATE => array("setProductTemplate", 128),
TheliaEvents::PRODUCT_FEATURE_UPDATE_VALUE => array("updateFeatureProductValue", 128),
TheliaEvents::PRODUCT_FEATURE_DELETE_VALUE => array("deleteFeatureProductValue", 128),
);
}
}

View File

@@ -135,6 +135,26 @@ class Template extends BaseAction implements EventSubscriberInterface
}
}
/**
* Changes position, selecting absolute ou relative change.
*
* @param CategoryChangePositionEvent $event
*/
public function updateAttributePosition(UpdatePositionEvent $event)
{
return $this->genericUpdatePosition(AttributeTemplateQuery::create(), $event);
}
/**
* Changes position, selecting absolute ou relative change.
*
* @param CategoryChangePositionEvent $event
*/
public function updateFeaturePosition(UpdatePositionEvent $event)
{
return $this->genericUpdatePosition(FeatureTemplateQuery::create(), $event);
}
public function deleteAttribute(TemplateDeleteAttributeEvent $event) {
$attribute_template = AttributeTemplateQuery::create()
@@ -185,6 +205,9 @@ class Template extends BaseAction implements EventSubscriberInterface
TheliaEvents::TEMPLATE_ADD_FEATURE => array("addFeature", 128),
TheliaEvents::TEMPLATE_DELETE_FEATURE => array("deleteFeature", 128),
TheliaEvents::TEMPLATE_CHANGE_ATTRIBUTE_POSITION => array('updateAttributePosition', 128),
TheliaEvents::TEMPLATE_CHANGE_FEATURE_POSITION => array('updateFeaturePosition', 128),
);
}
}

View File

@@ -36,6 +36,10 @@
<argument type="service" id="service_container"/>
<tag name="kernel.event_subscriber"/>
</service>
<service id="thelia.action.document" class="Thelia\Action\Document">
<argument type="service" id="service_container"/>
<tag name="kernel.event_subscriber"/>
</service>
<service id="thelia.action.category" class="Thelia\Action\Category">
<argument type="service" id="service_container"/>

View File

@@ -35,6 +35,7 @@
<loop class="Thelia\Core\Template\Loop\FolderTree" name="folder-tree"/>
<loop class="Thelia\Core\Template\Loop\Cart" name="cart"/>
<loop class="Thelia\Core\Template\Loop\Image" name="image"/>
<loop class="Thelia\Core\Template\Loop\Document" name="document"/>
<loop class="Thelia\Core\Template\Loop\Config" name="config"/>
<loop class="Thelia\Core\Template\Loop\Coupon" name="coupon"/>
<loop class="Thelia\Core\Template\Loop\Message" name="message"/>
@@ -58,18 +59,26 @@
<form name="thelia.admin.category.creation" class="Thelia\Form\CategoryCreationForm"/>
<form name="thelia.admin.category.modification" class="Thelia\Form\CategoryModificationForm"/>
<form name="thelia.admin.category.image.modification" class="Thelia\Form\CategoryImageModification"/>
<form name="thelia.admin.category.document.modification" class="Thelia\Form\CategoryDocumentModification"/>
<form name="thelia.admin.product.creation" class="Thelia\Form\ProductCreationForm"/>
<form name="thelia.admin.product.modification" class="Thelia\Form\ProductModificationForm"/>
<form name="thelia.admin.product.details.modification" class="Thelia\Form\ProductDetailsModificationForm"/>
<form name="thelia.admin.product.image.modification" class="Thelia\Form\ProductImageModification"/>
<form name="thelia.admin.product.document.modification" class="Thelia\Form\ProductDocumentModification"/>
<form name="thelia.admin.product.creation" class="Thelia\Form\ProductCreationForm"/>
<form name="thelia.admin.product.deletion" class="Thelia\Form\ProductModificationForm"/>
<form name="thelia.admin.folder.creation" class="Thelia\Form\FolderCreationForm"/>
<form name="thelia.admin.folder.modification" class="Thelia\Form\FolderModificationForm"/>
<form name="thelia.admin.folder.image.modification" class="Thelia\Form\FolderImageModification"/>
<form name="thelia.admin.folder.document.modification" class="Thelia\Form\FolderDocumentModification"/>
<form name="thelia.admin.content.creation" class="Thelia\Form\ContentCreationForm"/>
<form name="thelia.admin.content.modification" class="Thelia\Form\ContentModificationForm"/>
<form name="thelia.admin.content.image.modification" class="Thelia\Form\ContentImageModification"/>
<form name="thelia.admin.content.document.modification" class="Thelia\Form\ContentDocumentModification"/>
<form name="thelia.cart.add" class="Thelia\Form\CartAdd"/>
@@ -239,6 +248,11 @@
<argument type="service" id="thelia.securityContext" />
</service>
<service id="smarty.plugin.flashMessage" class="Thelia\Core\Template\Smarty\Plugins\FlashMessage" scope="request">
<tag name="thelia.parser.register_plugin"/>
<argument type="service" id="request" />
</service>
<service id="http_kernel" class="Thelia\Core\TheliaHttpKernel">
<argument type="service" id="event_dispatcher" />

View File

@@ -37,6 +37,70 @@
<default key="_controller">Thelia\Controller\Admin\CategoryController::defaultAction</default>
</route>
<!-- Route to the file controller -->
<route id="admin.image.save-ajax" path="/admin/image/type/{parentType}/{parentId}/save-ajax">
<default key="_controller">Thelia\Controller\Admin\FileController::saveImageAjaxAction</default>
<requirement key="parentType">.*</requirement>
<requirement key="parentId">\d+</requirement>
</route>
<route id="admin.image.form-ajax" path="/admin/image/type/{parentType}/{parentId}/form-ajax">
<default key="_controller">Thelia\Controller\Admin\FileController::getImageFormAjaxAction</default>
<requirement key="parentType">.*</requirement>
<requirement key="parentId">\d+</requirement>
</route>
<route id="admin.image.list-ajax" path="/admin/image/type/{parentType}/{parentId}/list-ajax">
<default key="_controller">Thelia\Controller\Admin\FileController::getImageListAjaxAction</default>
<requirement key="parentType">.*</requirement>
<requirement key="parentId">\d+</requirement>
</route>
<route id="admin.image.update.view" path="/admin/image/type/{parentType}/{imageId}/update" methods="get">
<default key="_controller">Thelia\Controller\Admin\FileController::viewImageAction</default>
<requirement key="parentType">.*</requirement>
<requirement key="imageId">\d+</requirement>
</route>
<route id="admin.image.update.process" path="/admin/image/type/{parentType}/{imageId}/update" methods="post">
<default key="_controller">Thelia\Controller\Admin\FileController::updateImageAction</default>
<requirement key="parentType">.*</requirement>
<requirement key="imageId">\d+</requirement>
</route>
<route id="admin.image.delete" path="/admin/image/type/{parentType}/delete/{imageId}">
<default key="_controller">Thelia\Controller\Admin\FileController::deleteImageAction</default>
<requirement key="parentType">.*</requirement>
<requirement key="imageId">\d+</requirement>
</route>
<route id="admin.document.save-ajax" path="/admin/document/type/{parentType}/{parentId}/save-ajax">
<default key="_controller">Thelia\Controller\Admin\FileController::saveDocumentAjaxAction</default>
<requirement key="parentType">.*</requirement>
<requirement key="parentId">\d+</requirement>
</route>
<route id="admin.document.form-ajax" path="/admin/document/type/{parentType}/{parentId}/form-ajax">
<default key="_controller">Thelia\Controller\Admin\FileController::getDocumentFormAjaxAction</default>
<requirement key="parentType">.*</requirement>
<requirement key="parentId">\d+</requirement>
</route>
<route id="admin.document.list-ajax" path="/admin/document/type/{parentType}/{parentId}/list-ajax">
<default key="_controller">Thelia\Controller\Admin\FileController::getDocumentListAjaxAction</default>
<requirement key="parentType">.*</requirement>
<requirement key="parentId">\d+</requirement>
</route>
<route id="admin.document.update.view" path="/admin/document/type/{parentType}/{documentId}/update" methods="get">
<default key="_controller">Thelia\Controller\Admin\FileController::viewDocumentAction</default>
<requirement key="parentType">.*</requirement>
<requirement key="documentId">\d+</requirement>
</route>
<route id="admin.document.update.process" path="/admin/document/type/{parentType}/{documentId}/update" methods="post">
<default key="_controller">Thelia\Controller\Admin\FileController::updateDocumentAction</default>
<requirement key="parentType">.*</requirement>
<requirement key="documentId">\d+</requirement>
</route>
<route id="admin.document.delete" path="/admin/document/type/{parentType}/delete/{documentId}">
<default key="_controller">Thelia\Controller\Admin\FileController::deleteDocumentAction</default>
<requirement key="parentType">.*</requirement>
<requirement key="documentId">\d+</requirement>
</route>
<!-- Customer rule management -->
<route id="admin.customers" path="/admin/customers">
@@ -106,6 +170,10 @@
<default key="_controller">Thelia\Controller\Admin\CategoryController::addRelatedContentAction</default>
</route>
<route id="admin.categories.related-content.add" path="/admin/categories/related-picture/add">
<default key="_controller">Thelia\Controller\Admin\CategoryController::addRelatedPictureAction</default>
</route>
<route id="admin.categories.related-content.delete" path="/admin/categories/related-content/delete">
<default key="_controller">Thelia\Controller\Admin\CategoryController::deleteRelatedContentAction</default>
</route>
@@ -150,22 +218,47 @@
<default key="_controller">Thelia\Controller\Admin\ProductController::updatePositionAction</default>
</route>
<!-- Related content -->
<route id="admin.products.related-content.add" path="/admin/products/related-content/add">
<route id="admin.products.general.tab" path="/admin/products/general/tab">
<default key="_controller">Thelia\Controller\Admin\ProductController::loadGeneralAjaxTabAction</default>
</route>
<!-- Product categories, content and accessories -->
<route id="admin.products.related.tab" path="/admin/products/related/tab">
<default key="_controller">Thelia\Controller\Admin\ProductController::loadRelatedAjaxTabAction</default>
</route>
<!-- categories -->
<route id="admin.products.additional-category.add" path="/admin/products/category/add">
<default key="_controller">Thelia\Controller\Admin\ProductController::addAdditionalCategoryAction</default>
</route>
<route id="admin.products.additional-category.delete" path="/admin/products/category/delete">
<default key="_controller">Thelia\Controller\Admin\ProductController::deleteAdditionalCategoryAction</default>
</route>
<!-- content -->
<route id="admin.products.related-content.add" path="/admin/products/content/add">
<default key="_controller">Thelia\Controller\Admin\ProductController::addRelatedContentAction</default>
</route>
<route id="admin.products.related-content.delete" path="/admin/products/related-content/delete">
<route id="admin.products.related-content.delete" path="/admin/products/content/delete">
<default key="_controller">Thelia\Controller\Admin\ProductController::deleteRelatedContentAction</default>
</route>
<route id="admin.product.available-related-content" path="/admin/product/{productId}/available-related-content/{folderId}.{_format}" methods="GET">
<route id="admin.product.available-related-content" path="/admin/product/{productId}/available-content/{folderId}.{_format}" methods="GET">
<default key="_controller">Thelia\Controller\Admin\ProductController::getAvailableRelatedContentAction</default>
<requirement key="_format">xml|json</requirement>
</route>
<!-- Product accessories -->
<route id="admin.product.update-content-position" path="/admin/product/update-content-position">
<default key="_controller">Thelia\Controller\Admin\ProductController::updateContentPositionAction</default>
</route>
<!-- accessories -->
<route id="admin.products.accessories.add" path="/admin/products/accessory/add">
<default key="_controller">Thelia\Controller\Admin\ProductController::addAccessoryAction</default>
@@ -180,18 +273,57 @@
<requirement key="_format">xml|json</requirement>
</route>
<route id="admin.products.update-accessory-position" path="/admin/products/update-accessory-position">
<route id="admin.product.update-accessory-position" path="/admin/product/update-accessory-position">
<default key="_controller">Thelia\Controller\Admin\ProductController::updateAccessoryPositionAction</default>
</route>
<!--Features and attributes -->
<!--Product Features and attributes -->
<route id="admin.products.attributes.tab" path="/admin/products/attributes/tab">
<default key="_controller">Thelia\Controller\Admin\ProductController::loadAttributesAjaxTabAction</default>
</route>
<route id="admin.products.set-product-template" path="/admin/product/{productId}/set-product-template">
<default key="_controller">Thelia\Controller\Admin\ProductController::setProductTemplateAction</default>
</route>
<route id="admin.products.update-attributes-and-features" path="/admin/product/{productId}/update-attributes-and-features">
<default key="_controller">Thelia\Controller\Admin\ProductController::updateAttributesAndFeaturesAction</default>
</route>
<!-- Combinations -->
<route id="admin.product.attribute-values" path="/admin/product/{productId}/attribute-values/{attributeId}.{_format}" methods="GET">
<default key="_controller">Thelia\Controller\Admin\ProductController::getAttributeValuesAction</default>
<requirement key="_format">xml|json</requirement>
</route>
<route id="admin.product.add-attribute-value-to-combination" path="/admin/product/{productId}/add-attribute-value-to-combination/{attributeAvId}/{combination}.{_format}" methods="GET">
<default key="_controller">Thelia\Controller\Admin\ProductController::addAttributeValueToCombinationAction</default>
<requirement key="_format">xml|json</requirement>
</route>
<route id="admin.product.combination.add" path="/admin/product/combination/add">
<default key="_controller">Thelia\Controller\Admin\ProductController::addCombinationAction</default>
</route>
<route id="admin.product.combination.delete" path="/admin/product/combination/delete">
<default key="_controller">Thelia\Controller\Admin\ProductController::deleteCombinationAction</default>
</route>
<route id="admin.product.combination.update" path="/admin/product/combination/update">
<default key="_controller">Thelia\Controller\Admin\ProductController::updateCombinationAction</default>
</route>
<route id="admin.product.combination.defaut-price.update" path="/admin/product/default-price/update">
<default key="_controller">Thelia\Controller\Admin\ProductController::updateDefaultPriceAction</default>
</route>
<!-- Folder routes management -->
<route id="admin.folders.default" path="/admin/folders">
<default key="_controller">Thelia\Controller\Admin\FolderController::defaultAction</default>
</route>
@@ -398,6 +530,10 @@
<default key="_controller">Thelia\Controller\Admin\TemplateController::deleteFeatureAction</default>
</route>
<route id="admin.configuration.templates.attributes.update-feature-position" path="/admin/template/update-feature-position">
<default key="_controller">Thelia\Controller\Admin\TemplateController::updateFeaturePositionAction</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>
@@ -410,6 +546,10 @@
<default key="_controller">Thelia\Controller\Admin\TemplateController::deleteAttributeAction</default>
</route>
<route id="admin.configuration.templates.attributes.update-attribute-position" path="/admin/template/update-attribute-position">
<default key="_controller">Thelia\Controller\Admin\TemplateController::updateAttributePositionAction</default>
</route>
<!-- attribute and attributes value management -->

View File

@@ -58,6 +58,7 @@ abstract class AbstractCrudController extends BaseAdminController
* @param string $objectName the lower case object name. Example. "message"
*
* @param string $defaultListOrder the default object list order, or null if list is not sortable. Example: manual
* @param string $orderRequestParameterName Name of the request parameter that set the list order (null if list is not sortable)
*
* @param string $viewPermissionIdentifier the 'view' permission identifier. Example: "admin.configuration.message.view"
* @param string $createPermissionIdentifier the 'create' permission identifier. Example: "admin.configuration.message.create"
@@ -445,6 +446,8 @@ abstract class AbstractCrudController extends BaseAdminController
/**
* Update object position (only for objects whichsupport that)
*
* FIXME: integrate with genericUpdatePositionAction
*/
public function updatePositionAction()
{
@@ -482,6 +485,38 @@ abstract class AbstractCrudController extends BaseAdminController
}
}
protected function genericUpdatePositionAction($object, $eventName, $doFinalRedirect = true) {
// Check current user authorization
if (null !== $response = $this->checkAuth($this->updatePermissionIdentifier)) return $response;
if ($object != null) {
try {
$mode = $this->getRequest()->get('mode', null);
if ($mode == 'up')
$mode = UpdatePositionEvent::POSITION_UP;
else if ($mode == 'down')
$mode = UpdatePositionEvent::POSITION_DOWN;
else
$mode = UpdatePositionEvent::POSITION_ABSOLUTE;
$position = $this->getRequest()->get('position', null);
$event = new UpdatePositionEvent($object->getId(), $mode, $position);
$this->dispatch($eventName, $event);
}
catch (\Exception $ex) {
// Any error
return $this->errorPage($ex);
}
}
if ($doFinalRedirect) $this->redirectToEditionTemplate();
}
/**
* Online status toggle (only for object which support it)
*/

View File

@@ -42,6 +42,7 @@ use Thelia\Log\Tlog;
use Symfony\Component\Routing\Router;
use Thelia\Model\Admin;
use Thelia\Core\Security\Token\CookieTokenProvider;
use Thelia\Model\CurrencyQuery;
class BaseAdminController extends BaseController
{
@@ -250,6 +251,23 @@ class BaseAdminController extends BaseController
$this->redirect(URL::getInstance()->absoluteUrl($this->getRoute($routeId), $urlParameters));
}
/**
* Get the current edition currency ID, checking if a change was requested in the current request.
*/
protected function getCurrentEditionCurrency()
{
// Return the new language if a change is required.
if (null !== $edit_currency_id = $this->getRequest()->get('edit_currency_id', null)) {
if (null !== $edit_currency = CurrencyQuery::create()->findOneById($edit_currency_id)) {
return $edit_currency;
}
}
// Otherwise return the lang stored in session.
return $this->getSession()->getAdminEditionCurrency();
}
/**
* Get the current edition lang ID, checking if a change was requested in the current request.
*/
@@ -376,6 +394,9 @@ class BaseAdminController extends BaseController
// Find the current edit language ID
$edition_language = $this->getCurrentEditionLang();
// Find the current edit currency ID
$edition_currency = $this->getCurrentEditionCurrency();
// Prepare common template variables
$args = array_merge($args, array(
'locale' => $session->getLang()->getLocale(),
@@ -385,11 +406,16 @@ class BaseAdminController extends BaseController
'edit_language_id' => $edition_language->getId(),
'edit_language_locale' => $edition_language->getLocale(),
'edit_currency_id' => $edition_currency->getId(),
'current_url' => $this->getRequest()->getUri()
));
// Update the current edition language in session
$this->getSession()->setAdminEditionLang($edition_language);
// Update the current edition language & currency in session
$this->getSession()
->setAdminEditionLang($edition_language)
->setAdminEditionCurrency($edition_currency)
;
// Render the template.
try {

View File

@@ -23,10 +23,13 @@
namespace Thelia\Controller\Admin;
use Symfony\Component\HttpFoundation\Response;
use Thelia\Core\Event\CategoryDeleteEvent;
use Thelia\Core\Event\ImageCreateOrUpdateEvent;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Core\Event\CategoryUpdateEvent;
use Thelia\Core\Event\CategoryCreateEvent;
use Thelia\Log\Tlog;
use Thelia\Model\CategoryQuery;
use Thelia\Form\CategoryModificationForm;
use Thelia\Form\CategoryCreationForm;
@@ -34,7 +37,6 @@ use Thelia\Core\Event\UpdatePositionEvent;
use Thelia\Core\Event\CategoryToggleVisibilityEvent;
use Thelia\Core\Event\CategoryDeleteContentEvent;
use Thelia\Core\Event\CategoryAddContentEvent;
use Thelia\Model\CategoryAssociatedContent;
use Thelia\Model\FolderQuery;
use Thelia\Model\ContentQuery;
use Propel\Runtime\ActiveQuery\Criteria;
@@ -306,6 +308,39 @@ class CategoryController extends AbstractCrudController
$this->redirectToEditionTemplate();
}
/**
* Add category pictures
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function addRelatedPictureAction()
{
// Check current user authorization
if (null !== $response = $this->checkAuth("admin.categories.update")) {
return $response;
}
// $content_id = intval($this->getRequest()->get('content_id'));
//
// if ($content_id > 0) {
//
// $event = new CategoryAddContentEvent(
// $this->getExistingObject(),
// $content_id
// );
//
// try {
// $this->dispatch(TheliaEvents::CATEGORY_ADD_CONTENT, $event);
// }
// catch (\Exception $ex) {
// // Any error
// return $this->errorPage($ex);
// }
// }
$this->redirectToEditionTemplate();
}
public function deleteRelatedContentAction() {
// Check current user authorization
@@ -331,4 +366,5 @@ class CategoryController extends AbstractCrudController
$this->redirectToEditionTemplate();
}
}

View File

@@ -0,0 +1,680 @@
<?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;
use Propel\Runtime\Exception\PropelException;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Router;
use Thelia\Core\Event\DocumentCreateOrUpdateEvent;
use Thelia\Core\Event\DocumentDeleteEvent;
use Thelia\Core\Event\ImageCreateOrUpdateEvent;
use Thelia\Core\Event\ImageDeleteEvent;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Core\Translation\Translator;
use Thelia\Form\Exception\FormValidationException;
use Thelia\Log\Tlog;
use Thelia\Model\CategoryDocument;
use Thelia\Model\CategoryImage;
use Thelia\Model\ContentDocument;
use Thelia\Model\ContentImage;
use Thelia\Model\FolderDocument;
use Thelia\Model\FolderImage;
use Thelia\Model\ProductDocument;
use Thelia\Model\ProductImage;
use Thelia\Tools\FileManager;
use Thelia\Tools\Rest\ResponseRest;
/**
* Created by JetBrains PhpStorm.
* Date: 8/19/13
* Time: 3:24 PM
*
* Control View and Action (Model) via Events
* Control Files and Images
*
* @package File
* @author Guillaume MOREL <gmorel@openstudio.fr>
*
*/
class FileController extends BaseAdminController
{
/**
* Manage how a image collection has to be saved
*
* @param int $parentId Parent id owning images being saved
* @param string $parentType Parent Type owning images being saved
*
* @return Response
*/
public function saveImageAjaxAction($parentId, $parentType)
{
$this->checkAuth('ADMIN', 'admin.image.save');
$this->checkXmlHttpRequest();
if ($this->isParentTypeValid($parentType)) {
if ($this->getRequest()->isMethod('POST')) {
/** @var UploadedFile $fileBeingUploaded */
$fileBeingUploaded = $this->getRequest()->files->get('file');
$fileManager = new FileManager($this->container);
// Validate if file is too big
if ($fileBeingUploaded->getError() == 1) {
$message = $this->getTranslator()
->trans(
'File is too heavy, please retry with a file having a size less than %size%.',
array('%size%' => ini_get('post_max_size')),
'image'
);
return new ResponseRest($message, 'text', 403);
}
// Validate if it is a image or file
if (!$fileManager->isImage($fileBeingUploaded->getMimeType())) {
$message = $this->getTranslator()
->trans(
'You can only upload images (.png, .jpg, .jpeg, .gif)',
array(),
'image'
);
return new ResponseRest($message, 'text', 415);
}
$parentModel = $fileManager->getParentFileModel($parentType, $parentId);
$imageModel = $fileManager->getImageModel($parentType);
if ($parentModel === null || $imageModel === null || $fileBeingUploaded === null) {
return new Response('', 404);
}
$defaultTitle = $parentModel->getTitle();
$imageModel->setParentId($parentId);
$imageModel->setTitle($defaultTitle);
$imageCreateOrUpdateEvent = new ImageCreateOrUpdateEvent(
$parentType,
$parentId
);
$imageCreateOrUpdateEvent->setModelImage($imageModel);
$imageCreateOrUpdateEvent->setUploadedFile($fileBeingUploaded);
$imageCreateOrUpdateEvent->setParentName($parentModel->getTitle());
// Dispatch Event to the Action
$this->dispatch(
TheliaEvents::IMAGE_SAVE,
$imageCreateOrUpdateEvent
);
return new ResponseRest(array('status' => true, 'message' => ''));
}
}
return new Response('', 404);
}
/**
* Manage how a document collection has to be saved
*
* @param int $parentId Parent id owning documents being saved
* @param string $parentType Parent Type owning documents being saved
*
* @return Response
*/
public function saveDocumentAjaxAction($parentId, $parentType)
{
$this->checkAuth('ADMIN', 'admin.document.save');
$this->checkXmlHttpRequest();
if ($this->isParentTypeValid($parentType)) {
if ($this->getRequest()->isMethod('POST')) {
/** @var UploadedFile $fileBeingUploaded */
$fileBeingUploaded = $this->getRequest()->files->get('file');
$fileManager = new FileManager($this->container);
// Validate if file is too big
if ($fileBeingUploaded->getError() == 1) {
$message = $this->getTranslator()
->trans(
'File is too heavy, please retry with a file having a size less than %size%.',
array('%size%' => ini_get('post_max_size')),
'document'
);
return new ResponseRest($message, 'text', 403);
}
$parentModel = $fileManager->getParentFileModel($parentType, $parentId);
$documentModel = $fileManager->getDocumentModel($parentType);
if ($parentModel === null || $documentModel === null || $fileBeingUploaded === null) {
return new Response('', 404);
}
$documentModel->setParentId($parentId);
$documentModel->setTitle($fileBeingUploaded->getClientOriginalName());
$documentCreateOrUpdateEvent = new DocumentCreateOrUpdateEvent(
$parentType,
$parentId
);
$documentCreateOrUpdateEvent->setModelDocument($documentModel);
$documentCreateOrUpdateEvent->setUploadedFile($fileBeingUploaded);
$documentCreateOrUpdateEvent->setParentName($parentModel->getTitle());
// Dispatch Event to the Action
$this->dispatch(
TheliaEvents::DOCUMENT_SAVE,
$documentCreateOrUpdateEvent
);
return new ResponseRest(array('status' => true, 'message' => ''));
}
}
return new Response('', 404);
}
/**
* Manage how a image list will be displayed in AJAX
*
* @param int $parentId Parent id owning images being saved
* @param string $parentType Parent Type owning images being saved
*
* @return Response
*/
public function getImageListAjaxAction($parentId, $parentType)
{
$this->checkAuth('ADMIN', 'admin.image.save');
$this->checkXmlHttpRequest();
$args = array('imageType' => $parentType, 'parentId' => $parentId);
return $this->render('includes/image-upload-list-ajax', $args);
}
/**
* Manage how a document list will be displayed in AJAX
*
* @param int $parentId Parent id owning documents being saved
* @param string $parentType Parent Type owning documents being saved
*
* @return Response
*/
public function getDocumentListAjaxAction($parentId, $parentType)
{
$this->checkAuth('ADMIN', 'admin.document.save');
$this->checkXmlHttpRequest();
$args = array('documentType' => $parentType, 'parentId' => $parentId);
return $this->render('includes/document-upload-list-ajax', $args);
}
/**
* Manage how an image list will be uploaded in AJAX
*
* @param int $parentId Parent id owning images being saved
* @param string $parentType Parent Type owning images being saved
*
* @return Response
*/
public function getImageFormAjaxAction($parentId, $parentType)
{
$this->checkAuth('ADMIN', 'admin.image.save');
$this->checkXmlHttpRequest();
$args = array('imageType' => $parentType, 'parentId' => $parentId);
return $this->render('includes/image-upload-form', $args);
}
/**
* Manage how an document list will be uploaded in AJAX
*
* @param int $parentId Parent id owning documents being saved
* @param string $parentType Parent Type owning documents being saved
*
* @return Response
*/
public function getDocumentFormAjaxAction($parentId, $parentType)
{
$this->checkAuth('ADMIN', 'admin.document.save');
$this->checkXmlHttpRequest();
$args = array('documentType' => $parentType, 'parentId' => $parentId);
return $this->render('includes/document-upload-form', $args);
}
/**
* Manage how an image is viewed
*
* @param int $imageId Parent id owning images being saved
* @param string $parentType Parent Type owning images being saved
*
* @return Response
*/
public function viewImageAction($imageId, $parentType)
{
if (null !== $response = $this->checkAuth('admin.image.view')) {
return $response;
}
try {
$fileManager = new FileManager($this->container);
$image = $fileManager->getImageModelQuery($parentType)->findPk($imageId);
$redirectUrl = $fileManager->getRedirectionUrl($parentType, $image->getParentId(), FileManager::FILE_TYPE_IMAGES);
return $this->render('image-edit', array(
'imageId' => $imageId,
'imageType' => $parentType,
'redirectUrl' => $redirectUrl,
'formId' => $fileManager->getFormId($parentType, FileManager::FILE_TYPE_IMAGES)
));
} catch (\Exception $e) {
$this->pageNotFound();
}
}
/**
* Manage how an document is viewed
*
* @param int $documentId Parent id owning images being saved
* @param string $parentType Parent Type owning images being saved
*
* @return Response
*/
public function viewDocumentAction($documentId, $parentType)
{
if (null !== $response = $this->checkAuth('admin.document.view')) {
return $response;
}
try {
$fileManager = new FileManager($this->container);
$document = $fileManager->getDocumentModelQuery($parentType)->findPk($documentId);
$redirectUrl = $fileManager->getRedirectionUrl($parentType, $document->getParentId(), FileManager::FILE_TYPE_DOCUMENTS);
return $this->render('document-edit', array(
'documentId' => $documentId,
'documentType' => $parentType,
'redirectUrl' => $redirectUrl,
'formId' => $fileManager->getFormId($parentType, FileManager::FILE_TYPE_DOCUMENTS)
));
} catch (\Exception $e) {
$this->pageNotFound();
}
}
/**
* Manage how an image is updated
*
* @param int $imageId Parent id owning images being saved
* @param string $parentType Parent Type owning images being saved
*
* @return Response
*/
public function updateImageAction($imageId, $parentType)
{
if (null !== $response = $this->checkAuth('admin.image.update')) {
return $response;
}
$message = false;
$fileManager = new FileManager($this->container);
$imageModification = $fileManager->getImageForm($parentType, $this->getRequest());
try {
$image = $fileManager->getImageModelQuery($parentType)->findPk($imageId);
$oldImage = clone $image;
if (null === $image) {
throw new \InvalidArgumentException(sprintf('%d image id does not exist', $imageId));
}
$form = $this->validateForm($imageModification);
$event = $this->createImageEventInstance($parentType, $image, $form->getData());
$event->setOldModelImage($oldImage);
$files = $this->getRequest()->files;
$fileForm = $files->get($imageModification->getName());
if (isset($fileForm['file'])) {
$event->setUploadedFile($fileForm['file']);
}
$this->dispatch(TheliaEvents::IMAGE_UPDATE, $event);
$imageUpdated = $event->getModelImage();
$this->adminLogAppend(sprintf('Image with Ref %s (ID %d) modified', $imageUpdated->getTitle(), $imageUpdated->getId()));
if ($this->getRequest()->get('save_mode') == 'close') {
$this->redirectToRoute('admin.images');
} else {
$this->redirectSuccess($imageModification);
}
} catch (FormValidationException $e) {
$message = sprintf('Please check your input: %s', $e->getMessage());
} catch (PropelException $e) {
$message = $e->getMessage();
} catch (\Exception $e) {
$message = sprintf('Sorry, an error occurred: %s', $e->getMessage().' '.$e->getFile());
}
if ($message !== false) {
Tlog::getInstance()->error(sprintf('Error during image editing : %s.', $message));
$imageModification->setErrorMessage($message);
$this->getParserContext()
->addForm($imageModification)
->setGeneralError($message);
}
$redirectUrl = $fileManager->getRedirectionUrl($parentType, $image->getParentId(), FileManager::FILE_TYPE_IMAGES);
return $this->render('image-edit', array(
'imageId' => $imageId,
'imageType' => $parentType,
'redirectUrl' => $redirectUrl,
'formId' => $fileManager->getFormId($parentType, FileManager::FILE_TYPE_IMAGES)
));
}
/**
* Manage how an document is updated
*
* @param int $documentId Parent id owning documents being saved
* @param string $parentType Parent Type owning documents being saved
*
* @return Response
*/
public function updateDocumentAction($documentId, $parentType)
{
if (null !== $response = $this->checkAuth('admin.document.update')) {
return $response;
}
$message = false;
$fileManager = new FileManager($this->container);
$documentModification = $fileManager->getDocumentForm($parentType, $this->getRequest());
try {
$document = $fileManager->getDocumentModelQuery($parentType)->findPk($documentId);
$oldDocument = clone $document;
if (null === $document) {
throw new \InvalidArgumentException(sprintf('%d document id does not exist', $documentId));
}
$form = $this->validateForm($documentModification);
$event = $this->createDocumentEventInstance($parentType, $document, $form->getData());
$event->setOldModelDocument($oldDocument);
$files = $this->getRequest()->files;
$fileForm = $files->get($documentModification->getName());
if (isset($fileForm['file'])) {
$event->setUploadedFile($fileForm['file']);
}
$this->dispatch(TheliaEvents::DOCUMENT_UPDATE, $event);
$documentUpdated = $event->getModelDocument();
$this->adminLogAppend(sprintf('Document with Ref %s (ID %d) modified', $documentUpdated->getTitle(), $documentUpdated->getId()));
if ($this->getRequest()->get('save_mode') == 'close') {
$this->redirectToRoute('admin.documents');
} else {
$this->redirectSuccess($documentModification);
}
} catch (FormValidationException $e) {
$message = sprintf('Please check your input: %s', $e->getMessage());
} catch (PropelException $e) {
$message = $e->getMessage();
} catch (\Exception $e) {
$message = sprintf('Sorry, an error occurred: %s', $e->getMessage().' '.$e->getFile());
}
if ($message !== false) {
Tlog::getInstance()->error(sprintf('Error during document editing : %s.', $message));
$documentModification->setErrorMessage($message);
$this->getParserContext()
->addForm($documentModification)
->setGeneralError($message);
}
$redirectUrl = $fileManager->getRedirectionUrl($parentType, $document->getParentId(), FileManager::FILE_TYPE_DOCUMENTS);
return $this->render('document-edit', array(
'documentId' => $documentId,
'documentType' => $parentType,
'redirectUrl' => $redirectUrl,
'formId' => $fileManager->getFormId($parentType, FileManager::FILE_TYPE_DOCUMENTS)
));
}
/**
* Manage how a image has to be deleted (AJAX)
*
* @param int $imageId Parent id owning image being deleted
* @param string $parentType Parent Type owning image being deleted
*
* @return Response
*/
public function deleteImageAction($imageId, $parentType)
{
$this->checkAuth('ADMIN', 'admin.image.delete');
$this->checkXmlHttpRequest();
$fileManager = new FileManager($this->container);
$imageModelQuery = $fileManager->getImageModelQuery($parentType);
$model = $imageModelQuery->findPk($imageId);
if ($model == null) {
return $this->pageNotFound();
}
// Feed event
$imageDeleteEvent = new ImageDeleteEvent(
$model,
$parentType
);
// Dispatch Event to the Action
$this->dispatch(
TheliaEvents::IMAGE_DELETE,
$imageDeleteEvent
);
$message = $this->getTranslator()
->trans(
'Images deleted successfully',
array(),
'image'
);
return new Response($message);
}
/**
* Manage how a document has to be deleted (AJAX)
*
* @param int $documentId Parent id owning document being deleted
* @param string $parentType Parent Type owning document being deleted
*
* @return Response
*/
public function deleteDocumentAction($documentId, $parentType)
{
$this->checkAuth('ADMIN', 'admin.document.delete');
$this->checkXmlHttpRequest();
$fileManager = new FileManager($this->container);
$documentModelQuery = $fileManager->getDocumentModelQuery($parentType);
$model = $documentModelQuery->findPk($documentId);
if ($model == null) {
return $this->pageNotFound();
}
// Feed event
$documentDeleteEvent = new DocumentDeleteEvent(
$model,
$parentType
);
// Dispatch Event to the Action
$this->dispatch(
TheliaEvents::DOCUMENT_DELETE,
$documentDeleteEvent
);
$message = $this->getTranslator()
->trans(
'Document deleted successfully',
array(),
'document'
);
return new Response($message);
}
/**
* Log error message
*
* @param string $parentType Parent type
* @param string $action Creation|Update|Delete
* @param string $message Message to log
* @param \Exception $e Exception to log
*
* @return $this
*/
protected function logError($parentType, $action, $message, $e)
{
Tlog::getInstance()->error(
sprintf(
'Error during ' . $parentType . ' ' . $action . ' process : %s. Exception was %s',
$message,
$e->getMessage()
)
);
return $this;
}
/**
* Check if parent type is valid or not
*
* @param string $parentType Parent type
*
* @return bool
*/
public function isParentTypeValid($parentType)
{
return (in_array($parentType, FileManager::getAvailableTypes()));
}
/**
* Create Image Event instance
*
* @param string $parentType Parent Type owning images being saved
* @param CategoryImage|ProductImage|ContentImage|FolderImage $model Image model
* @param array $data Post data
*
* @return ImageCreateOrUpdateEvent
*/
protected function createImageEventInstance($parentType, $model, $data)
{
$imageCreateEvent = new ImageCreateOrUpdateEvent($parentType, null);
if (isset($data['title'])) {
$model->setTitle($data['title']);
}
if (isset($data['chapo'])) {
$model->setChapo($data['chapo']);
}
if (isset($data['description'])) {
$model->setDescription($data['description']);
}
if (isset($data['file'])) {
$model->setFile($data['file']);
}
if (isset($data['postscriptum'])) {
$model->setPostscriptum($data['postscriptum']);
}
$imageCreateEvent->setModelImage($model);
return $imageCreateEvent;
}
/**
* Create Document Event instance
*
* @param string $parentType Parent Type owning documents being saved
* @param CategoryDocument|ProductDocument|ContentDocument|FolderDocument $model Document model
* @param array $data Post data
*
* @return DocumentCreateOrUpdateEvent
*/
protected function createDocumentEventInstance($parentType, $model, $data)
{
$documentCreateEvent = new DocumentCreateOrUpdateEvent($parentType, null);
if (isset($data['title'])) {
$model->setTitle($data['title']);
}
if (isset($data['chapo'])) {
$model->setChapo($data['chapo']);
}
if (isset($data['description'])) {
$model->setDescription($data['description']);
}
if (isset($data['file'])) {
$model->setFile($data['file']);
}
if (isset($data['postscriptum'])) {
$model->setPostscriptum($data['postscriptum']);
}
$documentCreateEvent->setModelDocument($model);
return $documentCreateEvent;
}
}

View File

@@ -43,6 +43,20 @@ use Thelia\Model\AccessoryQuery;
use Thelia\Model\CategoryQuery;
use Thelia\Core\Event\ProductAddAccessoryEvent;
use Thelia\Core\Event\ProductDeleteAccessoryEvent;
use Thelia\Core\Event\FeatureProductUpdateEvent;
use Thelia\Model\FeatureQuery;
use Thelia\Core\Event\FeatureProductDeleteEvent;
use Thelia\Model\FeatureTemplateQuery;
use Thelia\Core\Event\ProductSetTemplateEvent;
use Thelia\Core\Event\ProductAddCategoryEvent;
use Thelia\Core\Event\ProductDeleteCategoryEvent;
use Thelia\Model\AttributeQuery;
use Thelia\Model\AttributeAvQuery;
use Thelia\Model\ProductSaleElementsQuery;
use Thelia\Model\AttributeCombination;
use Thelia\Model\AttributeAv;
use Thelia\Core\Event\ProductCreateCombinationEvent;
use Thelia\Core\Event\ProductDeleteCombinationEvent;
/**
* Manages products
@@ -72,6 +86,35 @@ class ProductController extends AbstractCrudController
);
}
/**
* Attributes ajax tab loading
*/
public function loadAttributesAjaxTabAction() {
return $this->render(
'ajax/product-attributes-tab',
array(
'product_id' => $this->getRequest()->get('product_id', 0),
)
);
}
/**
* Related information ajax tab loading
*/
public function loadRelatedAjaxTabAction() {
return $this->render(
'ajax/product-related-tab',
array(
'product_id' => $this->getRequest()->get('product_id', 0),
'folder_id' => $this->getRequest()->get('folder_id', 0),
'accessory_category_id' => $this->getRequest()->get('accessory_category_id', 0)
)
);
}
protected function getCreationForm()
{
return new ProductCreationForm($this->getRequest());
@@ -92,6 +135,10 @@ class ProductController extends AbstractCrudController
->setLocale($formData['locale'])
->setDefaultCategory($formData['default_category'])
->setVisible($formData['visible'])
->setBasePrice($formData['price'])
->setBaseWeight($formData['weight'])
->setCurrencyId($formData['currency'])
->setTaxRuleId($formData['tax_rule'])
;
return $createEvent;
@@ -110,7 +157,7 @@ class ProductController extends AbstractCrudController
->setPostscriptum($formData['postscriptum'])
->setVisible($formData['visible'])
->setUrl($formData['url'])
->setParent($formData['parent'])
->setDefaultCategory($formData['default_category'])
;
return $changeEvent;
@@ -137,9 +184,15 @@ class ProductController extends AbstractCrudController
protected function hydrateObjectForm($object)
{
// Get the default produc sales element
$salesElement = ProductSaleElementsQuery::create()->filterByProduct($object)->filterByIsDefault(true)->findOne();
// $prices = $salesElement->getProductPrices();
// Prepare the data that will hydrate the form
$data = array(
'id' => $object->getId(),
'ref' => $object->getRef(),
'locale' => $object->getLocale(),
'title' => $object->getTitle(),
'chapo' => $object->getChapo(),
@@ -148,6 +201,8 @@ class ProductController extends AbstractCrudController
'visible' => $object->getVisible(),
'url' => $object->getRewrittenUrl($this->getCurrentEditionLocale()),
'default_category' => $object->getDefaultCategoryId()
// A terminer pour les prix
);
// Setup the object form
@@ -182,7 +237,7 @@ class ProductController extends AbstractCrudController
'category_id' => $this->getCategoryId(),
'product_id' => $this->getRequest()->get('product_id', 0),
'folder_id' => $this->getRequest()->get('folder_id', 0),
'accessory_category_id'=> $this->getRequest()->get('accessory_category_id', 0),
'accessory_category_id' => $this->getRequest()->get('accessory_category_id', 0),
'current_tab' => $this->getRequest()->get('current_tab', 'general')
);
}
@@ -417,7 +472,6 @@ class ProductController extends AbstractCrudController
public function deleteAccessoryAction()
{
// Check current user authorization
if (null !== $response = $this->checkAuth("admin.products.update")) return $response;
@@ -443,28 +497,294 @@ class ProductController extends AbstractCrudController
}
/**
* Update accessory position (only for objects whichsupport that)
* Update accessory position
*/
public function updateAccessoryPositionAction()
{
$accessory = AccessoryQuery::create()->findPk($this->getRequest()->get('accessory_id', null));
return $this->genericUpdatePositionAction(
$accessory,
TheliaEvents::PRODUCT_UPDATE_ACCESSORY_POSITION
);
}
/**
* Update related content position
*/
public function updateContentPositionAction()
{
$content = ProductAssociatedContentQuery::create()->findPk($this->getRequest()->get('content_id', null));
return $this->genericUpdatePositionAction(
$content,
TheliaEvents::PRODUCT_UPDATE_CONTENT_POSITION
);
}
/**
* Change product template for a given product.
*
* @param unknown $productId
*/
public function setProductTemplateAction($productId) {
// Check current user authorization
if (null !== $response = $this->checkAuth('admin.products.update')) return $response;
$product = ProductQuery::create()->findPk($productId);
if ($product != null) {
$template_id = intval($this->getRequest()->get('template_id', 0));
$this->dispatch(
TheliaEvents::PRODUCT_SET_TEMPLATE,
new ProductSetTemplateEvent($product, $template_id)
);
}
$this->redirectToEditionTemplate();
}
/**
* Update product attributes and features
*/
public function updateAttributesAndFeaturesAction($productId) {
$product = ProductQuery::create()->findPk($productId);
if ($product != null) {
$featureTemplate = FeatureTemplateQuery::create()->filterByTemplateId($product->getTemplateId())->find();
if ($featureTemplate !== null) {
// Get all features for the template attached to this product
$allFeatures = FeatureQuery::create()
->filterByFeatureTemplate($featureTemplate)
->find();
$updatedFeatures = array();
// Update all features values, starting with feature av. values
$featureValues = $this->getRequest()->get('feature_value', array());
foreach($featureValues as $featureId => $featureValueList) {
// Delete all features av. for this feature.
$event = new FeatureProductDeleteEvent($productId, $featureId);
$this->dispatch(TheliaEvents::PRODUCT_FEATURE_DELETE_VALUE, $event);
// Add then all selected values
foreach($featureValueList as $featureValue) {
$event = new FeatureProductUpdateEvent($productId, $featureId, $featureValue);
$this->dispatch(TheliaEvents::PRODUCT_FEATURE_UPDATE_VALUE, $event);
}
$updatedFeatures[] = $featureId;
}
// Update then features text values
$featureTextValues = $this->getRequest()->get('feature_text_value', array());
foreach($featureTextValues as $featureId => $featureValue) {
// considere empty text as empty feature value (e.g., we will delete it)
if (empty($featureValue)) continue;
$event = new FeatureProductUpdateEvent($productId, $featureId, $featureValue, true);
$this->dispatch(TheliaEvents::PRODUCT_FEATURE_UPDATE_VALUE, $event);
$updatedFeatures[] = $featureId;
}
// Delete features which don't have any values
foreach($allFeatures as $feature) {
if (! in_array($feature->getId(), $updatedFeatures)) {
$event = new FeatureProductDeleteEvent($productId, $feature->getId());
$this->dispatch(TheliaEvents::PRODUCT_FEATURE_DELETE_VALUE, $event);
}
}
}
}
// 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 category/product list
$this->redirectToListTemplate();
}
public function addAdditionalCategoryAction() {
// Check current user authorization
if (null !== $response = $this->checkAuth("admin.products.update")) return $response;
$category_id = intval($this->getRequest()->get('additional_category_id'));
if ($category_id > 0) {
$event = new ProductAddCategoryEvent(
$this->getExistingObject(),
$category_id
);
try {
$mode = $this->getRequest()->get('mode', null);
$this->dispatch(TheliaEvents::PRODUCT_ADD_CATEGORY, $event);
}
catch (\Exception $ex) {
// Any error
return $this->errorPage($ex);
}
}
if ($mode == 'up')
$mode = UpdatePositionEvent::POSITION_UP;
else if ($mode == 'down')
$mode = UpdatePositionEvent::POSITION_DOWN;
else
$mode = UpdatePositionEvent::POSITION_ABSOLUTE;
$this->redirectToEditionTemplate();
}
$position = $this->getRequest()->get('position', null);
public function deleteAdditionalCategoryAction() {
$event = new UpdatePositionEvent($mode, $position);
// Check current user authorization
if (null !== $response = $this->checkAuth("admin.products.update")) return $response;
$this->dispatch(TheliaEvents::PRODUCT_UPDATE_ACCESSORY_POSITION, $event);
$category_id = intval($this->getRequest()->get('additional_category_id'));
if ($category_id > 0) {
$event = new ProductDeleteCategoryEvent(
$this->getExistingObject(),
$category_id
);
try {
$this->dispatch(TheliaEvents::PRODUCT_REMOVE_CATEGORY, $event);
}
catch (\Exception $ex) {
// Any error
return $this->errorPage($ex);
}
}
$this->redirectToEditionTemplate();
}
// -- Product combination management ---------------------------------------
public function getAttributeValuesAction($productId, $attributeId) {
$result = array();
// Get attribute for this product
$attribute = AttributeQuery::create()->findPk($attributeId);
if ($attribute !== null) {
$values = AttributeAvQuery::create()
->joinWithI18n($this->getCurrentEditionLocale())
->filterByAttribute($attribute)
->find();
;
if ($values !== null) {
foreach($values as $value) {
$result[] = array('id' => $value->getId(), 'title' => $value->getTitle());
}
}
}
return $this->jsonResponse(json_encode($result));
}
public function addAttributeValueToCombinationAction($productId, $attributeAvId, $combination) {
$result = array();
// Get attribute for this product
$attributeAv = AttributeAvQuery::create()->joinWithI18n($this->getCurrentEditionLocale())->findPk($attributeAvId);
if ($attributeAv !== null) {
$addIt = true;
$attribute = $attributeAv->getAttribute();
// Check if this attribute is not already present
$combinationArray = explode(',', $combination);
foreach ($combinationArray as $id) {
$attrAv = AttributeAvQuery::create()->joinWithI18n($this->getCurrentEditionLocale())->findPk($id);
if ($attrAv !== null) {
if ($attrAv->getAttributeId() == $attribute->getId()) {
$result['error'] = $this->getTranslator()->trans(
'A value for attribute "%name" is already present in the combination',
array('%name' => $attribute->getTitle())
);
$addIt = false;
}
$result[] = array('id' => $attrAv->getId(), 'title' => $attrAv->getAttribute()->getTitle() . " : " . $attrAv->getTitle());
}
}
if ($addIt) $result[] = array('id' => $attributeAv->getId(), 'title' => $attribute->getTitle() . " : " . $attributeAv->getTitle());
}
return $this->jsonResponse(json_encode($result));
}
/**
* A a new combination to a product
*/
public function addCombinationAction() {
// Check current user authorization
if (null !== $response = $this->checkAuth("admin.products.update")) return $response;
$event = new ProductCreateCombinationEvent(
$this->getExistingObject(),
$this->getRequest()->get('combination_attributes', array()),
$this->getCurrentEditionCurrency()->getId()
);
try {
$this->dispatch(TheliaEvents::PRODUCT_ADD_COMBINATION, $event);
}
catch (\Exception $ex) {
// Any error
return $this->errorPage($ex);
}
$this->redirectToEditionTemplate();
}
/**
* A a new combination to a product
*/
public function deleteCombinationAction() {
// Check current user authorization
if (null !== $response = $this->checkAuth("admin.products.update")) return $response;
$event = new ProductDeleteCombinationEvent(
$this->getExistingObject(),
$this->getRequest()->get('product_sale_element_id',0)
);
try {
$this->dispatch(TheliaEvents::PRODUCT_DELETE_COMBINATION, $event);
}
catch (\Exception $ex) {
// Any error

View File

@@ -39,6 +39,8 @@ use Thelia\Core\Event\TemplateDeleteAttributeEvent;
use Thelia\Core\Event\TemplateAddAttributeEvent;
use Thelia\Core\Event\TemplateAddFeatureEvent;
use Thelia\Core\Event\TemplateDeleteFeatureEvent;
use Thelia\Model\FeatureTemplateQuery;
use Thelia\Model\AttributeTemplateQuery;
/**
* Manages product templates
@@ -255,6 +257,21 @@ class TemplateController extends AbstractCrudController
$this->redirectToEditionTemplate();
}
public function updateAttributePositionAction() {
// Find attribute_template
$attributeTemplate = AttributeTemplateQuery::create()
->filterByTemplateId($this->getRequest()->get('template_id', null))
->filterByAttributeId($this->getRequest()->get('attribute_id', null))
->findOne()
;
return $this->genericUpdatePositionAction(
$attributeTemplate,
TheliaEvents::TEMPLATE_CHANGE_ATTRIBUTE_POSITION
);
}
public function addFeatureAction() {
// Check current user authorization
@@ -299,4 +316,18 @@ class TemplateController extends AbstractCrudController
$this->redirectToEditionTemplate();
}
public function updateFeaturePositionAction() {
// Find feature_template
$featureTemplate = FeatureTemplateQuery::create()
->filterByTemplateId($this->getRequest()->get('template_id', null))
->filterByFeatureId($this->getRequest()->get('feature_id', null))
->findOne()
;
return $this->genericUpdatePositionAction(
$featureTemplate,
TheliaEvents::TEMPLATE_CHANGE_FEATURE_POSITION
);
}
}

View File

@@ -0,0 +1,217 @@
<?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 Symfony\Component\HttpFoundation\File\UploadedFile;
use Thelia\Model\CategoryDocument;
use Thelia\Model\ContentDocument;
use Thelia\Model\FolderDocument;
use Thelia\Model\ProductDocument;
/**
* Created by JetBrains PhpStorm.
* Date: 9/18/13
* Time: 3:56 PM
*
* Occurring when a Document is saved
*
* @package Document
* @author Guillaume MOREL <gmorel@openstudio.fr>
*
*/
class DocumentCreateOrUpdateEvent extends ActionEvent
{
/** @var CategoryDocument|ProductDocument|ContentDocument|FolderDocument model to save */
protected $modelDocument = array();
/** @var CategoryDocument|ProductDocument|ContentDocument|FolderDocument model to save */
protected $oldModelDocument = array();
/** @var UploadedFile Document file to save */
protected $uploadedFile = null;
/** @var int Document parent id */
protected $parentId = null;
/** @var string Document type */
protected $documentType = null;
/** @var string Parent name */
protected $parentName = null;
/**
* Constructor
*
* @param string $documentType Document type
* ex : FileManager::TYPE_CATEGORY
* @param int $parentId Document parent id
*/
public function __construct($documentType, $parentId)
{
$this->documentType = $documentType;
$this->parentId = $parentId;
}
/**
* Set Document to save
*
* @param CategoryDocument|ProductDocument|ContentDocument|FolderDocument $document Document to save
*
* @return $this
*/
public function setModelDocument($document)
{
$this->modelDocument = $document;
return $this;
}
/**
* Get Document being saved
*
* @return CategoryDocument|ProductDocument|ContentDocument|FolderDocument
*/
public function getModelDocument()
{
return $this->modelDocument;
}
/**
* Set document type
*
* @param string $documentType Document type
*
* @return $this
*/
public function setDocumentType($documentType)
{
$this->documentType = $documentType;
return $this;
}
/**
* Get document type
*
* @return string
*/
public function getDocumentType()
{
return $this->documentType;
}
/**
* Set Document parent id
*
* @param int $parentId Document parent id
*
* @return $this
*/
public function setParentId($parentId)
{
$this->parentId = $parentId;
return $this;
}
/**
* Get Document parent id
*
* @return int
*/
public function getParentId()
{
return $this->parentId;
}
/**
* Set uploaded file
*
* @param UploadedFile $uploadedFile File being uploaded
*
* @return $this
*/
public function setUploadedFile($uploadedFile)
{
$this->uploadedFile = $uploadedFile;
return $this;
}
/**
* Get uploaded file
*
* @return UploadedFile
*/
public function getUploadedFile()
{
return $this->uploadedFile;
}
/**
* Set parent name
*
* @param string $parentName Parent name
*
* @return $this
*/
public function setParentName($parentName)
{
$this->parentName = $parentName;
return $this;
}
/**
* Get parent name
*
* @return string
*/
public function getParentName()
{
return $this->parentName;
}
/**
* Set old model value
*
* @param CategoryDocument|ContentDocument|FolderDocument|ProductDocument $oldModelDocument
*/
public function setOldModelDocument($oldModelDocument)
{
$this->oldModelDocument = $oldModelDocument;
}
/**
* Get old model value
*
* @return CategoryDocument|ContentDocument|FolderDocument|ProductDocument
*/
public function getOldModelDocument()
{
return $this->oldModelDocument;
}
}

View File

@@ -0,0 +1,112 @@
<?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\CategoryDocument;
use Thelia\Model\ContentDocument;
use Thelia\Model\FolderDocument;
use Thelia\Model\ProductDocument;
/**
* Created by JetBrains PhpStorm.
* Date: 9/18/13
* Time: 3:56 PM
*
* Occurring when a Document is about to be deleted
*
* @package Document
* @author Guillaume MOREL <gmorel@openstudio.fr>
*
*/
class DocumentDeleteEvent extends ActionEvent
{
/** @var string Document type */
protected $documentType = null;
/** @var CategoryDocument|ProductDocument|ContentDocument|FolderDocument Document about to be deleted */
protected $documentToDelete = null;
/**
* Constructor
*
* @param CategoryDocument|ProductDocument|ContentDocument|FolderDocument $documentToDelete Document about to be deleted
* @param string $documentType Document type
* ex : FileManager::TYPE_CATEGORY
*/
public function __construct($documentToDelete, $documentType)
{
$this->documentToDelete = $documentToDelete;
$this->documentType = $documentType;
}
/**
* Set picture type
*
* @param string $documentType Document type
*
* @return $this
*/
public function setDocumentType($documentType)
{
$this->documentType = $documentType;
return $this;
}
/**
* Get picture type
*
* @return string
*/
public function getDocumentType()
{
return $this->documentType;
}
/**
* Set Document about to be deleted
*
* @param CategoryDocument|ProductDocument|ContentDocument|FolderDocument $documentToDelete Document about to be deleted
*
* @return $this
*/
public function setDocumentToDelete($documentToDelete)
{
$this->documentToDelete = $documentToDelete;
return $this;
}
/**
* Get Document about to be deleted
*
* @return CategoryDocument|ProductDocument|ContentDocument|FolderDocument
*/
public function getDocumentToDelete()
{
return $this->documentToDelete;
}
}

View File

@@ -23,43 +23,60 @@
namespace Thelia\Core\Event;
/**
* Class DocumentEvent
*
* @package Thelia\Core\Event
*/
class DocumentEvent extends CachedFileEvent
{
protected $document_path;
protected $document_url;
protected $documentPath;
protected $documentUrl;
/**
* @return the document file path
* Get Document path
*
* @return string The document file path
*/
public function getDocumentPath()
{
return $this->document_path;
return $this->documentPath;
}
/**
* @param string $document_path the document file path
* Set Document path
*
* @param string $documentPath the document file path
*
* @return $this
*/
public function setDocumentPath($document_path)
public function setDocumentPath($documentPath)
{
$this->document_path = $document_path;
$this->documentPath = $documentPath;
return $this;
}
/**
* @return the document URL
* Get Document URL
*
* @return string The document URL
*/
public function getDocumentUrl()
{
return $this->document_url;
return $this->documentUrl;
}
/**
* @param string $document_url the document URL
* Set Document URL
*
* @param string $documentUrl the document URL
*
* @return $this
*/
public function setDocumentUrl($document_url)
public function setDocumentUrl($documentUrl)
{
$this->document_url = $document_url;
$this->documentUrl = $documentUrl;
return $this;
}

View File

@@ -0,0 +1,61 @@
<?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\FeatureProduct;
class FeatureProductDeleteEvent extends FeatureProductEvent
{
protected $product_id;
protected $feature_id;
public function __construct($product_id, $feature_id)
{
$this->product_id = $product_id;
$this->feature_id = $feature_id;
}
public function getProductId()
{
return $this->product_id;
}
public function setProductId($product_id)
{
$this->product_id = $product_id;
return $this;
}
public function getFeatureId()
{
return $this->feature_id;
}
public function setFeatureId($feature_id)
{
$this->feature_id = $feature_id;
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;
use Thelia\Model\FeatureProduct;
class FeatureProductEvent extends ActionEvent
{
protected $featureProduct = null;
public function __construct(FeatureProduct $featureProduct = null)
{
$this->featureProduct = $featureProduct;
}
public function hasFeatureProduct()
{
return ! is_null($this->featureProduct);
}
public function getFeatureProduct()
{
return $this->featureProduct;
}
public function setFeatureProduct($featureProduct)
{
$this->featureProduct = $featureProduct;
return $this;
}
}

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\Core\Event;
use Thelia\Model\FeatureProduct;
class FeatureProductUpdateEvent extends FeatureProductEvent
{
protected $product_id;
protected $feature_id;
protected $feature_value;
protected $is_text_value;
public function __construct($product_id, $feature_id, $feature_value, $is_text_value = false)
{
$this->product_id = $product_id;
$this->feature_id = $feature_id;
$this->feature_value = $feature_value;
$this->is_text_value = $is_text_value;
}
public function getProductId()
{
return $this->product_id;
}
public function setProductId($product_id)
{
$this->product_id = $product_id;
return $this;
}
public function getFeatureId()
{
return $this->feature_id;
}
public function setFeatureId($feature_id)
{
$this->feature_id = $feature_id;
return $this;
}
public function getFeatureValue()
{
return $this->feature_value;
}
public function setFeatureValue($feature_value)
{
$this->feature_value = $feature_value;
return $this;
}
public function getIsTextValue()
{
return $this->is_text_value;
}
public function setIsTextValue($is_text_value)
{
$this->is_text_value = $is_text_value;
return $this;
}
}

View File

@@ -0,0 +1,213 @@
<?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 Symfony\Component\HttpFoundation\File\UploadedFile;
/**
* Created by JetBrains PhpStorm.
* Date: 9/18/13
* Time: 3:56 PM
*
* Occurring when an Image is saved
*
* @package Image
* @author Guillaume MOREL <gmorel@openstudio.fr>
*
*/
class ImageCreateOrUpdateEvent extends ActionEvent
{
/** @var \Thelia\Model\CategoryImage|\Thelia\Model\ProductImage|\Thelia\Model\ContentImage|\Thelia\Model\FolderImage model to save */
protected $modelImage = array();
/** @var \Thelia\Model\CategoryImage|\Thelia\Model\ProductImage|\Thelia\Model\ContentImage|\Thelia\Model\FolderImage model to save */
protected $oldModelImage = array();
/** @var UploadedFile Image file to save */
protected $uploadedFile = null;
/** @var int Image parent id */
protected $parentId = null;
/** @var string Image type */
protected $imageType = null;
/** @var string Parent name */
protected $parentName = null;
/**
* Constructor
*
* @param string $imageType Image type
* ex : FileManager::TYPE_CATEGORY
* @param int $parentId Image parent id
*/
public function __construct($imageType, $parentId)
{
$this->imageType = $imageType;
$this->parentId = $parentId;
}
/**
* Set Image to save
*
* @param $image \Thelia\Model\CategoryImage|\Thelia\Model\ProductImage|\Thelia\Model\ContentImage|\Thelia\Model\FolderImage
*
* @return $this
*/
public function setModelImage($image)
{
$this->modelImage = $image;
return $this;
}
/**
* Get Image being saved
*
* @return \Thelia\Model\CategoryImage|\Thelia\Model\ProductImage|\Thelia\Model\ContentImage|\Thelia\Model\FolderImage
*/
public function getModelImage()
{
return $this->modelImage;
}
/**
* Set picture type
*
* @param string $imageType Image type
*
* @return $this
*/
public function setImageType($imageType)
{
$this->imageType = $imageType;
return $this;
}
/**
* Get picture type
*
* @return string
*/
public function getImageType()
{
return $this->imageType;
}
/**
* Set Image parent id
*
* @param int $parentId Image parent id
*
* @return $this
*/
public function setParentId($parentId)
{
$this->parentId = $parentId;
return $this;
}
/**
* Get Image parent id
*
* @return int
*/
public function getParentId()
{
return $this->parentId;
}
/**
* Set uploaded file
*
* @param UploadedFile $uploadedFile File being uploaded
*
* @return $this
*/
public function setUploadedFile($uploadedFile)
{
$this->uploadedFile = $uploadedFile;
return $this;
}
/**
* Get uploaded file
*
* @return UploadedFile
*/
public function getUploadedFile()
{
return $this->uploadedFile;
}
/**
* Set parent name
*
* @param string $parentName Parent name
*
* @return $this
*/
public function setParentName($parentName)
{
$this->parentName = $parentName;
return $this;
}
/**
* Get parent name
*
* @return string
*/
public function getParentName()
{
return $this->parentName;
}
/**
* Set old model value
*
* @param \Thelia\Model\CategoryImage|\Thelia\Model\ContentImage|\Thelia\Model\FolderImage|\Thelia\Model\ProductImage $oldModelImage
*/
public function setOldModelImage($oldModelImage)
{
$this->oldModelImage = $oldModelImage;
}
/**
* Get old model value
*
* @return \Thelia\Model\CategoryImage|\Thelia\Model\ContentImage|\Thelia\Model\FolderImage|\Thelia\Model\ProductImage
*/
public function getOldModelImage()
{
return $this->oldModelImage;
}
}

View File

@@ -0,0 +1,112 @@
<?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\CategoryImage;
use Thelia\Model\ContentImage;
use Thelia\Model\FolderImage;
use Thelia\Model\ProductImage;
/**
* Created by JetBrains PhpStorm.
* Date: 9/18/13
* Time: 3:56 PM
*
* Occurring when a Image is about to be deleted
*
* @package Image
* @author Guillaume MOREL <gmorel@openstudio.fr>
*
*/
class ImageDeleteEvent extends ActionEvent
{
/** @var string Image type */
protected $imageType = null;
/** @var CategoryImage|ProductImage|ContentImage|FolderImage Image about to be deleted */
protected $imageToDelete = null;
/**
* Constructor
*
* @param CategoryImage|ProductImage|ContentImage|FolderImage $imageToDelete Image about to be deleted
* @param string $imageType Image type
* ex : FileManager::TYPE_CATEGORY
*/
public function __construct($imageToDelete, $imageType)
{
$this->imageToDelete = $imageToDelete;
$this->imageType = $imageType;
}
/**
* Set picture type
*
* @param string $imageType Image type
*
* @return $this
*/
public function setImageType($imageType)
{
$this->imageType = $imageType;
return $this;
}
/**
* Get picture type
*
* @return string
*/
public function getImageType()
{
return $this->imageType;
}
/**
* Set Image about to be deleted
*
* @param CategoryImage|ProductImage|ContentImage|FolderImage $imageToDelete Image about to be deleted
*
* @return $this
*/
public function setImageToDelete($imageToDelete)
{
$this->imageToDelete = $imageToDelete;
return $this;
}
/**
* Get Image about to be deleted
*
* @return CategoryImage|ProductImage|ContentImage|FolderImage
*/
public function getImageToDelete()
{
return $this->imageToDelete;
}
}

View File

@@ -0,0 +1,48 @@
<?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\Product;
class ProductAddCategoryEvent extends ProductEvent
{
protected $category_id;
public function __construct(Product $product, $category_id)
{
parent::__construct($product);
$this->category_id = $category_id;
}
public function getCategoryId()
{
return $this->category_id;
}
public function setCategoryId($category_id)
{
$this->category_id = $category_id;
}
}

View File

@@ -0,0 +1,64 @@
<?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\Product;
class ProductCreateCombinationEvent extends ProductEvent
{
protected $attribute_av_list;
protected $currency_id;
public function __construct(Product $product, $attribute_av_list, $currency_id)
{
parent::__construct($product);
$this->attribute_av_list = $attribute_av_list;
$this->currency_id = $currency_id;
}
public function getAttributeAvList()
{
return $this->attribute_av_list;
}
public function setAttributeAvList($attribute_av_list)
{
$this->attribute_av_list = $attribute_av_list;
return $this;
}
public function getCurrencyId()
{
return $this->currency_id;
}
public function setCurrencyId($currency_id)
{
$this->currency_id = $currency_id;
return $this;
}
}

View File

@@ -31,6 +31,11 @@ class ProductCreateEvent extends ProductEvent
protected $default_category;
protected $visible;
protected $basePrice;
protected $baseWeight;
protected $taxRuleId;
protected $currencyId;
public function getRef()
{
return $this->ref;
@@ -85,4 +90,48 @@ class ProductCreateEvent extends ProductEvent
$this->visible = $visible;
return $this;
}
public function getBasePrice()
{
return $this->basePrice;
}
public function setBasePrice($basePrice)
{
$this->basePrice = $basePrice;
return $this;
}
public function getBaseWeight()
{
return $this->baseWeight;
}
public function setBaseWeight($baseWeight)
{
$this->baseWeight = $baseWeight;
return $this;
}
public function getTaxRuleId()
{
return $this->taxRuleId;
}
public function setTaxRuleId($taxRuleId)
{
$this->taxRuleId = $taxRuleId;
return $this;
}
public function getCurrencyId()
{
return $this->currencyId;
}
public function setCurrencyId($currencyId)
{
$this->currencyId = $currencyId;
return $this;
}
}

View File

@@ -0,0 +1,50 @@
<?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\Product;
class ProductDeleteCategoryEvent extends ProductEvent
{
protected $category_id;
public function __construct(Product $product, $category_id)
{
parent::__construct($product);
$this->category_id = $category_id;
}
public function getCategoryId()
{
return $this->category_id;
}
public function setCategoryId($category_id)
{
$this->category_id = $category_id;
return $this;
}
}

View File

@@ -0,0 +1,47 @@
<?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\Product;
class ProductDeleteCombinationEvent extends ProductEvent
{
protected $product_sale_element_id;
public function __construct(Product $product, $product_sale_element_id)
{
parent::__construct($product);
$this->product_sale_element_id = $product_sale_element_id;
}
public function getProductSaleElementId()
{
return $this->product_sale_element_id;
}
public function setProductSaleElementId($product_sale_element_id)
{
$this->product_sale_element_id = $product_sale_element_id;
}
}

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\Product;
use Thelia\Core\Event\ActionEvent;
class ProductSetTemplateEvent extends ProductEvent
{
public $template_id = null;
public function __construct(Product $product = null, $template_id)
{
parent::__construct($product);
$this->template_id = $template_id;
}
public function getTemplateId()
{
return $this->template_id;
}
public function setTemplateId($template_id)
{
$this->template_id = $template_id;
return $this;
}
}

View File

@@ -210,8 +210,8 @@ final class TheliaEvents
const BEFORE_CREATECATEGORY_ASSOCIATED_CONTENT = "action.before_createCategoryAssociatedContent";
const AFTER_CREATECATEGORY_ASSOCIATED_CONTENT = "action.after_createCategoryAssociatedContent";
const BEFORE_DELETECATEGORY_ASSOCIATED_CONTENT = "action.before_deleteCategoryAssociatedContenty";
const AFTER_DELETECATEGORY_ASSOCIATED_CONTENT = "action.after_deleteproduct_accessory";
const BEFORE_DELETECATEGORY_ASSOCIATED_CONTENT = "action.before_deleteCategoryAssociatedContent";
const AFTER_DELETECATEGORY_ASSOCIATED_CONTENT = "action.after_deleteCategoryAssociatedContent";
const BEFORE_UPDATECATEGORY_ASSOCIATED_CONTENT = "action.before_updateCategoryAssociatedContent";
const AFTER_UPDATECATEGORY_ASSOCIATED_CONTENT = "action.after_updateCategoryAssociatedContent";
@@ -226,10 +226,22 @@ final class TheliaEvents
const PRODUCT_ADD_CONTENT = "action.productAddContent";
const PRODUCT_REMOVE_CONTENT = "action.productRemoveContent";
const PRODUCT_UPDATE_CONTENT_POSITION = "action.updateProductContentPosition";
const PRODUCT_ADD_ACCESSORY = "action.productAddAccessory";
const PRODUCT_REMOVE_ACCESSORY = "action.productRemoveAccessory";
const PRODUCT_UPDATE_ACCESSORY_POSITION = "action.updateProductPosition";
const PRODUCT_ADD_COMBINATION = "action.productAddCombination";
const PRODUCT_DELETE_COMBINATION = "action.productDeleteCombination";
const PRODUCT_SET_TEMPLATE = "action.productSetTemplate";
const PRODUCT_ADD_ACCESSORY = "action.productAddProductAccessory";
const PRODUCT_REMOVE_ACCESSORY = "action.productRemoveProductAccessory";
const PRODUCT_UPDATE_ACCESSORY_POSITION = "action.updateProductAccessoryPosition";
const PRODUCT_FEATURE_UPDATE_VALUE = "action.updateProductFeatureValue";
const PRODUCT_FEATURE_DELETE_VALUE = "action.deleteProductFeatureValue";
const PRODUCT_ADD_CATEGORY = "action.addProductCategory";
const PRODUCT_REMOVE_CATEGORY = "action.deleteProductCategory";
const BEFORE_CREATEPRODUCT = "action.before_createproduct";
const AFTER_CREATEPRODUCT = "action.after_createproduct";
@@ -251,17 +263,28 @@ final class TheliaEvents
const BEFORE_UPDATEACCESSORY = "action.before_updateAccessory";
const AFTER_UPDATEACCESSORY = "action.after_updateAccessory";
// -- Product Associated Content --------------------------------------------------
// -- Product Associated Content -------------------------------------------
const BEFORE_CREATEPRODUCT_ASSOCIATED_CONTENT = "action.before_createProductAssociatedContent";
const AFTER_CREATEPRODUCT_ASSOCIATED_CONTENT = "action.after_createProductAssociatedContent";
const BEFORE_DELETEPRODUCT_ASSOCIATED_CONTENT = "action.before_deleteProductAssociatedContenty";
const AFTER_DELETEPRODUCT_ASSOCIATED_CONTENT = "action.after_deleteproduct_accessory";
const BEFORE_DELETEPRODUCT_ASSOCIATED_CONTENT = "action.before_deleteProductAssociatedContent";
const AFTER_DELETEPRODUCT_ASSOCIATED_CONTENT = "action.after_deleteProductAssociatedContent";
const BEFORE_UPDATEPRODUCT_ASSOCIATED_CONTENT = "action.before_updateProductAssociatedContent";
const AFTER_UPDATEPRODUCT_ASSOCIATED_CONTENT = "action.after_updateProductAssociatedContent";
// -- Feature product ------------------------------------------------------
const BEFORE_CREATEFEATURE_PRODUCT = "action.before_createFeatureProduct";
const AFTER_CREATEFEATURE_PRODUCT = "action.after_createFeatureProduct";
const BEFORE_DELETEFEATURE_PRODUCT = "action.before_deleteFeatureProduct";
const AFTER_DELETEFEATURE_PRODUCT = "action.after_deleteFeatureProduct";
const BEFORE_UPDATEFEATURE_PRODUCT = "action.before_updateFeatureProduct";
const AFTER_UPDATEFEATURE_PRODUCT = "action.after_updateFeatureProduct";
/**
* sent when a new existing cat id duplicated. This append when current customer is different from current cart
*/
@@ -314,11 +337,46 @@ final class TheliaEvents
*/
const DOCUMENT_PROCESS = "action.processDocument";
/**
* Sent on image cache clear request
*/
const DOCUMENT_CLEAR_CACHE = "action.clearDocumentCache";
/**
* Save given documents
*/
const DOCUMENT_SAVE = "action.saveDocument";
/**
* Save given documents
*/
const DOCUMENT_UPDATE = "action.updateDocument";
/**
* Delete given document
*/
const DOCUMENT_DELETE = "action.deleteDocument";
/**
* Sent on image cache clear request
*/
const IMAGE_CLEAR_CACHE = "action.clearImageCache";
/**
* Save given images
*/
const IMAGE_SAVE = "action.saveImages";
/**
* Save given images
*/
const IMAGE_UPDATE = "action.updateImages";
/**
* Delete given image
*/
const IMAGE_DELETE = "action.deleteImage";
/**
* Sent when creating a Coupon
*/
@@ -429,6 +487,7 @@ final class TheliaEvents
const AFTER_DELETECURRENCY = "action.after_deleteCurrency";
const CHANGE_DEFAULT_CURRENCY = 'action.changeDefaultCurrency';
// -- Product templates management -----------------------------------------
const TEMPLATE_CREATE = "action.createTemplate";
@@ -441,6 +500,9 @@ final class TheliaEvents
const TEMPLATE_ADD_FEATURE = "action.templateAddFeature";
const TEMPLATE_DELETE_FEATURE = "action.templateDeleteFeature";
const TEMPLATE_CHANGE_FEATURE_POSITION = "action.templateChangeAttributePosition";
const TEMPLATE_CHANGE_ATTRIBUTE_POSITION = "action.templateChangeFeaturePosition";
const BEFORE_CREATETEMPLATE = "action.before_createTemplate";
const AFTER_CREATETEMPLATE = "action.after_createTemplate";

View File

@@ -65,23 +65,6 @@ class Session extends BaseSession
return $this;
}
public function getAdminEditionLang()
{
$lang = $this->get('thelia.admin.edition.lang');
if (null === $lang) {
$lang = Lang::getDefaultLanguage();
}
return $lang;
}
public function setAdminEditionLang($langId)
{
$this->set('thelia.admin.edition.lang', $langId);
return $this;
}
public function setCurrency(Currency $currency)
{
$this->set("thelia.current.currency", $currency);
@@ -98,6 +81,43 @@ class Session extends BaseSession
return $currency;
}
// -- Admin lang and currency ----------------------------------------------
public function getAdminEditionCurrency()
{
$currency = $this->get('thelia.admin.edition.currency', null);
if (null === $currency) {
$currency = Currency::getDefaultCurrency();
}
return $currency;
}
public function setAdminEditionCurrency($currencyId)
{
$this->set('thelia.admin.edition.currency', $currencyId);
return $this;
}
public function getAdminEditionLang()
{
$lang = $this->get('thelia.admin.edition.lang');
if (null === $lang) {
$lang = Lang::getDefaultLanguage();
}
return $lang;
}
public function setAdminEditionLang($lang)
{
$this->set('thelia.admin.edition.lang', $lang);
return $this;
}
// -- Customer user --------------------------------------------------------
public function setCustomerUser(UserInterface $user)

View File

@@ -74,6 +74,7 @@ class Accessory extends Product
$search = AccessoryQuery::create();
$product = $this->getProduct();
$search->filterByProductId($product, Criteria::IN);
$order = $this->getOrder();
@@ -93,10 +94,16 @@ class Accessory extends Product
$accessories = $this->search($search);
$accessoryIdList = array(0);
$accessoryPosition = array();
$accessoryPosition = $accessoryId = array();
foreach ($accessories as $accessory) {
array_push($accessoryIdList, $accessory->getAccessory());
$accessoryPosition[$accessory->getAccessory()] = $accessory->getPosition();
$accessoryProductId = $accessory->getAccessory();
array_push($accessoryIdList, $accessoryProductId);
$accessoryPosition[$accessoryProductId] = $accessory->getPosition();
$accessoryId[$accessoryProductId] = $accessory->getId();
}
$receivedIdList = $this->getId();
@@ -111,12 +118,15 @@ class Accessory extends Product
$loopResult = parent::exec($pagination);
foreach($loopResult as $loopResultRow) {
$accessoryProductId = $loopResultRow->get('ID');
$loopResultRow
->set("POSITION" , $accessoryPosition[$loopResultRow->get('ID')])
->set("ID" , $accessoryId[$accessoryProductId])
->set("POSITION", $accessoryPosition[$accessoryProductId])
;
}
return $loopResult;
}
}

View File

@@ -135,8 +135,17 @@ class AssociatedContent extends Content
$associatedContents = $this->search($search);
$associatedContentIdList = array(0);
$contentIdList = array(0);
$contentPosition = $contentId = array();
foreach ($associatedContents as $associatedContent) {
array_push($associatedContentIdList, $associatedContent->getContentId());
$associatedContentId = $associatedContent->getContentId();
array_push($associatedContentIdList, $associatedContentId);
$contentPosition[$associatedContentId] = $associatedContent->getPosition();
$contentId[$associatedContentId] = $associatedContent->getId();
}
$receivedIdList = $this->getId();
@@ -148,7 +157,18 @@ class AssociatedContent extends Content
$this->args->get('id')->setValue( implode(',', array_intersect($receivedIdList, $associatedContentIdList)) );
}
return parent::exec($pagination);
$loopResult = parent::exec($pagination);
foreach($loopResult as $loopResultRow) {
$relatedContentId = $loopResultRow->get('ID');
$loopResultRow
->set("ID" , $contentId[$relatedContentId])
->set("POSITION", $contentPosition[$relatedContentId])
;
}
return $loopResult;
}
}

View File

@@ -41,7 +41,8 @@ use Thelia\Type\BooleanOrBothType;
use Thelia\Model\ProductQuery;
use Thelia\Model\TemplateQuery;
use Thelia\Model\AttributeTemplateQuery;
use Thelia\Core\Translation\Translator;
use Thelia\Model\Map\AttributeTemplateTableMap;
/**
*
* Attribute loop
@@ -106,33 +107,50 @@ class Attribute extends BaseI18nLoop
$product = $this->getProduct();
$template = $this->getTemplate();
if (null !== $product) {
// Find the template assigned to the product.
$productObj = ProductQuery::create()->findPk($product);
// Ignore if the product cannot be found.
if ($productObj !== null)
$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('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
);
$use_attribute_pos = true;
if (null !== $product) {
// Find all template assigned to the products.
$products = ProductQuery::create()->findById($product);
// Ignore if the product cannot be found.
if ($products !== null) {
// Create template array
if ($template == null) $template = array();
foreach($products as $product) {
$tpl_id = $product->getTemplateId();
if (! is_null($tpl_id)) $template[] = $tpl_id;
}
}
}
if (! empty($template)) {
// Join with feature_template table to get position
$search
->withColumn(AttributeTemplateTableMap::POSITION, 'position')
->filterByTemplate(TemplateQuery::create()->findById($template), Criteria::IN)
;
$use_attribute_pos = false;
}
else if (null !== $exclude_template) {
// Join with attribute_template table to get position
$exclude_attributes = AttributeTemplateQuery::create()->filterByTemplateId($exclude_template)->select('attribute_id')->find();
$search
->joinAttributeTemplate(null, Criteria::LEFT_JOIN)
->withColumn(AttributeTemplateTableMap::POSITION, 'position')
->filterById($exclude_attributes, Criteria::NOT_IN)
;
$use_attribute_pos = false;
}
$orders = $this->getOrder();
@@ -152,10 +170,16 @@ class Attribute extends BaseI18nLoop
$search->addDescendingOrderByColumn('i18n_TITLE');
break;
case "manual":
if ($use_attribute_pos)
$search->orderByPosition(Criteria::ASC);
else
$search->addAscendingOrderByColumn(AttributeTemplateTableMap::POSITION);
break;
case "manual_reverse":
if ($use_attribute_pos)
$search->orderByPosition(Criteria::DESC);
else
$search->addDescendingOrderByColumn(AttributeTemplateTableMap::POSITION);
break;
}
}
@@ -174,7 +198,8 @@ class Attribute extends BaseI18nLoop
->set("CHAPO", $attribute->getVirtualColumn('i18n_CHAPO'))
->set("DESCRIPTION", $attribute->getVirtualColumn('i18n_DESCRIPTION'))
->set("POSTSCRIPTUM", $attribute->getVirtualColumn('i18n_POSTSCRIPTUM'))
->set("POSITION", $attribute->getPosition());
->set("POSITION", $use_attribute_pos ? $attribute->getPosition() : $attribute->getVirtualColumn('position'))
;
$loopResult->addRow($loopResultRow);
}

View File

@@ -35,6 +35,7 @@ use Thelia\Model\CategoryQuery;
use Thelia\Type\TypeCollection;
use Thelia\Type;
use Thelia\Type\BooleanOrBothType;
use Thelia\Model\ProductQuery;
/**
*
@@ -73,6 +74,8 @@ class Category extends BaseI18nLoop
return new ArgumentCollection(
Argument::createIntListTypeArgument('id'),
Argument::createIntTypeArgument('parent'),
Argument::createIntTypeArgument('product'),
Argument::createIntTypeArgument('exclude_product'),
Argument::createBooleanTypeArgument('current'),
Argument::createBooleanTypeArgument('not_empty', 0),
Argument::createBooleanOrBothTypeArgument('visible', 1),
@@ -128,6 +131,22 @@ class Category extends BaseI18nLoop
if ($this->getVisible() != BooleanOrBothType::ANY)
$search->filterByVisible($this->getVisible() ? 1 : 0);
$product = $this->getProduct();
if ($product != null) {
$obj = ProductQuery::create()->findPk($product);
if ($obj != null) $search->filterByProduct($obj, Criteria::IN);
}
$exclude_product = $this->getExclude_product();
if ($exclude_product != null) {
$obj = ProductQuery::create()->findPk($exclude_product);
if ($obj != null) $search->filterByProduct($obj, Criteria::NOT_IN);
}
$orders = $this->getOrder();
foreach ($orders as $order) {

View File

@@ -251,9 +251,9 @@ class Document extends BaseI18nLoop
$loopResultRow
->set("ID" , $result->getId())
->set("LOCALE" ,$locale)
->set("LOCALE" , $locale)
->set("DOCUMENT_URL" , $event->getFileUrl())
->set("DOCUMENT_PATH" , $event->getCacheFilepath())
->set("DOCUMENT_PATH" , $event->getDocumentPath())
->set("ORIGINAL_DOCUMENT_PATH", $source_filepath)
->set("TITLE" , $result->getVirtualColumn('i18n_TITLE'))
->set("CHAPO" , $result->getVirtualColumn('i18n_CHAPO'))

View File

@@ -41,6 +41,8 @@ use Thelia\Type\TypeCollection;
use Thelia\Type;
use Thelia\Type\BooleanOrBothType;
use Thelia\Model\FeatureTemplateQuery;
use Thelia\Model\TemplateQuery;
use Thelia\Model\Map\FeatureTemplateTableMap;
/**
*
@@ -70,7 +72,7 @@ class Feature extends BaseI18nLoop
new Argument(
'order',
new TypeCollection(
new Type\EnumListType(array('alpha', 'alpha-reverse', 'manual', 'manual_reverse'))
new Type\EnumListType(array('id', 'id_reverse', 'alpha', 'alpha-reverse', 'manual', 'manual_reverse'))
),
'manual'
),
@@ -108,39 +110,55 @@ class Feature extends BaseI18nLoop
$product = $this->getProduct();
$template = $this->getTemplate();
if (null !== $product) {
// Find the template assigned to the product.
$productObj = ProductQuery::create()->findPk($product);
// 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
);
}
$exclude_template = $this->getExcludeTemplate();
// If we have to filter by template, find all features assigned to this template, and filter by found IDs
$use_feature_pos = true;
if (null !== $product) {
// Find all template assigned to the products.
$products = ProductQuery::create()->findById($product);
// Ignore if the product cannot be found.
if ($products !== null) {
// Create template array
if ($template == null) $template = array();
foreach($products as $product) {
$tpl_id = $product->getTemplateId();
if (! is_null($tpl_id)) $template[] = $tpl_id;
}
}
}
if (! empty($template)) {
// Join with feature_template table to get position
$search
->withColumn(FeatureTemplateTableMap::POSITION, 'position')
->filterByTemplate(TemplateQuery::create()->findById($template), Criteria::IN)
;
$use_feature_pos = false;
}
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
);
$exclude_features = FeatureTemplateQuery::create()->filterByTemplateId($exclude_template)->select('feature_id')->find();
$search
->joinFeatureTemplate(null, Criteria::LEFT_JOIN)
->withColumn(FeatureTemplateTableMap::POSITION, 'position')
->filterById($exclude_features, Criteria::NOT_IN)
;
$use_feature_pos = false;
}
$title = $this->getTitle();
if (null !== $title) {
//find all feture that match exactly this title and find with all locales.
//find all feature that match exactly this title and find with all locales.
$features = FeatureI18nQuery::create()
->filterByTitle($title, Criteria::LIKE)
->select('id')
@@ -158,6 +176,12 @@ class Feature extends BaseI18nLoop
foreach ($orders as $order) {
switch ($order) {
case "id":
$search->orderById(Criteria::ASC);
break;
case "id_reverse":
$search->orderById(Criteria::DESC);
break;
case "alpha":
$search->addAscendingOrderByColumn('i18n_TITLE');
break;
@@ -165,14 +189,22 @@ class Feature extends BaseI18nLoop
$search->addDescendingOrderByColumn('i18n_TITLE');
break;
case "manual":
if ($use_feature_pos)
$search->orderByPosition(Criteria::ASC);
else
$search->addAscendingOrderByColumn(FeatureTemplateTableMap::POSITION);
break;
case "manual_reverse":
if ($use_feature_pos)
$search->orderByPosition(Criteria::DESC);
else
$search->addDescendingOrderByColumn(FeatureTemplateTableMap::POSITION);
break;
}
}
/* perform search */
$features = $this->search($search, $pagination);
@@ -187,7 +219,8 @@ class Feature extends BaseI18nLoop
->set("CHAPO", $feature->getVirtualColumn('i18n_CHAPO'))
->set("DESCRIPTION", $feature->getVirtualColumn('i18n_DESCRIPTION'))
->set("POSTSCRIPTUM", $feature->getVirtualColumn('i18n_POSTSCRIPTUM'))
->set("POSITION", $feature->getPosition());
->set("POSITION", $use_feature_pos ? $feature->getPosition() : $feature->getVirtualColumn('position'))
;
$loopResult->addRow($loopResultRow);
}

View File

@@ -59,7 +59,7 @@ class FeatureValue extends BaseI18nLoop
Argument::createIntTypeArgument('product', null, true),
Argument::createIntListTypeArgument('feature_availability'),
Argument::createBooleanTypeArgument('exclude_feature_availability', 0),
Argument::createBooleanTypeArgument('exclude_personal_values', 0),
Argument::createBooleanTypeArgument('exclude_free_text', 0),
new Argument(
'order',
new TypeCollection(
@@ -79,7 +79,7 @@ class FeatureValue extends BaseI18nLoop
{
$search = FeatureProductQuery::create();
/* manage featureAv translations */
// manage featureAv translations
$locale = $this->configureI18nProcessing(
$search,
array('TITLE', 'CHAPO', 'DESCRIPTION', 'POSTSCRIPTUM'),
@@ -103,13 +103,9 @@ class FeatureValue extends BaseI18nLoop
}
$excludeFeatureAvailability = $this->getExclude_feature_availability();
if ($excludeFeatureAvailability == true) {
$search->filterByFeatureAvId(null, Criteria::NULL);
}
$excludeDefaultValues = $this->getExclude_personal_values();
if ($excludeDefaultValues == true) {
$search->filterByByDefault(null, Criteria::NULL);
if ($excludeFeatureAvailability == true) {
$search->filterByFeatureAvId(null, Criteria::ISNULL);
}
$orders = $this->getOrder();
@@ -136,17 +132,26 @@ class FeatureValue extends BaseI18nLoop
$loopResult = new LoopResult($featureValues);
foreach ($featureValues as $featureValue) {
$loopResultRow = new LoopResultRow($loopResult, $featureValue, $this->versionable, $this->timestampable, $this->countable);
$loopResultRow->set("ID", $featureValue->getId());
$loopResultRow
->set("LOCALE",$locale)
->set("PERSONAL_VALUE", $featureValue->getByDefault())
->set("TITLE",$featureValue->getVirtualColumn(FeatureAvTableMap::TABLE_NAME . '_i18n_TITLE'))
->set("CHAPO", $featureValue->getVirtualColumn(FeatureAvTableMap::TABLE_NAME . '_i18n_CHAPO'))
->set("DESCRIPTION", $featureValue->getVirtualColumn(FeatureAvTableMap::TABLE_NAME . '_i18n_DESCRIPTION'))
->set("POSTSCRIPTUM", $featureValue->getVirtualColumn(FeatureAvTableMap::TABLE_NAME . '_i18n_POSTSCRIPTUM'))
->set("POSITION", $featureValue->getPosition());
->set("ID" , $featureValue->getId())
->set("PRODUCT" , $featureValue->getProductId())
->set("FEATURE_AV_ID" , $featureValue->getFeatureAvId())
->set("FREE_TEXT_VALUE" , $featureValue->getFreeTextValue())
->set("IS_FREE_TEXT" , is_null($featureValue->getFeatureAvId()) ? 1 : 0)
->set("IS_FEATURE_AV" , is_null($featureValue->getFeatureAvId()) ? 0 : 1)
->set("LOCALE" , $locale)
->set("TITLE" , $featureValue->getVirtualColumn(FeatureAvTableMap::TABLE_NAME . '_i18n_TITLE'))
->set("CHAPO" , $featureValue->getVirtualColumn(FeatureAvTableMap::TABLE_NAME . '_i18n_CHAPO'))
->set("DESCRIPTION" , $featureValue->getVirtualColumn(FeatureAvTableMap::TABLE_NAME . '_i18n_DESCRIPTION'))
->set("POSTSCRIPTUM" , $featureValue->getVirtualColumn(FeatureAvTableMap::TABLE_NAME . '_i18n_POSTSCRIPTUM'))
->set("POSITION" , $featureValue->getPosition())
;
$loopResult->addRow($loopResultRow);
}

View File

@@ -650,6 +650,7 @@ class Product extends BaseI18nLoop
->set("IS_NEW" , $product->getVirtualColumn('main_product_is_new'))
->set("POSITION" , $product->getPosition())
->set("VISIBLE" , $product->getVisible() ? "1" : "0")
->set("TEMPLATE" , $product->getTemplateId())
->set("HAS_PREVIOUS" , $previous != null ? 1 : 0)
->set("HAS_NEXT" , $next != null ? 1 : 0)
->set("PREVIOUS" , $previous != null ? $previous->getId() : -1)

View File

@@ -170,17 +170,19 @@ class ProductSaleElements extends BaseLoop
$taxedPromoPrice = null;
}
$loopResultRow->set("ID", $PSEValue->getId())
->set("QUANTITY", $PSEValue->getQuantity())
->set("IS_PROMO", $PSEValue->getPromo() === 1 ? 1 : 0)
->set("IS_NEW", $PSEValue->getNewness() === 1 ? 1 : 0)
->set("WEIGHT", $PSEValue->getWeight())
->set("PRICE", $price)
->set("PRICE_TAX", $taxedPrice - $price)
->set("TAXED_PRICE", $taxedPrice)
->set("PROMO_PRICE", $promoPrice)
->set("PROMO_PRICE_TAX", $taxedPromoPrice - $promoPrice)
->set("TAXED_PROMO_PRICE", $taxedPromoPrice);
$loopResultRow
->set("ID" , $PSEValue->getId())
->set("QUANTITY" , $PSEValue->getQuantity())
->set("IS_PROMO" , $PSEValue->getPromo() === 1 ? 1 : 0)
->set("IS_NEW" , $PSEValue->getNewness() === 1 ? 1 : 0)
->set("IS_DEFAULT" , $PSEValue->getIsDefault() === 1 ? 1 : 0)
->set("WEIGHT" , $PSEValue->getWeight())
->set("PRICE" , $price)
->set("PRICE_TAX" , $taxedPrice - $price)
->set("TAXED_PRICE" , $taxedPrice)
->set("PROMO_PRICE" , $promoPrice)
->set("PROMO_PRICE_TAX" , $taxedPromoPrice - $promoPrice)
->set("TAXED_PROMO_PRICE" , $taxedPromoPrice);
$loopResult->addRow($loopResultRow);
}

View File

@@ -0,0 +1,103 @@
<?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\Smarty\Plugins;
use Symfony\Component\Form\FormView;
use Thelia\Form\BaseForm;
use Thelia\Core\Template\Element\Exception\ElementNotFoundException;
use Symfony\Component\HttpFoundation\Request;
use Thelia\Core\Template\Smarty\SmartyPluginDescriptor;
use Thelia\Core\Template\Smarty\AbstractSmartyPlugin;
use Thelia\Core\Template\ParserContext;
/**
* Created by JetBrains PhpStorm.
* Date: 9/18/13
* Time: 3:56 PM
*
* Plugin for smarty defining blocks allowing to get flash message
* A flash message is a variable, array, object stored in session under the flashMessage key
* ex $SESSION['flashMessage']['myKey']
*
* blocks :
* - {flashMessage key="myKey"} ... {/flashMessage}
*
* Class Form
*
* @package Thelia\Core\Template\Smarty\Plugins
* @author Guillaume MOREL <gmorel@openstudio.fr>
*/
class FlashMessage extends AbstractSmartyPlugin
{
/** @var Request Request service */
protected $request;
/**
* Constructor
*
* @param Request $request Request service
*/
public function __construct(Request $request)
{
$this->request = $request;
}
/**
* Get FlashMessage
* And clean session from this key
*
* @param array $params Block parameters
* @param mixed $content Block content
* @param \Smarty_Internal_Template $template Template
* @param bool $repeat Control how many times
* the block is displayed
*
* @return mixed
*/
public function getFlashMessage($params, $content, \Smarty_Internal_Template $template, &$repeat)
{
if ($repeat) {
$key = $params['key'];
$flashBag = $this->request->getSession()->get('flashMessage');
$template->assign('value', $flashBag[$key]);
// Reset flash message (can be read once)
unset($flashBag[$key]);
$this->request->getSession()->set('flashMessage', $flashBag);
} else {
return $content;
}
}
/**
* @return array an array of SmartyPluginDescriptor
*/
public function getPluginDescriptors()
{
return array(
new SmartyPluginDescriptor("block", "flashMessage", $this, "getFlashMessage")
);
}
}

View File

@@ -49,7 +49,8 @@ class UrlGenerator extends AbstractSmartyPlugin
{
// the path to process
$path = $this->getParam($params, 'path', null);
$file = $this->getParam($params, 'file', null);
$file = $this->getParam($params, 'file', null); // Do not invoke index.php in URL (get a static file in web space
$noamp = $this->getParam($params, 'noamp', null); // Do not change & in &amp;
if ($file !== null) {
$path = $file;
@@ -66,10 +67,12 @@ class UrlGenerator extends AbstractSmartyPlugin
$url = URL::getInstance()->absoluteUrl(
$path,
$this->getArgsFromParam($params, array('path', 'file', 'target')),
$this->getArgsFromParam($params, array('noamp', 'path', 'file', 'target')),
$mode
);
if ($noamp == null) $url = str_replace('&', '&amp;', $url);
if ($target != null) $url .= '#'.$target;
return $url;

View File

@@ -0,0 +1,54 @@
<?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 Thelia\Core\Translation\Translator;
use Thelia\Form\Image\DocumentModification;
use Thelia\Form\Image\ImageModification;
/**
* Created by JetBrains PhpStorm.
* Date: 9/18/13
* Time: 3:56 PM
*
* Form allowing to process an document collection
*
* @package Image
* @author Guillaume MOREL <gmorel@openstudio.fr>
*
*/
class CategoryDocumentModification extends DocumentModification
{
/**
* Get form name
* This name must be unique
*
* @return string
*/
public function getName()
{
return 'thelia_category_document_modification';
}
}

View File

@@ -0,0 +1,53 @@
<?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 Thelia\Core\Translation\Translator;
use Thelia\Form\Image\ImageModification;
/**
* Created by JetBrains PhpStorm.
* Date: 9/18/13
* Time: 3:56 PM
*
* Form allowing to process an image collection
*
* @package Image
* @author Guillaume MOREL <gmorel@openstudio.fr>
*
*/
class CategoryImageModification extends ImageModification
{
/**
* Get form name
* This name must be unique
*
* @return string
*/
public function getName()
{
return 'thelia_category_image_modification';
}
}

View File

@@ -0,0 +1,54 @@
<?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 Thelia\Core\Translation\Translator;
use Thelia\Form\Image\DocumentModification;
use Thelia\Form\Image\ImageModification;
/**
* Created by JetBrains PhpStorm.
* Date: 9/18/13
* Time: 3:56 PM
*
* Form allowing to process a file
*
* @package File
* @author Guillaume MOREL <gmorel@openstudio.fr>
*
*/
class ContentDocumentModification extends DocumentModification
{
/**
* Get form name
* This name must be unique
*
* @return string
*/
public function getName()
{
return 'thelia_content_document_modification';
}
}

View File

@@ -0,0 +1,53 @@
<?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 Thelia\Core\Translation\Translator;
use Thelia\Form\Image\ImageModification;
/**
* Created by JetBrains PhpStorm.
* Date: 9/18/13
* Time: 3:56 PM
*
* Form allowing to process an image collection
*
* @package Image
* @author Guillaume MOREL <gmorel@openstudio.fr>
*
*/
class ContentImageModification extends ImageModification
{
/**
* Get form name
* This name must be unique
*
* @return string
*/
public function getName()
{
return 'thelia_content_image_modification';
}
}

View File

@@ -0,0 +1,54 @@
<?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 Thelia\Core\Translation\Translator;
use Thelia\Form\Image\DocumentModification;
use Thelia\Form\Image\ImageModification;
/**
* Created by JetBrains PhpStorm.
* Date: 9/18/13
* Time: 3:56 PM
*
* Form allowing to process a file
*
* @package Image
* @author Guillaume MOREL <gmorel@openstudio.fr>
*
*/
class FolderDocumentModification extends DocumentModification
{
/**
* Get form name
* This name must be unique
*
* @return string
*/
public function getName()
{
return 'thelia_folder_document_modification';
}
}

View File

@@ -0,0 +1,53 @@
<?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 Thelia\Core\Translation\Translator;
use Thelia\Form\Image\ImageModification;
/**
* Created by JetBrains PhpStorm.
* Date: 9/18/13
* Time: 3:56 PM
*
* Form allowing to process an image collection
*
* @package Image
* @author Guillaume MOREL <gmorel@openstudio.fr>
*
*/
class FolderImageModification extends ImageModification
{
/**
* Get form name
* This name must be unique
*
* @return string
*/
public function getName()
{
return 'thelia_folder_image_modification';
}
}

View File

@@ -0,0 +1,138 @@
<?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\Image;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Validator\Constraints\Image;
use Symfony\Component\Validator\Constraints\NotBlank;
use Thelia\Core\Translation\Translator;
use Thelia\Form\BaseForm;
/**
* Created by JetBrains PhpStorm.
* Date: 9/18/13
* Time: 3:56 PM
*
* Form allowing to process a file
* @todo refactor make all document using propel inheritance and factorise image behaviour into one single clean action
*
* @package File
* @author Guillaume MOREL <gmorel@openstudio.fr>
*
*/
abstract class DocumentModification extends BaseForm
{
/**
*
* in this function you add all the fields you need for your Form.
* Form this you have to call add method on $this->form attribute :
*
* $this->form->add('name', 'text')
* ->add('email', 'email', array(
* 'attr' => array(
* 'class' => 'field'
* ),
* 'label' => 'email',
* 'constraints' => array(
* new NotBlank()
* )
* )
* )
* ->add('age', 'integer');
*
* @return null
*/
protected function buildForm()
{
$this->formBuilder->add(
'file',
'file',
array(
'constraints' => array(),
'label' => Translator::getInstance()->trans('Replace current document by this file'),
'label_attr' => array(
'for' => 'file'
)
)
);
$this->formBuilder
->add(
'title',
'text',
array(
'constraints' => array(
new NotBlank()
),
'label' => Translator::getInstance()->trans('Title'),
'label_attr' => array(
'for' => 'title'
)
)
)
->add(
'description',
'text',
array(
'constraints' => array(),
'label' => Translator::getInstance()->trans('Description'),
'label_attr' => array(
'for' => 'description'
)
)
)
->add(
'chapo',
'text',
array(
'constraints' => array(),
'label' => Translator::getInstance()->trans('Chapo'),
'label_attr' => array(
'for' => 'chapo'
)
)
)
->add(
'postscriptum',
'text',
array(
'constraints' => array(),
'label' => Translator::getInstance()->trans('Post Scriptum'),
'label_attr' => array(
'for' => 'postscriptum'
)
)
)
->add(
'postscriptum',
'text',
array(
'constraints' => array(),
'label' => Translator::getInstance()->trans('Post Scriptum'),
'label_attr' => array(
'for' => 'postscriptum'
)
)
);
}
}

View File

@@ -0,0 +1,146 @@
<?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\Image;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Validator\Constraints\Image;
use Symfony\Component\Validator\Constraints\NotBlank;
use Thelia\Core\Translation\Translator;
use Thelia\Form\BaseForm;
/**
* Created by JetBrains PhpStorm.
* Date: 9/18/13
* Time: 3:56 PM
*
* Form allowing to process an image
* @todo refactor make all pictures using propel inheritance and factorise image behaviour into one single clean action
*
* @package Image
* @author Guillaume MOREL <gmorel@openstudio.fr>
*
*/
abstract class ImageModification extends BaseForm
{
/**
*
* in this function you add all the fields you need for your Form.
* Form this you have to call add method on $this->form attribute :
*
* $this->form->add('name', 'text')
* ->add('email', 'email', array(
* 'attr' => array(
* 'class' => 'field'
* ),
* 'label' => 'email',
* 'constraints' => array(
* new NotBlank()
* )
* )
* )
* ->add('age', 'integer');
*
* @return null
*/
protected function buildForm()
{
$this->formBuilder->add(
'file',
'file',
array(
'constraints' => array(
new Image(
array(
// 'minWidth' => 200,
// 'minHeight' => 200
)
)
),
'label' => Translator::getInstance()->trans('Replace current image by this file'),
'label_attr' => array(
'for' => 'file'
)
)
);
$this->formBuilder
->add(
'title',
'text',
array(
'constraints' => array(
new NotBlank()
),
'label' => Translator::getInstance()->trans('Title'),
'label_attr' => array(
'for' => 'title'
)
)
)
->add(
'description',
'text',
array(
'constraints' => array(),
'label' => Translator::getInstance()->trans('Description'),
'label_attr' => array(
'for' => 'description'
)
)
)
->add(
'chapo',
'text',
array(
'constraints' => array(),
'label' => Translator::getInstance()->trans('Chapo'),
'label_attr' => array(
'for' => 'chapo'
)
)
)
->add(
'postscriptum',
'text',
array(
'constraints' => array(),
'label' => Translator::getInstance()->trans('Post Scriptum'),
'label_attr' => array(
'for' => 'postscriptum'
)
)
)
->add(
'postscriptum',
'text',
array(
'constraints' => array(),
'label' => Translator::getInstance()->trans('Post Scriptum'),
'label_attr' => array(
'for' => 'postscriptum'
)
)
);
}
}

View File

@@ -47,25 +47,48 @@ class ProductCreationForm extends BaseForm
"label_attr" => array("for" => "ref")
))
->add("title", "text", array(
"constraints" => array(
new NotBlank()
),
"constraints" => array(new NotBlank()),
"label" => "Product title *",
"label_attr" => array("for" => "title")
))
->add("default_category", "integer", array(
"constraints" => array(new NotBlank()),
"label" => Translator::getInstance()->trans("Default product category."),
"label" => Translator::getInstance()->trans("Default product category *"),
"label_attr" => array("for" => "default_category_field")
))
->add("locale", "text", array(
"constraints" => array(new NotBlank())
))
->add("visible", "integer", array(
"label" => Translator::getInstance()->trans("This product is online."),
"label" => Translator::getInstance()->trans("This product is online"),
"label_attr" => array("for" => "visible_field")
))
;
if (! $change_mode) {
$this->formBuilder
->add("price", "number", array(
"constraints" => array(new NotBlank()),
"label" => Translator::getInstance()->trans("Product base price excluding taxes *"),
"label_attr" => array("for" => "price_field")
))
->add("currency", "integer", array(
"constraints" => array(new NotBlank()),
"label" => Translator::getInstance()->trans("Price currency *"),
"label_attr" => array("for" => "currency_field")
))
->add("tax_rule", "integer", array(
"constraints" => array(new NotBlank()),
"label" => Translator::getInstance()->trans("Tax rule for this product *"),
"label_attr" => array("for" => "tax_rule_field")
))
->add("weight", "number", array(
"constraints" => array(new NotBlank()),
"label" => Translator::getInstance()->trans("Weight *"),
"label_attr" => array("for" => "weight_field")
))
;
}
}
public function checkDuplicateRef($value, ExecutionContextInterface $context)

View File

@@ -0,0 +1,90 @@
<?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 Thelia\Core\Translation\Translator;
use Symfony\Component\Validator\Constraints\NotBlank;
class ProductDetailsModificationForm extends BaseForm
{
use StandardDescriptionFieldsTrait;
protected function buildForm()
{
$this->formBuilder
->add("id", "integer", array(
"label" => Translator::getInstance()->trans("Prodcut ID *"),
"label_attr" => array("for" => "product_id_field"),
"constraints" => array(new GreaterThan(array('value' => 0)))
))
->add("price", "number", array(
"constraints" => array(new NotBlank()),
"label" => Translator::getInstance()->trans("Product base price excluding taxes *"),
"label_attr" => array("for" => "price_field")
))
->add("price_with_tax", "number", array(
"label" => Translator::getInstance()->trans("Product base price including taxes *"),
"label_attr" => array("for" => "price_with_tax_field")
))
->add("currency", "integer", array(
"constraints" => array(new NotBlank()),
"label" => Translator::getInstance()->trans("Price currency *"),
"label_attr" => array("for" => "currency_field")
))
->add("tax_rule", "integer", array(
"constraints" => array(new NotBlank()),
"label" => Translator::getInstance()->trans("Tax rule for this product *"),
"label_attr" => array("for" => "tax_rule_field")
))
->add("weight", "number", array(
"constraints" => array(new NotBlank()),
"label" => Translator::getInstance()->trans("Weight *"),
"label_attr" => array("for" => "weight_field")
))
->add("quantity", "number", array(
"constraints" => array(new NotBlank()),
"label" => Translator::getInstance()->trans("Current quantity *"),
"label_attr" => array("for" => "quantity_field")
))
->add("sale_price", "number", array(
"label" => Translator::getInstance()->trans("Sale price *"),
"label_attr" => array("for" => "price_with_tax_field")
))
->add("onsale", "integer", array(
"label" => Translator::getInstance()->trans("This product is on sale"),
"label_attr" => array("for" => "onsale_field")
))
->add("isnew", "integer", array(
"label" => Translator::getInstance()->trans("Advertise this product as new"),
"label_attr" => array("for" => "isnew_field")
))
;
}
public function getName()
{
return "thelia_product_details_modification";
}
}

View File

@@ -0,0 +1,54 @@
<?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 Thelia\Core\Translation\Translator;
use Thelia\Form\Image\DocumentModification;
use Thelia\Form\Image\ImageModification;
/**
* Created by JetBrains PhpStorm.
* Date: 9/18/13
* Time: 3:56 PM
*
* Form allowing to process a file
*
* @package File
* @author Guillaume MOREL <gmorel@openstudio.fr>
*
*/
class ProductDocumentModification extends DocumentModification
{
/**
* Get form name
* This name must be unique
*
* @return string
*/
public function getName()
{
return 'thelia_product_document_modification';
}
}

View File

@@ -0,0 +1,53 @@
<?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 Thelia\Core\Translation\Translator;
use Thelia\Form\Image\ImageModification;
/**
* Created by JetBrains PhpStorm.
* Date: 9/18/13
* Time: 3:56 PM
*
* Form allowing to process an image collection
*
* @package Image
* @author Guillaume MOREL <gmorel@openstudio.fr>
*
*/
class ProductImageModification extends ImageModification
{
/**
* Get form name
* This name must be unique
*
* @return string
*/
public function getName()
{
return 'thelia_product_image_modification';
}
}

View File

@@ -3,8 +3,29 @@
namespace Thelia\Model;
use Thelia\Model\Base\AttributeTemplate as BaseAttributeTemplate;
use Propel\Runtime\Connection\ConnectionInterface;
class AttributeTemplate extends BaseAttributeTemplate
class AttributeTemplate extends BaseAttributeTemplate
{
use \Thelia\Model\Tools\ModelEventDispatcherTrait;
use \Thelia\Model\Tools\PositionManagementTrait;
/**
* Calculate next position relative to our template
*/
protected function addCriteriaToPositionQuery($query)
{
$query->filterByTemplateId($this->getTemplateId());
}
/**
* {@inheritDoc}
*/
public function preInsert(ConnectionInterface $con = null)
{
$this->setPosition($this->getNextPosition());
return true;
}
}

View File

@@ -82,6 +82,12 @@ abstract class AttributeTemplate implements ActiveRecordInterface
*/
protected $position;
/**
* The value for the attribute_templatecol field.
* @var string
*/
protected $attribute_templatecol;
/**
* The value for the created_at field.
* @var string
@@ -410,6 +416,17 @@ abstract class AttributeTemplate implements ActiveRecordInterface
return $this->position;
}
/**
* Get the [attribute_templatecol] column value.
*
* @return string
*/
public function getAttributeTemplatecol()
{
return $this->attribute_templatecol;
}
/**
* Get the [optionally formatted] temporal [created_at] column value.
*
@@ -542,6 +559,27 @@ abstract class AttributeTemplate implements ActiveRecordInterface
return $this;
} // setPosition()
/**
* Set the value of [attribute_templatecol] column.
*
* @param string $v new value
* @return \Thelia\Model\AttributeTemplate The current object (for fluent API support)
*/
public function setAttributeTemplatecol($v)
{
if ($v !== null) {
$v = (string) $v;
}
if ($this->attribute_templatecol !== $v) {
$this->attribute_templatecol = $v;
$this->modifiedColumns[] = AttributeTemplateTableMap::ATTRIBUTE_TEMPLATECOL;
}
return $this;
} // setAttributeTemplatecol()
/**
* Sets the value of [created_at] column to a normalized version of the date/time value specified.
*
@@ -633,13 +671,16 @@ abstract class AttributeTemplate implements ActiveRecordInterface
$col = $row[TableMap::TYPE_NUM == $indexType ? 3 + $startcol : AttributeTemplateTableMap::translateFieldName('Position', TableMap::TYPE_PHPNAME, $indexType)];
$this->position = (null !== $col) ? (int) $col : null;
$col = $row[TableMap::TYPE_NUM == $indexType ? 4 + $startcol : AttributeTemplateTableMap::translateFieldName('CreatedAt', TableMap::TYPE_PHPNAME, $indexType)];
$col = $row[TableMap::TYPE_NUM == $indexType ? 4 + $startcol : AttributeTemplateTableMap::translateFieldName('AttributeTemplatecol', TableMap::TYPE_PHPNAME, $indexType)];
$this->attribute_templatecol = (null !== $col) ? (string) $col : null;
$col = $row[TableMap::TYPE_NUM == $indexType ? 5 + $startcol : AttributeTemplateTableMap::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 ? 5 + $startcol : AttributeTemplateTableMap::translateFieldName('UpdatedAt', TableMap::TYPE_PHPNAME, $indexType)];
$col = $row[TableMap::TYPE_NUM == $indexType ? 6 + $startcol : AttributeTemplateTableMap::translateFieldName('UpdatedAt', TableMap::TYPE_PHPNAME, $indexType)];
if ($col === '0000-00-00 00:00:00') {
$col = null;
}
@@ -652,7 +693,7 @@ abstract class AttributeTemplate implements ActiveRecordInterface
$this->ensureConsistency();
}
return $startcol + 6; // 6 = AttributeTemplateTableMap::NUM_HYDRATE_COLUMNS.
return $startcol + 7; // 7 = AttributeTemplateTableMap::NUM_HYDRATE_COLUMNS.
} catch (Exception $e) {
throw new PropelException("Error populating \Thelia\Model\AttributeTemplate object", 0, $e);
@@ -911,6 +952,9 @@ abstract class AttributeTemplate implements ActiveRecordInterface
if ($this->isColumnModified(AttributeTemplateTableMap::POSITION)) {
$modifiedColumns[':p' . $index++] = 'POSITION';
}
if ($this->isColumnModified(AttributeTemplateTableMap::ATTRIBUTE_TEMPLATECOL)) {
$modifiedColumns[':p' . $index++] = 'ATTRIBUTE_TEMPLATECOL';
}
if ($this->isColumnModified(AttributeTemplateTableMap::CREATED_AT)) {
$modifiedColumns[':p' . $index++] = 'CREATED_AT';
}
@@ -940,6 +984,9 @@ abstract class AttributeTemplate implements ActiveRecordInterface
case 'POSITION':
$stmt->bindValue($identifier, $this->position, PDO::PARAM_INT);
break;
case 'ATTRIBUTE_TEMPLATECOL':
$stmt->bindValue($identifier, $this->attribute_templatecol, PDO::PARAM_STR);
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;
@@ -1021,9 +1068,12 @@ abstract class AttributeTemplate implements ActiveRecordInterface
return $this->getPosition();
break;
case 4:
return $this->getCreatedAt();
return $this->getAttributeTemplatecol();
break;
case 5:
return $this->getCreatedAt();
break;
case 6:
return $this->getUpdatedAt();
break;
default:
@@ -1059,8 +1109,9 @@ abstract class AttributeTemplate implements ActiveRecordInterface
$keys[1] => $this->getAttributeId(),
$keys[2] => $this->getTemplateId(),
$keys[3] => $this->getPosition(),
$keys[4] => $this->getCreatedAt(),
$keys[5] => $this->getUpdatedAt(),
$keys[4] => $this->getAttributeTemplatecol(),
$keys[5] => $this->getCreatedAt(),
$keys[6] => $this->getUpdatedAt(),
);
$virtualColumns = $this->virtualColumns;
foreach($virtualColumns as $key => $virtualColumn)
@@ -1122,9 +1173,12 @@ abstract class AttributeTemplate implements ActiveRecordInterface
$this->setPosition($value);
break;
case 4:
$this->setCreatedAt($value);
$this->setAttributeTemplatecol($value);
break;
case 5:
$this->setCreatedAt($value);
break;
case 6:
$this->setUpdatedAt($value);
break;
} // switch()
@@ -1155,8 +1209,9 @@ abstract class AttributeTemplate implements ActiveRecordInterface
if (array_key_exists($keys[1], $arr)) $this->setAttributeId($arr[$keys[1]]);
if (array_key_exists($keys[2], $arr)) $this->setTemplateId($arr[$keys[2]]);
if (array_key_exists($keys[3], $arr)) $this->setPosition($arr[$keys[3]]);
if (array_key_exists($keys[4], $arr)) $this->setCreatedAt($arr[$keys[4]]);
if (array_key_exists($keys[5], $arr)) $this->setUpdatedAt($arr[$keys[5]]);
if (array_key_exists($keys[4], $arr)) $this->setAttributeTemplatecol($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]]);
}
/**
@@ -1172,6 +1227,7 @@ abstract class AttributeTemplate implements ActiveRecordInterface
if ($this->isColumnModified(AttributeTemplateTableMap::ATTRIBUTE_ID)) $criteria->add(AttributeTemplateTableMap::ATTRIBUTE_ID, $this->attribute_id);
if ($this->isColumnModified(AttributeTemplateTableMap::TEMPLATE_ID)) $criteria->add(AttributeTemplateTableMap::TEMPLATE_ID, $this->template_id);
if ($this->isColumnModified(AttributeTemplateTableMap::POSITION)) $criteria->add(AttributeTemplateTableMap::POSITION, $this->position);
if ($this->isColumnModified(AttributeTemplateTableMap::ATTRIBUTE_TEMPLATECOL)) $criteria->add(AttributeTemplateTableMap::ATTRIBUTE_TEMPLATECOL, $this->attribute_templatecol);
if ($this->isColumnModified(AttributeTemplateTableMap::CREATED_AT)) $criteria->add(AttributeTemplateTableMap::CREATED_AT, $this->created_at);
if ($this->isColumnModified(AttributeTemplateTableMap::UPDATED_AT)) $criteria->add(AttributeTemplateTableMap::UPDATED_AT, $this->updated_at);
@@ -1240,6 +1296,7 @@ abstract class AttributeTemplate implements ActiveRecordInterface
$copyObj->setAttributeId($this->getAttributeId());
$copyObj->setTemplateId($this->getTemplateId());
$copyObj->setPosition($this->getPosition());
$copyObj->setAttributeTemplatecol($this->getAttributeTemplatecol());
$copyObj->setCreatedAt($this->getCreatedAt());
$copyObj->setUpdatedAt($this->getUpdatedAt());
if ($makeNew) {
@@ -1381,6 +1438,7 @@ abstract class AttributeTemplate implements ActiveRecordInterface
$this->attribute_id = null;
$this->template_id = null;
$this->position = null;
$this->attribute_templatecol = null;
$this->created_at = null;
$this->updated_at = null;
$this->alreadyInSave = false;

View File

@@ -25,6 +25,7 @@ use Thelia\Model\Map\AttributeTemplateTableMap;
* @method ChildAttributeTemplateQuery orderByAttributeId($order = Criteria::ASC) Order by the attribute_id column
* @method ChildAttributeTemplateQuery orderByTemplateId($order = Criteria::ASC) Order by the template_id column
* @method ChildAttributeTemplateQuery orderByPosition($order = Criteria::ASC) Order by the position column
* @method ChildAttributeTemplateQuery orderByAttributeTemplatecol($order = Criteria::ASC) Order by the attribute_templatecol column
* @method ChildAttributeTemplateQuery orderByCreatedAt($order = Criteria::ASC) Order by the created_at column
* @method ChildAttributeTemplateQuery orderByUpdatedAt($order = Criteria::ASC) Order by the updated_at column
*
@@ -32,6 +33,7 @@ use Thelia\Model\Map\AttributeTemplateTableMap;
* @method ChildAttributeTemplateQuery groupByAttributeId() Group by the attribute_id column
* @method ChildAttributeTemplateQuery groupByTemplateId() Group by the template_id column
* @method ChildAttributeTemplateQuery groupByPosition() Group by the position column
* @method ChildAttributeTemplateQuery groupByAttributeTemplatecol() Group by the attribute_templatecol column
* @method ChildAttributeTemplateQuery groupByCreatedAt() Group by the created_at column
* @method ChildAttributeTemplateQuery groupByUpdatedAt() Group by the updated_at column
*
@@ -54,6 +56,7 @@ use Thelia\Model\Map\AttributeTemplateTableMap;
* @method ChildAttributeTemplate findOneByAttributeId(int $attribute_id) Return the first ChildAttributeTemplate filtered by the attribute_id column
* @method ChildAttributeTemplate findOneByTemplateId(int $template_id) Return the first ChildAttributeTemplate filtered by the template_id column
* @method ChildAttributeTemplate findOneByPosition(int $position) Return the first ChildAttributeTemplate filtered by the position column
* @method ChildAttributeTemplate findOneByAttributeTemplatecol(string $attribute_templatecol) Return the first ChildAttributeTemplate filtered by the attribute_templatecol column
* @method ChildAttributeTemplate findOneByCreatedAt(string $created_at) Return the first ChildAttributeTemplate filtered by the created_at column
* @method ChildAttributeTemplate findOneByUpdatedAt(string $updated_at) Return the first ChildAttributeTemplate filtered by the updated_at column
*
@@ -61,6 +64,7 @@ use Thelia\Model\Map\AttributeTemplateTableMap;
* @method array findByAttributeId(int $attribute_id) Return ChildAttributeTemplate objects filtered by the attribute_id column
* @method array findByTemplateId(int $template_id) Return ChildAttributeTemplate objects filtered by the template_id column
* @method array findByPosition(int $position) Return ChildAttributeTemplate objects filtered by the position column
* @method array findByAttributeTemplatecol(string $attribute_templatecol) Return ChildAttributeTemplate objects filtered by the attribute_templatecol column
* @method array findByCreatedAt(string $created_at) Return ChildAttributeTemplate objects filtered by the created_at column
* @method array findByUpdatedAt(string $updated_at) Return ChildAttributeTemplate objects filtered by the updated_at column
*
@@ -151,7 +155,7 @@ abstract class AttributeTemplateQuery extends ModelCriteria
*/
protected function findPkSimple($key, $con)
{
$sql = 'SELECT ID, ATTRIBUTE_ID, TEMPLATE_ID, POSITION, CREATED_AT, UPDATED_AT FROM attribute_template WHERE ID = :p0';
$sql = 'SELECT ID, ATTRIBUTE_ID, TEMPLATE_ID, POSITION, ATTRIBUTE_TEMPLATECOL, CREATED_AT, UPDATED_AT FROM attribute_template WHERE ID = :p0';
try {
$stmt = $con->prepare($sql);
$stmt->bindValue(':p0', $key, PDO::PARAM_INT);
@@ -408,6 +412,35 @@ abstract class AttributeTemplateQuery extends ModelCriteria
return $this->addUsingAlias(AttributeTemplateTableMap::POSITION, $position, $comparison);
}
/**
* Filter the query on the attribute_templatecol column
*
* Example usage:
* <code>
* $query->filterByAttributeTemplatecol('fooValue'); // WHERE attribute_templatecol = 'fooValue'
* $query->filterByAttributeTemplatecol('%fooValue%'); // WHERE attribute_templatecol LIKE '%fooValue%'
* </code>
*
* @param string $attributeTemplatecol The value to use as filter.
* Accepts wildcards (* and % trigger a LIKE)
* @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL
*
* @return ChildAttributeTemplateQuery The current query, for fluid interface
*/
public function filterByAttributeTemplatecol($attributeTemplatecol = null, $comparison = null)
{
if (null === $comparison) {
if (is_array($attributeTemplatecol)) {
$comparison = Criteria::IN;
} elseif (preg_match('/[\%\*]/', $attributeTemplatecol)) {
$attributeTemplatecol = str_replace('*', '%', $attributeTemplatecol);
$comparison = Criteria::LIKE;
}
}
return $this->addUsingAlias(AttributeTemplateTableMap::ATTRIBUTE_TEMPLATECOL, $attributeTemplatecol, $comparison);
}
/**
* Filter the query on the created_at column
*

View File

@@ -25,4 +25,28 @@ class CategoryDocument extends BaseCategoryDocument
return true;
}
/**
* Set Document parent id
*
* @param int $parentId parent id
*
* @return $this
*/
public function setParentId($parentId)
{
$this->setCategoryId($parentId);
return $this;
}
/**
* Get Document parent id
*
* @return int parent id
*/
public function getParentId()
{
return $this->getCategoryId();
}
}

View File

@@ -2,6 +2,8 @@
namespace Thelia\Model;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Thelia\Model\Base\CategoryImage as BaseCategoryImage;
use Propel\Runtime\Connection\ConnectionInterface;
@@ -25,4 +27,29 @@ class CategoryImage extends BaseCategoryImage
return true;
}
/**
* Set Image parent id
*
* @param int $parentId parent id
*
* @return $this
*/
public function setParentId($parentId)
{
$this->setCategoryId($parentId);
return $this;
}
/**
* Get Image parent id
*
* @return int parent id
*/
public function getParentId()
{
return $this->getCategoryId();
}
}

View File

@@ -25,4 +25,28 @@ class ContentDocument extends BaseContentDocument
return true;
}
/**
* Set Document parent id
*
* @param int $parentId parent id
*
* @return $this
*/
public function setParentId($parentId)
{
$this->setContentId($parentId);
return $this;
}
/**
* Get Document parent id
*
* @return int parent id
*/
public function getParentId()
{
return $this->getContentId();
}
}

View File

@@ -25,4 +25,28 @@ class ContentImage extends BaseContentImage
return true;
}
/**
* Set Image parent id
*
* @param int $parentId parent id
*
* @return $this
*/
public function setParentId($parentId)
{
$this->setContentId($parentId);
return $this;
}
/**
* Get Image parent id
*
* @return int parent id
*/
public function getParentId()
{
return $this->getContentId();
}
}

View File

@@ -3,8 +3,66 @@
namespace Thelia\Model;
use Thelia\Model\Base\FeatureProduct as BaseFeatureProduct;
use Thelia\Core\Event\TheliaEvents;
use Propel\Runtime\Connection\ConnectionInterface;
use Thelia\Core\Event\FeatureProductEvent;
class FeatureProduct extends BaseFeatureProduct
class FeatureProduct extends BaseFeatureProduct
{
use \Thelia\Model\Tools\ModelEventDispatcherTrait;
/**
* {@inheritDoc}
*/
public function preInsert(ConnectionInterface $con = null)
{
$this->dispatchEvent(TheliaEvents::BEFORE_CREATEFEATURE_PRODUCT, new FeatureProductEvent($this));
return true;
}
/**
* {@inheritDoc}
*/
public function postInsert(ConnectionInterface $con = null)
{
$this->dispatchEvent(TheliaEvents::AFTER_CREATEFEATURE_PRODUCT, new FeatureProductEvent($this));
}
/**
* {@inheritDoc}
*/
public function preUpdate(ConnectionInterface $con = null)
{
$this->dispatchEvent(TheliaEvents::BEFORE_UPDATEFEATURE_PRODUCT, new FeatureProductEvent($this));
return true;
}
/**
* {@inheritDoc}
*/
public function postUpdate(ConnectionInterface $con = null)
{
$this->dispatchEvent(TheliaEvents::AFTER_UPDATEFEATURE_PRODUCT, new FeatureProductEvent($this));
}
/**
* {@inheritDoc}
*/
public function preDelete(ConnectionInterface $con = null)
{
$this->dispatchEvent(TheliaEvents::BEFORE_DELETEFEATURE_PRODUCT, new FeatureProductEvent($this));
return true;
}
/**
* {@inheritDoc}
*/
public function postDelete(ConnectionInterface $con = null)
{
$this->dispatchEvent(TheliaEvents::AFTER_DELETEFEATURE_PRODUCT, new FeatureProductEvent($this));
}
}

View File

@@ -3,8 +3,30 @@
namespace Thelia\Model;
use Thelia\Model\Base\FeatureTemplate as BaseFeatureTemplate;
use Propel\Runtime\Connection\ConnectionInterface;
class FeatureTemplate extends BaseFeatureTemplate
class FeatureTemplate extends BaseFeatureTemplate
{
use \Thelia\Model\Tools\ModelEventDispatcherTrait;
use \Thelia\Model\Tools\PositionManagementTrait;
/**
* Calculate next position relative to our template
*/
protected function addCriteriaToPositionQuery($query)
{
$query->filterByTemplateId($this->getTemplateId());
}
/**
* {@inheritDoc}
*/
public function preInsert(ConnectionInterface $con = null)
{
// Set the current position for the new object
$this->setPosition($this->getNextPosition());
return true;
}
}

View File

@@ -25,4 +25,28 @@ class FolderDocument extends BaseFolderDocument
return true;
}
/**
* Set Document parent id
*
* @param int $parentId parent id
*
* @return $this
*/
public function setParentId($parentId)
{
$this->setFolderId($parentId);
return $this;
}
/**
* Get Document parent id
*
* @return int parent id
*/
public function getParentId()
{
return $this->getFolderId();
}
}

View File

@@ -25,4 +25,28 @@ class FolderImage extends BaseFolderImage
return true;
}
/**
* Set Image parent id
*
* @param int $parentId parent id
*
* @return $this
*/
public function setParentId($parentId)
{
$this->setFolderId($parentId);
return $this;
}
/**
* Get Image parent id
*
* @return int parent id
*/
public function getParentId()
{
return $this->getFolderId();
}
}

View File

@@ -57,7 +57,7 @@ class AttributeTemplateTableMap extends TableMap
/**
* The total number of columns
*/
const NUM_COLUMNS = 6;
const NUM_COLUMNS = 7;
/**
* The number of lazy-loaded columns
@@ -67,7 +67,7 @@ class AttributeTemplateTableMap extends TableMap
/**
* The number of columns to hydrate (NUM_COLUMNS - NUM_LAZY_LOAD_COLUMNS)
*/
const NUM_HYDRATE_COLUMNS = 6;
const NUM_HYDRATE_COLUMNS = 7;
/**
* the column name for the ID field
@@ -89,6 +89,11 @@ class AttributeTemplateTableMap extends TableMap
*/
const POSITION = 'attribute_template.POSITION';
/**
* the column name for the ATTRIBUTE_TEMPLATECOL field
*/
const ATTRIBUTE_TEMPLATECOL = 'attribute_template.ATTRIBUTE_TEMPLATECOL';
/**
* the column name for the CREATED_AT field
*/
@@ -111,12 +116,12 @@ class AttributeTemplateTableMap extends TableMap
* e.g. self::$fieldNames[self::TYPE_PHPNAME][0] = 'Id'
*/
protected static $fieldNames = array (
self::TYPE_PHPNAME => array('Id', 'AttributeId', 'TemplateId', 'Position', 'CreatedAt', 'UpdatedAt', ),
self::TYPE_STUDLYPHPNAME => array('id', 'attributeId', 'templateId', 'position', 'createdAt', 'updatedAt', ),
self::TYPE_COLNAME => array(AttributeTemplateTableMap::ID, AttributeTemplateTableMap::ATTRIBUTE_ID, AttributeTemplateTableMap::TEMPLATE_ID, AttributeTemplateTableMap::POSITION, AttributeTemplateTableMap::CREATED_AT, AttributeTemplateTableMap::UPDATED_AT, ),
self::TYPE_RAW_COLNAME => array('ID', 'ATTRIBUTE_ID', 'TEMPLATE_ID', 'POSITION', 'CREATED_AT', 'UPDATED_AT', ),
self::TYPE_FIELDNAME => array('id', 'attribute_id', 'template_id', 'position', 'created_at', 'updated_at', ),
self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, )
self::TYPE_PHPNAME => array('Id', 'AttributeId', 'TemplateId', 'Position', 'AttributeTemplatecol', 'CreatedAt', 'UpdatedAt', ),
self::TYPE_STUDLYPHPNAME => array('id', 'attributeId', 'templateId', 'position', 'attributeTemplatecol', 'createdAt', 'updatedAt', ),
self::TYPE_COLNAME => array(AttributeTemplateTableMap::ID, AttributeTemplateTableMap::ATTRIBUTE_ID, AttributeTemplateTableMap::TEMPLATE_ID, AttributeTemplateTableMap::POSITION, AttributeTemplateTableMap::ATTRIBUTE_TEMPLATECOL, AttributeTemplateTableMap::CREATED_AT, AttributeTemplateTableMap::UPDATED_AT, ),
self::TYPE_RAW_COLNAME => array('ID', 'ATTRIBUTE_ID', 'TEMPLATE_ID', 'POSITION', 'ATTRIBUTE_TEMPLATECOL', 'CREATED_AT', 'UPDATED_AT', ),
self::TYPE_FIELDNAME => array('id', 'attribute_id', 'template_id', 'position', 'attribute_templatecol', 'created_at', 'updated_at', ),
self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, )
);
/**
@@ -126,12 +131,12 @@ class AttributeTemplateTableMap extends TableMap
* e.g. self::$fieldKeys[self::TYPE_PHPNAME]['Id'] = 0
*/
protected static $fieldKeys = array (
self::TYPE_PHPNAME => array('Id' => 0, 'AttributeId' => 1, 'TemplateId' => 2, 'Position' => 3, 'CreatedAt' => 4, 'UpdatedAt' => 5, ),
self::TYPE_STUDLYPHPNAME => array('id' => 0, 'attributeId' => 1, 'templateId' => 2, 'position' => 3, 'createdAt' => 4, 'updatedAt' => 5, ),
self::TYPE_COLNAME => array(AttributeTemplateTableMap::ID => 0, AttributeTemplateTableMap::ATTRIBUTE_ID => 1, AttributeTemplateTableMap::TEMPLATE_ID => 2, AttributeTemplateTableMap::POSITION => 3, AttributeTemplateTableMap::CREATED_AT => 4, AttributeTemplateTableMap::UPDATED_AT => 5, ),
self::TYPE_RAW_COLNAME => array('ID' => 0, 'ATTRIBUTE_ID' => 1, 'TEMPLATE_ID' => 2, 'POSITION' => 3, 'CREATED_AT' => 4, 'UPDATED_AT' => 5, ),
self::TYPE_FIELDNAME => array('id' => 0, 'attribute_id' => 1, 'template_id' => 2, 'position' => 3, 'created_at' => 4, 'updated_at' => 5, ),
self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, )
self::TYPE_PHPNAME => array('Id' => 0, 'AttributeId' => 1, 'TemplateId' => 2, 'Position' => 3, 'AttributeTemplatecol' => 4, 'CreatedAt' => 5, 'UpdatedAt' => 6, ),
self::TYPE_STUDLYPHPNAME => array('id' => 0, 'attributeId' => 1, 'templateId' => 2, 'position' => 3, 'attributeTemplatecol' => 4, 'createdAt' => 5, 'updatedAt' => 6, ),
self::TYPE_COLNAME => array(AttributeTemplateTableMap::ID => 0, AttributeTemplateTableMap::ATTRIBUTE_ID => 1, AttributeTemplateTableMap::TEMPLATE_ID => 2, AttributeTemplateTableMap::POSITION => 3, AttributeTemplateTableMap::ATTRIBUTE_TEMPLATECOL => 4, AttributeTemplateTableMap::CREATED_AT => 5, AttributeTemplateTableMap::UPDATED_AT => 6, ),
self::TYPE_RAW_COLNAME => array('ID' => 0, 'ATTRIBUTE_ID' => 1, 'TEMPLATE_ID' => 2, 'POSITION' => 3, 'ATTRIBUTE_TEMPLATECOL' => 4, 'CREATED_AT' => 5, 'UPDATED_AT' => 6, ),
self::TYPE_FIELDNAME => array('id' => 0, 'attribute_id' => 1, 'template_id' => 2, 'position' => 3, 'attribute_templatecol' => 4, 'created_at' => 5, 'updated_at' => 6, ),
self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, )
);
/**
@@ -155,6 +160,7 @@ class AttributeTemplateTableMap extends TableMap
$this->addForeignKey('ATTRIBUTE_ID', 'AttributeId', 'INTEGER', 'attribute', 'ID', true, null, null);
$this->addForeignKey('TEMPLATE_ID', 'TemplateId', 'INTEGER', 'template', 'ID', true, null, null);
$this->addColumn('POSITION', 'Position', 'INTEGER', false, null, null);
$this->addColumn('ATTRIBUTE_TEMPLATECOL', 'AttributeTemplatecol', 'VARCHAR', false, 45, null);
$this->addColumn('CREATED_AT', 'CreatedAt', 'TIMESTAMP', false, null, null);
$this->addColumn('UPDATED_AT', 'UpdatedAt', 'TIMESTAMP', false, null, null);
} // initialize()
@@ -323,6 +329,7 @@ class AttributeTemplateTableMap extends TableMap
$criteria->addSelectColumn(AttributeTemplateTableMap::ATTRIBUTE_ID);
$criteria->addSelectColumn(AttributeTemplateTableMap::TEMPLATE_ID);
$criteria->addSelectColumn(AttributeTemplateTableMap::POSITION);
$criteria->addSelectColumn(AttributeTemplateTableMap::ATTRIBUTE_TEMPLATECOL);
$criteria->addSelectColumn(AttributeTemplateTableMap::CREATED_AT);
$criteria->addSelectColumn(AttributeTemplateTableMap::UPDATED_AT);
} else {
@@ -330,6 +337,7 @@ class AttributeTemplateTableMap extends TableMap
$criteria->addSelectColumn($alias . '.ATTRIBUTE_ID');
$criteria->addSelectColumn($alias . '.TEMPLATE_ID');
$criteria->addSelectColumn($alias . '.POSITION');
$criteria->addSelectColumn($alias . '.ATTRIBUTE_TEMPLATECOL');
$criteria->addSelectColumn($alias . '.CREATED_AT');
$criteria->addSelectColumn($alias . '.UPDATED_AT');
}

View File

@@ -87,12 +87,46 @@ class Product extends BaseProduct
return $this;
}
public function updateDefaultCategory($defaultCategoryId) {
// Allow uncategorized products (NULL instead of 0, to bypass delete cascade constraint)
if ($defaultCategoryId <= 0) $defaultCategoryId = NULL;
// Update the default category
$productCategory = ProductCategoryQuery::create()
->filterByProductId($this->getId())
->filterByDefaultCategory(true)
->findOne()
;
if ($productCategory == null || $productCategory->getCategoryId() != $defaultCategoryId) {
exit;
// Delete the old default category
if ($productCategory !== null) $productCategory->delete();
// Add the new default category
$productCategory = new ProductCategory();
$productCategory
->setProduct($this)
->setCategoryId($defaultCategoryId)
->setDefaultCategory(true)
->save()
;
}
}
/**
* Create a new product, along with the default category ID
*
* @param int $defaultCategoryId the default category ID of this product
* @param float $basePrice the product base price
* @param int $priceCurrencyId the price currency Id
* @param int $taxRuleId the product tax rule ID
* @param float $baseWeight base weight in Kg
*/
public function create($defaultCategoryId) {
public function create($defaultCategoryId, $basePrice, $priceCurrencyId, $taxRuleId, $baseWeight) {
$con = Propel::getWriteConnection(ProductTableMap::DATABASE_NAME);
@@ -105,18 +139,13 @@ class Product extends BaseProduct
$this->save($con);
// Add the default category
$pc = new ProductCategory();
$pc
->setProduct($this)
->setCategoryId($defaultCategoryId)
->setDefaultCategory(true)
->save($con)
;
$this->updateDefaultCategory($defaultCategoryId);
// Set the position
$this->setPosition($this->getNextPosition())->save($con);
$this->setTaxRuleId($taxRuleId);
// Create an empty product sale element
$sale_elements = new ProductSaleElements();
@@ -125,7 +154,8 @@ class Product extends BaseProduct
->setRef($this->getRef())
->setPromo(0)
->setNewness(0)
->setWeight(0)
->setWeight($baseWeight)
->setIsDefault(true)
->save($con)
;
@@ -134,9 +164,9 @@ class Product extends BaseProduct
$product_price
->setProductSaleElements($sale_elements)
->setPromoPrice(0)
->setPrice(0)
->setCurrency(CurrencyQuery::create()->findOneByByDefault(true))
->setPromoPrice($basePrice)
->setPrice($basePrice)
->setCurrencyId($priceCurrencyId)
->save($con)
;

View File

@@ -11,11 +11,22 @@ class ProductAssociatedContent extends BaseProductAssociatedContent {
use \Thelia\Model\Tools\ModelEventDispatcherTrait;
use \Thelia\Model\Tools\PositionManagementTrait;
/**
* Calculate next position relative to our product
*/
protected function addCriteriaToPositionQuery($query) {
$query->filterByProductId($this->getProductId());
}
/**
* {@inheritDoc}
*/
public function preInsert(ConnectionInterface $con = null)
{
$this->setPosition($this->getNextPosition());
$this->dispatchEvent(TheliaEvents::BEFORE_CREATEPRODUCT_ASSOCIATED_CONTENT, new ProductAssociatedContentEvent($this));
return true;

View File

@@ -26,4 +26,28 @@ class ProductDocument extends BaseProductDocument
return true;
}
/**
* Set Document parent id
*
* @param int $parentId parent id
*
* @return $this
*/
public function setParentId($parentId)
{
$this->setProductId($parentId);
return $this;
}
/**
* Get Document parent id
*
* @return int parent id
*/
public function getParentId()
{
return $this->getProductId();
}
}

View File

@@ -25,4 +25,28 @@ class ProductImage extends BaseProductImage
return true;
}
/**
* Set Image parent id
*
* @param int $parentId parent id
*
* @return $this
*/
public function setParentId($parentId)
{
$this->setProductId($parentId);
return $this;
}
/**
* Get Image parent id
*
* @return int parent id
*/
public function getParentId()
{
return $this->getProductId();
}
}

View File

@@ -126,7 +126,8 @@ trait PositionManagementTrait {
$result->setDispatcher($this->getDispatcher())->setPosition($my_position)->save();
$cnx->commit();
} catch (Exception $e) {
}
catch (Exception $e) {
$cnx->rollback();
}
}
@@ -179,7 +180,10 @@ trait PositionManagementTrait {
try {
foreach ($results as $result) {
$result->setDispatcher($this->getDispatcher())->setPosition($result->getPosition() + $delta)->save($cnx);
$objNewPosition = $result->getPosition() + $delta;
$result->setDispatcher($this->getDispatcher())->setPosition($objNewPosition)->save($cnx);
}
$this
@@ -188,7 +192,8 @@ trait PositionManagementTrait {
;
$cnx->commit();
} catch (Exception $e) {
}
catch (Exception $e) {
$cnx->rollback();
}
}

View File

@@ -0,0 +1,906 @@
<?php
/**
* Created by JetBrains PhpStorm.
* Date: 9/18/13
* Time: 8:47 PM
*
* @author Guillaume MOREL <gmorel@openstudio.fr>
*/
namespace Thelia\Tests\Type;
use Thelia\Core\Event\DocumentCreateOrUpdateEvent;
use Thelia\Core\Event\ImageCreateOrUpdateEvent;
use Thelia\Core\Translation\Translator;
use Thelia\Exception\ImageException;
use Thelia\Model\Admin;
use Thelia\Tools\FileManager;
/**
* Class FileManagerTest
*
* @package Thelia\Tests\Type
*/
class FileManagerTest extends \PHPUnit_Framework_TestCase {
/**
* @covers Thelia\Tools\FileManager::copyUploadedFile
*/
public function testCopyUploadedFile()
{
$this->markTestIncomplete(
'Mock issue'
);
$stubTranslator = $this->getMockBuilder('\Thelia\Core\Translation\Translator')
->disableOriginalConstructor()
->getMock();
$stubTranslator->expects($this->any())
->method('trans')
->will($this->returnValue('translated'));
$stubRequest = $this->getMockBuilder('\Thelia\Core\HttpFoundation\Request')
->disableOriginalConstructor()
->getMock();
$stubSecurity = $this->getMockBuilder('\Thelia\Core\Security\SecurityContext')
->disableOriginalConstructor()
->getMock();
$stubSecurity->expects($this->any())
->method('getAdminUser')
->will($this->returnValue(new Admin()));
// Create a map of arguments to return values.
$map = array(
array('thelia.translator', $stubTranslator),
array('request', $stubRequest),
array('thelia.securityContext', $stubSecurity)
);
$stubContainer = $this->getMockBuilder('\Symfony\Component\DependencyInjection\ContainerInterface')
->disableOriginalConstructor()
->getMock();
$stubContainer->expects($this->any())
->method('get')
->will($this->returnValueMap($map));
$stubProductImage = $this->getMockBuilder('\Thelia\Model\ProductImage')
->disableOriginalConstructor()
->getMock();
$stubProductImage->expects($this->any())
->method('getUploadDir')
->will($this->returnValue(THELIA_LOCAL_DIR . 'media/images/product'));
$stubProductImage->expects($this->any())
->method('getId')
->will($this->returnValue(42));
$stubProductImage->expects($this->any())
->method('setFile')
->will($this->returnValue(true));
$stubProductImage->expects($this->any())
->method('save')
->will($this->returnValue(0));
$stubUploadedFile = $this->getMockBuilder('\Symfony\Component\HttpFoundation\File\UploadedFile')
->disableOriginalConstructor()
->getMock();
$stubUploadedFile->expects($this->any())
->method('getClientOriginalName')
->will($this->returnValue('goodName'));
$stubUploadedFile->expects($this->any())
->method('getClientOriginalExtension')
->will($this->returnValue('png'));
$stubUploadedFile->expects($this->any())
->method('move')
->will($this->returnValue($stubUploadedFile));
$fileManager = new FileManager($stubContainer);
$newUploadedFiles = array();
$actual = $fileManager->copyUploadedFile(24, FileManager::TYPE_PRODUCT, $stubProductImage, $stubUploadedFile, $newUploadedFiles, FileManager::FILE_TYPE_IMAGES);
$this->assertCount(1, $actual);
}
/**
* @covers Thelia\Tools\FileManager::copyUploadedFile
* @expectedException \Thelia\Exception\ImageException
*/
public function testCopyUploadedFileExceptionImageException()
{
$this->markTestIncomplete(
'Mock issue'
);
$stubTranslator = $this->getMockBuilder('\Thelia\Core\Translation\Translator')
->disableOriginalConstructor()
->getMock();
$stubTranslator->expects($this->any())
->method('trans')
->will($this->returnValue('translated'));
$stubRequest = $this->getMockBuilder('\Thelia\Core\HttpFoundation\Request')
->disableOriginalConstructor()
->getMock();
$stubSecurity = $this->getMockBuilder('\Thelia\Core\Security\SecurityContext')
->disableOriginalConstructor()
->getMock();
$stubSecurity->expects($this->any())
->method('getAdminUser')
->will($this->returnValue(new Admin()));
// Create a map of arguments to return values.
$map = array(
array('thelia.translator', $stubTranslator),
array('request', $stubRequest),
array('thelia.securityContext', $stubSecurity)
);
$stubContainer = $this->getMockBuilder('\Symfony\Component\DependencyInjection\ContainerInterface')
->disableOriginalConstructor()
->getMock();
$stubContainer->expects($this->any())
->method('get')
->will($this->returnValueMap($map));
$stubProductImage = $this->getMockBuilder('\Thelia\Model\ProductImage')
->disableOriginalConstructor()
->getMock();
$stubProductImage->expects($this->any())
->method('getUploadDir')
->will($this->returnValue(THELIA_LOCAL_DIR . 'media/images/product'));
$stubProductImage->expects($this->any())
->method('getId')
->will($this->returnValue(42));
$stubProductImage->expects($this->any())
->method('setFile')
->will($this->returnValue(true));
$stubProductImage->expects($this->any())
->method('save')
->will($this->returnValue(0));
$stubUploadedFile = $this->getMockBuilder('\Symfony\Component\HttpFoundation\File\UploadedFile')
->disableOriginalConstructor()
->getMock();
$stubUploadedFile->expects($this->any())
->method('getClientOriginalName')
->will($this->returnValue('goodName'));
$stubUploadedFile->expects($this->any())
->method('getClientOriginalExtension')
->will($this->returnValue('png'));
$stubUploadedFile->expects($this->any())
->method('move')
->will($this->returnValue($stubUploadedFile));
$fileManager = new FileManager($stubContainer);
$newUploadedFiles = array();
$actual = $fileManager->copyUploadedFile(24, FileManager::TYPE_PRODUCT, $stubProductImage, $stubUploadedFile, $newUploadedFiles, FileManager::FILE_TYPE_DOCUMENTS);
}
/**
* @covers Thelia\Tools\FileManager::saveImage
*/
public function testSaveImageProductImage()
{
$stubContainer = $this->getMockBuilder('\Symfony\Component\DependencyInjection\ContainerInterface')
->disableOriginalConstructor()
->getMock();
$stubProductImage = $this->getMockBuilder('\Thelia\Model\ProductImage')
->disableOriginalConstructor()
->getMock();
$stubProductImage->expects($this->any())
->method('save')
->will($this->returnValue(10));
$stubProductImage->expects($this->any())
->method('getFile')
->will($this->returnValue('file'));
$fileManager = new FileManager($stubContainer);
$event = new ImageCreateOrUpdateEvent(FileManager::TYPE_PRODUCT, 24);
$expected = 10;
$actual = $fileManager->saveImage($event, $stubProductImage);
$this->assertEquals($expected, $actual);
}
/**
* @covers Thelia\Tools\FileManager::saveDocument
*/
public function testSaveDocumentProductDocument()
{
$stubContainer = $this->getMockBuilder('\Symfony\Component\DependencyInjection\ContainerInterface')
->disableOriginalConstructor()
->getMock();
$stubProductDocument = $this->getMockBuilder('\Thelia\Model\ProductDocument')
->disableOriginalConstructor()
->getMock();
$stubProductDocument->expects($this->any())
->method('save')
->will($this->returnValue(10));
$stubProductDocument->expects($this->any())
->method('getFile')
->will($this->returnValue('file'));
$fileManager = new FileManager($stubContainer);
$event = new DocumentCreateOrUpdateEvent(FileManager::TYPE_PRODUCT, 24);
$expected = 10;
$actual = $fileManager->saveDocument($event, $stubProductDocument);
$this->assertEquals($expected, $actual);
}
/**
* @covers Thelia\Tools\FileManager::saveImage
*/
public function testSaveImageCategoryImage()
{
$stubContainer = $this->getMockBuilder('\Symfony\Component\DependencyInjection\ContainerInterface')
->disableOriginalConstructor()
->getMock();
$stubCategoryImage = $this->getMockBuilder('\Thelia\Model\CategoryImage')
->disableOriginalConstructor()
->getMock();
$stubCategoryImage->expects($this->any())
->method('save')
->will($this->returnValue(10));
$stubCategoryImage->expects($this->any())
->method('getFile')
->will($this->returnValue('file'));
$fileManager = new FileManager($stubContainer);
$event = new ImageCreateOrUpdateEvent(FileManager::TYPE_CATEGORY, 24);
$expected = 10;
$actual = $fileManager->saveImage($event, $stubCategoryImage);
$this->assertEquals($expected, $actual);
}
/**
* @covers Thelia\Tools\FileManager::saveDocument
*/
public function testSaveDocumentCategoryDocument()
{
$stubContainer = $this->getMockBuilder('\Symfony\Component\DependencyInjection\ContainerInterface')
->disableOriginalConstructor()
->getMock();
$stubCategoryDocument = $this->getMockBuilder('\Thelia\Model\CategoryDocument')
->disableOriginalConstructor()
->getMock();
$stubCategoryDocument->expects($this->any())
->method('save')
->will($this->returnValue(10));
$stubCategoryDocument->expects($this->any())
->method('getFile')
->will($this->returnValue('file'));
$fileManager = new FileManager($stubContainer);
$event = new DocumentCreateOrUpdateEvent(FileManager::TYPE_CATEGORY, 24);
$expected = 10;
$actual = $fileManager->saveDocument($event, $stubCategoryDocument);
$this->assertEquals($expected, $actual);
}
/**
* @covers Thelia\Tools\FileManager::saveImage
*/
public function testSaveImageFolderImage()
{
$stubContainer = $this->getMockBuilder('\Symfony\Component\DependencyInjection\ContainerInterface')
->disableOriginalConstructor()
->getMock();
$stubFolderImage = $this->getMockBuilder('\Thelia\Model\FolderImage')
->disableOriginalConstructor()
->getMock();
$stubFolderImage->expects($this->any())
->method('save')
->will($this->returnValue(10));
$stubFolderImage->expects($this->any())
->method('getFile')
->will($this->returnValue('file'));
$fileManager = new FileManager($stubContainer);
$event = new ImageCreateOrUpdateEvent(FileManager::TYPE_FOLDER, 24);
$expected = 10;
$actual = $fileManager->saveImage($event, $stubFolderImage);
$this->assertEquals($expected, $actual);
}
/**
* @covers Thelia\Tools\FileManager::saveDocument
*/
public function testSaveDocumentFolderDocument()
{
$stubContainer = $this->getMockBuilder('\Symfony\Component\DependencyInjection\ContainerInterface')
->disableOriginalConstructor()
->getMock();
$stubFolderDocument = $this->getMockBuilder('\Thelia\Model\FolderDocument')
->disableOriginalConstructor()
->getMock();
$stubFolderDocument->expects($this->any())
->method('save')
->will($this->returnValue(10));
$stubFolderDocument->expects($this->any())
->method('getFile')
->will($this->returnValue('file'));
$fileManager = new FileManager($stubContainer);
$event = new DocumentCreateOrUpdateEvent(FileManager::TYPE_FOLDER, 24);
$expected = 10;
$actual = $fileManager->saveDocument($event, $stubFolderDocument);
$this->assertEquals($expected, $actual);
}
/**
* @covers Thelia\Tools\FileManager::saveImage
*/
public function testSaveImageContentImage()
{
$stubContainer = $this->getMockBuilder('\Symfony\Component\DependencyInjection\ContainerInterface')
->disableOriginalConstructor()
->getMock();
$stubContentImage = $this->getMockBuilder('\Thelia\Model\ContentImage')
->disableOriginalConstructor()
->getMock();
$stubContentImage->expects($this->any())
->method('save')
->will($this->returnValue(10));
$stubContentImage->expects($this->any())
->method('getFile')
->will($this->returnValue('file'));
$fileManager = new FileManager($stubContainer);
$event = new ImageCreateOrUpdateEvent(FileManager::TYPE_CONTENT, 24);
$expected = 10;
$actual = $fileManager->saveImage($event, $stubContentImage);
$this->assertEquals($expected, $actual);
}
/**
* @covers Thelia\Tools\FileManager::saveDocument
*/
public function testSaveDocumentContentDocument()
{
$stubContainer = $this->getMockBuilder('\Symfony\Component\DependencyInjection\ContainerInterface')
->disableOriginalConstructor()
->getMock();
$stubContentDocument = $this->getMockBuilder('\Thelia\Model\ContentDocument')
->disableOriginalConstructor()
->getMock();
$stubContentDocument->expects($this->any())
->method('save')
->will($this->returnValue(10));
$stubContentDocument->expects($this->any())
->method('getFile')
->will($this->returnValue('file'));
$fileManager = new FileManager($stubContainer);
$event = new DocumentCreateOrUpdateEvent(FileManager::TYPE_CONTENT, 24);
$expected = 10;
$actual = $fileManager->saveDocument($event, $stubContentDocument);
$this->assertEquals($expected, $actual);
}
/**
* @covers Thelia\Tools\FileManager::saveImage
* @expectedException \Thelia\Exception\ImageException
*/
public function testSaveImageExceptionImageException()
{
$stubContainer = $this->getMockBuilder('\Symfony\Component\DependencyInjection\ContainerInterface')
->disableOriginalConstructor()
->getMock();
$fileManager = new FileManager($stubContainer);
$stubProductImage = $this->getMockBuilder('\Thelia\Model\ProductImage')
->disableOriginalConstructor()
->getMock();
$stubProductImage->expects($this->any())
->method('save')
->will($this->returnValue(10));
$stubProductImage->expects($this->any())
->method('getFile')
->will($this->returnValue('file'));
$event = new ImageCreateOrUpdateEvent('bad', 24);
$fileManager->saveImage($event, $stubProductImage);
}
/**
* @covers Thelia\Tools\FileManager::saveDocument
* @expectedException \Thelia\Model\Exception\InvalidArgumentException
*/
public function testSaveDocumentExceptionDocumentException()
{
$stubContainer = $this->getMockBuilder('\Symfony\Component\DependencyInjection\ContainerInterface')
->disableOriginalConstructor()
->getMock();
$fileManager = new FileManager($stubContainer);
$stubProductDocument = $this->getMockBuilder('\Thelia\Model\ProductDocument')
->disableOriginalConstructor()
->getMock();
$stubProductDocument->expects($this->any())
->method('save')
->will($this->returnValue(10));
$stubProductDocument->expects($this->any())
->method('getFile')
->will($this->returnValue('file'));
$event = new DocumentCreateOrUpdateEvent('bad', 24);
$fileManager->saveDocument($event, $stubProductDocument);
}
/**
* @covers Thelia\Tools\FileManager::saveImage
* @expectedException \Thelia\Exception\ImageException
*/
public function testSaveImageExceptionImageException2()
{
$stubContainer = $this->getMockBuilder('\Symfony\Component\DependencyInjection\ContainerInterface')
->disableOriginalConstructor()
->getMock();
$fileManager = new FileManager($stubContainer);
$stubProductImage = $this->getMockBuilder('\Thelia\Model\ProductImage')
->disableOriginalConstructor()
->getMock();
$stubProductImage->expects($this->any())
->method('save')
->will($this->returnValue(0));
$stubProductImage->expects($this->any())
->method('getFile')
->will($this->returnValue('file'));
$event = new ImageCreateOrUpdateEvent(FileManager::TYPE_PRODUCT, 24);
$fileManager->saveImage($event, $stubProductImage);
}
/**
* @covers Thelia\Tools\FileManager::saveDocument
* @expectedException \Thelia\Model\Exception\InvalidArgumentException
*/
public function testSaveDocumentExceptionDocumentException2()
{
$stubContainer = $this->getMockBuilder('\Symfony\Component\DependencyInjection\ContainerInterface')
->disableOriginalConstructor()
->getMock();
$fileManager = new FileManager($stubContainer);
$stubProductDocument = $this->getMockBuilder('\Thelia\Model\ProductDocument')
->disableOriginalConstructor()
->getMock();
$stubProductDocument->expects($this->any())
->method('save')
->will($this->returnValue(0));
$stubProductDocument->expects($this->any())
->method('getFile')
->will($this->returnValue('file'));
$event = new DocumentCreateOrUpdateEvent(FileManager::TYPE_PRODUCT, 24);
$fileManager->saveDocument($event, $stubProductDocument);
}
/**
* @covers Thelia\Tools\FileManager::sanitizeFileName
*/
public function testSanitizeFileName()
{
$stubContainer = $this->getMockBuilder('\Symfony\Component\DependencyInjection\ContainerInterface')
->disableOriginalConstructor()
->getMock();
$fileManager = new FileManager($stubContainer);
$badFileName = 'a/ze\érà~çè§^"$*+-_°)(&é<>@#ty2/[\/:*?"<>|]/fi?.fUPPERile.exel../e*';
$expected = 'azer-_ty2fi.fupperile.exel..e';
$actual = $fileManager->sanitizeFileName($badFileName);
$this->assertEquals($expected, $actual);
}
/**
* @covers Thelia\Tools\FileManager::getImageModel
*/
public function testGetImageModel()
{
$stubContainer = $this->getMockBuilder('\Symfony\Component\DependencyInjection\ContainerInterface')
->disableOriginalConstructor()
->getMock();
$fileManager = new FileManager($stubContainer);
$actual = $fileManager->getImageModel(FileManager::TYPE_PRODUCT);
$this->assertInstanceOf('\Thelia\Model\ProductImage', $actual);
$actual = $fileManager->getImageModel(FileManager::TYPE_CATEGORY);
$this->assertInstanceOf('\Thelia\Model\CategoryImage', $actual);
$actual = $fileManager->getImageModel(FileManager::TYPE_CONTENT);
$this->assertInstanceOf('\Thelia\Model\ContentImage', $actual);
$actual = $fileManager->getImageModel(FileManager::TYPE_FOLDER);
$this->assertInstanceOf('\Thelia\Model\FolderImage', $actual);
$actual = $fileManager->getImageModel('bad');
$this->assertNull($actual);
}
/**
* @covers Thelia\Tools\FileManager::getDocumentModel
*/
public function testGetDocumentModel()
{
$stubContainer = $this->getMockBuilder('\Symfony\Component\DependencyInjection\ContainerInterface')
->disableOriginalConstructor()
->getMock();
$fileManager = new FileManager($stubContainer);
$actual = $fileManager->getDocumentModel(FileManager::TYPE_PRODUCT);
$this->assertInstanceOf('\Thelia\Model\ProductDocument', $actual);
$actual = $fileManager->getDocumentModel(FileManager::TYPE_CATEGORY);
$this->assertInstanceOf('\Thelia\Model\CategoryDocument', $actual);
$actual = $fileManager->getDocumentModel(FileManager::TYPE_CONTENT);
$this->assertInstanceOf('\Thelia\Model\ContentDocument', $actual);
$actual = $fileManager->getDocumentModel(FileManager::TYPE_FOLDER);
$this->assertInstanceOf('\Thelia\Model\FolderDocument', $actual);
$actual = $fileManager->getDocumentModel('bad');
$this->assertNull($actual);
}
/**
* @covers Thelia\Tools\FileManager::getImageModelQuery
*/
public function testGetImageModelQuery()
{
$stubContainer = $this->getMockBuilder('\Symfony\Component\DependencyInjection\ContainerInterface')
->disableOriginalConstructor()
->getMock();
$fileManager = new FileManager($stubContainer);
$actual = $fileManager->getImageModelQuery(FileManager::TYPE_PRODUCT);
$this->assertInstanceOf('\Thelia\Model\ProductImageQuery', $actual);
$actual = $fileManager->getImageModelQuery(FileManager::TYPE_CATEGORY);
$this->assertInstanceOf('\Thelia\Model\CategoryImageQuery', $actual);
$actual = $fileManager->getImageModelQuery(FileManager::TYPE_CONTENT);
$this->assertInstanceOf('\Thelia\Model\ContentImageQuery', $actual);
$actual = $fileManager->getImageModelQuery(FileManager::TYPE_FOLDER);
$this->assertInstanceOf('\Thelia\Model\FolderImageQuery', $actual);
$actual = $fileManager->getImageModelQuery('bad');
$this->assertNull($actual);
}
/**
* @covers Thelia\Tools\FileManager::getDocumentModelQuery
*/
public function testGetDocumentModelQuery()
{
$stubContainer = $this->getMockBuilder('\Symfony\Component\DependencyInjection\ContainerInterface')
->disableOriginalConstructor()
->getMock();
$fileManager = new FileManager($stubContainer);
$actual = $fileManager->getDocumentModelQuery(FileManager::TYPE_PRODUCT);
$this->assertInstanceOf('\Thelia\Model\ProductDocumentQuery', $actual);
$actual = $fileManager->getDocumentModelQuery(FileManager::TYPE_CATEGORY);
$this->assertInstanceOf('\Thelia\Model\CategoryDocumentQuery', $actual);
$actual = $fileManager->getDocumentModelQuery(FileManager::TYPE_CONTENT);
$this->assertInstanceOf('\Thelia\Model\ContentDocumentQuery', $actual);
$actual = $fileManager->getDocumentModelQuery(FileManager::TYPE_FOLDER);
$this->assertInstanceOf('\Thelia\Model\FolderDocumentQuery', $actual);
$actual = $fileManager->getDocumentModelQuery('bad');
$this->assertNull($actual);
}
/**
* @covers Thelia\Tools\FileManager::getParentFileModel
*/
public function testGetParentFileModel()
{
$stubContainer = $this->getMockBuilder('\Symfony\Component\DependencyInjection\ContainerInterface')
->disableOriginalConstructor()
->getMock();
$fileManager = new FileManager($stubContainer);
$actual = $fileManager->getParentFileModel(FileManager::TYPE_PRODUCT, 1);
$this->assertInstanceOf('\Thelia\Model\Product', $actual);
$actual = $fileManager->getParentFileModel(FileManager::TYPE_CATEGORY, 1);
$this->assertInstanceOf('\Thelia\Model\Category', $actual);
$actual = $fileManager->getParentFileModel(FileManager::TYPE_CONTENT, 1);
$this->assertInstanceOf('\Thelia\Model\Content', $actual);
$actual = $fileManager->getParentFileModel(FileManager::TYPE_FOLDER, 1);
$this->assertInstanceOf('\Thelia\Model\Folder', $actual, 1);
$actual = $fileManager->getParentFileModel('bad', 1);
$this->assertNull($actual);
}
/**
* @covers Thelia\Tools\FileManager::getImageForm
*/
public function testGetImageForm()
{
// Mock issue
$this->markTestIncomplete(
'This test has not been implemented yet.'
);
}
/**
* @covers Thelia\Tools\FileManager::getDocumentForm
*/
public function testGetDocumentForm()
{
// Mock issue
$this->markTestIncomplete(
'This test has not been implemented yet.'
);
}
/**
* @covers Thelia\Tools\FileManager::getUploadDir
*/
public function testGetUploadDir()
{
$stubContainer = $this->getMockBuilder('\Symfony\Component\DependencyInjection\ContainerInterface')
->disableOriginalConstructor()
->getMock();
$fileManager = new FileManager($stubContainer);
$actual = $fileManager->getUploadDir(FileManager::TYPE_PRODUCT, FileManager::FILE_TYPE_IMAGES);
$this->assertEquals(THELIA_LOCAL_DIR . 'media/images/product', $actual);
$actual = $fileManager->getUploadDir(FileManager::TYPE_CATEGORY, FileManager::FILE_TYPE_IMAGES);
$this->assertEquals(THELIA_LOCAL_DIR . 'media/images/category', $actual);
$actual = $fileManager->getUploadDir(FileManager::TYPE_CONTENT, FileManager::FILE_TYPE_IMAGES);
$this->assertEquals(THELIA_LOCAL_DIR . 'media/images/content', $actual);
$actual = $fileManager->getUploadDir(FileManager::TYPE_FOLDER, FileManager::FILE_TYPE_IMAGES);
$this->assertEquals(THELIA_LOCAL_DIR . 'media/images/folder', $actual);
$actual = $fileManager->getUploadDir('bad', FileManager::FILE_TYPE_IMAGES);
$this->assertEquals(false, $actual);
$actual = $fileManager->getUploadDir(FileManager::TYPE_PRODUCT, FileManager::FILE_TYPE_DOCUMENTS);
$this->assertEquals(THELIA_LOCAL_DIR . 'media/documents/product', $actual);
$actual = $fileManager->getUploadDir(FileManager::TYPE_CATEGORY, FileManager::FILE_TYPE_DOCUMENTS);
$this->assertEquals(THELIA_LOCAL_DIR . 'media/documents/category', $actual);
$actual = $fileManager->getUploadDir(FileManager::TYPE_CONTENT, FileManager::FILE_TYPE_DOCUMENTS);
$this->assertEquals(THELIA_LOCAL_DIR . 'media/documents/content', $actual);
$actual = $fileManager->getUploadDir(FileManager::TYPE_FOLDER, FileManager::FILE_TYPE_DOCUMENTS);
$this->assertEquals(THELIA_LOCAL_DIR . 'media/documents/folder', $actual);
$actual = $fileManager->getUploadDir('bad', FileManager::FILE_TYPE_DOCUMENTS);
$this->assertEquals(false, $actual);
$actual = $fileManager->getUploadDir(FileManager::TYPE_FOLDER, 'bad');
$this->assertEquals(false, $actual);
}
/**
* @covers Thelia\Tools\FileManager::getRedirectionUrl
*/
public function testGetRedirectionUrl()
{
$stubContainer = $this->getMockBuilder('\Symfony\Component\DependencyInjection\ContainerInterface')
->disableOriginalConstructor()
->getMock();
$fileManager = new FileManager($stubContainer);
$actual = $fileManager->getRedirectionUrl(FileManager::TYPE_PRODUCT, 1, FileManager::FILE_TYPE_IMAGES);
$this->assertEquals('/admin/products/update?product_id=1&current_tab=images', $actual);
$actual = $fileManager->getRedirectionUrl(FileManager::TYPE_CATEGORY, 1, FileManager::FILE_TYPE_IMAGES);
$this->assertEquals('/admin/categories/update?category_id=1&current_tab=images', $actual);
$actual = $fileManager->getRedirectionUrl(FileManager::TYPE_CONTENT, 1, FileManager::FILE_TYPE_IMAGES);
$this->assertEquals('/admin/content/update/1?current_tab=images', $actual);
$actual = $fileManager->getRedirectionUrl(FileManager::TYPE_FOLDER, 1, FileManager::FILE_TYPE_IMAGES);
$this->assertEquals('/admin/folders/update/1?current_tab=images', $actual);
$actual = $fileManager->getRedirectionUrl('bad', 1, FileManager::FILE_TYPE_IMAGES);
$this->assertEquals(false, $actual);
$actual = $fileManager->getRedirectionUrl(FileManager::TYPE_PRODUCT, 1, FileManager::FILE_TYPE_DOCUMENTS);
$this->assertEquals('/admin/products/update?product_id=1&current_tab=documents', $actual);
$actual = $fileManager->getRedirectionUrl(FileManager::TYPE_CATEGORY, 1, FileManager::FILE_TYPE_DOCUMENTS);
$this->assertEquals('/admin/categories/update?category_id=1&current_tab=documents', $actual);
$actual = $fileManager->getRedirectionUrl(FileManager::TYPE_CONTENT, 1, FileManager::FILE_TYPE_DOCUMENTS);
$this->assertEquals('/admin/content/update/1?current_tab=documents', $actual);
$actual = $fileManager->getRedirectionUrl(FileManager::TYPE_FOLDER, 1, FileManager::FILE_TYPE_DOCUMENTS);
$this->assertEquals('/admin/folders/update/1?current_tab=documents', $actual);
$actual = $fileManager->getRedirectionUrl('bad', 1, FileManager::FILE_TYPE_DOCUMENTS);
$this->assertEquals(false, $actual);
$actual = $fileManager->getRedirectionUrl(FileManager::TYPE_FOLDER, 1, 'bad');
$this->assertEquals(false, $actual);
}
/**
* @covers Thelia\Tools\FileManager::getFormId
*/
public function testGetFormId()
{
$stubContainer = $this->getMockBuilder('\Symfony\Component\DependencyInjection\ContainerInterface')
->disableOriginalConstructor()
->getMock();
$fileManager = new FileManager($stubContainer);
$actual = $fileManager->getFormId(FileManager::TYPE_PRODUCT, FileManager::FILE_TYPE_IMAGES);
$this->assertEquals('thelia.admin.product.image.modification', $actual);
$actual = $fileManager->getFormId(FileManager::TYPE_CATEGORY, FileManager::FILE_TYPE_IMAGES);
$this->assertEquals('thelia.admin.category.image.modification', $actual);
$actual = $fileManager->getFormId(FileManager::TYPE_CONTENT, FileManager::FILE_TYPE_IMAGES);
$this->assertEquals('thelia.admin.content.image.modification', $actual);
$actual = $fileManager->getFormId(FileManager::TYPE_FOLDER, FileManager::FILE_TYPE_IMAGES);
$this->assertEquals('thelia.admin.folder.image.modification', $actual);
$actual = $fileManager->getFormId('bad', FileManager::FILE_TYPE_IMAGES);
$this->assertEquals(false, $actual);
$actual = $fileManager->getFormId(FileManager::TYPE_PRODUCT, FileManager::FILE_TYPE_DOCUMENTS);
$this->assertEquals('thelia.admin.product.document.modification', $actual);
$actual = $fileManager->getFormId(FileManager::TYPE_CATEGORY, FileManager::FILE_TYPE_DOCUMENTS);
$this->assertEquals('thelia.admin.category.document.modification', $actual);
$actual = $fileManager->getFormId(FileManager::TYPE_CONTENT, FileManager::FILE_TYPE_DOCUMENTS);
$this->assertEquals('thelia.admin.content.document.modification', $actual);
$actual = $fileManager->getFormId(FileManager::TYPE_FOLDER, FileManager::FILE_TYPE_DOCUMENTS);
$this->assertEquals('thelia.admin.folder.document.modification', $actual);
$actual = $fileManager->getFormId('bad', FileManager::FILE_TYPE_DOCUMENTS);
$this->assertEquals(false, $actual);
}
/**
* @covers Thelia\Tools\FileManager::renameFile
*/
public function testRenameFile()
{
$stubContainer = $this->getMockBuilder('\Symfony\Component\DependencyInjection\ContainerInterface')
->disableOriginalConstructor()
->getMock();
$stubUploadedFile = $this->getMockBuilder('\Symfony\Component\HttpFoundation\File\UploadedFile')
->disableOriginalConstructor()
->getMock();
$stubUploadedFile->expects($this->any())
->method('getClientOriginalExtension')
->will($this->returnValue('yml'));
$stubUploadedFile->expects($this->any())
->method('getClientOriginalName')
->will($this->returnValue('or1-g_n?al*/&é"filen@me#'));
$fileManager = new FileManager($stubContainer);
$expected = 'or1-g_nalfilenme-1.yml';
$actual = $fileManager->renameFile(1, $stubUploadedFile);
$this->assertEquals($expected, $actual);
}
/**
* @covers Thelia\Tools\FileManager::renameFile
*/
public function testRenameFileWithoutExtension()
{
$stubContainer = $this->getMockBuilder('\Symfony\Component\DependencyInjection\ContainerInterface')
->disableOriginalConstructor()
->getMock();
$stubUploadedFile = $this->getMockBuilder('\Symfony\Component\HttpFoundation\File\UploadedFile')
->disableOriginalConstructor()
->getMock();
$stubUploadedFile->expects($this->any())
->method('getClientOriginalExtension')
->will($this->returnValue(''));
$stubUploadedFile->expects($this->any())
->method('getClientOriginalName')
->will($this->returnValue('or1-g_n?al*/&é"filen@me#'));
$fileManager = new FileManager($stubContainer);
$expected = 'or1-g_nalfilenme-1';
$actual = $fileManager->renameFile(1, $stubUploadedFile);
$this->assertEquals($expected, $actual);
}
/**
* @covers Thelia\Tools\FileManager::isImage
*/
public function testIsImage()
{
$stubContainer = $this->getMockBuilder('\Symfony\Component\DependencyInjection\ContainerInterface')
->disableOriginalConstructor()
->getMock();
$fileManager = new FileManager($stubContainer);
$actual = $fileManager->isImage('image/jpeg');
$this->assertTrue($actual);
$actual = $fileManager->isImage('image/png');
$this->assertTrue($actual);
$actual = $fileManager->isImage('image/gif');
$this->assertTrue($actual);
$actual = $fileManager->isImage('bad');
$this->assertFalse($actual);
$actual = $fileManager->isImage('image/jpg');
$this->assertFalse($actual);
$actual = $fileManager->isImage('application/x-msdownload');
$this->assertFalse($actual);
$actual = $fileManager->isImage('application/x-sh');
$this->assertFalse($actual);
}
/**
* @covers Thelia\Tools\FileManager::getAvailableTypes
*/
public function testGetAvailableTypes()
{
$expected = array(
FileManager::TYPE_CATEGORY,
FileManager::TYPE_CONTENT,
FileManager::TYPE_FOLDER,
FileManager::TYPE_PRODUCT,
FileManager::TYPE_MODULE,
);
$actual = FileManager::getAvailableTypes();
$this->assertEquals($expected, $actual);
}
/**
* @covers Thelia\Tools\FileManager::adminLogAppend
*/
public function testAdminLogAppend()
{
$this->markTestIncomplete(
'This test has not been implemented yet.'
);
}
/**
* @covers Thelia\Tools\FileManager::deleteFile
*/
public function testDeleteFile()
{
// @todo see http://tech.vg.no/2011/03/09/mocking-the-file-system-using-phpunit-and-vfsstream/
$this->markTestIncomplete(
'This test has not been implemented yet.'
);
}
}

View File

@@ -0,0 +1,726 @@
<?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\Tools;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Thelia\Core\Event\DocumentCreateOrUpdateEvent;
use Thelia\Core\Event\ImageCreateOrUpdateEvent;
use Thelia\Core\HttpFoundation\Request;
use Thelia\Core\Translation\Translator;
use Thelia\Exception\ImageException;
use Thelia\Form\CategoryDocumentModification;
use Thelia\Form\CategoryImageModification;
use Thelia\Form\ContentDocumentModification;
use Thelia\Form\ContentImageModification;
use Thelia\Form\FolderDocumentModification;
use Thelia\Form\FolderImageModification;
use Thelia\Form\ProductDocumentModification;
use Thelia\Form\ProductImageModification;
use Thelia\Model\AdminLog;
use Thelia\Model\CategoryDocument;
use Thelia\Model\CategoryDocumentQuery;
use Thelia\Model\CategoryImage;
use Thelia\Model\CategoryImageQuery;
use Thelia\Model\CategoryQuery;
use Thelia\Model\ContentDocument;
use Thelia\Model\ContentDocumentQuery;
use Thelia\Model\ContentImage;
use Thelia\Model\ContentImageQuery;
use Thelia\Model\ContentQuery;
use Thelia\Model\Exception\InvalidArgumentException;
use Thelia\Model\FolderDocument;
use Thelia\Model\FolderDocumentQuery;
use Thelia\Model\FolderImage;
use Thelia\Model\FolderImageQuery;
use Thelia\Model\FolderQuery;
use Thelia\Model\ProductDocument;
use Thelia\Model\ProductDocumentQuery;
use Thelia\Model\ProductImage;
use Thelia\Model\ProductImageQuery;
use Thelia\Model\ProductQuery;
/**
* Created by JetBrains PhpStorm.
* Date: 9/19/13
* Time: 3:24 PM
*
* File Manager
*
* @package File
* @author Guillaume MOREL <gmorel@openstudio.fr>
*
*/
class FileManager
{
CONST TYPE_PRODUCT = 'product';
CONST TYPE_CATEGORY = 'category';
CONST TYPE_CONTENT = 'content';
CONST TYPE_FOLDER = 'folder';
CONST TYPE_MODULE = 'module';
CONST FILE_TYPE_IMAGES = 'images';
CONST FILE_TYPE_DOCUMENTS = 'documents';
/** @var ContainerInterface Service Container */
protected $container = null;
/** @var Translator Service Translator */
protected $translator = null;
/**
* Constructor
*
* @param ContainerInterface $container Service container
*/
public function __construct(ContainerInterface $container)
{
$this->container = $container;
$this->translator = $this->container->get('thelia.translator');
}
/**
* Copy UploadedFile into the server storage directory
*
* @param int $parentId Parent id
* @param string $parentType Image type
* @param FolderImage|ContentImage|CategoryImage|ProductImage|FolderDocument|ContentDocument|CategoryDocument|ProductDocument $model Model saved
* @param UploadedFile $uploadedFile Ready to be uploaded file
* @param string $fileType File type ex FileManager::FILE_TYPE_IMAGES
*
* @throws \Thelia\Exception\ImageException
* @return UploadedFile
*/
public function copyUploadedFile($parentId, $parentType, $model, $uploadedFile, $fileType)
{
$newUploadedFile = null;
if ($uploadedFile !== null) {
$directory = $this->getUploadDir($parentType, $fileType);
$fileName = $this->renameFile($model->getId(), $uploadedFile);
$this->adminLogAppend(
$this->translator->trans(
'Uploading %type% %fileName% to %directory% for parent_id %parentId% (%parentType%)',
array(
'%type%' => $fileType,
'%fileName%' => $uploadedFile->getClientOriginalName(),
'%directory%' => $directory . '/' . $fileName,
'%parentId%' => $parentId,
'%parentType%' => $parentType
),
'image'
)
);
$newUploadedFile = $uploadedFile->move($directory, $fileName);
$model->setFile($fileName);
if (!$model->save()) {
throw new ImageException(
sprintf(
'%s %s (%s) failed to be saved (image file)',
ucfirst($parentType),
$model->getFile(),
$fileType
)
);
}
}
return $newUploadedFile;
}
/**
* Save image into the database
*
* @param ImageCreateOrUpdateEvent $event Image event
* @param FolderImage|ContentImage|CategoryImage|ProductImage $modelImage Image to save
*
* @return int Nb lines modified
* @throws \Thelia\Exception\ImageException
* @todo refactor make all pictures using propel inheritance and factorise image behaviour into one single clean action
*/
public function saveImage(ImageCreateOrUpdateEvent $event, $modelImage)
{
$nbModifiedLines = 0;
if ($modelImage->getFile() !== null) {
switch ($event->getImageType()) {
case self::TYPE_PRODUCT:
/** @var ProductImage $modelImage */
$modelImage->setProductId($event->getParentId());
break;
case self::TYPE_CATEGORY:
/** @var CategoryImage $modelImage */
$modelImage->setCategoryId($event->getParentId());
break;
case self::TYPE_CONTENT:
/** @var ContentImage $modelImage */
$modelImage->setContentId($event->getParentId());
break;
case self::TYPE_FOLDER:
/** @var FolderImage $modelImage */
$modelImage->setFolderId($event->getParentId());
break;
default:
throw new ImageException(
sprintf(
'Picture parent type is unknown (available types : %s)',
implode(
',',
self::getAvailableTypes()
)
)
);
}
$nbModifiedLines = $modelImage->save();
if (!$nbModifiedLines) {
throw new ImageException(
sprintf(
'Image %s failed to be saved (image content)',
$modelImage->getFile()
)
);
}
}
return $nbModifiedLines;
}
/**
* Save document into the database
*
* @param DocumentCreateOrUpdateEvent $event Image event
* @param FolderDocument|ContentDocument|CategoryDocument|ProductDocument $modelDocument Document to save
*
* @throws \Thelia\Model\Exception\InvalidArgumentException
* @return int Nb lines modified
* @todo refactor make all documents using propel inheritance and factorise image behaviour into one single clean action
*/
public function saveDocument(DocumentCreateOrUpdateEvent $event, $modelDocument)
{
$nbModifiedLines = 0;
if ($modelDocument->getFile() !== null) {
switch ($event->getDocumentType()) {
case self::TYPE_PRODUCT:
/** @var ProductImage $modelImage */
$modelDocument->setProductId($event->getParentId());
break;
case self::TYPE_CATEGORY:
/** @var CategoryImage $modelImage */
$modelDocument->setCategoryId($event->getParentId());
break;
case self::TYPE_CONTENT:
/** @var ContentImage $modelImage */
$modelDocument->setContentId($event->getParentId());
break;
case self::TYPE_FOLDER:
/** @var FolderImage $modelImage */
$modelDocument->setFolderId($event->getParentId());
break;
default:
throw new InvalidArgumentException(
sprintf(
'Document parent type is unknown (available types : %s)',
implode(
',',
self::getAvailableTypes()
)
)
);
}
$nbModifiedLines = $modelDocument->save();
if (!$nbModifiedLines) {
throw new InvalidArgumentException(
sprintf(
'Document %s failed to be saved (document content)',
$modelDocument->getFile()
)
);
}
}
return $nbModifiedLines;
}
/**
* Sanitizes a filename replacing whitespace with dashes
*
* Removes special characters that are illegal in filenames on certain
* operating systems and special characters requiring special escaping
* to manipulate at the command line.
*
* @param string $string The filename to be sanitized
*
* @return string The sanitized filename
*/
public function sanitizeFileName($string)
{
return strtolower(preg_replace('/[^a-zA-Z0-9-_\.]/', '', $string));
}
/**
* Helper to append a message to the admin log.
*
* @param string $message
*/
public function adminLogAppend($message)
{
AdminLog::append(
$message,
$this->container->get('request'),
$this->container->get('thelia.securityContext')->getAdminUser()
);
}
/**
* Delete image from file storage and database
*
* @param CategoryImage|ProductImage|ContentImage|FolderImage|CategoryDocument|ProductDocument|ContentDocument|FolderDocument $model File being deleted
* @param string $parentType Parent type ex : self::TYPE_PRODUCT
* @param string $fileType File type ex FileManager::FILE_TYPE_DOCUMENTS
*
* @todo refactor make all pictures using propel inheritance and factorise image behaviour into one single clean action
*/
public function deleteFile($model, $parentType, $fileType)
{
$url = $this->getUploadDir($parentType, $fileType) . '/' . $model->getFile();
unlink(str_replace('..', '', $url));
$model->delete();
}
/**
* Get image model from type
*
* @param string $parentType Parent type ex : self::TYPE_PRODUCT
*
* @return null|\Thelia\Model\CategoryImage|\Thelia\Model\ContentImage|\Thelia\Model\FolderImage|\Thelia\Model\ProductImage
*
* @todo refactor make all pictures using propel inheritance and factorise image behaviour into one single clean action
*/
public function getImageModel($parentType)
{
switch ($parentType) {
case self::TYPE_PRODUCT:
$model = new ProductImage();
break;
case self::TYPE_CATEGORY:
$model = new CategoryImage();
break;
case self::TYPE_CONTENT:
$model = new ContentImage();
break;
case self::TYPE_FOLDER:
$model = new FolderImage();
break;
default:
$model = null;
}
return $model;
}
/**
* Get document model from type
*
* @param string $parentType Parent type ex : self::TYPE_PRODUCT
*
* @return null|ProductDocument|CategoryDocument|ContentDocument|FolderDocument
*
* @todo refactor make all documents using propel inheritance and factorise image behaviour into one single clean action
*/
public function getDocumentModel($parentType)
{
switch ($parentType) {
case self::TYPE_PRODUCT:
$model = new ProductDocument();
break;
case self::TYPE_CATEGORY:
$model = new CategoryDocument();
break;
case self::TYPE_CONTENT:
$model = new ContentDocument();
break;
case self::TYPE_FOLDER:
$model = new FolderDocument();
break;
default:
$model = null;
}
return $model;
}
/**
* Get image model query from type
*
* @param string $parentType Parent type ex : self::TYPE_PRODUCT
*
* @return null|\Thelia\Model\CategoryImageQuery|\Thelia\Model\ContentImageQuery|\Thelia\Model\FolderImageQuery|\Thelia\Model\ProductImageQuery
*
* @todo refactor make all pictures using propel inheritance and factorise image behaviour into one single clean action
*/
public function getImageModelQuery($parentType)
{
switch ($parentType) {
case self::TYPE_PRODUCT:
$model = new ProductImageQuery();
break;
case self::TYPE_CATEGORY:
$model = new CategoryImageQuery();
break;
case self::TYPE_CONTENT:
$model = new ContentImageQuery();
break;
case self::TYPE_FOLDER:
$model = new FolderImageQuery();
break;
default:
$model = null;
}
return $model;
}
/**
* Get document model query from type
*
* @param string $parentType Parent type ex : self::TYPE_PRODUCT
*
* @return null|ProductDocumentQuery|CategoryDocumentQuery|ContentDocumentQuery|FolderDocumentQuery
*
* @todo refactor make all documents using propel inheritance and factorise image behaviour into one single clean action
*/
public function getDocumentModelQuery($parentType)
{
switch ($parentType) {
case self::TYPE_PRODUCT:
$model = new ProductDocumentQuery();
break;
case self::TYPE_CATEGORY:
$model = new CategoryDocumentQuery();
break;
case self::TYPE_CONTENT:
$model = new ContentDocumentQuery();
break;
case self::TYPE_FOLDER:
$model = new FolderDocumentQuery();
break;
default:
$model = null;
}
return $model;
}
/**
* Get form service id from type
*
* @param string $parentType Parent type ex : self::TYPE_PRODUCT
* @param string $fileType Parent id
*
* @return string
*
* @todo refactor make all documents using propel inheritance and factorise image behaviour into one single clean action
*/
public function getFormId($parentType, $fileType)
{
switch ($fileType) {
case self::FILE_TYPE_IMAGES:
$type = 'image';
break;
case self::FILE_TYPE_DOCUMENTS:
$type = 'document';
break;
default:
return false;
}
switch ($parentType) {
case self::TYPE_PRODUCT:
$formId = 'thelia.admin.product.' . $type . '.modification';
break;
case self::TYPE_CATEGORY:
$formId = 'thelia.admin.category.' . $type . '.modification';
break;
case self::TYPE_CONTENT:
$formId = 'thelia.admin.content.' . $type . '.modification';
break;
case self::TYPE_FOLDER:
$formId = 'thelia.admin.folder.' . $type . '.modification';
break;
default:
$formId = false;
}
return $formId;
}
/**
* Get image parent model from type
*
* @param string $parentType Parent type ex : self::TYPE_PRODUCT
* @param int $parentId Parent Id
*
* @return null|\Thelia\Model\Category|\Thelia\Model\Content|\Thelia\Model\Folder|\Thelia\Model\Product
*
* @todo refactor make all pictures using propel inheritance and factorise image behaviour into one single clean action
*/
public function getParentFileModel($parentType, $parentId)
{
switch ($parentType) {
case self::TYPE_PRODUCT:
$model = ProductQuery::create()->findPk($parentId);
break;
case self::TYPE_CATEGORY:
$model = CategoryQuery::create()->findPk($parentId);
break;
case self::TYPE_CONTENT:
$model = ContentQuery::create()->findPk($parentId);
break;
case self::TYPE_FOLDER:
$model = FolderQuery::create()->findPk($parentId);
break;
default:
$model = null;
}
return $model;
}
/**
* Get image parent model from type
*
* @param string $parentType Parent type ex : self::TYPE_PRODUCT
* @param Request $request Request service
*
* @todo refactor make all pictures using propel inheritance and factorise image behaviour into one single clean action
* @return ProductImageModification|CategoryImageModification|ContentImageModification|FolderImageModification
*/
public function getImageForm($parentType, Request $request)
{
switch ($parentType) {
case self::TYPE_PRODUCT:
$form = new ProductImageModification($request);
break;
case self::TYPE_CATEGORY:
$form = new CategoryImageModification($request);
break;
case self::TYPE_CONTENT:
$form = new ContentImageModification($request);
break;
case self::TYPE_FOLDER:
$form = new FolderImageModification($request);
break;
default:
$form = null;
}
return $form;
}
/**
* Get document parent model from type
*
* @param string $parentType Parent type ex : self::TYPE_PRODUCT
* @param Request $request Request service
*
* @todo refactor make all document using propel inheritance and factorise image behaviour into one single clean action
* @return ProductDocumentModification|CategoryDocumentModification|ContentDocumentModification|FolderDocumentModification
*/
public function getDocumentForm($parentType, Request $request)
{
switch ($parentType) {
case self::TYPE_PRODUCT:
$form = new ProductDocumentModification($request);
break;
case self::TYPE_CATEGORY:
$form = new CategoryDocumentModification($request);
break;
case self::TYPE_CONTENT:
$form = new ContentDocumentModification($request);
break;
case self::TYPE_FOLDER:
$form = new FolderDocumentModification($request);
break;
default:
$form = null;
}
return $form;
}
/**
* Get image upload dir
*
* @param string $parentType Parent type ex FileManager::TYPE_PRODUCT
* @param string $fileType File type ex : self::FILE_TYPE_DOCUMENTS
*
* @return string Uri
*/
public function getUploadDir($parentType, $fileType)
{
if (!in_array($fileType, self::$availableFileType)) {
return false;
}
switch ($parentType) {
case self::TYPE_PRODUCT:
$uri = THELIA_LOCAL_DIR . 'media/' . $fileType . '/' . self::TYPE_PRODUCT;
break;
case self::TYPE_CATEGORY:
$uri = THELIA_LOCAL_DIR . 'media/' . $fileType . '/' . self::TYPE_CATEGORY;
break;
case self::TYPE_CONTENT:
$uri = THELIA_LOCAL_DIR . 'media/' . $fileType . '/' . self::TYPE_CONTENT;
break;
case self::TYPE_FOLDER:
$uri = THELIA_LOCAL_DIR . 'media/' . $fileType . '/' . self::TYPE_FOLDER;
break;
default:
$uri = false;
}
return $uri;
}
/**
* Deduce image redirecting URL from parent type
*
* @param string $parentType Parent type ex : self::TYPE_PRODUCT
* @param int $parentId Parent id
* @param string $fileType File type ex : self::FILE_TYPE_DOCUMENTS
*
* @return string
*/
public function getRedirectionUrl($parentType, $parentId, $fileType)
{
if (!in_array($fileType, self::$availableFileType)) {
return false;
}
switch ($parentType) {
case self::TYPE_PRODUCT:
$uri = '/admin/products/update?product_id=' . $parentId . '&current_tab=' . $fileType;
break;
case self::TYPE_CATEGORY:
$uri = '/admin/categories/update?category_id=' . $parentId . '&current_tab=' . $fileType;
break;
case self::TYPE_CONTENT:
$uri = '/admin/content/update/' . $parentId . '?current_tab=' . $fileType;
break;
case self::TYPE_FOLDER:
$uri = '/admin/folders/update/' . $parentId . '?current_tab=' . $fileType;
break;
default:
$uri = false;
}
return $uri;
}
/** @var array Available file parent type */
public static $availableType = array(
self::TYPE_PRODUCT,
self::TYPE_CATEGORY,
self::TYPE_CONTENT,
self::TYPE_FOLDER,
self::TYPE_MODULE
);
/** @var array Available file type type */
public static $availableFileType = array(
self::FILE_TYPE_DOCUMENTS,
self::FILE_TYPE_IMAGES
);
/**
* Rename file with image model id
*
* @param int $modelId Model id
* @param UploadedFile $uploadedFile File being saved
*
* @return string
*/
public function renameFile($modelId, $uploadedFile)
{
$extension = $uploadedFile->getClientOriginalExtension();
if (!empty($extension)) {
$extension = '.' . strtolower($extension);
}
$fileName = $this->sanitizeFileName(
str_replace(
$extension,
'',
$uploadedFile->getClientOriginalName()
) . '-' . $modelId . $extension
);
return $fileName;
}
/**
* Check if a file is an image
* Check based on mime type
*
* @param string $mimeType File mime type
*
* @return bool
*/
public function isImage($mimeType)
{
$isValid = false;
$allowedType = array('image/jpeg' , 'image/png' ,'image/gif');
if (in_array($mimeType, $allowedType)) {
$isValid = true;
}
return $isValid;
}
/**
* Return all document and image types
*
* @return array
*/
public static function getAvailableTypes()
{
return array(
self::TYPE_CATEGORY,
self::TYPE_CONTENT,
self::TYPE_FOLDER,
self::TYPE_PRODUCT,
self::TYPE_MODULE,
);
}
}

View File

@@ -26,7 +26,7 @@ class ResponseRest extends Response
* Constructor.
*
* @param array $data Array to be serialized
* @param string $format serialization format, xml or json available
* @param string $format serialization format, text, xml or json available
* @param integer $status The response status code
* @param array $headers An array of response headers
*
@@ -38,6 +38,13 @@ class ResponseRest extends Response
{
parent::__construct('', $status, $headers);
if ($format == 'text') {
if (isset($data)) {
$this->setContent($data);
}
$this->headers->set('Content-Type', 'text/plain');
} else {
$this->format = $format;
$serializer = $this->getSerializer();
@@ -47,6 +54,7 @@ class ResponseRest extends Response
$this->headers->set('Content-Type', 'application/' . $this->format);
}
}
/**
* Set Content to be serialized in the response, array or object

View File

@@ -425,6 +425,7 @@ try {
$stock->setPromo($faker->randomNumber(0,1));
$stock->setNewness($faker->randomNumber(0,1));
$stock->setWeight($faker->randomFloat(2, 100,10000));
$stock->setIsDefault($i == 0);
$stock->save();
$productPrice = new \Thelia\Model\ProductPrice();
@@ -463,8 +464,7 @@ try {
$featureAvId[array_rand($featureAvId, 1)]
);
} else { //no av
// @todo uncomment
// $featureProduct->setByDefault($faker->text(10));
$featureProduct->setFreeTextValue($faker->text(10));
}
$featureProduct->save();

View File

@@ -1153,7 +1153,7 @@ INSERT INTO `tax` (`id`, `type`, `serialized_requirements`, `created_at`, `upda
INSERT INTO `tax_i18n` (`id`, `locale`, `title`)
VALUES
(1, 'fr_FR', 'TVA française à 19.6%'),
(1, 'en_US', 'french 19.6% tax');
(1, 'en_US', 'French 19.6% VAT');
INSERT INTO `tax_rule` (`id`, `is_default`, `created_at`, `updated_at`)
VALUES
@@ -1162,7 +1162,7 @@ INSERT INTO `tax_rule` (`id`, `is_default`, `created_at`, `updated_at`)
INSERT INTO `tax_rule_i18n` (`id`, `locale`, `title`)
VALUES
(1, 'fr_FR', 'TVA française à 19.6%'),
(1, 'en_US', 'french 19.6% tax');
(1, 'en_US', 'French 19.6% VAT');
INSERT INTO `tax_rule_country` (`tax_rule_id`, `country_id`, `tax_id`, `position`, `created_at`, `updated_at`)
VALUES

View File

@@ -389,6 +389,7 @@ CREATE TABLE `attribute_template`
`attribute_id` INTEGER NOT NULL,
`template_id` INTEGER NOT NULL,
`position` INTEGER,
`attribute_templatecol` VARCHAR(45),
`created_at` DATETIME,
`updated_at` DATETIME,
PRIMARY KEY (`id`),
@@ -818,7 +819,7 @@ CREATE TABLE `order_product_attribute_combination`
`attribute_title` VARCHAR(255) NOT NULL,
`attribute_chapo` TEXT,
`attribute_description` LONGTEXT,
`attribute_postscriptum` TEXT,
`attribute_postscriptumn` TEXT,
`attribute_av_title` VARCHAR(255) NOT NULL,
`attribute_av_chapo` TEXT,
`attribute_av_description` LONGTEXT,
@@ -1589,7 +1590,6 @@ CREATE TABLE `order_product_tax`
`title` VARCHAR(255) NOT NULL,
`description` LONGTEXT,
`amount` FLOAT NOT NULL,
`promo_amount` FLOAT,
`created_at` DATETIME,
`updated_at` DATETIME,
PRIMARY KEY (`id`),

0
local/modules/Cheque/images/cheque.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

0
local/modules/FakeCB/images/mastercard.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

0
local/modules/FakeCB/images/visa.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -0,0 +1,248 @@
{loop name="product_edit" type="product" visible="*" id=$product_id backend_context="1" lang=$edit_language_id}
<div class="form-container">
<div class="row">
<div class="col-md-12">
<p></p> {* <---- FIXME Lame ! *}
<form method="POST" class="clearfix" action="{url path="/admin/product/$ID/set-product-template"}" id="product_template_form">
<input type="hidden" name="product_id" value="{$product_id}" />
<input type="hidden" name="current_tab" value="attributes" />
<div class="row">
<div class="col-md-12">
<div class="well well-sm">
<p>{intl
l="To use features or attributes on this product, please select a product template. You can define product templates in the <a href=\"%tpl_mgmt_url\" target=\"tpl_window\">configuration section</a> of the administration."
tpl_mgmt_url={url path='/admin/configuration/templates'}
}
</p>
<label for="template_id" class="control-label">
{intl l='Current product template'} :
</label>
<div class="input-group">
<select required="required" name="template_id" id="template_id" class="form-control">
<option value="0">{intl l='Do not use a product template'}</option>
{loop name="product_template_select" type="template"}
<option value="{$ID}" {if $TEMPLATE == $ID}selected="selected"{/if}>{$NAME}</option>
{/loop}
</select>
<span class="input-group-btn" id="apply_template_button">
<button class="btn btn-default btn-primary action-btn" type="submit">{intl l="Apply"}</button>
</span>
</div>
</div>
</div>
</div>
</form>
</div>
</div>
{* Check if a product template is defined *}
<div class="row">
<div class="col-md-12">
<form method="POST" action="{url path="/admin/product/$ID/update-attributes-and-features"}" id="attribute_form">
<input type="hidden" name="product_id" value="{$product_id}" />
<input type="hidden" name="current_tab" value="attributes" />
{include
file = "includes/inner-form-toolbar.html"
hide_submit_buttons = false
page_url = "{url path='/admin/products/update' product_id=$ID}"
close_url = "{url path='/admin/categories' category_id=$DEFAULT_CATEGORY}"
}
{* -- Begin attributes management ------------------------------- *}
<div class="row">
<div class="col-md-12">
<div class="well well-sm">
<div class="form-group">
<p class="title title-without-tabs">{intl l='Product Attributes'}</p>
<p>
{if $TEMPLATE}
{intl
l="You can change template attributes and their positions in <a href=\"%tpl_mgmt_url\" target=\"tpl_window\">the template configuration page</a>."
tpl_mgmt_url={url path='/admin/configuration/templates/update' template_id=$TEMPLATE}
}
{else}
{intl
l="You can change attributes and their positions in <a href=\"%tpl_mgmt_url\" target=\"tpl_window\">the attributes configuration page</a>."
tpl_mgmt_url={url path='/admin/configuration/attributes'}
}
{/if}
</p>
<div class="table-responsive">
<table class="table table-striped table-condensed table-left-aligned">
<thead>
<tr>
<th>{intl l='ID'}</th>
<th>{intl l='Attribute Name'}</th>
{module_include location='product_attributes_table_header'}
</tr>
</thead>
<tbody>
{loop name="product-attributes" type="attribute" order="manual" product=$product_id backend_context="1" lang="$edit_language_id"}
<tr>
<td>{$ID}</td>
<td>{$TITLE}</td>
{module_include location='product_features_table_row'}
</tr>
{/loop}
{elseloop rel="product-attributes"}
<tr>
<td colspan="2">
<div class="alert alert-info">
{intl l="This product template does not contains any features"}
</div>
</td>
</tr>
{/elseloop}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
{* -- Begin features management ---------------------------------- *}
<div class="row">
<div class="col-md-12">
<div class="well well-sm">
<div class="form-group">
<p class="title title-without-tabs">{intl l='Product Features'}</p>
<p>
{if $TEMPLATE}
{intl
l="You can change templates features and their positions in <a href=\"%tpl_mgmt_url\" target=\"tpl_window\">the template configuration page</a>."
tpl_mgmt_url={url path='/admin/configuration/templates/update' template_id=$TEMPLATE}
}
{else}
{intl
l="You can change feature and their positions in <a href=\"%tpl_mgmt_url\" target=\"tpl_window\">the features configuration page</a>."
tpl_mgmt_url={url path='/admin/configuration/features'}
}
{/if}
</p>
<div class="table-responsive">
<table class="table table-striped table-condensed table-left-aligned">
<thead>
<tr>
<th>{intl l='ID'}</th>
<th>{intl l='Feature Name'}</th>
<th>{intl l='Feature value for this product'}</th>
{module_include location='product_features_table_header'}
</tr>
</thead>
<tbody>
{loop name="product-features" type="feature" order="manual" product=$product_id backend_context="1" lang="$edit_language_id"}
<tr>
<td>{$ID}</td>
<td>{$TITLE}</td>
<td>
{* Multiple values *}
{ifloop rel="product-features-av"}
{* load all selected values in an array to speed up things a little *}
{$selected = array()}
{loop name="free-text-value" exclude_free_text="true" type="feature_value" product=$product_id feature=$ID backend_context="1" lang="$edit_language_id"}
{$selected[] = $FEATURE_AV_ID}
{/loop}
{capture "select_options"}
{loop name="product-features-av" type="feature-availability" feature=$ID order="manual" backend_context="1" lang="$edit_language_id"}
<option value="{$ID}" {if in_array($ID, $selected)}selected="selected"{/if}>{$TITLE}</option>
{$options_count = $LOOP_COUNT} {* LOOP_COUNT is only available inside the loop ! *}
{/loop}
{/capture}
<div class="input-form">
<select multiple="multiple" name="feature_value[{$ID}][]" id="feature_value_{$ID}" size="{$options_count}" class="form-control">
{$smarty.capture.select_options nofilter}
</select>
</div>
<span class="help-block text-right">
{intl l='Use Ctrl+click to select more than one value. You can also <a href="#" class="clear_feature_value" data-id="%id">clear selected values</a>.' id=$ID}
</span>
{/ifloop}
{* Free text *}
{elseloop rel="product-features-av"}
{* Get the free text value *}
{loop name="free-text-value" exclude_feature_availability="1" type="feature_value" product=$product_id feature=$ID backend_context="1" lang="$edit_language_id"}
{$feature_value=$FREE_TEXT_VALUE}
{/loop}
<input type="text" id="feature_text_value_{$ID}" name="feature_text_value[{$ID}]" title="{intl l='Enter here the feature value as free text'}" placeholder="{intl l='Feature value'}" class="form-control" value="{$feature_value|default:''}">
{/elseloop}
</td>
{module_include location='product_features_table_row'}
</tr>
{/loop}
{elseloop rel="product-features"}
<tr>
<td colspan="3">
<div class="alert alert-info">
{intl l="This product template does not contains any features"}
</div>
</td>
</tr>
{/elseloop}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
{/loop}
<script>
$(function() {
// Unselect all options in attribute + feature tab
$('.clear_feature_value').click(function(event){
$('#feature_value_' + $(this).data('id') + ' option').prop('selected', false);
event.preventDefault();
});
});
</script>

View File

@@ -0,0 +1,576 @@
{loop name="product_edit" type="product" visible="*" id=$product_id backend_context="1" lang=$edit_language_id}
<div class="form-container">
{include
file = "includes/inner-form-toolbar.html"
hide_submit_buttons = true
page_url = "{url path='/admin/products/update' product_id=$ID}"
close_url = "{url path='/admin/categories' category_id=$DEFAULT_CATEGORY}"
}
<div class="row">
{* -- Begin related content management ------------------------------ *}
<div class="col-md-6">
<div class="well well-sm">
<div class="form-group">
<form method="POST" action="{url path='/admin/products/content/add'}" id="related_content_form">
<p class="title title-without-tabs">{intl l='Related content'}</p>
<p>{intl l='You can attach here some content to this product'}</p>
<input type="hidden" name="product_id" value="{$product_id}" />
<input type="hidden" name="current_tab" value="related" />
{ifloop rel="folders"}
<div class="form-group">
<select name="folder_id" id="folder_id" class="form-control">
<option value="">{intl l='Select a folder...'}</option>
{loop name="folders" type="folder-tree" folder="0" backend_context="1" lang="$edit_language_id"}
<option value="{$ID}" style="padding-left: {3 + $LEVEL * 20}px">{$TITLE}</option>
{/loop}
</select>
<span class="help-block">{intl l='Select a folder to get its content'}</span>
</div>
<div id="content_selector" class="hide">
<div class="input-group">
<select required="required" name="content_id" id="content_id" class="form-control">
<option value="">{intl l='Select a folder content...'}</option>
</select>
<span class="input-group-btn" id="content_add_button">
<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 a content and click (+) to add it to this product'}</span>
</div>
<div id="content_selector_empty" class="hide">
<div class="alert alert-info">
{intl l="No available content in this folder"}
</div>
</div>
{/ifloop}
{elseloop rel="folders"}
<div class="alert alert-info">{intl l="No folders found"}</div>
{/elseloop}
</form>
</div>
<div class="table-responsive">
<table class="table table-striped table-condensed table-left-aligned">
<thead>
<tr>
<th>{intl l='ID'}</th>
<th>{intl l='Content title'}</th>
<th class="text-center">{intl l='Position'}</th>
{module_include location='product_contents_table_header'}
<th class="actions">{intl l="Actions"}</th>
</tr>
</thead>
<tbody>
{loop name="assigned_contents" type="associated_content" product="$product_id" backend_context="1" lang="$edit_language_id"}
<tr>
<td>{$ID}</td>
<td>
{$TITLE}
</td>
<td class="text-center">
{admin_position_block
permission="admin.products.edit"
path={url path='/admin/product/update-content-position' product_id=$product_id current_tab="related"}
url_parameter="content_id"
in_place_edit_class="contentPositionChange"
position=$POSITION
id=$ID
}
</td>
{module_include location='product_contents_table_row'}
<td class="actions">
<div class="btn-group">
{loop type="auth" name="can_create" roles="ADMIN" permissions="admin.product.content.delete"}
<a class="btn btn-default btn-xs delete-content" title="{intl l='Delete this content'}" href="#delete_content_dialog" data-id="{$ID}" data-toggle="modal">
<span class="glyphicon glyphicon-trash"></span>
</a>
{/loop}
</div>
</td>
</tr>
{/loop}
{elseloop rel="assigned_contents"}
<tr>
<td colspan="4">
<div class="alert alert-info">
{intl l="This product contains no contents"}
</div>
</td>
</tr>
{/elseloop}
</tbody>
</table>
</div>
</div>
</div>
{* -- End related content management -------------------------------- *}
{* -- Begin accessories management ---------------------------------- *}
<div class="col-md-6">
<div class=" well well-sm">
<div class="form-group">
<form method="POST" action="{url path='/admin/products/accessory/add'}" id="accessory_form">
<p class="title title-without-tabs">{intl l='Product accessories'}</p>
<p>{intl l='Define here this product\'s accessories'}</p>
<input type="hidden" name="product_id" value="{$product_id}" />
<input type="hidden" name="current_tab" value="related" />
{ifloop rel="categories"}
<div class="form-group">
<select name="accessory_category_id" id="accessory_category_id" class="form-control">
<option value="">{intl l='Select a category...'}</option>
{loop name="categories" type="category-tree" category="0" backend_context="1" lang="$edit_language_id"}
<option value="{$ID}" style="padding-left: {3 + $LEVEL * 20}px">{$TITLE}</option>
{/loop}
</select>
<span class="help-block">{intl l='Select a category to get its products'}</span>
</div>
<div id="accessory_selector" class="hide">
<div class="input-group">
<select required="required" name="accessory_id" id="accessory_id" class="form-control">
<option value="">{intl l='Select a product...'}</option>
</select>
<span class="input-group-btn" id="accessory_add_button">
<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 a product and click (+) to add it as an accessory'}</span>
</div>
<div id="accessory_selector_empty" class="hide">
<div class="alert alert-info">
{intl l="No available product in this category"}
</div>
</div>
{/ifloop}
{elseloop rel="categories"}
<div class="alert alert-info">{intl l="No categories found"}</div>
{/elseloop}
</form>
</div>
<div class="table-responsive">
<table class="table table-striped table-condensed table-left-aligned">
<thead>
<tr>
<th>{intl l='ID'}</th>
<th>{intl l='Accessory title'}</th>
<th class="text-center">{intl l='Position'}</th>
{module_include location='product_accessories_table_header'}
<th class="actions">{intl l="Actions"}</th>
</tr>
</thead>
<tbody>
{loop name="assigned_accessories" order="accessory" type="accessory" product="$product_id" backend_context="1" lang="$edit_language_id"}
<tr>
<td>{$ID}</td>
<td>
{$TITLE}
</td>
<td class="text-center">
{admin_position_block
permission="admin.products.edit"
path={url path='/admin/product/update-accessory-position' product_id=$product_id current_tab="related"}
url_parameter="accessory_id"
in_place_edit_class="accessoryPositionChange"
position=$POSITION
id=$ID
}
</td>
{module_include location='product_accessories_table_row'}
<td class="actions">
<div class="btn-group">
{loop type="auth" name="can_create" roles="ADMIN" permissions="admin.product.accessory.delete"}
<a class="btn btn-default btn-xs delete-accessory" title="{intl l='Delete this accessory'}" href="#delete_accessory_dialog" data-id="{$ID}" data-toggle="modal">
<span class="glyphicon glyphicon-trash"></span>
</a>
{/loop}
</div>
</td>
</tr>
{/loop}
{elseloop rel="assigned_accessories"}
<tr>
<td colspan="4">
<div class="alert alert-info">
{intl l="This product contains no accessories"}
</div>
</td>
</tr>
{/elseloop}
</tbody>
</table>
</div>
</div>
</div>
{* -- End accessories management ------------------------------------ *}
</div>
<div class="row">
{* -- Begin categories management ----------------------------------- *}
<div class="col-md-6">
<div class="well well-sm">
<div class="form-group">
<form method="POST" action="{url path='/admin/products/category/add'}" id="related_content_form">
<p class="title title-without-tabs">{intl l='Additional categories'}</p>
<p>{intl l='A product could be attached to more than one category. Select here the additional categories for this product.'}
{loop name="default_category" type="category" id=$DEFAULT_CATEGORY}
{intl l='You can change the default category (%title) in the "General" tab.' title=$TITLE}
{/loop}
{$exclude_from_tree = "-1"}
{loop name="additional_categories" type="category" product=$product_id exclude=$DEFAULT_CATEGORY backend_context="1" lang="$edit_language_id"}
{$exclude_from_tree = "$exclude_from_tree,$ID"}
{/loop}
<input type="hidden" name="product_id" value="{$product_id}" />
<input type="hidden" name="current_tab" value="related" />
{ifloop rel="categories"}
<div class="input-group">
<select name="additional_category_id" id="accessory_category_id" class="form-control">
<option value="">{intl l='Select a category...'}</option>
{loop name="categories" type="category-tree" category="0" exclude=$exclude_from_tree backend_context="1" lang="$edit_language_id"}
<option value="{$ID}" style="padding-left: {3 + $LEVEL * 20}px" {if $DEFAULT_CATEGORY==$ID}disabled="disabled"{/if}>
{$TITLE} {if $DEFAULT_CATEGORY==$ID}{intl l=' (default)'}{/if}
</option>
{/loop}
</select>
<span class="input-group-btn" id="content_add_button">
<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 a category and click (+) to add it to the additional category list'}</span>
{/ifloop}
{elseloop rel="categories"}
<div class="alert alert-info">{intl l="No categories found"}</div>
{/elseloop}
</form>
</div>
<div class="table-responsive">
<table class="table table-striped table-condensed table-left-aligned">
<thead>
<tr>
<th>{intl l='ID'}</th>
<th>{intl l='Category title'}</th>
{module_include location='product_categories_table_header'}
<th class="actions">{intl l="Actions"}</th>
</tr>
</thead>
<tbody>
{loop name="additional_categories" type="category" product=$product_id exclude=$DEFAULT_CATEGORY backend_context="1" lang="$edit_language_id"}
<tr>
<td>{$ID}</td>
<td>
{$TITLE}
</td>
{module_include location='product_categories_table_row'}
<td class="actions">
<div class="btn-group">
{loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.product.category.delete"}
<a class="btn btn-default btn-xs delete-category" title="{intl l='Remove the product from this category'}" href="#delete_category_dialog" data-id="{$ID}" data-toggle="modal">
<span class="glyphicon glyphicon-trash"></span>
</a>
{/loop}
</div>
</td>
</tr>
{/loop}
{elseloop rel="additional_categories"}
<tr>
<td colspan="3">
<div class="alert alert-info">
{intl l="This product doesn't belong to any additional category."}
</div>
</td>
</tr>
{/elseloop}
</tbody>
</table>
</div>
</div>
</div>
{* -- End categories management ------------------------------------- *}
</div>
</div>
{* Delete related content confirmation dialog *}
{capture "delete_content_dialog"}
<input type="hidden" name="product_id" value="{$product_id}" />
<input type="hidden" name="content_id" id="content_delete_id" value="" />
<input type="hidden" name="folder_id" id="folder_delete_id" value="" />
<input type="hidden" name="current_tab" value="related" />
{/capture}
{include
file = "includes/generic-confirm-dialog.html"
dialog_id = "delete_content_dialog"
dialog_title = {intl l="Remove related content"}
dialog_message = {intl l="Do you really want to remove this related content from the product ?"}
form_action = {url path='/admin/products/content/delete'}
form_content = {$smarty.capture.delete_content_dialog nofilter}
}
{* Delete accessory confirmation dialog *}
{capture "delete_accessory_dialog"}
<input type="hidden" name="product_id" value="{$product_id}" />
<input type="hidden" name="accessory_id" id="accessory_delete_id" value="" />
<input type="hidden" name="accessory_category_id" id="accessory_category_delete_id" value="" />
<input type="hidden" name="current_tab" value="related" />
{/capture}
{include
file = "includes/generic-confirm-dialog.html"
dialog_id = "delete_accessory_dialog"
dialog_title = {intl l="Remove an accessory"}
dialog_message = {intl l="Do you really want to remove this accessory from the product ?"}
form_action = {url path='/admin/products/accessory/delete'}
form_content = {$smarty.capture.delete_accessory_dialog nofilter}
}
{* Delete category confirmation dialog *}
{capture "delete_category_dialog"}
<input type="hidden" name="product_id" value="{$product_id}" />
<input type="hidden" name="additional_category_id" id="additional_category_delete_id" value="" />
<input type="hidden" name="current_tab" value="related" />
{/capture}
{include
file = "includes/generic-confirm-dialog.html"
dialog_id = "delete_category_dialog"
dialog_title = {intl l="Remove from category"}
dialog_message = {intl l="Do you really want to remove the product from this category ?"}
form_action = {url path='/admin/products/category/delete'}
form_content = {$smarty.capture.delete_category_dialog nofilter}
}
<script>
$(function() {
// Set proper content ID in delete content from
$('a.delete-content').click(function(ev) {
$('#content_delete_id').val($(this).data('id'));
$('#folder_delete_id').val($('#folder_id').val());
});
// Set proper content ID in accessory delete from
$('a.delete-accessory').click(function(ev) {
$('#accessory_delete_id').val($(this).data('id'));
$('#accessory_category_delete_id').val($('#accessory_category_id').val());
});
// Set proper content ID in accessory delete from
$('a.delete-category').click(function(ev) {
$('#additional_category_delete_id').val($(this).data('id'));
});
// Load content on folder selection
$('#folder_id').change(function(event) {
var val = $(this).val();
if (val != "") {
$.ajax({
url : '{url path="/admin/product/$product_id/available-content/"}' + $(this).val() + '.xml',
type : 'get',
dataType : 'json',
success : function(json) {
$('#content_id :not(:first-child)').remove();
var have_content = false;
$.each(json, function(idx, value) {
$('#content_id').append($('<option>').text(value.title).attr('value', value.id));
have_content = true; // Lame...
});
if (have_content) {
$('#content_selector_empty').addClass('hide');
$('#content_selector').removeClass('hide');
}
else {
$('#content_selector_empty').removeClass('hide');
$('#content_selector').addClass('hide');
}
}
});
}
else {
$('#content_selector_empty').addClass('hide');
$('#content_selector').addClass('hide');
}
});
// Load accessory on category selection
$('#accessory_category_id').change(function(event) {
var val = $(this).val();
if (val != "") {
$.ajax({
url : '{url path="/admin/product/$product_id/available-accessories/"}' + $(this).val() + '.xml',
type : 'get',
dataType : 'json',
success : function(json) {
$('#accessory_id :not(:first-child)').remove();
var have_content = false;
$.each(json, function(idx, value) {
$('#accessory_id').append($('<option>').text(value.title).attr('value', value.id));
have_content = true; // Lame...
});
if (have_content) {
$('#accessory_selector_empty').addClass('hide');
$('#accessory_selector').removeClass('hide');
}
else {
$('#accessory_selector_empty').removeClass('hide');
$('#accessory_selector').addClass('hide');
}
}
});
}
else {
$('#accessory_selector_empty').addClass('hide');
$('#accessory_selector').addClass('hide');
}
});
{* Inline editing of accessory position using bootstrap-editable *}
$('.accessoryPositionChange').editable({
type : 'text',
title : '{intl l="Enter new accessory position"}',
mode : 'popup',
inputclass : 'input-mini',
placement : 'left',
success : function(response, newValue) {
// The URL template
var url = "{url noamp='1' path='/admin/product/update-accessory-position' accessory_id='__ID__' position='__POS__' product_id=$product_id current_tab='related' }";
// Perform subtitutions
url = url.replace('__ID__', $(this).data('id')).replace('__POS__', newValue);
// Reload the page
location.href = url;
}
});
$('.contentPositionChange').editable({
type : 'text',
title : '{intl l="Enter new content position"}',
mode : 'popup',
inputclass : 'input-mini',
placement : 'left',
success : function(response, newValue) {
// The URL template
var url = "{url noamp='1' path='/admin/product/update-content-position' content_id='__ID__' position='__POS__' product_id=$product_id current_tab='related' }";
// Perform subtitutions
url = url.replace('__ID__', $(this).data('id')).replace('__POS__', newValue);
// Reload the page
location.href = url;
}
});
// Initialize folder (id={$folder_id}) select value
{if $folder_id != 0}
$('#folder_id').val("{$folder_id}").change();
{/if}
// Initialize accessory category id (id={$accessory_category_id}) select value
{if $accessory_category_id != 0}
$('#accessory_category_id').val("{$accessory_category_id}").change();
{/if}
// Unselect all options in attribute + feature tab
$('.clear_feature_value').click(function(event){
$('#feature_value_' + $(this).data('id') + ' option').prop('selected', false);
event.preventDefault();
});
});
</script>
{/loop}

View File

@@ -1,12 +1,12 @@
<div class="form-group">
{ifloop rel="free_attributes"}
<form action="{url path='/admin/configuration/templates/attributes/add'}">
<form method="POST" 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>
<option value="">{intl l='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}
@@ -33,6 +33,8 @@
<th>{intl l='Attribute title'}</th>
<th class="text-center">{intl l='Position'}</th>
{module_include location='template_attributes_table_header'}
<th class="actions">{intl l="Actions"}</th>
@@ -44,8 +46,17 @@
<tr>
<td>{$ID}</td>
<td>
{$TITLE}
<td>{$TITLE}</td>
<td class="text-center">
{admin_position_block
permission="admin.templates.edit"
path={url path="admin/template/update-attribute-position" template_id=$template_id}
url_parameter="attribute_id"
in_place_edit_class="attributePositionChange"
position=$POSITION
id=$ID
}
</td>
{module_include location='template_attributes_table_row'}
@@ -64,7 +75,7 @@
{elseloop rel="assigned_attributes"}
<tr>
<td colspan="3">
<td colspan="4">
<div class="alert alert-info">
{intl l="This template contains no attributes"}
</div>
@@ -93,11 +104,33 @@
}
<script>
$(function() {
// Set proper attribute ID in delete attribute from
$('a.delete-attribute').click(function(ev) {
$('#attribute_delete_id').val($(this).data('id'));
});
{* Inline editing of object position using bootstrap-editable *}
$('.attributePositionChange').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 noamp='1' path="admin/template/update-attribute-position" template_id=$template_id attribute_id='__ID__' position='__POS__'}";
// Perform subtitutions
url = url.replace('__ID__', $(this).data('id')).replace('__POS__', newValue);
// Reload the page
location.href = url;
}
});
});
</script>

View File

@@ -1,12 +1,12 @@
<div class="form-group">
{ifloop rel="free_features"}
<form action="{url path='/admin/configuration/templates/features/add'}">
<form method="POST" 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>
<option value="">{intl l='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}
@@ -33,6 +33,8 @@
<th>{intl l='Feature title'}</th>
<th class="text-center">{intl l='Position'}</th>
{module_include location='template_features_table_header'}
<th class="actions">{intl l="Actions"}</th>
@@ -48,6 +50,17 @@
{$TITLE}
</td>
<td class="text-center">
{admin_position_block
permission="admin.templates.edit"
path={url path="/admin/template/update-feature-position" template_id=$template_id}
url_parameter="feature_id"
in_place_edit_class="featurePositionChange"
position=$POSITION
id=$ID
}
</td>
{module_include location='template_features_table_row'}
<td class="actions">
@@ -64,7 +77,7 @@
{elseloop rel="assigned_features"}
<tr>
<td colspan="3">
<td colspan="4">
<div class="alert alert-info">
{intl l="This template contains no features"}
</div>
@@ -100,5 +113,26 @@
$('a.delete-feature').click(function(ev) {
$('#feature_delete_id').val($(this).data('id'));
});
{* Inline editing of object position using bootstrap-editable *}
$('.featurePositionChange').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 noamp='1' path='/admin/template/update-feature-position' template_id=$template_id feature_id='__ID__' position='__POS__'}";
// Perform subtitutions
url = url.replace('__ID__', $(this).data('id')).replace('__POS__', newValue);
// Reload the page
location.href = url;
}
});
});
</script>

View File

@@ -0,0 +1,100 @@
$(function($){
// Manage document upload
$.documentUploadManager = {};
Dropzone.autoDiscover = false;
// Remove image on click
$.documentUploadManager.initDocumentDropZone = function() {
$.documentUploadManager.onClickDeleteDocument();
var documentDropzone = new Dropzone("#documents-dropzone", {
dictDefaultMessage : $('.btn-browse').html(),
uploadMultiple: false,
maxFilesize: 8
});
var totalFiles = 0,
completedFiles = 0;
documentDropzone.on("addedfile", function(file){
totalFiles += 1;
if(totalFiles == 1){
$('.dz-message').hide();
}
});
documentDropzone.on("complete", function(file){
completedFiles += 1;
if (completedFiles === totalFiles){
$('.dz-message').slideDown();
}
});
documentDropzone.on("success", function(file) {
documentDropzone.removeFile(file);
$.documentUploadManager.updateDocumentListAjax();
$.documentUploadManager.onClickDeleteDocument();
});
};
// Update picture list via AJAX call
$.documentUploadManager.updateDocumentListAjax = function() {
var $documentListArea = $(".document-manager .existing-document");
$documentListArea.html('<div class="loading" ></div>');
$.ajax({
type: "POST",
url: documentListUrl,
statusCode: {
404: function() {
$documentListArea.html(
documentListErrorMessage
);
}
}
}).done(function(data) {
$documentListArea.html(
data
);
$.documentUploadManager.onClickDeleteDocument();
});
};
// Remove image on click
$.documentUploadManager.onClickDeleteDocument = function() {
$('.document-manager .document-delete-btn').on('click', function (e) {
e.preventDefault();
var $this = $(this);
var $parent = $this.parent();
$parent.find('a').remove();
$parent.append('<div class="loading" ></div>');
var $url = $this.attr("href");
var errorMessage = $this.attr("data-error-message");
$.ajax({
type: "POST",
url: $url,
statusCode: {
404: function() {
$(".document-manager .message").html(
errorMessage
);
}
}
}).done(function(data) {
$parent.parents('tr').remove();
$(".document-manager .message").html(
data
);
});
return false;
});
};
});

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,102 @@
$(function($){
// Manage picture upload
$.imageUploadManager = {};
Dropzone.autoDiscover = false;
// Remove image on click
$.imageUploadManager.initImageDropZone = function() {
$.imageUploadManager.onClickDeleteImage();
var imageDropzone = new Dropzone("#images-dropzone", {
dictDefaultMessage : $('.btn-browse').html(),
uploadMultiple: false,
maxFilesize: 8,
acceptedFiles: 'image/png, image/gif, image/jpeg'
});
var totalFiles = 0,
completedFiles = 0;
imageDropzone.on("addedfile", function(file){
totalFiles += 1;
if(totalFiles == 1){
$('.dz-message').hide();
}
});
imageDropzone.on("complete", function(file){
completedFiles += 1;
if (completedFiles === totalFiles){
$('.dz-message').slideDown();
}
});
imageDropzone.on("success", function(file) {
imageDropzone.removeFile(file);
$.imageUploadManager.updateImageListAjax();
$.imageUploadManager.onClickDeleteImage();
});
};
// Update picture list via AJAX call
$.imageUploadManager.updateImageListAjax = function() {
var $imageListArea = $(".image-manager .existing-image");
$imageListArea.html('<div class="loading" ></div>');
$.ajax({
type: "POST",
url: imageListUrl,
statusCode: {
404: function() {
$imageListArea.html(
imageListErrorMessage
);
}
}
}).done(function(data) {
$imageListArea.html(
data
);
$.imageUploadManager.onClickDeleteImage();
});
};
// Remove image on click
$.imageUploadManager.onClickDeleteImage = function() {
$('.image-manager .image-delete-btn').on('click', function (e) {
e.preventDefault();
var $this = $(this);
var $parent = $this.parent();
var $greatParent = $parent.parent();
$greatParent.append('<div class="loading" ></div>');
$greatParent.find('.btn-group').remove();
var $url = $this.attr("href");
var errorMessage = $this.attr("data-error-message");
$.ajax({
type: "POST",
url: $url,
statusCode: {
404: function() {
$(".image-manager .message").html(
errorMessage
);
}
}
}).done(function(data) {
$greatParent.remove();
$(".image-manager .message").html(
data
);
});
return false;
});
};
});

View File

@@ -0,0 +1,160 @@
.dropzone{
cursor: pointer;
border: 4px dashed @gray-lighter;
padding: 70px;
margin: 20px 0;
&.dz-drag-hover{
border-color: @brand-primary;
}
.dz-message {
text-align: center;
span{
font-size: @font-size-large;
display: block;
color: @gray;
span{
display: block;
font-weight: bold;
margin: 10px 0;
font-size: @font-size-small;
}
button{
span{
display: inline-block;
font-size: @font-size-base;
margin: 0;
color: inherit;
}
}
}
}
.dz-error{
.alert();
.alert-danger();
margin: 10px 0;
}
.dz-preview,
.dropzone-previews .dz-preview {
background: rgba(255,255,255,0.8);
position: relative;
display: inline-block;
margin: 17px;
vertical-align: top;
border: 1px solid #acacac;
padding: 6px 6px 6px 6px;
}
.dz-preview.dz-file-preview [data-dz-thumbnail],
.dropzone-previews .dz-preview.dz-file-preview [data-dz-thumbnail] {
display: none;
}
.dz-preview .dz-details,
.dropzone-previews .dz-preview .dz-details {
width: 100px;
height: 100px;
position: relative;
background: #ebebeb;
padding: 5px;
margin-bottom: 22px;
}
.dz-preview .dz-details .dz-filename,
.dropzone-previews .dz-preview .dz-details .dz-filename {
overflow: hidden;
height: 100%;
}
.dz-preview .dz-details img,
.dropzone-previews .dz-preview .dz-details img {
position: absolute;
top: 0;
left: 0;
width: 100px;
height: 100px;
}
.dz-preview .dz-details .dz-size,
.dropzone-previews .dz-preview .dz-details .dz-size {
position: absolute;
bottom: -28px;
left: 3px;
height: 28px;
line-height: 28px;
}
.dz-preview.dz-error .dz-error-mark,
.dropzone-previews .dz-preview.dz-error .dz-error-mark {
display: block;
}
.dz-preview.dz-success .dz-success-mark,
.dropzone-previews .dz-preview.dz-success .dz-success-mark {
display: block;
}
.dz-preview:hover .dz-details img,
.dropzone-previews .dz-preview:hover .dz-details img {
display: none;
}
.dz-preview .dz-success-mark,
.dropzone-previews .dz-preview .dz-success-mark,
.dz-preview .dz-error-mark,
.dropzone-previews .dz-preview .dz-error-mark {
display: none;
position: absolute;
width: 40px;
height: 40px;
font-size: 30px;
text-align: center;
right: -10px;
top: -10px;
}
.dz-preview .dz-success-mark,
.dropzone-previews .dz-preview .dz-success-mark {
color: #8cc657;
}
.dz-preview .dz-error-mark,
.dropzone-previews .dz-preview .dz-error-mark {
color: #ee162d;
}
.dz-preview .dz-progress,
.dropzone-previews .dz-preview .dz-progress {
position: absolute;
top: 100px;
left: 6px;
right: 6px;
height: 6px;
background: #d7d7d7;
display: none;
}
.dz-preview .dz-progress .dz-upload,
.dropzone-previews .dz-preview .dz-progress .dz-upload {
position: absolute;
top: 0;
bottom: 0;
left: 0;
width: 0%;
background-color: #8cc657;
}
.dz-preview.dz-processing .dz-progress,
.dropzone-previews .dz-preview.dz-processing .dz-progress {
display: block;
}
.dz-preview .dz-error-message,
.dropzone-previews .dz-preview .dz-error-message {
display: none;
position: absolute;
top: -5px;
left: -20px;
background: rgba(245,245,245,0.8);
padding: 8px 10px;
color: #800;
min-width: 140px;
max-width: 500px;
z-index: 500;
}
.dz-preview:hover.dz-error .dz-error-message,
.dropzone-previews .dz-preview:hover.dz-error .dz-error-message {
display: block;
}
}

View File

@@ -14,6 +14,7 @@
@import "bootstrap-switch.less";
@import "bootstrap-select.less";
@import "jqplot.less";
@import "dropzone.less";
// -- Base styling ------------------------------------------------------------
@@ -226,6 +227,14 @@
}
}
.tab-content {
// Center loading indicator
.loading {
margin: 8em auto;
text-align: center;
}
}
// The overall form container
.form-container {
@@ -275,5 +284,33 @@
.loading{
background: url("@{imgDir}/ajax-loader.gif") no-repeat;
height: 30px;
width: 30px;
display: inline-block;
line-height: 30px;
padding-left: 40px;
width: auto;
}
.existing-image .col-sm-6{
position: relative;
margin-bottom: 30px;
.btn-group{
position: absolute;
bottom: 5px;
right: 20px;
}
.loading{
position: absolute;
bottom: 5px;
right: 20px;
display: block;
line-height: 1;
padding: 0;
margin: 0 auto;
z-index: 2;
width: 30px;
height: 30px;
}
}

View File

@@ -303,7 +303,7 @@
placement : 'left',
success : function(response, newValue) {
// The URL template
var url = "{url path='/admin/configuration/attributes-av/update-position' attributeav_id='__ID__' position='__POS__' attribute_id=$attribute_id}";
var url = "{url noamp='1' path='/admin/configuration/attributes-av/update-position' attributeav_id='__ID__' position='__POS__' attribute_id=$attribute_id}";
// Perform subtitutions
url = url.replace('__ID__', $(this).data('id')).replace('__POS__', newValue);

View File

@@ -312,7 +312,7 @@
placement : 'left',
success : function(response, newValue) {
// The URL template
var url = "{url path='/admin/configuration/attributes/update-position' attribute_id='__ID__' position='__POS__'}";
var url = "{url noamp='1' path='/admin/configuration/attributes/update-position' attribute_id='__ID__' position='__POS__'}";
// Perform subtitutions
url = url.replace('__ID__', $(this).data('id'))

View File

@@ -256,7 +256,7 @@
}
</th>
<th>&nbsp;</th>
<th class="actions">{intl l="Actions"}</th>
</tr>
</thead>
@@ -303,7 +303,7 @@
}
</td>
<td>
<td class="actions">
<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/products/update' product_id=$ID}"><i class="glyphicon glyphicon-edit"></i></a>
@@ -445,7 +445,7 @@
{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"}
{loop type="lang" name="default-lang" default_only="1" backend_context="1"}
<div class="input-group">
<input type="text" id="{$label_attr.for}" required="required" name="{$name}" class="form-control" value="{$value}" title="{$label}" placeholder="{intl l='Title'}">
<span class="input-group-addon"><img src="{image file="assets/img/flags/{$CODE}.gif"}" alt="$TITLE" /></span>
@@ -463,6 +463,64 @@
</div>
{/form_field}
{form_field form=$form field='price'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{$label} : </label>
{loop type="currency" name="default-currency" default_only="1" backend_context="1"}
<div class="row">
<div class="col-lg-4">
<div class="input-group">
<input type="text" id="{$label_attr.for}" required="required" name="{$name}" class="col-lg-2 form-control" value="{$value}" title="{$label}" placeholder="{intl l='Product price'}">
<span class="input-group-addon">{$SYMBOL}</span>
</div>
</div>
</div>
<div class="help-block">{intl l='Enter here the product price in the default currency (%title)' title=$NAME}</div>
{form_field form=$form field='currency'}
<input type="hidden" name="{$name}" value="{$ID}" />
{/form_field}
{/loop}
</div>
{/form_field}
{form_field form=$form field='tax_rule'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{$label} : </label>
<div class="form-group">
<select id="{$label_attr.for}" required="required" name="{$name}" class="form-control">
<option value="">{intl l="Select a tax tule"}</option>
{loop name="tax" type="tax-rule" backend_context="1"}
<option value="{$ID}" {if $IS_DEFAULT}selected="selected"{/if}>{$TITLE}</option>
{/loop}
</select>
</div>
<div class="help-block">{intl l='Select here the tax applicable to this product'}</div>
</div>
{/form_field}
{form_field form=$form field='weight'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{$label}: </label>
<div class="row">
<div class="col-lg-4">
<div class="input-group">
<input type="text" id="{$label_attr.for}" required="required" name="{$name}" class="form-control" value="{$value}" title="{$label}" placeholder="{intl l='Product weight'}">
<span class="input-group-addon">{intl l="Kg"}</span>
</div>
</div>
</div>
<div class="help-block">{intl l='Enter here the product weight, in Kilogrammes'}</div>
</div>
{/form_field}
{form_field form=$form field='visible'}
<div class="form-group {if $error}has-error{/if}">
<div class="checkbox">
@@ -604,7 +662,7 @@
placement : 'left',
success : function(response, newValue) {
// The URL template
var url = "{url path='/admin/categories/update-position' category_id='__ID__' position='__POS__'}";
var url = "{url noamp='1' path='/admin/categories/update-position' category_id='__ID__' position='__POS__'}";
// Perform subtitutions
url = url.replace('__ID__', $(this).data('id'))
@@ -623,7 +681,7 @@
placement : 'left',
success : function(response, newValue) {
// The URL template
var url = "{url path='/admin/products/update-position' product_id='__ID__' position='__POS__'}";
var url = "{url noamp='1' path='/admin/products/update-position' product_id='__ID__' position='__POS__'}";
// Perform subtitutions
url = url.replace('__ID__', $(this).data('id'))

View File

@@ -163,7 +163,7 @@
<div class="col-md-6">
<div class="form-group">
<select name="folder_id" id="folder_id" class="form-control">
<option value="">Select a folder...</option>
<option value="">{intl l='Select a folder...'}</option>
{loop name="folders" type="folder-tree" folder="0" backend_context="1" lang="$edit_language_id"}
<option value="{$ID}" style="padding-left: {3 + $LEVEL * 20}px">{$TITLE}</option>
{/loop}
@@ -176,7 +176,7 @@
<div id="content_selector" class="hide">
<div class="input-group">
<select required="required" name="content_id" id="content_id" class="form-control">
<option value="">Select a folder content...</option>
<option value="">{intl l='Select a folder content...'}</option>
</select>
<span class="input-group-btn" id="content_add_button">
<button class="btn btn-default btn-primary action-btn" type="submit"><span class="glyphicon glyphicon-plus-sign"></span></button>
@@ -256,9 +256,11 @@
</div>
<div class="tab-pane fade {if $current_tab == 'images'}active in{/if}" id="images">
{include file='includes/image-upload-form.html' imageType='category' parentId=$category_id}
</div>
<div class="tab-pane fade {if $current_tab == 'documents'}active in{/if}" id="documents">
{include file='includes/document-upload-form.html' documentType='category' parentId=$category_id}
</div>
<div class="tab-pane fade {if $current_tab == 'modules'}active in{/if}" id="modules">
@@ -296,6 +298,17 @@
{/block}
{block name="javascript-initialization"}
{javascripts file='assets/js/dropzone.js'}
<script src="{$asset_url}"></script>
{/javascripts}
{javascripts file='assets/js/image-upload.js'}
<script src="{$asset_url}"></script>
{/javascripts}
{javascripts file='assets/js/document-upload.js'}
<script src="{$asset_url}"></script>
{/javascripts}
<script src="{url file='/tinymce/tinymce.min.js'}"></script>
<script>
@@ -315,11 +328,10 @@
filemanager_title:"{intl l='Files manager'}" ,
external_plugins: { "filemanager" : "{url file='/tinymce/plugins/filemanager/plugin.min.js'}"}
});
</script>
<script>
$(function() {
$.imageUploadManager.initImageDropZone();
$.documentUploadManager.initDocumentDropZone();
$('.use_default_rewriten_url').click(function(ev) {
alert("Not functionnal");

Some files were not shown because too many files have changed in this diff Show More