diff --git a/core/lib/Thelia/Action/Category.php b/core/lib/Thelia/Action/Category.php index 64254d734..25a94711f 100755 --- a/core/lib/Thelia/Action/Category.php +++ b/core/lib/Thelia/Action/Category.php @@ -160,6 +160,7 @@ class Category extends BaseAction implements EventSubscriberInterface $content = new CategoryAssociatedContent(); $content + ->setDispatcher($this->getDispatcher()) ->setCategory($event->getCategory()) ->setContentId($event->getContentId()) ->save() @@ -174,7 +175,11 @@ class Category extends BaseAction implements EventSubscriberInterface ->filterByCategory($event->getCategory())->findOne() ; - if ($content !== null) $content->delete(); + if ($content !== null) { + $content + ->setDispatcher($this->getDispatcher()) + ->delete(); + } } diff --git a/core/lib/Thelia/Action/Product.php b/core/lib/Thelia/Action/Product.php index cb7bb04df..69a07c157 100644 --- a/core/lib/Thelia/Action/Product.php +++ b/core/lib/Thelia/Action/Product.php @@ -44,6 +44,10 @@ use Thelia\Model\ProductCategory; use Thelia\Model\TaxRule; use Thelia\Model\TaxRuleQuery; use Thelia\Model\TaxQuery; +use Thelia\Model\AccessoryQuery; +use Thelia\Model\Accessory; +use Thelia\Core\Event\ProductAddAccessoryEvent; +use Thelia\Core\Event\ProductDeleteAccessoryEvent; class Product extends BaseAction implements EventSubscriberInterface { @@ -167,6 +171,7 @@ class Product extends BaseAction implements EventSubscriberInterface $content = new ProductAssociatedContent(); $content + ->setDispatcher($this->getDispatcher()) ->setProduct($event->getProduct()) ->setContentId($event->getContentId()) ->save() @@ -181,9 +186,66 @@ class Product extends BaseAction implements EventSubscriberInterface ->filterByProduct($event->getProduct())->findOne() ; - if ($content !== null) $content->delete(); + if ($content !== null) + $content + ->setDispatcher($this->getDispatcher()) + ->delete() + ; } + public function addAccessory(ProductAddAccessoryEvent $event) { + + if (AccessoryQuery::create() + ->filterByAccessory($event->getAccessoryId()) + ->filterByProductId($event->getProduct()->getId())->count() <= 0) { + + $accessory = new Accessory(); + + $accessory + ->setDispatcher($this->getDispatcher()) + ->setProductId($event->getProduct()->getId()) + ->setAccessory($event->getAccessoryId()) + ->save() + ; + } + } + + public function removeAccessory(ProductDeleteAccessoryEvent $event) { + + $accessory = AccessoryQuery::create() + ->filterByAccessory($event->getAccessoryId()) + ->filterByProductId($event->getProduct()->getId())->findOne() + ; + + if ($accessory !== null) + $accessory + ->setDispatcher($this->getDispatcher()) + ->delete() + ; + } + + + /** + * Changes position, selecting absolute ou relative change. + * + * @param ProductChangePositionEvent $event + */ + public function updateAccessoryPosition(UpdatePositionEvent $event) + { + if (null !== $accessory = AccessoryQuery::create()->findPk($event->getObjectId())) { + + $accessory->setDispatcher($this->getDispatcher()); + + $mode = $event->getMode(); + + 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(); + } + } /** * {@inheritDoc} @@ -198,9 +260,12 @@ class Product extends BaseAction implements EventSubscriberInterface TheliaEvents::PRODUCT_UPDATE_POSITION => array("updatePosition", 128), - TheliaEvents::PRODUCT_ADD_CONTENT => array("addContent", 128), - TheliaEvents::PRODUCT_REMOVE_CONTENT => array("removeContent", 128), + TheliaEvents::PRODUCT_ADD_CONTENT => array("addContent", 128), + TheliaEvents::PRODUCT_REMOVE_CONTENT => array("removeContent", 128), + TheliaEvents::PRODUCT_UPDATE_ACCESSORY_POSITION => array("updateAccessoryPosition", 128), + TheliaEvents::PRODUCT_ADD_ACCESSORY => array("addAccessory", 128), + TheliaEvents::PRODUCT_REMOVE_ACCESSORY => array("removeAccessory", 128), ); } } diff --git a/core/lib/Thelia/Config/Resources/config.xml b/core/lib/Thelia/Config/Resources/config.xml index 9df11ba72..43e48f6e4 100755 --- a/core/lib/Thelia/Config/Resources/config.xml +++ b/core/lib/Thelia/Config/Resources/config.xml @@ -31,6 +31,7 @@ + diff --git a/core/lib/Thelia/Config/Resources/routing/admin.xml b/core/lib/Thelia/Config/Resources/routing/admin.xml index 693224fa7..a34cbdca6 100755 --- a/core/lib/Thelia/Config/Resources/routing/admin.xml +++ b/core/lib/Thelia/Config/Resources/routing/admin.xml @@ -150,6 +150,8 @@ Thelia\Controller\Admin\ProductController::updatePositionAction + + Thelia\Controller\Admin\ProductController::addRelatedContentAction @@ -162,7 +164,27 @@ Thelia\Controller\Admin\ProductController::getAvailableRelatedContentAction xml|json - + + + + + Thelia\Controller\Admin\ProductController::addAccessoryAction + + + + Thelia\Controller\Admin\ProductController::deleteAccessoryAction + + + + Thelia\Controller\Admin\ProductController::getAvailableAccessoriesAction + xml|json + + + + Thelia\Controller\Admin\ProductController::updateAccessoryPositionAction + + + Thelia\Controller\Admin\FolderController::indexAction diff --git a/core/lib/Thelia/Controller/Admin/ProductController.php b/core/lib/Thelia/Controller/Admin/ProductController.php index 2dc57d3cb..27c559442 100644 --- a/core/lib/Thelia/Controller/Admin/ProductController.php +++ b/core/lib/Thelia/Controller/Admin/ProductController.php @@ -39,6 +39,10 @@ use Thelia\Model\FolderQuery; use Thelia\Model\ContentQuery; use Propel\Runtime\ActiveQuery\Criteria; use Thelia\Model\ProductAssociatedContentQuery; +use Thelia\Model\AccessoryQuery; +use Thelia\Model\CategoryQuery; +use Thelia\Core\Event\ProductAddAccessoryEvent; +use Thelia\Core\Event\ProductDeleteAccessoryEvent; /** * Manages products @@ -175,10 +179,11 @@ class ProductController extends AbstractCrudController protected function getEditionArguments() { return array( - 'category_id' => $this->getCategoryId(), - 'product_id' => $this->getRequest()->get('product_id', 0), - 'folder_id' => $this->getRequest()->get('folder_id', 0), - 'current_tab' => $this->getRequest()->get('current_tab', 'general') + '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), + 'current_tab' => $this->getRequest()->get('current_tab', 'general') ); } @@ -275,6 +280,8 @@ class ProductController extends AbstractCrudController ); } + // -- Related content management ------------------------------------------- + public function getAvailableRelatedContentAction($productId, $folderId) { $result = array(); @@ -353,4 +360,118 @@ class ProductController extends AbstractCrudController $this->redirectToEditionTemplate(); } + + + // -- Accessories management ---------------------------------------------- + + public function getAvailableAccessoriesAction($productId, $categoryId) + { + $result = array(); + + $categories = CategoryQuery::create()->filterById($categoryId)->find(); + + if ($categories !== null) { + + $list = ProductQuery::create() + ->joinWithI18n($this->getCurrentEditionLocale()) + ->filterByCategory($categories, Criteria::IN) + ->filterById(AccessoryQuery::create()->select('accessory')->findByProductId($productId), Criteria::NOT_IN) + ->find(); + ; + + if ($list !== null) { + foreach($list as $item) { + $result[] = array('id' => $item->getId(), 'title' => $item->getTitle()); + } + } + } + + return $this->jsonResponse(json_encode($result)); + } + + public function addAccessoryAction() + { + // Check current user authorization + if (null !== $response = $this->checkAuth("admin.products.update")) return $response; + + $accessory_id = intval($this->getRequest()->get('accessory_id')); + + if ($accessory_id > 0) { + + $event = new ProductAddAccessoryEvent( + $this->getExistingObject(), + $accessory_id + ); + + try { + $this->dispatch(TheliaEvents::PRODUCT_ADD_ACCESSORY, $event); + } + catch (\Exception $ex) { + // Any error + return $this->errorPage($ex); + } + } + + $this->redirectToEditionTemplate(); + } + + public function deleteAccessoryAction() + { + + // Check current user authorization + if (null !== $response = $this->checkAuth("admin.products.update")) return $response; + + $accessory_id = intval($this->getRequest()->get('accessory_id')); + + if ($accessory_id > 0) { + + $event = new ProductDeleteAccessoryEvent( + $this->getExistingObject(), + $accessory_id + ); + + try { + $this->dispatch(TheliaEvents::PRODUCT_REMOVE_ACCESSORY, $event); + } + catch (\Exception $ex) { + // Any error + return $this->errorPage($ex); + } + } + + $this->redirectToEditionTemplate(); + } + + /** + * Update accessory position (only for objects whichsupport that) + */ + public function updateAccessoryPositionAction() + { + // Check current user authorization + if (null !== $response = $this->checkAuth('admin.products.update')) return $response; + + 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($mode, $position); + + $this->dispatch(TheliaEvents::PRODUCT_UPDATE_ACCESSORY_POSITION, $event); + } + catch (\Exception $ex) { + // Any error + return $this->errorPage($ex); + } + + $this->redirectToEditionTemplate(); + } + } diff --git a/core/lib/Thelia/Core/Event/AccessoryEvent.php b/core/lib/Thelia/Core/Event/AccessoryEvent.php new file mode 100644 index 000000000..1e14e6fb7 --- /dev/null +++ b/core/lib/Thelia/Core/Event/AccessoryEvent.php @@ -0,0 +1,54 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Core\Event; + +use Thelia\Model\Accessory; +use Thelia\Core\Event\ActionEvent; + +class AccessoryEvent extends ActionEvent +{ + public $accessory = null; + + public function __construct(Accessory $accessory = null) + { + $this->accessory = $accessory; + } + + public function hasAccessory() + { + return ! is_null($this->accessory); + } + + public function getAccessory() + { + return $this->accessory; + } + + public function setAccessory(Accessory $accessory) + { + $this->accessory = $accessory; + + return $this; + } +} diff --git a/core/lib/Thelia/Core/Event/CategoryAssociatedContentEvent.php b/core/lib/Thelia/Core/Event/CategoryAssociatedContentEvent.php new file mode 100644 index 000000000..1984a042c --- /dev/null +++ b/core/lib/Thelia/Core/Event/CategoryAssociatedContentEvent.php @@ -0,0 +1,54 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Core\Event; + +use Thelia\Model\CategoryAssociatedContent; +use Thelia\Core\Event\ActionEvent; + +class CategoryAssociatedContentEvent extends ActionEvent +{ + public $content = null; + + public function __construct(CategoryAssociatedContent $content = null) + { + $this->content = $content; + } + + public function hasCategoryAssociatedContent() + { + return ! is_null($this->content); + } + + public function getCategoryAssociatedContent() + { + return $this->content; + } + + public function setCategoryAssociatedContent(CategoryAssociatedContent $content) + { + $this->content = $content; + + return $this; + } +} diff --git a/core/lib/Thelia/Core/Event/ProductAddAccessoryEvent.php b/core/lib/Thelia/Core/Event/ProductAddAccessoryEvent.php new file mode 100644 index 000000000..d3f2ba19b --- /dev/null +++ b/core/lib/Thelia/Core/Event/ProductAddAccessoryEvent.php @@ -0,0 +1,48 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Core\Event; + +use Thelia\Model\Product; + +class ProductAddAccessoryEvent extends ProductEvent +{ + protected $accessory_id; + + public function __construct(Product $product, $accessory_id) + { + parent::__construct($product); + + $this->accessory_id = $accessory_id; + } + + public function getAccessoryId() + { + return $this->accessory_id; + } + + public function setAccessoryId($accessory_id) + { + $this->accessory_id = $accessory_id; + } +} diff --git a/core/lib/Thelia/Core/Event/ProductAssociatedContentEvent.php b/core/lib/Thelia/Core/Event/ProductAssociatedContentEvent.php new file mode 100644 index 000000000..ba41b5ede --- /dev/null +++ b/core/lib/Thelia/Core/Event/ProductAssociatedContentEvent.php @@ -0,0 +1,54 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Core\Event; + +use Thelia\Model\ProductAssociatedContent; +use Thelia\Core\Event\ActionEvent; + +class ProductAssociatedContentEvent extends ActionEvent +{ + public $content = null; + + public function __construct(ProductAssociatedContent $content = null) + { + $this->content = $content; + } + + public function hasProductAssociatedContent() + { + return ! is_null($this->content); + } + + public function getProductAssociatedContent() + { + return $this->content; + } + + public function setProductAssociatedContent(ProductAssociatedContent $content) + { + $this->content = $content; + + return $this; + } +} diff --git a/core/lib/Thelia/Core/Event/ProductDeleteAccessoryEvent.php b/core/lib/Thelia/Core/Event/ProductDeleteAccessoryEvent.php new file mode 100644 index 000000000..9644cdacc --- /dev/null +++ b/core/lib/Thelia/Core/Event/ProductDeleteAccessoryEvent.php @@ -0,0 +1,48 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Core\Event; + +use Thelia\Model\Product; + +class ProductDeleteAccessoryEvent extends ProductEvent +{ + protected $accessory_id; + + public function __construct(Product $product, $accessory_id) + { + parent::__construct($product); + + $this->accessory_id = $accessory_id; + } + + public function getAccessoryId() + { + return $this->accessory_id; + } + + public function setAccessoryId($accessory_id) + { + $this->accessory_id = $accessory_id; + } +} diff --git a/core/lib/Thelia/Core/Event/TheliaEvents.php b/core/lib/Thelia/Core/Event/TheliaEvents.php index 3b049bfef..75f5314f0 100755 --- a/core/lib/Thelia/Core/Event/TheliaEvents.php +++ b/core/lib/Thelia/Core/Event/TheliaEvents.php @@ -165,6 +165,17 @@ final class TheliaEvents const BEFORE_UPDATECATEGORY = "action.before_updateCategory"; const AFTER_UPDATECATEGORY = "action.after_updateCategory"; + // -- Categories Associated Content ---------------------------------------- + + 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_UPDATECATEGORY_ASSOCIATED_CONTENT = "action.before_updateCategoryAssociatedContent"; + const AFTER_UPDATECATEGORY_ASSOCIATED_CONTENT = "action.after_updateCategoryAssociatedContent"; + // -- Product management ----------------------------------------------- const PRODUCT_CREATE = "action.createProduct"; @@ -176,6 +187,10 @@ final class TheliaEvents const PRODUCT_ADD_CONTENT = "action.productAddContent"; const PRODUCT_REMOVE_CONTENT = "action.productRemoveContent"; + const PRODUCT_ADD_ACCESSORY = "action.productAddAccessory"; + const PRODUCT_REMOVE_ACCESSORY = "action.productRemoveAccessory"; + const PRODUCT_UPDATE_ACCESSORY_POSITION = "action.updateProductPosition"; + const BEFORE_CREATEPRODUCT = "action.before_createproduct"; const AFTER_CREATEPRODUCT = "action.after_createproduct"; @@ -185,6 +200,28 @@ final class TheliaEvents const BEFORE_UPDATEPRODUCT = "action.before_updateProduct"; const AFTER_UPDATEPRODUCT = "action.after_updateProduct"; + // -- Product Accessories -------------------------------------------------- + + const BEFORE_CREATEACCESSORY = "action.before_createAccessory"; + const AFTER_CREATEACCESSORY = "action.after_createAccessory"; + + const BEFORE_DELETEACCESSORY = "action.before_deleteAccessory"; + const AFTER_DELETEACCESSORY = "action.after_deleteAccessory"; + + const BEFORE_UPDATEACCESSORY = "action.before_updateAccessory"; + const AFTER_UPDATEACCESSORY = "action.after_updateAccessory"; + + // -- 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_UPDATEPRODUCT_ASSOCIATED_CONTENT = "action.before_updateProductAssociatedContent"; + const AFTER_UPDATEPRODUCT_ASSOCIATED_CONTENT = "action.after_updateProductAssociatedContent"; + /** * sent when a new existing cat id duplicated. This append when current customer is different from current cart */ diff --git a/core/lib/Thelia/Core/Template/Loop/AssociatedContent.php b/core/lib/Thelia/Core/Template/Loop/AssociatedContent.php index d85f75fa6..20fe5cb1e 100755 --- a/core/lib/Thelia/Core/Template/Loop/AssociatedContent.php +++ b/core/lib/Thelia/Core/Template/Loop/AssociatedContent.php @@ -97,9 +97,9 @@ class AssociatedContent extends Content $exclude_product = $this->getExcludeProduct(); - // If we have to filter by template, find all attributes assigned to this template, and filter by found IDs + // If we have to filter by product, find all products assigned to this product, and filter by found IDs if (null !== $exclude_product) { - // Exclure tous les attribut qui sont attachés aux templates indiqués + // Exclude all contents related to the given product $search->filterById( ProductAssociatedContentQuery::create()->filterByProductId($exclude_product)->select('product_id')->find(), Criteria::NOT_IN @@ -108,7 +108,7 @@ class AssociatedContent extends Content $exclude_category = $this->getExcludeCategory(); - // If we have to filter by template, find all attributes assigned to this template, and filter by found IDs + // If we have to filter by category, find all contents assigned to this category, and filter by found IDs if (null !== $exclude_category) { // Exclure tous les attribut qui sont attachés aux templates indiqués $search->filterById( diff --git a/core/lib/Thelia/Core/Template/Loop/FolderTree.php b/core/lib/Thelia/Core/Template/Loop/FolderTree.php new file mode 100644 index 000000000..9549f2467 --- /dev/null +++ b/core/lib/Thelia/Core/Template/Loop/FolderTree.php @@ -0,0 +1,118 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Core\Template\Loop; +use Propel\Runtime\ActiveQuery\Criteria; +use Thelia\Core\Template\Element\LoopResult; +use Thelia\Core\Template\Element\LoopResultRow; + +use Thelia\Core\Template\Loop\Argument\ArgumentCollection; +use Thelia\Core\Template\Loop\Argument\Argument; + +use Thelia\Model\FolderQuery; +use Thelia\Type; +use Thelia\Type\BooleanOrBothType; +use Thelia\Core\Template\Element\BaseI18nLoop; + +/** + * + * Folder tree loop, to get a folder tree from a given folder to a given depth. + * + * - folder is the folder id + * - depth is the maximum depth to go, default unlimited + * - visible if true or missing, only visible categories will be displayed. If false, all categories (visible or not) are returned. + * + * @package Thelia\Core\Template\Loop + * @author Franck Allimant + */ +class FolderTree extends BaseI18nLoop +{ + /** + * @return ArgumentCollection + */ + protected function getArgDefinitions() + { + return new ArgumentCollection( + Argument::createIntTypeArgument('folder', null, true), + Argument::createIntTypeArgument('depth', PHP_INT_MAX), + Argument::createBooleanOrBothTypeArgument('visible', true, false), + Argument::createIntListTypeArgument('exclude', array()) + ); + } + + // changement de rubrique + protected function buildFolderTree($parent, $visible, $level, $max_level, $exclude, LoopResult &$loopResult) + { + if ($level > $max_level) return; + + $search = FolderQuery::create(); + + $locale = $this->configureI18nProcessing($search, array( + 'TITLE' + )); + + $search->filterByParent($parent); + + if ($visible != BooleanOrBothType::ANY) $search->filterByVisible($visible); + + if ($exclude != null) $search->filterById($exclude, Criteria::NOT_IN); + + $search->orderByPosition(Criteria::ASC); + + $results = $search->find(); + + foreach ($results as $result) { + + $loopResultRow = new LoopResultRow(); + + $loopResultRow + ->set("ID", $result->getId())->set("TITLE", $result->getVirtualColumn('i18n_TITLE')) + ->set("PARENT", $result->getParent())->set("URL", $result->getUrl($locale)) + ->set("VISIBLE", $result->getVisible() ? "1" : "0")->set("LEVEL", $level) + ; + + $loopResult->addRow($loopResultRow); + + $this->buildFolderTree($result->getId(), $visible, 1 + $level, $max_level, $exclude, $loopResult); + } + } + + /** + * @param $pagination (ignored) + * + * @return \Thelia\Core\Template\Element\LoopResult + */ + public function exec(&$pagination) + { + $id = $this->getFolder(); + $depth = $this->getDepth(); + $visible = $this->getVisible(); + $exclude = $this->getExclude(); + + $loopResult = new LoopResult(); + + $this->buildFolderTree($id, $visible, 0, $depth, $exclude, $loopResult); + + return $loopResult; + } +} diff --git a/core/lib/Thelia/Form/ProductCreationForm.php b/core/lib/Thelia/Form/ProductCreationForm.php index a4ffdde32..9329ca2ec 100644 --- a/core/lib/Thelia/Form/ProductCreationForm.php +++ b/core/lib/Thelia/Form/ProductCreationForm.php @@ -43,35 +43,29 @@ class ProductCreationForm extends BaseForm $this->formBuilder ->add("ref", "text", array( "constraints" => $ref_constraints, - "label" => "Product reference *", - "label_attr" => array( - "for" => "ref" - ) + "label" => "Product reference *", + "label_attr" => array("for" => "ref") )) ->add("title", "text", array( "constraints" => array( new NotBlank() ), "label" => "Product title *", - "label_attr" => array( - "for" => "title" - ) + "label_attr" => array("for" => "title") )) ->add("default_category", "integer", array( - "constraints" => array( - new NotBlank() - ) + "constraints" => array(new NotBlank()), + "label" => Translator::getInstance()->trans("Default product category."), + "label_attr" => array("for" => "default_category_field") )) ->add("locale", "text", array( - "constraints" => array( - new NotBlank() - ) + "constraints" => array(new NotBlank()) )) ->add("visible", "integer", array( - "label" => Translator::getInstance()->trans("This product is online."), - "label_attr" => array("for" => "visible_create") + "label" => Translator::getInstance()->trans("This product is online."), + "label_attr" => array("for" => "visible_field") )) - ; + ; } public function checkDuplicateRef($value, ExecutionContextInterface $context) diff --git a/core/lib/Thelia/Model/Accessory.php b/core/lib/Thelia/Model/Accessory.php index 2e927ff7c..f24aab680 100755 --- a/core/lib/Thelia/Model/Accessory.php +++ b/core/lib/Thelia/Model/Accessory.php @@ -3,7 +3,77 @@ namespace Thelia\Model; use Thelia\Model\Base\Accessory as BaseAccessory; +use Thelia\Core\Event\TheliaEvents; +use Propel\Runtime\Connection\ConnectionInterface; +use Thelia\Core\Event\AccessoryEvent; class Accessory extends BaseAccessory { + 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_CREATEACCESSORY, new AccessoryEvent($this)); + + return true; + } + + /** + * {@inheritDoc} + */ + public function postInsert(ConnectionInterface $con = null) + { + $this->dispatchEvent(TheliaEvents::AFTER_CREATEACCESSORY, new AccessoryEvent($this)); + } + + /** + * {@inheritDoc} + */ + public function preUpdate(ConnectionInterface $con = null) + { + $this->dispatchEvent(TheliaEvents::BEFORE_UPDATEACCESSORY, new AccessoryEvent($this)); + + return true; + } + + /** + * {@inheritDoc} + */ + public function postUpdate(ConnectionInterface $con = null) + { + $this->dispatchEvent(TheliaEvents::AFTER_UPDATEACCESSORY, new AccessoryEvent($this)); + } + + /** + * {@inheritDoc} + */ + public function preDelete(ConnectionInterface $con = null) + { + $this->dispatchEvent(TheliaEvents::BEFORE_DELETEACCESSORY, new AccessoryEvent($this)); + + return true; + } + + /** + * {@inheritDoc} + */ + public function postDelete(ConnectionInterface $con = null) + { + $this->dispatchEvent(TheliaEvents::AFTER_DELETEACCESSORY, new AccessoryEvent($this)); + } + } diff --git a/core/lib/Thelia/Model/CategoryAssociatedContent.php b/core/lib/Thelia/Model/CategoryAssociatedContent.php index 9296e6274..9154767bc 100644 --- a/core/lib/Thelia/Model/CategoryAssociatedContent.php +++ b/core/lib/Thelia/Model/CategoryAssociatedContent.php @@ -3,7 +3,66 @@ namespace Thelia\Model; use Thelia\Model\Base\CategoryAssociatedContent as BaseCategoryAssociatedContent; +use Thelia\Core\Event\CategoryAssociatedContentEvent; +use Thelia\Core\Event\TheliaEvents; +use Propel\Runtime\Connection\ConnectionInterface; class CategoryAssociatedContent extends BaseCategoryAssociatedContent { + use \Thelia\Model\Tools\ModelEventDispatcherTrait; + + /** + * {@inheritDoc} + */ + public function preInsert(ConnectionInterface $con = null) + { + $this->dispatchEvent(TheliaEvents::BEFORE_CREATECATEGORY_ASSOCIATED_CONTENT, new CategoryAssociatedContentEvent($this)); + + return true; + } + + /** + * {@inheritDoc} + */ + public function postInsert(ConnectionInterface $con = null) + { + $this->dispatchEvent(TheliaEvents::AFTER_CREATECATEGORY_ASSOCIATED_CONTENT, new CategoryAssociatedContentEvent($this)); + } + + /** + * {@inheritDoc} + */ + public function preUpdate(ConnectionInterface $con = null) + { + $this->dispatchEvent(TheliaEvents::BEFORE_UPDATECATEGORY_ASSOCIATED_CONTENT, new CategoryAssociatedContentEvent($this)); + + return true; + } + + /** + * {@inheritDoc} + */ + public function postUpdate(ConnectionInterface $con = null) + { + $this->dispatchEvent(TheliaEvents::AFTER_UPDATECATEGORY_ASSOCIATED_CONTENT, new CategoryAssociatedContentEvent($this)); + } + + /** + * {@inheritDoc} + */ + public function preDelete(ConnectionInterface $con = null) + { + $this->dispatchEvent(TheliaEvents::BEFORE_DELETECATEGORY_ASSOCIATED_CONTENT, new CategoryAssociatedContentEvent($this)); + + return true; + } + + /** + * {@inheritDoc} + */ + public function postDelete(ConnectionInterface $con = null) + { + $this->dispatchEvent(TheliaEvents::AFTER_DELETECATEGORY_ASSOCIATED_CONTENT, new CategoryAssociatedContentEvent($this)); + } + } diff --git a/core/lib/Thelia/Model/ProductAssociatedContent.php b/core/lib/Thelia/Model/ProductAssociatedContent.php index 9b007baf1..e07ee2cd6 100644 --- a/core/lib/Thelia/Model/ProductAssociatedContent.php +++ b/core/lib/Thelia/Model/ProductAssociatedContent.php @@ -3,7 +3,65 @@ namespace Thelia\Model; use Thelia\Model\Base\ProductAssociatedContent as BaseProductAssociatedContent; +use Propel\Runtime\Connection\ConnectionInterface; +use Thelia\Core\Event\ProductAssociatedContentEvent; +use Thelia\Core\Event\TheliaEvents; class ProductAssociatedContent extends BaseProductAssociatedContent { + use \Thelia\Model\Tools\ModelEventDispatcherTrait; + + /** + * {@inheritDoc} + */ + public function preInsert(ConnectionInterface $con = null) + { + $this->dispatchEvent(TheliaEvents::BEFORE_CREATEPRODUCT_ASSOCIATED_CONTENT, new ProductAssociatedContentEvent($this)); + + return true; + } + + /** + * {@inheritDoc} + */ + public function postInsert(ConnectionInterface $con = null) + { + $this->dispatchEvent(TheliaEvents::AFTER_CREATEPRODUCT_ASSOCIATED_CONTENT, new ProductAssociatedContentEvent($this)); + } + + /** + * {@inheritDoc} + */ + public function preUpdate(ConnectionInterface $con = null) + { + $this->dispatchEvent(TheliaEvents::BEFORE_UPDATEPRODUCT_ASSOCIATED_CONTENT, new ProductAssociatedContentEvent($this)); + + return true; + } + + /** + * {@inheritDoc} + */ + public function postUpdate(ConnectionInterface $con = null) + { + $this->dispatchEvent(TheliaEvents::AFTER_UPDATEPRODUCT_ASSOCIATED_CONTENT, new ProductAssociatedContentEvent($this)); + } + + /** + * {@inheritDoc} + */ + public function preDelete(ConnectionInterface $con = null) + { + $this->dispatchEvent(TheliaEvents::BEFORE_DELETEPRODUCT_ASSOCIATED_CONTENT, new ProductAssociatedContentEvent($this)); + + return true; + } + + /** + * {@inheritDoc} + */ + public function postDelete(ConnectionInterface $con = null) + { + $this->dispatchEvent(TheliaEvents::AFTER_DELETEPRODUCT_ASSOCIATED_CONTENT, new ProductAssociatedContentEvent($this)); + } } diff --git a/templates/admin/default/categories.html b/templates/admin/default/categories.html index b24b625cb..990cafd56 100755 --- a/templates/admin/default/categories.html +++ b/templates/admin/default/categories.html @@ -267,14 +267,14 @@ {loop type="image" name="cat_image" source="product" source_id="$ID" limit="1" width="50" height="50" resize_mode="crop" backend_context="1"} - + {$TITLE} {/loop} - {$REF} + {$REF} - {$TITLE} + {$TITLE} {module_include location='product_list_row'} @@ -306,7 +306,7 @@
{loop type="auth" name="can_change" roles="ADMIN" permissions="admin.product.edit"} - + {/loop} {loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.product.delete"} diff --git a/templates/admin/default/category-edit.html b/templates/admin/default/category-edit.html index 05c9c02f8..b974a4564 100755 --- a/templates/admin/default/category-edit.html +++ b/templates/admin/default/category-edit.html @@ -40,24 +40,23 @@
-
+
{form name="thelia.admin.category.modification"}
- {include file="includes/inner-form-toolbar.html" close_url="{url path='/admin/categories' category_id=$category_id}"} + {include file="includes/inner-form-toolbar.html" close_url="{url path='/admin/categories' category_id=$PARENT}"} {* Be sure to get the category ID, even if the form could not be validated *} @@ -141,7 +140,7 @@
-
+
@@ -149,9 +148,12 @@ {include file="includes/inner-form-toolbar.html" hide_submit_buttons=true - close_url="{url path='/admin/categories' category_id=$category_id}" + close_url="{url path='/admin/categories' category_id=$PARENT}" } +

{intl l='Related content'}

+

{intl l='You can attach here some content to this product'}

+ @@ -162,8 +164,8 @@
@@ -183,6 +185,12 @@ {intl l='Select a content and click (+) to add it to this category'}
+ +
+
+ {intl l="No available content in this folder"} +
+
@@ -194,14 +202,14 @@
- -
+ +
- + {module_include location='category_contents_table_header'} @@ -247,13 +255,13 @@ -
+
-
+
-
+
@@ -289,7 +297,7 @@ {block name="javascript-initialization"} - + @@ -319,12 +327,6 @@ $(function() { ev.preventDefault(); }); - // Show proper tab, if defined - {if ! empty($current_tab)} - $('#tabbed-menu a[href="#{$current_tab}"]').tab('show') - {/if} - - // Set proper content ID in delete content from $('a.delete-content').click(function(ev) { $('#content_delete_id').val($(this).data('id')); @@ -333,28 +335,41 @@ $(function() { // Load content on folder selection $('#folder_id').change(function(event) { - $.ajax({ - url : '{url path="/admin/category/$category_id/available-related-content/"}' + $(this).val() + '.xml', - type : 'get', - dataType : 'json', - success : function(json) { - $('#content_id :not(:first-child)').remove(); - var have_content = false; + var val = $(this).val(); - $.each(json, function(idx, value) { - $('#content_id').append($('
{intl l='ID'}{intl l='Attribute title'}{intl l='Content title'}
+ + + + + + + {module_include location='product_contents_table_header'} + + + + + + + {loop name="assigned_contents" type="associated_content" product="$product_id" backend_context="1" lang="$edit_language_id"} + + + + + + {module_include location='product_contents_table_row'} + + + + {/loop} + + {elseloop rel="assigned_contents"} + + + + {/elseloop} + +
{intl l='ID'}{intl l='Content title'}{intl l="Actions"}
{$ID} + {$TITLE} + +
+ {loop type="auth" name="can_create" roles="ADMIN" permissions="admin.configuration.product.content.delete"} + + + + {/loop} +
+
+
+ {intl l="This product contains no contents"} +
+
+
+ + {* -- End related content management ---- *} + + {* -- Begin accessories management ------ *} + +
+
+
+ +

{intl l='Product accessories'}

+

{intl l='Define here this product\'s accessories'}

+ + + + + {ifloop rel="categories"} +
+ + + {intl l='Select a category to get its products'} +
+ +
+
+ + + + +
+ + {intl l='Select a product and click (+) to add it as an accessory'} +
+ +
+
+ {intl l="No available product in this category"} +
+
+ + {/ifloop} + + {elseloop rel="categories"} +
{intl l="No categories found"}
+ {/elseloop} + +
+
+ + + + + + + + + + + {module_include location='product_accessories_table_header'} + + + + + + + {loop name="assigned_accessories" order="accessory" type="accessory" product="$product_id" backend_context="1" lang="$edit_language_id"} + + + + + + + + {module_include location='product_accessories_table_row'} + + + + {/loop} + + {elseloop rel="assigned_accessories"} + + + + {/elseloop} + +
{intl l='ID'}{intl l='Accessory title'}{intl l='Position'}{intl l="Actions"}
{$ID} + {$TITLE} + + {admin_position_block + permission="admin.products.edit" + path={url path='/admin/products/update-accessory-position' product_id=$ID} + url_parameter="accessory_id" + in_place_edit_class="accessoryPositionChange" + position=$POSITION + id=$ID + } + +
+ {loop type="auth" name="can_create" roles="ADMIN" permissions="admin.configuration.product.accessory.delete"} + + + + {/loop} +
+
+
+ {intl l="This product contains no accessories"} +
+
+
+ + {* -- End accessories management -------- *} + +
+
+ +
+
+ +
+
+ +
+
+
+
+
+ + {/loop} + + + + + +{* Delete related content confirmation dialog *} + +{capture "delete_content_dialog"} + + + + + +{/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/related-content/delete'} + form_content = {$smarty.capture.delete_content_dialog nofilter} +} + +{* Delete accessory confirmation dialog *} + +{capture "delete_accessory_dialog"} + + + + + +{/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} +} +{/block} + +{block name="javascript-initialization"} + +{javascripts file='assets/js/bootstrap-editable/bootstrap-editable.js'} + +{/javascripts} + + + + + +{/block} \ No newline at end of file