MAJ en Thelia 2.3.4
This commit is contained in:
@@ -20,13 +20,16 @@ A repository containing all thelia modules is available at this address : https:
|
||||
Requirements
|
||||
------------
|
||||
|
||||
* php 5.4
|
||||
* php 5.5
|
||||
* Required extensions :
|
||||
* PDO_Mysql
|
||||
* mcrypt
|
||||
* openssl
|
||||
* intl
|
||||
* gd
|
||||
* curl
|
||||
* calendar
|
||||
* dom
|
||||
* fileinfo
|
||||
* safe_mode off
|
||||
* memory_limit at least 128M, preferably 256.
|
||||
* post_max_size 20M
|
||||
|
||||
1
core/Thelia
Normal file → Executable file
1
core/Thelia
Normal file → Executable file
@@ -1,4 +1,3 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
if (php_sapi_name() != 'cli') {
|
||||
|
||||
@@ -55,7 +55,8 @@
|
||||
"smarty/smarty": "3.1.20",
|
||||
"ramsey/array_column": "~1.1",
|
||||
"propel/propel": "dev-thelia-2.3",
|
||||
"commerceguys/addressing": "0.8.*"
|
||||
"commerceguys/addressing": "0.8.*",
|
||||
"symfony/cache": "~3.1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"fzaninotto/faker": "1.5.*",
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Thelia\Action;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Thelia\Core\Event\Brand\BrandCreateEvent;
|
||||
use Thelia\Core\Event\Brand\BrandDeleteEvent;
|
||||
use Thelia\Core\Event\Brand\BrandToggleVisibilityEvent;
|
||||
@@ -21,6 +22,7 @@ use Thelia\Core\Event\Brand\BrandUpdateEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\Event\UpdatePositionEvent;
|
||||
use Thelia\Core\Event\UpdateSeoEvent;
|
||||
use Thelia\Core\Event\ViewCheckEvent;
|
||||
use Thelia\Model\Brand as BrandModel;
|
||||
use Thelia\Model\BrandQuery;
|
||||
|
||||
@@ -121,6 +123,36 @@ class Brand extends BaseAction implements EventSubscriberInterface
|
||||
$this->genericUpdatePosition(BrandQuery::create(), $event, $dispatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if is a brand view and if brand_id is visible
|
||||
*
|
||||
* @param ViewCheckEvent $event
|
||||
* @param string $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function viewCheck(ViewCheckEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if ($event->getView() == 'brand') {
|
||||
$brand = BrandQuery::create()
|
||||
->filterById($event->getViewId())
|
||||
->filterByVisible(1)
|
||||
->count();
|
||||
|
||||
if ($brand == 0) {
|
||||
$dispatcher->dispatch(TheliaEvents::VIEW_BRAND_ID_NOT_VISIBLE, $event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ViewCheckEvent $event
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public function viewBrandIdNotVisible(ViewCheckEvent $event)
|
||||
{
|
||||
throw new NotFoundHttpException();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@@ -135,6 +167,9 @@ class Brand extends BaseAction implements EventSubscriberInterface
|
||||
|
||||
TheliaEvents::BRAND_UPDATE_POSITION => array('updatePosition', 128),
|
||||
TheliaEvents::BRAND_TOGGLE_VISIBILITY => array('toggleVisibility', 128),
|
||||
|
||||
TheliaEvents::VIEW_CHECK => array('viewCheck', 128),
|
||||
TheliaEvents::VIEW_BRAND_ID_NOT_VISIBLE => array('viewBrandIdNotVisible', 128),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
namespace Thelia\Action;
|
||||
|
||||
use Symfony\Component\Cache\Adapter\AdapterInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
use Thelia\Core\Event\Cache\CacheEvent;
|
||||
@@ -24,8 +25,23 @@ use Thelia\Core\Event\TheliaEvents;
|
||||
*/
|
||||
class Cache extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
/** @var AdapterInterface */
|
||||
protected $adapter;
|
||||
|
||||
/**
|
||||
* CacheListener constructor.
|
||||
* @param AdapterInterface $adapter
|
||||
*/
|
||||
public function __construct(AdapterInterface $adapter)
|
||||
{
|
||||
$this->adapter = $adapter;
|
||||
}
|
||||
|
||||
public function cacheClear(CacheEvent $event)
|
||||
{
|
||||
// clear cache on thelia.cache service
|
||||
$this->adapter->clear();
|
||||
|
||||
$dir = $event->getDir();
|
||||
|
||||
$fs = new Filesystem();
|
||||
|
||||
@@ -22,6 +22,7 @@ use Thelia\Core\Event\Cart\CartRestoreEvent;
|
||||
use Thelia\Core\Event\Cart\CartEvent;
|
||||
use Thelia\Core\Event\Currency\CurrencyChangeEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Exception\TheliaProcessException;
|
||||
use Thelia\Model\Base\CustomerQuery;
|
||||
use Thelia\Model\Base\ProductSaleElementsQuery;
|
||||
use Thelia\Model\Currency as CurrencyModel;
|
||||
@@ -100,9 +101,11 @@ class Cart extends BaseAction implements EventSubscriberInterface
|
||||
$productId = $event->getProduct();
|
||||
|
||||
// Search for an identical item in the cart
|
||||
$dispatcher->dispatch(TheliaEvents::CART_FINDITEM, $event);
|
||||
$findItemEvent = clone $event;
|
||||
|
||||
$cartItem = $event->getCartItem();
|
||||
$dispatcher->dispatch(TheliaEvents::CART_FINDITEM, $findItemEvent);
|
||||
|
||||
$cartItem = $findItemEvent->getCartItem();
|
||||
|
||||
if ($cartItem === null || $newness) {
|
||||
$productSaleElements = ProductSaleElementsQuery::create()->findPk($productSaleElementsId);
|
||||
@@ -111,6 +114,9 @@ class Cart extends BaseAction implements EventSubscriberInterface
|
||||
$productPrices = $productSaleElements->getPricesByCurrency($currency, $discount);
|
||||
|
||||
$cartItem = $this->doAddItem($dispatcher, $cart, $productId, $productSaleElements, $quantity, $productPrices);
|
||||
} else {
|
||||
// We did no find any PSE... Something is wrong with the DB, just throw an exception.
|
||||
throw new TheliaProcessException("This item cannot be added to the cart: no matching product sale element was found.");
|
||||
}
|
||||
} elseif ($append && $cartItem !== null) {
|
||||
$cartItem->addQuantity($quantity)->save();
|
||||
@@ -133,6 +139,10 @@ class Cart extends BaseAction implements EventSubscriberInterface
|
||||
->filterByCartId($cart->getId())
|
||||
->filterById($cartItemId)
|
||||
->delete();
|
||||
|
||||
// Force an update of the Cart object to provide
|
||||
// to other listeners an updated CartItem collection.
|
||||
$cart->clearCartItems();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -301,7 +311,9 @@ class Cart extends BaseAction implements EventSubscriberInterface
|
||||
*/
|
||||
public function findCartItem(CartEvent $event)
|
||||
{
|
||||
if (null !== $foundItem = CartItemQuery::create()
|
||||
// Do not try to find a cartItem if one exists in the event, as previous event handlers
|
||||
// mays have put it in th event.
|
||||
if (null === $event->getCartItem() && null !== $foundItem = CartItemQuery::create()
|
||||
->filterByCartId($event->getCart()->getId())
|
||||
->filterByProductId($event->getProduct())
|
||||
->filterByProductSaleElementsId($event->getProductSaleElementsId())
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace Thelia\Action;
|
||||
use Propel\Runtime\Propel;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Thelia\Core\Event\File\FileDeleteEvent;
|
||||
use Thelia\Core\Event\UpdateSeoEvent;
|
||||
use Thelia\Model\CategoryDocumentQuery;
|
||||
@@ -29,6 +30,7 @@ use Thelia\Core\Event\UpdatePositionEvent;
|
||||
use Thelia\Core\Event\Category\CategoryToggleVisibilityEvent;
|
||||
use Thelia\Core\Event\Category\CategoryAddContentEvent;
|
||||
use Thelia\Core\Event\Category\CategoryDeleteContentEvent;
|
||||
use Thelia\Core\Event\ViewCheckEvent;
|
||||
use Thelia\Model\CategoryAssociatedContent;
|
||||
use Thelia\Model\CategoryAssociatedContentQuery;
|
||||
use Thelia\Model\Map\CategoryTableMap;
|
||||
@@ -212,6 +214,36 @@ class Category extends BaseAction implements EventSubscriberInterface
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if is a category view and if category_id is visible
|
||||
*
|
||||
* @param ViewCheckEvent $event
|
||||
* @param string $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function viewCheck(ViewCheckEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if ($event->getView() == 'category') {
|
||||
$category = CategoryQuery::create()
|
||||
->filterById($event->getViewId())
|
||||
->filterByVisible(1)
|
||||
->count();
|
||||
|
||||
if ($category == 0) {
|
||||
$dispatcher->dispatch(TheliaEvents::VIEW_CATEGORY_ID_NOT_VISIBLE, $event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ViewCheckEvent $event
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public function viewcategoryIdNotVisible(ViewCheckEvent $event)
|
||||
{
|
||||
throw new NotFoundHttpException();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@@ -229,6 +261,8 @@ class Category extends BaseAction implements EventSubscriberInterface
|
||||
TheliaEvents::CATEGORY_ADD_CONTENT => array("addContent", 128),
|
||||
TheliaEvents::CATEGORY_REMOVE_CONTENT => array("removeContent", 128),
|
||||
|
||||
TheliaEvents::VIEW_CHECK => array('viewCheck', 128),
|
||||
TheliaEvents::VIEW_CATEGORY_ID_NOT_VISIBLE => array('viewcategoryIdNotVisible', 128),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ use Propel\Runtime\Exception\PropelException;
|
||||
use Propel\Runtime\Propel;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Thelia\Core\Event\Content\ContentAddFolderEvent;
|
||||
use Thelia\Core\Event\Content\ContentCreateEvent;
|
||||
use Thelia\Core\Event\Content\ContentDeleteEvent;
|
||||
@@ -26,6 +27,7 @@ use Thelia\Core\Event\File\FileDeleteEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\Event\UpdatePositionEvent;
|
||||
use Thelia\Core\Event\UpdateSeoEvent;
|
||||
use Thelia\Core\Event\ViewCheckEvent;
|
||||
use Thelia\Model\ContentDocumentQuery;
|
||||
use Thelia\Model\ContentFolder;
|
||||
use Thelia\Model\ContentFolderQuery;
|
||||
@@ -207,13 +209,43 @@ class Content extends BaseAction implements EventSubscriberInterface
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if is a content view and if content_id is visible
|
||||
*
|
||||
* @param ViewCheckEvent $event
|
||||
* @param string $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function viewCheck(ViewCheckEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if ($event->getView() == 'content') {
|
||||
$content = ContentQuery::create()
|
||||
->filterById($event->getViewId())
|
||||
->filterByVisible(1)
|
||||
->count();
|
||||
|
||||
if ($content == 0) {
|
||||
$dispatcher->dispatch(TheliaEvents::VIEW_CONTENT_ID_NOT_VISIBLE, $event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ViewCheckEvent $event
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public function viewContentIdNotVisible(ViewCheckEvent $event)
|
||||
{
|
||||
throw new NotFoundHttpException();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::CONTENT_CREATE => array('create', 128),
|
||||
TheliaEvents::CONTENT_CREATE => array('create', 128),
|
||||
TheliaEvents::CONTENT_UPDATE => array('update', 128),
|
||||
TheliaEvents::CONTENT_DELETE => array('delete', 128),
|
||||
TheliaEvents::CONTENT_TOGGLE_VISIBILITY => array('toggleVisibility', 128),
|
||||
@@ -223,6 +255,9 @@ class Content extends BaseAction implements EventSubscriberInterface
|
||||
|
||||
TheliaEvents::CONTENT_ADD_FOLDER => array('addFolder', 128),
|
||||
TheliaEvents::CONTENT_REMOVE_FOLDER => array('removeFolder', 128),
|
||||
|
||||
TheliaEvents::VIEW_CHECK => array('viewCheck', 128),
|
||||
TheliaEvents::VIEW_CONTENT_ID_NOT_VISIBLE => array('viewContentIdNotVisible', 128),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,8 @@ use Thelia\Model\Map\OrderCouponTableMap;
|
||||
use Thelia\Model\OrderCoupon;
|
||||
use Thelia\Model\OrderCouponCountry;
|
||||
use Thelia\Model\OrderCouponModule;
|
||||
use Thelia\Model\OrderCouponQuery;
|
||||
use Thelia\Model\OrderStatusQuery;
|
||||
|
||||
/**
|
||||
* Process Coupon Events
|
||||
@@ -322,7 +324,7 @@ class Coupon extends BaseAction implements EventSubscriberInterface
|
||||
$orderCoupon->setOrder($event->getOrder())
|
||||
->setCode($couponModel->getCode())
|
||||
->setType($couponModel->getType())
|
||||
->setAmount($couponModel->getAmount())
|
||||
->setAmount($couponCode->exec())
|
||||
|
||||
->setTitle($couponModel->getTitle())
|
||||
->setShortDescription($couponModel->getShortDescription())
|
||||
@@ -378,6 +380,58 @@ class Coupon extends BaseAction implements EventSubscriberInterface
|
||||
$dispatcher->dispatch(TheliaEvents::COUPON_CLEAR_ALL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels order coupons usage when order is canceled or refunded,
|
||||
* or use canceled coupons again if the order is no longer canceled or refunded
|
||||
*
|
||||
* @param OrderEvent $event
|
||||
* @param string $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
* @throws \Exception
|
||||
* @throws \Propel\Runtime\Exception\PropelException
|
||||
*/
|
||||
public function orderStatusChange(OrderEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
// The order has been canceled or refunded ?
|
||||
if ($event->getOrder()->isCancelled() || $event->getOrder()->isRefunded()) {
|
||||
// Cancel usage of all coupons for this order
|
||||
$usedCoupons = OrderCouponQuery::create()
|
||||
->filterByUsageCanceled(false)
|
||||
->findByOrderId($event->getOrder()->getId());
|
||||
|
||||
$customerId = $event->getOrder()->getCustomerId();
|
||||
|
||||
/** @var OrderCoupon $usedCoupon */
|
||||
foreach ($usedCoupons as $usedCoupon) {
|
||||
if (null !== $couponModel = CouponQuery::create()->findOneByCode($usedCoupon->getCode())) {
|
||||
// If the coupon still exists, restore one usage to the usage count.
|
||||
$this->couponManager->incrementQuantity($couponModel, $customerId);
|
||||
}
|
||||
|
||||
// Mark coupon usage as canceled in the OrderCoupon table
|
||||
$usedCoupon->setUsageCanceled(true)->save();
|
||||
}
|
||||
} else {
|
||||
// Mark canceled coupons for this order as used again
|
||||
$usedCoupons = OrderCouponQuery::create()
|
||||
->filterByUsageCanceled(true)
|
||||
->findByOrderId($event->getOrder()->getId());
|
||||
|
||||
$customerId = $event->getOrder()->getCustomerId();
|
||||
|
||||
/** @var OrderCoupon $usedCoupon */
|
||||
foreach ($usedCoupons as $usedCoupon) {
|
||||
if (null !== $couponModel = CouponQuery::create()->findOneByCode($usedCoupon->getCode())) {
|
||||
// If the coupon still exists, mark the coupon as used
|
||||
$this->couponManager->decrementQuantity($couponModel, $customerId);
|
||||
}
|
||||
|
||||
// The coupon is no longer canceled
|
||||
$usedCoupon->setUsageCanceled(false)->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@@ -392,9 +446,11 @@ class Coupon extends BaseAction implements EventSubscriberInterface
|
||||
TheliaEvents::COUPON_CONDITION_UPDATE => array("updateCondition", 128),
|
||||
TheliaEvents::ORDER_SET_POSTAGE => array("testFreePostage", 132),
|
||||
TheliaEvents::ORDER_BEFORE_PAYMENT => array("afterOrder", 128),
|
||||
TheliaEvents::ORDER_UPDATE_STATUS => array("orderStatusChange", 10),
|
||||
TheliaEvents::CART_ADDITEM => array("updateOrderDiscount", 10),
|
||||
TheliaEvents::CART_UPDATEITEM => array("updateOrderDiscount", 10),
|
||||
TheliaEvents::CART_DELETEITEM => array("updateOrderDiscount", 10),
|
||||
TheliaEvents::CUSTOMER_LOGIN => array("updateOrderDiscount", 10)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ use Thelia\Core\Security\SecurityContext;
|
||||
use Thelia\Core\Translation\Translator;
|
||||
use Thelia\Exception\CustomerException;
|
||||
use Thelia\Mailer\MailerFactory;
|
||||
use Thelia\Model\ConfigQuery;
|
||||
use Thelia\Model\Customer as CustomerModel;
|
||||
use Thelia\Model\CustomerQuery;
|
||||
use Thelia\Tools\Password;
|
||||
@@ -59,7 +60,29 @@ class Customer extends BaseAction implements EventSubscriberInterface
|
||||
$this->createOrUpdateCustomer($customer, $event, $dispatcher);
|
||||
|
||||
if ($event->getNotifyCustomerOfAccountCreation()) {
|
||||
$this->mailer->sendEmailToCustomer('customer_account_created', $customer, [ 'password' => $plainPassword ]);
|
||||
$this->mailer->sendEmailToCustomer(
|
||||
'customer_account_created',
|
||||
$customer,
|
||||
[ 'password' => $plainPassword ]
|
||||
);
|
||||
}
|
||||
|
||||
$dispatcher->dispatch(
|
||||
TheliaEvents::SEND_ACCOUNT_CONFIRMATION_EMAIL,
|
||||
new CustomerEvent($customer)
|
||||
);
|
||||
}
|
||||
|
||||
public function customerConfirmationEmail(CustomerEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$customer = $event->getCustomer();
|
||||
|
||||
if (ConfigQuery::isCustomerEmailConfirmationEnable() && $customer->getConfirmationToken() !== null && $customer !== null) {
|
||||
$this->mailer->sendEmailToCustomer(
|
||||
'customer_confirmation',
|
||||
$customer,
|
||||
['customer_id' => $customer->getId()]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,7 +232,8 @@ class Customer extends BaseAction implements EventSubscriberInterface
|
||||
TheliaEvents::CUSTOMER_LOGOUT => array('logout', 128),
|
||||
TheliaEvents::CUSTOMER_LOGIN => array('login', 128),
|
||||
TheliaEvents::CUSTOMER_DELETEACCOUNT => array('delete', 128),
|
||||
TheliaEvents::LOST_PASSWORD => array('lostPassword', 128)
|
||||
TheliaEvents::LOST_PASSWORD => array('lostPassword', 128),
|
||||
TheliaEvents::SEND_ACCOUNT_CONFIRMATION_EMAIL => array('customerConfirmationEmail', 128)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace Thelia\Action;
|
||||
use Propel\Runtime\Propel;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Thelia\Core\Event\File\FileDeleteEvent;
|
||||
use Thelia\Core\Event\Folder\FolderCreateEvent;
|
||||
use Thelia\Core\Event\Folder\FolderDeleteEvent;
|
||||
@@ -23,6 +24,7 @@ use Thelia\Core\Event\Folder\FolderUpdateEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\Event\UpdatePositionEvent;
|
||||
use Thelia\Core\Event\UpdateSeoEvent;
|
||||
use Thelia\Core\Event\ViewCheckEvent;
|
||||
use Thelia\Model\FolderDocumentQuery;
|
||||
use Thelia\Model\FolderImageQuery;
|
||||
use Thelia\Model\FolderQuery;
|
||||
@@ -155,6 +157,36 @@ class Folder extends BaseAction implements EventSubscriberInterface
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if is a folder view and if folder_id is visible
|
||||
*
|
||||
* @param ViewCheckEvent $event
|
||||
* @param string $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function viewCheck(ViewCheckEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if ($event->getView() == 'folder') {
|
||||
$folder = FolderQuery::create()
|
||||
->filterById($event->getViewId())
|
||||
->filterByVisible(1)
|
||||
->count();
|
||||
|
||||
if ($folder == 0) {
|
||||
$dispatcher->dispatch(TheliaEvents::VIEW_FOLDER_ID_NOT_VISIBLE, $event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ViewCheckEvent $event
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public function viewFolderIdNotVisible(ViewCheckEvent $event)
|
||||
{
|
||||
throw new NotFoundHttpException();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@@ -167,7 +199,10 @@ class Folder extends BaseAction implements EventSubscriberInterface
|
||||
TheliaEvents::FOLDER_TOGGLE_VISIBILITY => array("toggleVisibility", 128),
|
||||
|
||||
TheliaEvents::FOLDER_UPDATE_POSITION => array("updatePosition", 128),
|
||||
TheliaEvents::FOLDER_UPDATE_SEO => array('updateSeo', 128)
|
||||
TheliaEvents::FOLDER_UPDATE_SEO => array('updateSeo', 128),
|
||||
|
||||
TheliaEvents::VIEW_CHECK => array('viewCheck', 128),
|
||||
TheliaEvents::VIEW_FOLDER_ID_NOT_VISIBLE => array('viewFolderIdNotVisible', 128),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -301,11 +301,18 @@ class Image extends BaseCachedFile implements EventSubscriberInterface
|
||||
$delta_x = $delta_y = $border_width = $border_height = 0;
|
||||
|
||||
if ($width_diff > 1 && $height_diff > 1) {
|
||||
$resize_width = $width_orig;
|
||||
$resize_height = $height_orig;
|
||||
// Set the default final size. If zoom is allowed, we will get the required
|
||||
// image dimension. Otherwise, the final image may be smaller than required.
|
||||
if ($allow_zoom) {
|
||||
$resize_width = $dest_width;
|
||||
$resize_height = $dest_height;
|
||||
} else {
|
||||
$resize_width = $width_orig;
|
||||
$resize_height = $height_orig;
|
||||
}
|
||||
|
||||
// When cropping, be sure to always generate an image which is
|
||||
// no smaller than the required size, zooming it if required.
|
||||
// not smaller than the required size, zooming it if required.
|
||||
if ($resize_mode == self::EXACT_RATIO_WITH_CROP) {
|
||||
if ($allow_zoom) {
|
||||
if ($width_diff > $height_diff) {
|
||||
|
||||
@@ -84,6 +84,12 @@ class Module extends BaseAction implements EventSubscriberInterface
|
||||
if (null !== $module = ModuleQuery::create()->findPk($event->getModuleId())) {
|
||||
try {
|
||||
if ($module->getActivate() == BaseModule::IS_ACTIVATED) {
|
||||
if ($module->getMandatory() == BaseModule::IS_MANDATORY && $event->getAssumeDeactivate() === false) {
|
||||
throw new \Exception(
|
||||
Translator::getInstance()->trans('Can\'t deactivate a secure module')
|
||||
);
|
||||
}
|
||||
|
||||
if ($event->isRecursive()) {
|
||||
$this->recursiveDeactivation($event, $eventName, $dispatcher);
|
||||
}
|
||||
@@ -233,6 +239,11 @@ class Module extends BaseAction implements EventSubscriberInterface
|
||||
}
|
||||
|
||||
try {
|
||||
if ($module->getMandatory() == BaseModule::IS_MANDATORY && $event->getAssumeDelete() === false) {
|
||||
throw new \Exception(
|
||||
Translator::getInstance()->trans('Can\'t remove a core module')
|
||||
);
|
||||
}
|
||||
// First, try to create an instance
|
||||
$instance = $module->createInstance();
|
||||
|
||||
|
||||
@@ -642,6 +642,19 @@ class Order extends BaseAction implements EventSubscriberInterface
|
||||
$event->setOrder($order);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OrderEvent $event
|
||||
*/
|
||||
public function updateTransactionRef(OrderEvent $event)
|
||||
{
|
||||
$order = $event->getOrder();
|
||||
|
||||
$order->setTransactionRef($event->getTransactionRef());
|
||||
$order->save();
|
||||
|
||||
$event->setOrder($order);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OrderAddressEvent $event
|
||||
*/
|
||||
@@ -710,6 +723,7 @@ class Order extends BaseAction implements EventSubscriberInterface
|
||||
TheliaEvents::ORDER_SEND_NOTIFICATION_EMAIL => array("sendNotificationEmail", 128),
|
||||
TheliaEvents::ORDER_UPDATE_STATUS => array("updateStatus", 128),
|
||||
TheliaEvents::ORDER_UPDATE_DELIVERY_REF => array("updateDeliveryRef", 128),
|
||||
TheliaEvents::ORDER_UPDATE_TRANSACTION_REF => array("updateTransactionRef", 128),
|
||||
TheliaEvents::ORDER_UPDATE_ADDRESS => array("updateAddress", 128),
|
||||
TheliaEvents::ORDER_CREATE_MANUAL => array("createManual", 128),
|
||||
);
|
||||
|
||||
@@ -14,17 +14,53 @@ namespace Thelia\Action;
|
||||
|
||||
use Propel\Runtime\ActiveQuery\Criteria;
|
||||
use Propel\Runtime\Exception\PropelException;
|
||||
use Propel\Runtime\Propel;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Thelia\Core\Event\Feature\FeatureAvCreateEvent;
|
||||
use Thelia\Core\Event\Feature\FeatureAvDeleteEvent;
|
||||
use Thelia\Core\Event\FeatureProduct\FeatureProductDeleteEvent;
|
||||
use Thelia\Core\Event\FeatureProduct\FeatureProductUpdateEvent;
|
||||
use Thelia\Core\Event\File\FileDeleteEvent;
|
||||
use Thelia\Core\Event\Product\ProductAddAccessoryEvent;
|
||||
use Thelia\Core\Event\Product\ProductAddCategoryEvent;
|
||||
use Thelia\Core\Event\Product\ProductAddContentEvent;
|
||||
use Thelia\Core\Event\Product\ProductCloneEvent;
|
||||
use Thelia\Model\AttributeCombinationQuery;
|
||||
use Thelia\Core\Event\Product\ProductCreateEvent;
|
||||
use Thelia\Core\Event\Product\ProductDeleteAccessoryEvent;
|
||||
use Thelia\Core\Event\Product\ProductDeleteCategoryEvent;
|
||||
use Thelia\Core\Event\Product\ProductDeleteContentEvent;
|
||||
use Thelia\Core\Event\Product\ProductDeleteEvent;
|
||||
use Thelia\Core\Event\Product\ProductSetTemplateEvent;
|
||||
use Thelia\Core\Event\Product\ProductToggleVisibilityEvent;
|
||||
use Thelia\Core\Event\Product\ProductUpdateEvent;
|
||||
use Thelia\Core\Event\ProductSaleElement\ProductSaleElementDeleteEvent;
|
||||
use Thelia\Core\Event\Template\TemplateDeleteAttributeEvent;
|
||||
use Thelia\Core\Event\Template\TemplateDeleteFeatureEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\Event\UpdatePositionEvent;
|
||||
use Thelia\Core\Event\UpdateSeoEvent;
|
||||
use Thelia\Core\Event\ViewCheckEvent;
|
||||
use Thelia\Model\Accessory;
|
||||
use Thelia\Model\AccessoryQuery;
|
||||
use Thelia\Model\AttributeTemplateQuery;
|
||||
use Thelia\Model\Currency as CurrencyModel;
|
||||
use Thelia\Model\FeatureAvI18n;
|
||||
use Thelia\Model\FeatureAvI18nQuery;
|
||||
use Thelia\Model\FeatureAvQuery;
|
||||
use Thelia\Model\FeatureProduct;
|
||||
use Thelia\Model\FeatureProductQuery;
|
||||
use Thelia\Model\FeatureTemplateQuery;
|
||||
use Thelia\Model\Map\AttributeTemplateTableMap;
|
||||
use Thelia\Model\Map\FeatureTemplateTableMap;
|
||||
use Thelia\Model\Map\ProductSaleElementsTableMap;
|
||||
use Thelia\Model\Map\ProductTableMap;
|
||||
use Thelia\Model\Product as ProductModel;
|
||||
use Thelia\Model\ProductAssociatedContent;
|
||||
use Thelia\Model\ProductAssociatedContentQuery;
|
||||
use Thelia\Model\ProductCategory;
|
||||
use Thelia\Model\ProductCategoryQuery;
|
||||
use Thelia\Model\ProductDocument;
|
||||
use Thelia\Model\ProductDocumentQuery;
|
||||
use Thelia\Model\ProductI18n;
|
||||
@@ -34,34 +70,8 @@ use Thelia\Model\ProductImageQuery;
|
||||
use Thelia\Model\ProductPrice;
|
||||
use Thelia\Model\ProductPriceQuery;
|
||||
use Thelia\Model\ProductQuery;
|
||||
use Thelia\Model\Product as ProductModel;
|
||||
use Thelia\Model\ProductAssociatedContent;
|
||||
use Thelia\Model\ProductAssociatedContentQuery;
|
||||
use Thelia\Model\ProductCategory;
|
||||
use Thelia\Model\TaxRuleQuery;
|
||||
use Thelia\Model\AccessoryQuery;
|
||||
use Thelia\Model\Accessory;
|
||||
use Thelia\Model\FeatureProduct;
|
||||
use Thelia\Model\FeatureProductQuery;
|
||||
use Thelia\Model\ProductCategoryQuery;
|
||||
use Thelia\Model\ProductSaleElementsQuery;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\Event\Product\ProductUpdateEvent;
|
||||
use Thelia\Core\Event\Product\ProductCreateEvent;
|
||||
use Thelia\Core\Event\Product\ProductDeleteEvent;
|
||||
use Thelia\Core\Event\Product\ProductToggleVisibilityEvent;
|
||||
use Thelia\Core\Event\Product\ProductAddContentEvent;
|
||||
use Thelia\Core\Event\Product\ProductDeleteContentEvent;
|
||||
use Thelia\Core\Event\UpdatePositionEvent;
|
||||
use Thelia\Core\Event\UpdateSeoEvent;
|
||||
use Thelia\Core\Event\FeatureProduct\FeatureProductUpdateEvent;
|
||||
use Thelia\Core\Event\FeatureProduct\FeatureProductDeleteEvent;
|
||||
use Thelia\Core\Event\Product\ProductSetTemplateEvent;
|
||||
use Thelia\Core\Event\Product\ProductDeleteCategoryEvent;
|
||||
use Thelia\Core\Event\Product\ProductAddCategoryEvent;
|
||||
use Thelia\Core\Event\Product\ProductAddAccessoryEvent;
|
||||
use Thelia\Core\Event\Product\ProductDeleteAccessoryEvent;
|
||||
use Propel\Runtime\Propel;
|
||||
use Thelia\Model\TaxRuleQuery;
|
||||
|
||||
class Product extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
@@ -80,6 +90,11 @@ class Product extends BaseAction implements EventSubscriberInterface
|
||||
*/
|
||||
public function create(ProductCreateEvent $event)
|
||||
{
|
||||
$defaultTaxRuleId = null;
|
||||
if (null !== $defaultTaxRule = TaxRuleQuery::create()->findOneByIsDefault(true)) {
|
||||
$defaultTaxRuleId = $defaultTaxRule->getId();
|
||||
}
|
||||
|
||||
$product = new ProductModel();
|
||||
|
||||
$product
|
||||
@@ -90,17 +105,14 @@ class Product extends BaseAction implements EventSubscriberInterface
|
||||
->setTitle($event->getTitle())
|
||||
->setVisible($event->getVisible() ? 1 : 0)
|
||||
->setVirtual($event->getVirtual() ? 1 : 0)
|
||||
|
||||
// Set the default tax rule to this product
|
||||
->setTaxRule(TaxRuleQuery::create()->findOneByIsDefault(true))
|
||||
|
||||
->setTemplateId($event->getTemplateId())
|
||||
|
||||
->create(
|
||||
$event->getDefaultCategory(),
|
||||
$event->getBasePrice(),
|
||||
$event->getCurrencyId(),
|
||||
$event->getTaxRuleId(),
|
||||
// Set the default tax rule if not defined
|
||||
$event->getTaxRuleId() ?: $defaultTaxRuleId,
|
||||
$event->getBaseWeight(),
|
||||
$event->getBaseQuantity()
|
||||
)
|
||||
@@ -278,6 +290,7 @@ class Product extends BaseAction implements EventSubscriberInterface
|
||||
->findByProductId($event->getOriginalProduct()->getId());
|
||||
|
||||
// Set clone product associated contents
|
||||
/** @var ProductAssociatedContent $originalProductAssocCont */
|
||||
foreach ($originalProductAssocConts as $originalProductAssocCont) {
|
||||
$clonedProductCreatePAC = new ProductAddContentEvent($event->getClonedProduct(), $originalProductAssocCont->getContentId());
|
||||
$this->eventDispatcher->dispatch(TheliaEvents::PRODUCT_ADD_CONTENT, $clonedProductCreatePAC);
|
||||
@@ -291,6 +304,7 @@ class Product extends BaseAction implements EventSubscriberInterface
|
||||
->findByProductId($event->getOriginalProduct()->getId());
|
||||
|
||||
// Set clone product accessories
|
||||
/** @var Accessory $originalProductAccessory */
|
||||
foreach ($originalProductAccessoryList as $originalProductAccessory) {
|
||||
$clonedProductAddAccessoryEvent = new ProductAddAccessoryEvent($event->getClonedProduct(), $originalProductAccessory->getAccessory());
|
||||
$this->eventDispatcher->dispatch(TheliaEvents::PRODUCT_ADD_ACCESSORY, $clonedProductAddAccessoryEvent);
|
||||
@@ -387,22 +401,6 @@ class Product extends BaseAction implements EventSubscriberInterface
|
||||
->findByProductId($event->getProductId());
|
||||
$fileList['documentList']['type'] = TheliaEvents::DOCUMENT_DELETE;
|
||||
|
||||
// Delete free_text_feature AV (see issue #2061)
|
||||
$featureAvs = FeatureAvQuery::create()
|
||||
->useFeatureProductQuery()
|
||||
->filterByFreeTextValue(true)
|
||||
->filterByProductId($event->getProductId())
|
||||
->endUse()
|
||||
->find($con)
|
||||
;
|
||||
|
||||
foreach ($featureAvs as $featureAv) {
|
||||
$featureAv
|
||||
->setDispatcher($this->eventDispatcher)
|
||||
->delete($con)
|
||||
;
|
||||
}
|
||||
|
||||
// Delete product
|
||||
$product
|
||||
->setDispatcher($this->eventDispatcher)
|
||||
@@ -563,28 +561,69 @@ class Product extends BaseAction implements EventSubscriberInterface
|
||||
try {
|
||||
$product = $event->getProduct();
|
||||
|
||||
// Delete all product feature relations
|
||||
if (null !== $featureProducts = FeatureProductQuery::create()->findByProductId($product->getId())) {
|
||||
/** @var \Thelia\Model\FeatureProduct $featureProduct */
|
||||
foreach ($featureProducts as $featureProduct) {
|
||||
$eventDelete = new FeatureProductDeleteEvent($product->getId(), $featureProduct->getFeatureId());
|
||||
|
||||
$this->eventDispatcher->dispatch(TheliaEvents::PRODUCT_FEATURE_DELETE_VALUE, $eventDelete);
|
||||
}
|
||||
// Check differences between current coobination and the next one, and clear obsoletes values.
|
||||
$nextTemplateId = $event->getTemplateId();
|
||||
$currentTemplateId = $product->getTemplateId();
|
||||
|
||||
// 1. Process product features.
|
||||
|
||||
$currentFeatures = FeatureTemplateQuery::create()
|
||||
->filterByTemplateId($currentTemplateId)
|
||||
->select([ FeatureTemplateTableMap::FEATURE_ID ])
|
||||
->find($con);
|
||||
|
||||
$nextFeatures = FeatureTemplateQuery::create()
|
||||
->filterByTemplateId($nextTemplateId)
|
||||
->select([ FeatureTemplateTableMap::FEATURE_ID ])
|
||||
->find($con);
|
||||
|
||||
// Find features values we shoud delete. To do this, we have to
|
||||
// find all features in $currentFeatures that are not present in $nextFeatures
|
||||
$featuresToDelete = array_diff($currentFeatures->getData(), $nextFeatures->getData());
|
||||
|
||||
// Delete obsolete features values
|
||||
foreach ($featuresToDelete as $featureId) {
|
||||
$this->eventDispatcher->dispatch(
|
||||
TheliaEvents::PRODUCT_FEATURE_DELETE_VALUE,
|
||||
new FeatureProductDeleteEvent($product->getId(), $featureId)
|
||||
);
|
||||
}
|
||||
|
||||
// 2. Process product Attributes
|
||||
|
||||
$currentAttributes = AttributeTemplateQuery::create()
|
||||
->filterByTemplateId($currentTemplateId)
|
||||
->select([ AttributeTemplateTableMap::ATTRIBUTE_ID ])
|
||||
->find($con);
|
||||
|
||||
$nextAttributes = AttributeTemplateQuery::create()
|
||||
->filterByTemplateId($nextTemplateId)
|
||||
->select([ AttributeTemplateTableMap::ATTRIBUTE_ID ])
|
||||
->find($con);
|
||||
|
||||
// Find attributes values we shoud delete. To do this, we have to
|
||||
// find all attributes in $currentAttributes that are not present in $nextAttributes
|
||||
$attributesToDelete = array_diff($currentAttributes->getData(), $nextAttributes->getData());
|
||||
|
||||
// Delete all product attributes sale elements
|
||||
AttributeCombinationQuery::create()
|
||||
->filterByProductSaleElements($product->getProductSaleElementss())
|
||||
->delete($con)
|
||||
;
|
||||
|
||||
//Delete all productSaleElements except the default one (to keep price, weight, ean, etc...)
|
||||
ProductSaleElementsQuery::create()
|
||||
->filterByProduct($product)
|
||||
->filterByIsDefault(1, Criteria::NOT_EQUAL)
|
||||
->delete($con)
|
||||
;
|
||||
// Find PSE which includes $attributesToDelete for the current product/
|
||||
$pseToDelete = ProductSaleElementsQuery::create()
|
||||
->filterByProductId($product->getId())
|
||||
->useAttributeCombinationQuery()
|
||||
->filterByAttributeId($attributesToDelete, Criteria::IN)
|
||||
->endUse()
|
||||
->select([ ProductSaleElementsTableMap::ID ])
|
||||
->find();
|
||||
|
||||
// Delete obsolete PSEs
|
||||
foreach ($pseToDelete->getData() as $pseId) {
|
||||
$this->eventDispatcher->dispatch(
|
||||
TheliaEvents::PRODUCT_DELETE_PRODUCT_SALE_ELEMENT,
|
||||
new ProductSaleElementDeleteEvent(
|
||||
$pseId,
|
||||
CurrencyModel::getDefaultCurrency()->getId()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Update the product template
|
||||
$template_id = $event->getTemplateId();
|
||||
@@ -596,16 +635,6 @@ class Product extends BaseAction implements EventSubscriberInterface
|
||||
|
||||
$product->setTemplateId($template_id)->save($con);
|
||||
|
||||
//Be sure that the product has a default productSaleElements
|
||||
/** @var \Thelia\Model\ProductSaleElements $defaultPse */
|
||||
if (null == $defaultPse = ProductSaleElementsQuery::create()
|
||||
->filterByProduct($product)
|
||||
->filterByIsDefault(1)
|
||||
->findOne()) {
|
||||
// Create a new default product sale element
|
||||
$product->createProductSaleElement($con, 0, 0, 0, $event->getCurrencyId(), true);
|
||||
}
|
||||
|
||||
$product->clearProductSaleElementss();
|
||||
|
||||
$event->setProduct($product);
|
||||
@@ -618,7 +647,7 @@ class Product extends BaseAction implements EventSubscriberInterface
|
||||
throw $ex;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Changes accessry position, selecting absolute ou relative change.
|
||||
*
|
||||
@@ -781,6 +810,93 @@ class Product extends BaseAction implements EventSubscriberInterface
|
||||
$model->getProductSaleElementsProductDocuments()->delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When a feature is removed from a template, the products which are using this feature should be updated.
|
||||
*
|
||||
* @param TemplateDeleteFeatureEvent $event
|
||||
* @param string $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function deleteTemplateFeature(TemplateDeleteFeatureEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
// Detete the removed feature in all products which are using this template
|
||||
$products = ProductQuery::create()
|
||||
->filterByTemplateId($event->getTemplate()->getId())
|
||||
->find()
|
||||
;
|
||||
|
||||
foreach ($products as $product) {
|
||||
$dispatcher->dispatch(
|
||||
TheliaEvents::PRODUCT_FEATURE_DELETE_VALUE,
|
||||
new FeatureProductDeleteEvent($product->getId(), $event->getFeatureId())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When an attribute is removed from a template, the conbinations and PSE of products which are using this template
|
||||
* should be updated.
|
||||
*
|
||||
* @param TemplateDeleteAttributeEvent $event
|
||||
* @param string $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function deleteTemplateAttribute(TemplateDeleteAttributeEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
// Detete the removed attribute in all products which are using this template
|
||||
$pseToDelete = ProductSaleElementsQuery::create()
|
||||
->useProductQuery()
|
||||
->filterByTemplateId($event->getTemplate()->getId())
|
||||
->endUse()
|
||||
->useAttributeCombinationQuery()
|
||||
->filterByAttributeId($event->getAttributeId())
|
||||
->endUse()
|
||||
->select([ ProductSaleElementsTableMap::ID ])
|
||||
->find();
|
||||
|
||||
$currencyId = CurrencyModel::getDefaultCurrency()->getId();
|
||||
|
||||
foreach ($pseToDelete->getData() as $pseId) {
|
||||
$dispatcher->dispatch(
|
||||
TheliaEvents::PRODUCT_DELETE_PRODUCT_SALE_ELEMENT,
|
||||
new ProductSaleElementDeleteEvent(
|
||||
$pseId,
|
||||
$currencyId
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if is a product view and if product_id is visible
|
||||
*
|
||||
* @param ViewCheckEvent $event
|
||||
* @param string $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function viewCheck(ViewCheckEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if ($event->getView() == 'product') {
|
||||
$product = ProductQuery::create()
|
||||
->filterById($event->getViewId())
|
||||
->filterByVisible(1)
|
||||
->count();
|
||||
|
||||
if ($product == 0) {
|
||||
$dispatcher->dispatch(TheliaEvents::VIEW_PRODUCT_ID_NOT_VISIBLE, $event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ViewCheckEvent $event
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public function viewProductIdNotVisible(ViewCheckEvent $event)
|
||||
{
|
||||
throw new NotFoundHttpException();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
@@ -812,10 +928,16 @@ class Product extends BaseAction implements EventSubscriberInterface
|
||||
|
||||
TheliaEvents::PRODUCT_FEATURE_UPDATE_VALUE => array("updateFeatureProductValue", 128),
|
||||
TheliaEvents::PRODUCT_FEATURE_DELETE_VALUE => array("deleteFeatureProductValue", 128),
|
||||
|
||||
|
||||
TheliaEvents::TEMPLATE_DELETE_ATTRIBUTE => array("deleteTemplateAttribute", 128),
|
||||
TheliaEvents::TEMPLATE_DELETE_FEATURE => array("deleteTemplateFeature", 128),
|
||||
|
||||
// Those two have to be executed before
|
||||
TheliaEvents::IMAGE_DELETE => array("deleteImagePSEAssociations", 192),
|
||||
TheliaEvents::DOCUMENT_DELETE => array("deleteDocumentPSEAssociations", 192),
|
||||
|
||||
TheliaEvents::VIEW_CHECK => array('viewCheck', 128),
|
||||
TheliaEvents::VIEW_PRODUCT_ID_NOT_VISIBLE => array('viewProductIdNotVisible', 128),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,24 +15,26 @@ namespace Thelia\Action;
|
||||
use Propel\Runtime\Propel;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Model\CategoryQuery;
|
||||
use Thelia\Model\Map\TemplateTableMap;
|
||||
use Thelia\Model\TemplateQuery;
|
||||
use Thelia\Model\Template as TemplateModel;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\Event\Template\TemplateUpdateEvent;
|
||||
use Thelia\Core\Event\Template\TemplateCreateEvent;
|
||||
use Thelia\Core\Event\Template\TemplateDeleteEvent;
|
||||
use Thelia\Core\Event\UpdatePositionEvent;
|
||||
use Thelia\Model\ProductQuery;
|
||||
use Thelia\Core\Event\Template\TemplateAddAttributeEvent;
|
||||
use Thelia\Core\Event\Template\TemplateDeleteAttributeEvent;
|
||||
use Thelia\Model\AttributeTemplateQuery;
|
||||
use Thelia\Model\AttributeTemplate;
|
||||
use Thelia\Core\Event\Template\TemplateDeleteFeatureEvent;
|
||||
use Thelia\Core\Event\Template\TemplateAddFeatureEvent;
|
||||
use Thelia\Model\FeatureTemplateQuery;
|
||||
use Thelia\Core\Event\Template\TemplateCreateEvent;
|
||||
use Thelia\Core\Event\Template\TemplateDeleteAttributeEvent;
|
||||
use Thelia\Core\Event\Template\TemplateDeleteEvent;
|
||||
use Thelia\Core\Event\Template\TemplateDeleteFeatureEvent;
|
||||
use Thelia\Core\Event\Template\TemplateDuplicateEvent;
|
||||
use Thelia\Core\Event\Template\TemplateUpdateEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\Event\UpdatePositionEvent;
|
||||
use Thelia\Core\Translation\Translator;
|
||||
use Thelia\Model\AttributeTemplate;
|
||||
use Thelia\Model\AttributeTemplateQuery;
|
||||
use Thelia\Model\CategoryQuery;
|
||||
use Thelia\Model\FeatureTemplate;
|
||||
use Thelia\Model\FeatureTemplateQuery;
|
||||
use Thelia\Model\Map\TemplateTableMap;
|
||||
use Thelia\Model\ProductQuery;
|
||||
use Thelia\Model\Template as TemplateModel;
|
||||
use Thelia\Model\TemplateQuery;
|
||||
|
||||
class Template extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
@@ -46,19 +48,66 @@ class Template extends BaseAction implements EventSubscriberInterface
|
||||
public function create(TemplateCreateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$template = new TemplateModel();
|
||||
|
||||
|
||||
$template
|
||||
->setDispatcher($dispatcher)
|
||||
|
||||
|
||||
->setLocale($event->getLocale())
|
||||
->setName($event->getTemplateName())
|
||||
|
||||
|
||||
->save()
|
||||
;
|
||||
|
||||
|
||||
$event->setTemplate($template);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Dupliucate an existing template entry
|
||||
*
|
||||
* @param \Thelia\Core\Event\Template\TemplateCreateEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function duplicate(TemplateDuplicateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $source = TemplateQuery::create()->findPk($event->getSourceTemplateId())) {
|
||||
$source->setLocale($event->getLocale());
|
||||
|
||||
$createEvent = new TemplateCreateEvent();
|
||||
$createEvent
|
||||
->setLocale($event->getLocale())
|
||||
->setTemplateName(
|
||||
Translator::getInstance()->trans("Copy of %tpl", ["%tpl" => $source->getName() ])
|
||||
);
|
||||
|
||||
$dispatcher->dispatch(TheliaEvents::TEMPLATE_CREATE, $createEvent);
|
||||
|
||||
$clone = $createEvent->getTemplate();
|
||||
|
||||
$attrList = AttributeTemplateQuery::create()->findByTemplateId($source->getId());
|
||||
|
||||
/** @var $feat AttributeTemplate */
|
||||
foreach ($attrList as $feat) {
|
||||
$dispatcher->dispatch(
|
||||
TheliaEvents::TEMPLATE_ADD_ATTRIBUTE,
|
||||
new TemplateAddAttributeEvent($clone, $feat->getAttributeId())
|
||||
);
|
||||
}
|
||||
|
||||
$featList = FeatureTemplateQuery::create()->findByTemplateId($source->getId());
|
||||
|
||||
/** @var $feat FeatureTemplate */
|
||||
foreach ($featList as $feat) {
|
||||
$dispatcher->dispatch(
|
||||
TheliaEvents::TEMPLATE_ADD_FEATURE,
|
||||
new TemplateAddFeatureEvent($clone, $feat->getFeatureId())
|
||||
);
|
||||
}
|
||||
|
||||
$event->setTemplate($clone);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Change a product template
|
||||
*
|
||||
@@ -71,15 +120,15 @@ class Template extends BaseAction implements EventSubscriberInterface
|
||||
if (null !== $template = TemplateQuery::create()->findPk($event->getTemplateId())) {
|
||||
$template
|
||||
->setDispatcher($dispatcher)
|
||||
|
||||
->setLocale($event->getLocale())
|
||||
->setName($event->getTemplateName())
|
||||
->save();
|
||||
|
||||
|
||||
->setLocale($event->getLocale())
|
||||
->setName($event->getTemplateName())
|
||||
->save();
|
||||
|
||||
$event->setTemplate($template);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Delete a product template entry
|
||||
*
|
||||
@@ -92,54 +141,54 @@ class Template extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
if (null !== ($template = TemplateQuery::create()->findPk($event->getTemplateId()))) {
|
||||
// Check if template is used by a product
|
||||
$product_count = ProductQuery::create()->findByTemplateId($template->getId())->count();
|
||||
|
||||
if ($product_count <= 0) {
|
||||
$productCount = ProductQuery::create()->findByTemplateId($template->getId())->count();
|
||||
|
||||
if ($productCount <= 0) {
|
||||
$con = Propel::getWriteConnection(TemplateTableMap::DATABASE_NAME);
|
||||
$con->beginTransaction();
|
||||
|
||||
|
||||
try {
|
||||
$template
|
||||
->setDispatcher($dispatcher)
|
||||
->delete($con);
|
||||
|
||||
|
||||
// We have to also delete any reference of this template in category tables
|
||||
// We can't use a FK here, as the DefaultTemplateId column may be NULL
|
||||
// so let's take care of this.
|
||||
CategoryQuery::create()
|
||||
->filterByDefaultTemplateId($event->getTemplateId())
|
||||
->update([ 'DefaultTemplateId' => null], $con);
|
||||
|
||||
|
||||
$con->commit();
|
||||
} catch (\Exception $ex) {
|
||||
$con->rollback();
|
||||
|
||||
|
||||
throw $ex;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$event->setTemplate($template);
|
||||
|
||||
$event->setProductCount($product_count);
|
||||
|
||||
$event->setProductCount($productCount);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function addAttribute(TemplateAddAttributeEvent $event)
|
||||
{
|
||||
if (null === AttributeTemplateQuery::create()
|
||||
->filterByAttributeId($event->getAttributeId())
|
||||
->filterByTemplate($event->getTemplate())
|
||||
->findOne()) {
|
||||
$attribute_template = new AttributeTemplate();
|
||||
|
||||
$attribute_template
|
||||
$attributeTemplate = new AttributeTemplate();
|
||||
|
||||
$attributeTemplate
|
||||
->setAttributeId($event->getAttributeId())
|
||||
->setTemplate($event->getTemplate())
|
||||
->save()
|
||||
->save()
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Changes position, selecting absolute ou relative change.
|
||||
*
|
||||
@@ -151,7 +200,7 @@ class Template extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
$this->genericUpdatePosition(AttributeTemplateQuery::create(), $event, $dispatcher);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Changes position, selecting absolute ou relative change.
|
||||
*
|
||||
@@ -163,19 +212,24 @@ class Template extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
$this->genericUpdatePosition(FeatureTemplateQuery::create(), $event, $dispatcher);
|
||||
}
|
||||
|
||||
public function deleteAttribute(TemplateDeleteAttributeEvent $event)
|
||||
|
||||
public function deleteAttribute(TemplateDeleteAttributeEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$attribute_template = AttributeTemplateQuery::create()
|
||||
$attributeTemplate = AttributeTemplateQuery::create()
|
||||
->filterByAttributeId($event->getAttributeId())
|
||||
->filterByTemplate($event->getTemplate())->findOne()
|
||||
;
|
||||
|
||||
if ($attribute_template !== null) {
|
||||
$attribute_template->delete();
|
||||
|
||||
if ($attributeTemplate !== null) {
|
||||
$attributeTemplate
|
||||
->setDispatcher($dispatcher)
|
||||
->delete();
|
||||
} else {
|
||||
// Prevent event propagation
|
||||
$event->stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function addFeature(TemplateAddFeatureEvent $event)
|
||||
{
|
||||
if (null === FeatureTemplateQuery::create()
|
||||
@@ -183,28 +237,33 @@ class Template extends BaseAction implements EventSubscriberInterface
|
||||
->filterByTemplate($event->getTemplate())
|
||||
->findOne()
|
||||
) {
|
||||
$feature_template = new FeatureTemplate();
|
||||
|
||||
$feature_template
|
||||
->setFeatureId($event->getFeatureId())
|
||||
->setTemplate($event->getTemplate())
|
||||
->save()
|
||||
$featureTemplate = new FeatureTemplate();
|
||||
|
||||
$featureTemplate
|
||||
->setFeatureId($event->getFeatureId())
|
||||
->setTemplate($event->getTemplate())
|
||||
->save()
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
public function deleteFeature(TemplateDeleteFeatureEvent $event)
|
||||
|
||||
public function deleteFeature(TemplateDeleteFeatureEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$feature_template = FeatureTemplateQuery::create()
|
||||
$featureTemplate = FeatureTemplateQuery::create()
|
||||
->filterByFeatureId($event->getFeatureId())
|
||||
->filterByTemplate($event->getTemplate())->findOne()
|
||||
;
|
||||
|
||||
if ($feature_template !== null) {
|
||||
$feature_template->delete();
|
||||
|
||||
if ($featureTemplate !== null) {
|
||||
$featureTemplate
|
||||
->setDispatcher($dispatcher)
|
||||
->delete();
|
||||
} else {
|
||||
// Prevent event propagation
|
||||
$event->stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@@ -214,16 +273,16 @@ class Template extends BaseAction implements EventSubscriberInterface
|
||||
TheliaEvents::TEMPLATE_CREATE => array("create", 128),
|
||||
TheliaEvents::TEMPLATE_UPDATE => array("update", 128),
|
||||
TheliaEvents::TEMPLATE_DELETE => array("delete", 128),
|
||||
|
||||
TheliaEvents::TEMPLATE_DUPLICATE => array("duplicate", 128),
|
||||
|
||||
TheliaEvents::TEMPLATE_ADD_ATTRIBUTE => array("addAttribute", 128),
|
||||
TheliaEvents::TEMPLATE_DELETE_ATTRIBUTE => array("deleteAttribute", 128),
|
||||
|
||||
|
||||
TheliaEvents::TEMPLATE_ADD_FEATURE => array("addFeature", 128),
|
||||
TheliaEvents::TEMPLATE_DELETE_FEATURE => array("deleteFeature", 128),
|
||||
|
||||
|
||||
TheliaEvents::TEMPLATE_CHANGE_ATTRIBUTE_POSITION => array('updateAttributePosition', 128),
|
||||
TheliaEvents::TEMPLATE_CHANGE_FEATURE_POSITION => array('updateFeaturePosition', 128),
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,8 +96,9 @@ class ContainerAwareCommand extends Command implements ContainerAwareInterface
|
||||
|
||||
$requestContext = new RequestContext();
|
||||
$requestContext->fromRequest($request);
|
||||
$url = new URL($container);
|
||||
$url = $container->get('thelia.url.manager');
|
||||
$url->setRequestContext($requestContext);
|
||||
$this->getContainer()->get('router.admin')->setContext($requestContext);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -71,7 +71,6 @@ class HookCleanCommand extends ContainerAwareCommand
|
||||
} catch (\Exception $ex) {
|
||||
$output->writeln(sprintf("<error>%s</error>", $ex->getMessage()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function getModule(InputInterface $input)
|
||||
|
||||
@@ -12,10 +12,13 @@
|
||||
|
||||
namespace Thelia\Command;
|
||||
|
||||
use Symfony\Component\Console\Helper\QuestionHelper;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Question\ConfirmationQuestion;
|
||||
use Thelia\Action\Module;
|
||||
use Thelia\Core\Event\Module\ModuleToggleActivationEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Model\ModuleQuery;
|
||||
@@ -47,6 +50,12 @@ class ModuleDeactivateCommand extends BaseModuleGenerate
|
||||
InputArgument::REQUIRED,
|
||||
"module to deactivate"
|
||||
)
|
||||
->addOption(
|
||||
"assume-yes",
|
||||
'y',
|
||||
InputOption::VALUE_NONE,
|
||||
'Assume to deactivate a mandatory module'
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
@@ -67,6 +76,15 @@ class ModuleDeactivateCommand extends BaseModuleGenerate
|
||||
|
||||
try {
|
||||
$event = new ModuleToggleActivationEvent($module->getId());
|
||||
|
||||
$module = ModuleQuery::create()->findPk($module->getId());
|
||||
if ($module->getMandatory() == BaseModule::IS_MANDATORY) {
|
||||
if (!$this->askConfirmation($input, $output)) {
|
||||
return;
|
||||
}
|
||||
$event->setAssumeDeactivate(true);
|
||||
}
|
||||
|
||||
if ($input->getOption("with-dependencies")) {
|
||||
$event->setRecursive(true);
|
||||
}
|
||||
@@ -84,4 +102,33 @@ class ModuleDeactivateCommand extends BaseModuleGenerate
|
||||
), "bg=green;fg=black");
|
||||
}
|
||||
}
|
||||
|
||||
private function askConfirmation(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$assumeYes = $input->getOption("assume-yes");
|
||||
$moduleCode = $input->getArgument("module");
|
||||
|
||||
if (!$assumeYes) {
|
||||
/** @var QuestionHelper $helper */
|
||||
$helper = $this->getHelper('question');
|
||||
$questionText = "Module ";
|
||||
$questionText .= (empty($moduleCode))
|
||||
? ""
|
||||
: $moduleCode;
|
||||
$questionText .= " is mandatory.\n";
|
||||
$questionText .= "Would you like to deactivate the module ";
|
||||
$questionText .= (empty($moduleCode))
|
||||
? ""
|
||||
: $moduleCode;
|
||||
$questionText .= " ? (yes, or no) ";
|
||||
|
||||
$question = new ConfirmationQuestion($questionText, false);
|
||||
|
||||
if (!$helper->ask($input, $output, $question)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,4 +38,6 @@
|
||||
-->
|
||||
<thelia>2.2.0</thelia>
|
||||
<stability>other</stability>
|
||||
<mandatory>0</mandatory>
|
||||
<hidden>0</hidden>
|
||||
</module>
|
||||
|
||||
@@ -99,18 +99,18 @@ class CartContainsCategories extends ConditionAbstract
|
||||
|
||||
/** @var Category $category */
|
||||
foreach ($categories as $category) {
|
||||
$catecoryInCart = $this->conditionValidator->variableOpComparison(
|
||||
if (! $this->conditionValidator->variableOpComparison(
|
||||
$category->getId(),
|
||||
$this->operators[self::CATEGORIES_LIST],
|
||||
$this->values[self::CATEGORIES_LIST]
|
||||
);
|
||||
|
||||
if ($catecoryInCart) {
|
||||
return true;
|
||||
)) {
|
||||
// cart item doesn't match go to next cart item
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
// cart item match
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -103,7 +103,6 @@ class CartContainsProducts extends ConditionAbstract
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -79,5 +79,4 @@ class MatchForXArticlesIncludeQuantity extends MatchForXArticles
|
||||
|
||||
return $toolTip;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ return array(
|
||||
' note: only non-visible documents can be associated.' => ' note: only non-visible documents can be associated.',
|
||||
'"%param" parameter cannot be empty in loop type: %type, name: %name' => '"%param" parameter cannot be empty in loop type: %type, name: %name',
|
||||
'"%param" parameter is missing in loop type: %type, name: %name' => '"%param" parameter is missing in loop type: %type, name: %name',
|
||||
'#000000' => '#000000',
|
||||
'%module (version: %version)' => '%module (version: %version)',
|
||||
'%n for number, %c for the currency code, %s for the currency symbol' => '%n for number, %c for the currency code, %s for the currency symbol',
|
||||
'%obj SEO modification' => '%obj SEO modification',
|
||||
@@ -52,6 +53,7 @@ return array(
|
||||
'All countries' => 'All countries',
|
||||
'All shipping methods' => 'All shipping methods',
|
||||
'Amount' => 'Amount',
|
||||
'An administrator with thie email address already exists' => 'An administrator with this email address already exists',
|
||||
'An administrator with this email address already exists' => 'An administrator with this email address already exists',
|
||||
'An invalid token was provided, your password cannot be changed' => 'An invalid token was provided, your password cannot be changed',
|
||||
'Apply exchange rates on price in %sym' => 'Apply exchange rates on price in %sym',
|
||||
@@ -81,6 +83,8 @@ return array(
|
||||
'By Module' => 'By Module',
|
||||
'CSS' => 'CSS',
|
||||
'CSS stylesheet' => 'CSS stylesheet',
|
||||
'Can\'t deactivate a secure module' => 'Can\'t deactivate a secure module',
|
||||
'Can\'t remove a core module' => 'Can\'t remove a core module',
|
||||
'Cannot disable the default language' => 'Cannot disable the default language',
|
||||
'Cannot find a default country. Please define one.' => 'Cannot find a default country. Please define one.',
|
||||
'Cannot find the shop country. Please select a shop country.' => 'Cannot find the shop country. Please select a shop country.',
|
||||
@@ -106,6 +110,7 @@ return array(
|
||||
'Change password' => 'Change password',
|
||||
'Check country iso codes <a href="http://en.wikipedia.org/wiki/ISO_3166-1#Current_codes" target="_blank">here</a>.' => 'Check country iso codes <a href="http://en.wikipedia.org/wiki/ISO_3166-1#Current_codes" target="_blank">in Wikipedia</a>.',
|
||||
'Check the total Cart amount in the given currency' => 'Check the total Cart amount in the given currency',
|
||||
'Choice a color for this order status code' => 'Choice a color for this order status code',
|
||||
'City' => 'City',
|
||||
'Code' => 'Code',
|
||||
'Combination builder' => 'Combination builder',
|
||||
@@ -180,6 +185,8 @@ return array(
|
||||
'Enter here the brand name in the default language (%title%)' => 'Enter here the brand name in the default language (%title%)',
|
||||
'Enter here the category title in the default language (%title%)' => 'Enter here the category title in the default language (%title%)',
|
||||
'Enter here the mail template purpose in the default language (%title%)' => 'Enter here the mail template purpose in the default language (%title%)',
|
||||
'Enter here the order status code' => 'Enter here the order status code',
|
||||
'Enter here the order status name in the default language (%title%)' => 'Enter here the order status name in the default language (%title%)',
|
||||
'Enter here the sale name in the default language (%title%)' => 'Enter here the sale name in the default language (%title%)',
|
||||
'Enter the new password' => 'Enter the new password',
|
||||
'Enter the new password again' => 'Enter the new password again',
|
||||
@@ -187,6 +194,8 @@ return array(
|
||||
'Error during %action process : %error. Exception was %exc' => 'Error during %action process : %error. Exception was %exc',
|
||||
'Error occured while processing order ref. %ref, ID %id: %err' => 'Error occurred while processing order ref. %ref, ID %id: %err',
|
||||
'Error occured.' => 'Error occurred.',
|
||||
'Error occurred while cancelling order ref. %ref, ID %id: %err' => 'Error occurred while cancelling order ref. %ref, ID %id: %err',
|
||||
'Error occurred while saving payment transaction %transaction_ref for order ID %id.' => 'Error occurred while saving payment transaction %transaction_ref for order ID %id.',
|
||||
'Error(s) in import :<br />%errors' => 'Error(s) in import :<br />%errors',
|
||||
'Errors' => 'Errors',
|
||||
'Export' => 'Export',
|
||||
@@ -346,6 +355,9 @@ return array(
|
||||
'Order failed' => 'Order failed',
|
||||
'Order ref. %ref is now unpaid.' => 'Order ref. %ref is now unpaid.',
|
||||
'Order ref. %ref, ID %id has been successfully paid.' => 'Order ref. %ref, ID %id has been successfully paid.',
|
||||
'Order status code' => 'Order status code',
|
||||
'Order status color' => 'Order status color',
|
||||
'Order status name' => 'Order status name',
|
||||
'Orders' => 'Orders',
|
||||
'Overall' => 'Overall',
|
||||
'Page 404' => 'Page 404',
|
||||
@@ -357,6 +369,8 @@ return array(
|
||||
'Password confirmation' => 'Password confirmation',
|
||||
'Payment failed' => 'Payment failed',
|
||||
'Payment gateway' => 'Payment gateway',
|
||||
'Payment module ID not found' => 'Payment module ID not found',
|
||||
'Payment transaction %transaction_ref for order ref. %ref, ID %id has been successfully saved.' => 'Payment transaction %transaction_ref for order ref. %ref, ID %id has been successfully saved.',
|
||||
'Per customer' => 'Per customer',
|
||||
'Percent' => 'Percent',
|
||||
'Percentage' => 'Percentage',
|
||||
@@ -421,6 +435,7 @@ return array(
|
||||
'Range date Start' => 'Range date Start',
|
||||
'Rate' => 'Rate',
|
||||
'Rate from %currencyCode' => 'Rate from %currencyCode',
|
||||
'Recipient e-mail address' => 'Recipient e-mail address',
|
||||
'Redirecting ...' => 'Redirecting ...',
|
||||
'Redirecting to %url' => 'Redirecting to %url',
|
||||
'Reference' => 'Reference',
|
||||
@@ -453,6 +468,7 @@ return array(
|
||||
'Select the product brand, or supplier.' => 'Select the product brand, or supplier.',
|
||||
'Select the products covered by this operation' => 'Select the products covered by this operation',
|
||||
'Select the virtual document' => 'Select the virtual document',
|
||||
'Send test e-mail to:' => 'Send test e-mail to:',
|
||||
'Service ID' => 'Service ID',
|
||||
'Shipping configuration' => 'Shipping configuration',
|
||||
'Shipping zone name' => 'Shipping zone name',
|
||||
@@ -460,6 +476,8 @@ return array(
|
||||
'Short description text' => 'Short description text',
|
||||
'Show redirections *' => 'Show redirections *',
|
||||
'Sitemap' => 'Sitemap',
|
||||
'Some commands use this status.' => 'Some commands use this status.',
|
||||
'Something goes wrong, the message was not sent to recipient. Error is : %err' => 'Something goes wrong, the message was not sent to recipient. Error is : %err',
|
||||
'Sorry, an error occured.' => 'Sorry, an error occurred.',
|
||||
'Sorry, an error occured: %msg' => 'Sorry, an error occurred: %msg',
|
||||
'Sorry, an error occured: %s' => 'Sorry, an error occurred: %s',
|
||||
@@ -536,6 +554,7 @@ return array(
|
||||
'The lost admin password recovery feature is disabled.' => 'The lost admin password recovery feature is disabled.',
|
||||
'The mailing template in HTML format.' => 'The mailing template in HTML format.',
|
||||
'The mailing template in text-only format.' => 'The mailing template in text-only format.',
|
||||
'The message has been successfully sent to %recipient.' => 'The message has been successfully sent to %recipient.',
|
||||
'The method %method% doesn\'t exist in classname %classname%' => 'The method %method% doesn\'t exist in classname %classname%',
|
||||
'The method name that will handle the hook event.' => 'The method name that will handle the hook event.',
|
||||
'The module "%name%" is currently in use by at least one order, and can\'t be deleted.' => 'The module "%name%" is currently in use by at least one order, and can\'t be deleted.',
|
||||
@@ -545,6 +564,8 @@ return array(
|
||||
'The module has to be activated.' => 'The module has to be activated.',
|
||||
'The module is not valid : %message' => 'The module is not valid : %message',
|
||||
'The module zip file' => 'The module zip file',
|
||||
'The order status code' => 'The order status code',
|
||||
'The order status name or title' => 'The order status name or title',
|
||||
'The product document id %id doesn\'t exists' => 'The product document id %id doesn\'t exists',
|
||||
'The product image id %id doesn\'t exists' => 'The product image id %id doesn\'t exists',
|
||||
'The product sale element id %id doesn\'t exist' => 'The product sale element id %id doesn\'t exist',
|
||||
@@ -574,6 +595,7 @@ return array(
|
||||
'This administrator login already exists' => 'This administrator login already exists',
|
||||
'This brand is online' => 'This brand is online',
|
||||
'This category is online' => 'This category is online',
|
||||
'This code is already used.' => 'This code is already used.',
|
||||
'This condition is always true' => 'This condition is always true',
|
||||
'This content is online.' => 'This content is online.',
|
||||
'This country has states / provinces' => 'This country has states / provinces',
|
||||
@@ -596,6 +618,8 @@ return array(
|
||||
'This image is online' => 'This image is online',
|
||||
'This is a comma separated list of email addresses where store notifications (such as order placed) are sent.' => 'This is a comma separated list of email addresses where store notifications (such as order placed) are sent.',
|
||||
'This is an identifier that will be used in the code to get this message' => 'This is an identifier that will be used in the code to get this message',
|
||||
'This is not a hexadecimal color.' => 'This is not a hexadecimal color.',
|
||||
'This is not a valid code.' => 'This is not a valid code.',
|
||||
'This is the contact email address, and the sender email of all e-mails sent by your store.' => 'This is the contact email address, and the sender email of all e-mails sent by your store.',
|
||||
'This is the message purpose, such as \'Order confirmation\'.' => 'This is the message purpose, such as \'Order confirmation\'.',
|
||||
'This is the name used on the login screen' => 'This is the name used on the login screen',
|
||||
@@ -608,6 +632,7 @@ return array(
|
||||
'This product_sale_elements_id does not exists for this product : %d' => 'This product_sale_elements_id does not exists for this product : %d',
|
||||
'This state doesn\'t belong to this country.' => 'This state doesn\'t belong to this country.',
|
||||
'This state is online' => 'This state is online',
|
||||
'This status is protected.' => 'This status is protected.',
|
||||
'This template is in use in some of your products, and cannot be deleted. Delete it from all your products and try again.' => 'This template is in use in some of your products, and cannot be deleted. Delete it from all your products and try again.',
|
||||
'This the unique name of this message. Do not change this value unless you understand what you do.' => 'This the unique name of this message. Do not change this value unless you understand what you do.',
|
||||
'This value should not be blank.' => 'This value should not be blank.',
|
||||
@@ -654,6 +679,7 @@ return array(
|
||||
'Wrong form method, %s expected.' => 'Wrong form method, %s expected.',
|
||||
'Yes, I have a password :' => 'Yes, I have a password :',
|
||||
'You are already registered!' => 'You are already registered!',
|
||||
'You can not delete it.' => 'You can not delete it.',
|
||||
'You don\'t need to use commas or other punctuations.' => 'You don\'t need to use commas or other punctuations.',
|
||||
'You have to configure your store email first !' => 'You have to configure your store email first !',
|
||||
'You must select at least one attribute.' => 'You must select at least one attribute.',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
return array(
|
||||
' content create form' => 'Formulaire de création de contenu',
|
||||
' note: only non-visible documents can be associated.' => 'remarque : seuls ces modules. les documents non visibles peuvent être associés.',
|
||||
'"%param" parameter cannot be empty in loop type: %type, name: %name' => 'Le paramètre "%param" ne peut être vide dans la boucle type: %type, nom: %name ',
|
||||
@@ -70,6 +70,8 @@ return [
|
||||
'Available shipping zones' => 'Zones de livraison disponibles',
|
||||
'Back Office' => 'Back Office',
|
||||
'Bad tax list JSON' => 'Mauvais JSON de la liste des taxes',
|
||||
'Banner' => 'Bannière',
|
||||
'Banner of the website. Used in the e-mails send to the customers.' => 'Bannière du site utilisée dans le contenu des mails envoyés aux clients.',
|
||||
'Billing country' => 'Pays de facturation',
|
||||
'Billing country is' => 'Le pays de facturation est',
|
||||
'Brand' => 'Marque',
|
||||
@@ -80,6 +82,8 @@ return [
|
||||
'By Module' => 'Par module',
|
||||
'CSS' => 'CSS',
|
||||
'CSS stylesheet' => 'Feuille de style CSS',
|
||||
'Can\'t deactivate a secure module' => 'Impossible de désactiver un module sécurisé',
|
||||
'Can\'t remove a core module' => 'Impossible de supprimer un module de base',
|
||||
'Cannot disable the default language' => 'Impossible de désactiver la langue par défaut',
|
||||
'Cannot find a default country. Please define one.' => 'Impossible de trouver un pays par défaut. Veuillez en définir un.',
|
||||
'Cannot find the shop country. Please select a shop country.' => 'Impossible de trouver le pays du magasin. Veuillez en sélectionner un.',
|
||||
@@ -203,6 +207,7 @@ return [
|
||||
'Failed to open translation file %file. Please be sure that this file is writable by your Web server' => 'L\'ouverture du fichier %file a échoué. Merci de vérifier que ce fichier est accessible en écriture pour votre serveur Web.',
|
||||
'Failed to send message %code. Failed recipients: %failed_addresses' => 'Erreur lors de l\'envoi du message %code. Echec pour les destinataires %failed_addresses',
|
||||
'Failed to update language definition: %ex' => 'Erreur lors de la mise à jour de la définition de la langue : %ex',
|
||||
'Favicon image' => 'Icône du site',
|
||||
'Fax' => 'Fax',
|
||||
'Feature' => 'Caractéristique',
|
||||
'Feature value does not match FLOAT format' => 'valeur de caractéristique n\'est pas un FLOAT',
|
||||
@@ -240,6 +245,7 @@ return [
|
||||
'Hooks' => 'Points d\'accroche',
|
||||
'Host' => 'Nom de l\'hôte',
|
||||
'I would like to receive the newsletter or the latest news.' => 'Je souhaite recevoir la lettre d\'information ou les dernières actualités.',
|
||||
'Icon of the website. Only PNG and ICO files are allowed.' => 'Icône du site. Seuls les fichiers au format PNG ou ICO sont autorisés.',
|
||||
'ISO 4217 code' => 'Code ISO 4217',
|
||||
'ISO 639-1 Code' => 'Code ISO 639-1',
|
||||
'ISO Alpha-2 code' => 'Code ISO Alpha-2',
|
||||
@@ -355,6 +361,7 @@ return [
|
||||
'Password confirmation' => 'Confirmation du mot de passe.',
|
||||
'Payment failed' => 'Echec du paiement',
|
||||
'Payment gateway' => 'Passerelle de paiement',
|
||||
'Payment module ID not found' => 'ID du module de paiement non trouvé',
|
||||
'Per customer' => 'Par client',
|
||||
'Percent' => 'Pourcent',
|
||||
'Percentage' => 'Pourcentage',
|
||||
@@ -419,6 +426,7 @@ return [
|
||||
'Range date Start' => 'Date de début',
|
||||
'Rate' => 'Taux',
|
||||
'Rate from %currencyCode' => 'Taux pour %currencyCode',
|
||||
'Recipient e-mail address' => 'Adresse e-mail du destinataire',
|
||||
'Redirecting ...' => 'Redirection ...',
|
||||
'Redirecting to %url' => 'Redirection vers %url',
|
||||
'Reference' => 'Référence',
|
||||
@@ -451,6 +459,7 @@ return [
|
||||
'Select the product brand, or supplier.' => 'Choisissez la marque ou le fournisseur du produit.',
|
||||
'Select the products covered by this operation' => 'Produits inclus dans cette promotion',
|
||||
'Select the virtual document' => 'Sélectionnez le document virtuel',
|
||||
'Send test e-mail to:' => 'Envoyer un email de test à: ',
|
||||
'Service ID' => 'ID du service',
|
||||
'Shipping configuration' => 'Configuration du transport',
|
||||
'Shipping zone name' => 'Nom de la zone de livraison',
|
||||
@@ -478,6 +487,7 @@ return [
|
||||
'Store configuration failed.' => 'Erreur de configuration du magasin.',
|
||||
'Store description' => 'Description du magasin',
|
||||
'Store email address' => 'Adresse mail du magasin',
|
||||
'Store logo' => 'Logo de la boutique',
|
||||
'Store logs into text file' => 'Conserver les logs dans des fichiers texte',
|
||||
'Store logs into text file, up to a certian size, then a new file is created' => 'Sauvegarder les logs dans un fichier texte. A partir d\'une certaine taille un nouveau fichier est créé',
|
||||
'Store name' => 'Nom du magasin',
|
||||
@@ -535,7 +545,7 @@ return [
|
||||
'The method %method% doesn\'t exist in classname %classname%' => 'La méthode %method% n\'existe pas dans la classe %classname%',
|
||||
'The method name that will handle the hook event.' => 'Le nom de la méthode qui va traiter l\'évènement du point d\'accroche.',
|
||||
'The module "%name%" is currently in use by at least one order, and can\'t be deleted.' => 'Le module "%name%" est utilisé par au moins une commande, et ne peut être supprimé.',
|
||||
'The module %module has been installed successfully.' => 'Le module %module a été activé avec succès.',
|
||||
'The module %module has been installed successfully.' => 'Le module %module a été installé avec succès.',
|
||||
'The module %name is already installed in the same or greater version.' => 'Le module %name est déja installé dans la même version, ou dans une version plus récente.',
|
||||
'The module %name requires Thelia %version or newer' => 'Le module %name nécessite Thelia %version ou plus récent',
|
||||
'The module has to be activated.' => 'Le module doit être activé.',
|
||||
@@ -820,4 +830,4 @@ return [
|
||||
'update form' => 'Formulaire de modification',
|
||||
'value table header' => 'colonne tableau valeur',
|
||||
'value table row' => 'ligne tableau valeurs',
|
||||
];
|
||||
);
|
||||
|
||||
@@ -28,6 +28,10 @@
|
||||
<tag name="kernel.event_subscriber"/>
|
||||
</service>
|
||||
|
||||
<service id="thelia.action.order_status" class="Thelia\Action\OrderStatus">
|
||||
<tag name="kernel.event_subscriber"/>
|
||||
</service>
|
||||
|
||||
<service id="thelia.action.coupon" class="Thelia\Action\Coupon">
|
||||
<argument type="service" id="request_stack"/>
|
||||
<argument type="service" id="thelia.coupon.factory"/>
|
||||
@@ -171,6 +175,7 @@
|
||||
</service>
|
||||
|
||||
<service id="thelia.action.cache" class="Thelia\Action\Cache">
|
||||
<argument type="service" id="thelia.cache"/>
|
||||
<tag name="kernel.event_subscriber"/>
|
||||
</service>
|
||||
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
<parameter key="HOOK">admin.hook</parameter>
|
||||
<parameter key="MODULE_HOOK">admin.module-hook</parameter>
|
||||
<parameter key="ORDER">admin.order</parameter>
|
||||
<parameter key="ORDER_STATUS">admin.configuration.order-status</parameter>
|
||||
<parameter key="PRODUCT">admin.product</parameter>
|
||||
<parameter key="PROFILE">admin.configuration.profile</parameter>
|
||||
<parameter key="SHIPPING_ZONE">admin.configuration.shipping-zone</parameter>
|
||||
@@ -90,6 +91,9 @@
|
||||
|
||||
<!-- Thelia logger class -->
|
||||
<parameter key="thelia.logger.class">Thelia\Log\Tlog</parameter>
|
||||
|
||||
<!-- Thelia Cache Config -->
|
||||
<parameter key="thelia.cache.namespace">thelia_cache</parameter>
|
||||
</parameters>
|
||||
|
||||
|
||||
@@ -352,7 +356,6 @@
|
||||
<argument>%admin.resources%</argument>
|
||||
</service>
|
||||
|
||||
|
||||
<!-- Handlers -->
|
||||
<service id="thelia.export.handler" class="Thelia\Handler\ExportHandler">
|
||||
<argument type="service" id="event_dispatcher" />
|
||||
@@ -365,5 +368,12 @@
|
||||
<argument type="service" id="thelia.archiver.manager" />
|
||||
<argument type="service" id="service_container" />
|
||||
</service>
|
||||
|
||||
<!-- Cache -->
|
||||
<service id="thelia.cache" class="Symfony\Component\Cache\Adapter\FilesystemAdapter">
|
||||
<argument>%thelia.cache.namespace%</argument>
|
||||
<argument>600</argument>
|
||||
<argument>%kernel.cache_dir%</argument>
|
||||
</service>
|
||||
</services>
|
||||
</config>
|
||||
|
||||
@@ -74,6 +74,7 @@
|
||||
|
||||
<form name="thelia.admin.message.creation" class="Thelia\Form\MessageCreationForm"/>
|
||||
<form name="thelia.admin.message.modification" class="Thelia\Form\MessageModificationForm"/>
|
||||
<form name="thelia.admin.message.send-sample" class="Thelia\Form\MessageSendSampleForm"/>
|
||||
|
||||
<form name="thelia.admin.currency.creation" class="Thelia\Form\CurrencyCreationForm"/>
|
||||
<form name="thelia.admin.currency.modification" class="Thelia\Form\CurrencyModificationForm"/>
|
||||
@@ -162,6 +163,9 @@
|
||||
<form name="thelia_api_create" class="Thelia\Form\Api\ApiCreateForm"/>
|
||||
<form name="thelia_api_update" class="Thelia\Form\Api\ApiUpdateForm"/>
|
||||
|
||||
<form name="thelia.admin.order-status.creation" class="Thelia\Form\OrderStatus\OrderStatusCreationForm"/>
|
||||
<form name="thelia.admin.order-status.modification" class="Thelia\Form\OrderStatus\OrderStatusModificationForm"/>
|
||||
|
||||
</forms>
|
||||
|
||||
</config>
|
||||
|
||||
@@ -15,8 +15,9 @@
|
||||
|
||||
<services>
|
||||
<service id="thelia.listener.view" class="Thelia\Core\EventListener\ViewListener">
|
||||
<tag name="kernel.event_subscriber"/>
|
||||
<argument type="service" id="service_container"/>
|
||||
<argument type="service" id="event_dispatcher"/>
|
||||
<tag name="kernel.event_subscriber"/>
|
||||
</service>
|
||||
|
||||
<service id="controller.default" class="Thelia\Controller\DefaultController"/>
|
||||
|
||||
@@ -173,7 +173,7 @@
|
||||
|
||||
<route id="admin.customer.update.process" path="/admin/customer/save">
|
||||
<default key="_controller">Thelia\Controller\Admin\CustomerController::processUpdateAction</default>
|
||||
</route>
|
||||
</route>
|
||||
|
||||
<route id="admin.customer.delete" path="/admin/customer/delete">
|
||||
<default key="_controller">Thelia\Controller\Admin\CustomerController::deleteAction</default>
|
||||
@@ -252,6 +252,36 @@
|
||||
|
||||
<!-- end order management -->
|
||||
|
||||
<!-- order status management -->
|
||||
|
||||
<route id="admin.order-status.default" path="/admin/configuration/order-status">
|
||||
<default key="_controller">Thelia\Controller\Admin\OrderStatusController::defaultAction</default>
|
||||
</route>
|
||||
|
||||
<route id="admin.order-status.create" path="/admin/configuration/order-status/create">
|
||||
<default key="_controller">Thelia\Controller\Admin\OrderStatusController::createAction</default>
|
||||
</route>
|
||||
|
||||
<route id="admin.order-status.update" path="/admin/configuration/order-status/update/{order_status_id}">
|
||||
<default key="_controller">Thelia\Controller\Admin\OrderStatusController::updateAction</default>
|
||||
<requirement key="order_status_id">\d+</requirement>
|
||||
</route>
|
||||
|
||||
<route id="admin.order-status.save" path="/admin/configuration/order-status/save/{order_status_id}">
|
||||
<default key="_controller">Thelia\Controller\Admin\OrderStatusController::processUpdateAction</default>
|
||||
<requirement key="order_status_id">\d+</requirement>
|
||||
</route>
|
||||
|
||||
<route id="admin.order-status.delete" path="/admin/configuration/order-status/delete">
|
||||
<default key="_controller">Thelia\Controller\Admin\OrderStatusController::deleteAction</default>
|
||||
</route>
|
||||
|
||||
<route id="admin.order-status.update-position" path="/admin/configuration/order-status/update-position">
|
||||
<default key="_controller">Thelia\Controller\Admin\OrderStatusController::updatePositionAction</default>
|
||||
</route>
|
||||
|
||||
<!-- end order status management -->
|
||||
|
||||
<!-- Categories management -->
|
||||
|
||||
<route id="admin.categories.default" path="/admin/categories">
|
||||
@@ -725,6 +755,10 @@
|
||||
<default key="_controller">Thelia\Controller\Admin\TemplateController::deleteAction</default>
|
||||
</route>
|
||||
|
||||
<route id="admin.configuration.templates.duplicate" path="/admin/configuration/templates/duplicate">
|
||||
<default key="_controller">Thelia\Controller\Admin\TemplateController::duplicateAction</default>
|
||||
</route>
|
||||
|
||||
<route id="admin.configuration.templates.features.list" path="/admin/configuration/templates/features/list">
|
||||
<default key="_controller">Thelia\Controller\Admin\TemplateController::getAjaxFeaturesAction</default>
|
||||
</route>
|
||||
@@ -1544,6 +1578,11 @@
|
||||
<requirement key="messageId">\d+</requirement>
|
||||
</route>
|
||||
|
||||
<route id="admin.email.test_send" path="/admin/message/send/{messageId}" methods="post">
|
||||
<default key="_controller">Thelia:Admin\Message:sendSampleByEmail</default>
|
||||
<requirement key="messageId">\d+</requirement>
|
||||
</route>
|
||||
|
||||
<!-- The default route, to display a template -->
|
||||
|
||||
<route id="admin.processTemplate" path="/admin/{template}">
|
||||
|
||||
@@ -366,8 +366,6 @@ class BaseAdminController extends BaseController
|
||||
// Add the template standard extension
|
||||
$templateName .= '.html';
|
||||
|
||||
$session = $this->getSession();
|
||||
|
||||
// Find the current edit language ID
|
||||
$edition_language = $this->getCurrentEditionLang();
|
||||
|
||||
@@ -376,16 +374,9 @@ class BaseAdminController extends BaseController
|
||||
|
||||
// Prepare common template variables
|
||||
$args = array_merge($args, array(
|
||||
'locale' => $session->getLang()->getLocale(),
|
||||
'lang_code' => $session->getLang()->getCode(),
|
||||
'lang_id' => $session->getLang()->getId(),
|
||||
|
||||
'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 & currency in session
|
||||
|
||||
@@ -43,6 +43,29 @@ class ConfigStoreController extends BaseAdminController
|
||||
return $this->renderTemplate();
|
||||
}
|
||||
|
||||
protected function getAndWriteStoreMediaFileInConfig($form, $inputName, $configKey, $storeMediaUploadDir)
|
||||
{
|
||||
$file = $form->get($inputName)->getData();
|
||||
|
||||
if ($file != null) {
|
||||
// Delete the old file
|
||||
$fs = new \Symfony\Component\Filesystem\Filesystem();
|
||||
$oldFileName = ConfigQuery::read($configKey);
|
||||
|
||||
if ($oldFileName !== null) {
|
||||
$oldFilePath = $storeMediaUploadDir . DS . $oldFileName;
|
||||
if ($fs->exists($oldFilePath)) {
|
||||
$fs->remove($oldFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
// Write the new file
|
||||
$newFileName = uniqid() . '-' . $file->getClientOriginalName();
|
||||
$file->move($storeMediaUploadDir, $newFileName);
|
||||
ConfigQuery::write($configKey, $newFileName, false);
|
||||
}
|
||||
}
|
||||
|
||||
public function saveAction()
|
||||
{
|
||||
if (null !== $response = $this->checkAuth(AdminResources::STORE, array(), AccessManager::UPDATE)) {
|
||||
@@ -56,11 +79,33 @@ class ConfigStoreController extends BaseAdminController
|
||||
try {
|
||||
$form = $this->validateForm($configStoreForm);
|
||||
|
||||
$storeMediaUploadDir = ConfigQuery::read('images_library_path');
|
||||
|
||||
if ($storeMediaUploadDir === null) {
|
||||
$storeMediaUploadDir = THELIA_LOCAL_DIR . 'media' . DS . 'images';
|
||||
} else {
|
||||
$storeMediaUploadDir = THELIA_ROOT . $storeMediaUploadDir;
|
||||
}
|
||||
|
||||
$storeMediaUploadDir .= DS . 'store';
|
||||
|
||||
// List of medias that can be uploaded through this form.
|
||||
// [Name of the form input] => [Key in the config table]
|
||||
$storeMediaList = [
|
||||
'favicon_file' => 'favicon_file',
|
||||
'logo_file' => 'logo_file',
|
||||
'banner_file' => 'banner_file'
|
||||
];
|
||||
|
||||
foreach ($storeMediaList as $input_name => $config_key) {
|
||||
$this->getAndWriteStoreMediaFileInConfig($form, $input_name, $config_key, $storeMediaUploadDir);
|
||||
}
|
||||
|
||||
$data = $form->getData();
|
||||
|
||||
// Update store
|
||||
foreach ($data as $name => $value) {
|
||||
if (! $configStoreForm->isTemplateDefinedHiddenFieldName($name)) {
|
||||
if (!array_key_exists($name, $storeMediaList) && !$configStoreForm->isTemplateDefinedHiddenFieldName($name)) {
|
||||
ConfigQuery::write($name, $value, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,7 +127,6 @@ class CountryController extends AbstractCrudController
|
||||
;
|
||||
|
||||
return $event;
|
||||
|
||||
}
|
||||
|
||||
protected function hydrateEvent($event, $formData)
|
||||
|
||||
@@ -647,7 +647,7 @@ class CouponController extends BaseAdminController
|
||||
$this->pageNotFound();
|
||||
}
|
||||
|
||||
$response = new ResponseRest($couponManager->drawBackOfficeInputs());
|
||||
$response = new ResponseRest($couponManager->drawBackOfficeInputs(), 'text');
|
||||
} else {
|
||||
// Return an empty response if the service ID is not defined
|
||||
// Typically, when the user chooses "Please select a coupon type"
|
||||
@@ -815,7 +815,7 @@ class CouponController extends BaseAdminController
|
||||
|
||||
protected function getDefaultDateFormat()
|
||||
{
|
||||
return LangQuery::create()->findOneByByDefault(true)->getDateFormat();
|
||||
return LangQuery::create()->findOneByByDefault(true)->getDatetimeFormat();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -205,7 +205,6 @@ class CurrencyController extends AbstractCrudController
|
||||
'undefined_rates' => $event->getUndefinedRates()
|
||||
]);
|
||||
}
|
||||
|
||||
} catch (\Exception $ex) {
|
||||
// Any error
|
||||
return $this->errorPage($ex);
|
||||
|
||||
@@ -435,7 +435,6 @@ class LangController extends BaseAdminController
|
||||
),
|
||||
$changedObject->getId()
|
||||
);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Tlog::getInstance()->error(sprintf("Error on changing languages with message : %s", $e->getMessage()));
|
||||
$errorMessage = $e->getMessage();
|
||||
|
||||
@@ -22,7 +22,7 @@ use Thelia\Model\ConfigQuery;
|
||||
|
||||
class MailingSystemController extends BaseAdminController
|
||||
{
|
||||
const RESOURCE_CODE = "admin.mailing-system";
|
||||
const RESOURCE_CODE = "admin.configuration.mailing-system";
|
||||
|
||||
public function defaultAction()
|
||||
{
|
||||
@@ -130,7 +130,7 @@ class MailingSystemController extends BaseAdminController
|
||||
|
||||
$htmlMessage = "<p>$message</p>";
|
||||
|
||||
$instance = \Swift_Message::newInstance()
|
||||
$instance = $this->getMailer()->getMessageInstance()
|
||||
->addTo($emailTest, $storeName)
|
||||
->addFrom($contactEmail, $storeName)
|
||||
->setSubject($message)
|
||||
|
||||
@@ -22,6 +22,7 @@ use Thelia\Core\Security\AccessManager;
|
||||
use Thelia\Core\Security\Resource\AdminResources;
|
||||
use Thelia\Core\Template\TemplateDefinition;
|
||||
use Thelia\Form\Definition\AdminForm;
|
||||
use Thelia\Model\ConfigQuery;
|
||||
use Thelia\Model\Message;
|
||||
use Thelia\Model\MessageQuery;
|
||||
use Thelia\Model\Module;
|
||||
@@ -48,35 +49,35 @@ class MessageController extends AbstractCrudController
|
||||
null // No position update
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
protected function getCreationForm()
|
||||
{
|
||||
return $this->createForm(AdminForm::MESSAGE_CREATION);
|
||||
}
|
||||
|
||||
|
||||
protected function getUpdateForm()
|
||||
{
|
||||
return $this->createForm(AdminForm::MESSAGE_MODIFICATION);
|
||||
}
|
||||
|
||||
|
||||
protected function getCreationEvent($formData)
|
||||
{
|
||||
$createEvent = new MessageCreateEvent();
|
||||
|
||||
|
||||
$createEvent
|
||||
->setMessageName($formData['name'])
|
||||
->setLocale($formData["locale"])
|
||||
->setTitle($formData['title'])
|
||||
->setSecured($formData['secured'] ? true : false)
|
||||
;
|
||||
|
||||
;
|
||||
|
||||
return $createEvent;
|
||||
}
|
||||
|
||||
|
||||
protected function getUpdateEvent($formData)
|
||||
{
|
||||
$changeEvent = new MessageUpdateEvent($formData['id']);
|
||||
|
||||
|
||||
// Create and dispatch the change event
|
||||
$changeEvent
|
||||
->setMessageName($formData['name'])
|
||||
@@ -91,20 +92,20 @@ class MessageController extends AbstractCrudController
|
||||
->setHtmlMessage($formData['html_message'])
|
||||
->setTextMessage($formData['text_message'])
|
||||
;
|
||||
|
||||
|
||||
return $changeEvent;
|
||||
}
|
||||
|
||||
|
||||
protected function getDeleteEvent()
|
||||
{
|
||||
return new MessageDeleteEvent($this->getRequest()->get('message_id'));
|
||||
}
|
||||
|
||||
|
||||
protected function eventContainsObject($event)
|
||||
{
|
||||
return $event->hasMessage();
|
||||
}
|
||||
|
||||
|
||||
protected function hydrateObjectForm($object)
|
||||
{
|
||||
// Prepare the data that will hydrate the form
|
||||
@@ -117,34 +118,34 @@ class MessageController extends AbstractCrudController
|
||||
'subject' => $object->getSubject(),
|
||||
'html_message' => $object->getHtmlMessage(),
|
||||
'text_message' => $object->getTextMessage(),
|
||||
|
||||
|
||||
'html_layout_file_name' => $object->getHtmlLayoutFileName(),
|
||||
'html_template_file_name' => $object->getHtmlTemplateFileName(),
|
||||
'text_layout_file_name' => $object->getTextLayoutFileName(),
|
||||
'text_template_file_name' => $object->getTextTemplateFileName(),
|
||||
);
|
||||
|
||||
|
||||
// Setup the object form
|
||||
return $this->createForm(AdminForm::MESSAGE_MODIFICATION, "form", $data);
|
||||
}
|
||||
|
||||
|
||||
protected function getObjectFromEvent($event)
|
||||
{
|
||||
return $event->hasMessage() ? $event->getMessage() : null;
|
||||
}
|
||||
|
||||
|
||||
protected function getExistingObject()
|
||||
{
|
||||
$message = MessageQuery::create()
|
||||
->findOneById($this->getRequest()->get('message_id', 0));
|
||||
|
||||
->findOneById($this->getRequest()->get('message_id', 0));
|
||||
|
||||
if (null !== $message) {
|
||||
$message->setLocale($this->getCurrentEditionLocale());
|
||||
}
|
||||
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Message $object
|
||||
* @return string
|
||||
@@ -153,7 +154,7 @@ class MessageController extends AbstractCrudController
|
||||
{
|
||||
return $object->getName();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Message $object
|
||||
* @return int
|
||||
@@ -162,30 +163,30 @@ class MessageController extends AbstractCrudController
|
||||
{
|
||||
return $object->getId();
|
||||
}
|
||||
|
||||
|
||||
protected function renderListTemplate($currentOrder)
|
||||
{
|
||||
return $this->render('messages');
|
||||
}
|
||||
|
||||
|
||||
protected function listDirectoryContent($requiredExtension)
|
||||
{
|
||||
$list = array();
|
||||
|
||||
|
||||
$dir = $this->getTemplateHelper()->getActiveMailTemplate()->getAbsolutePath();
|
||||
|
||||
|
||||
$finder = Finder::create()->files()->in($dir)->ignoreDotFiles(true)->sortByName()->name("*.$requiredExtension");
|
||||
|
||||
|
||||
foreach ($finder as $file) {
|
||||
$list[] = $file->getBasename();
|
||||
}
|
||||
|
||||
|
||||
// Add modules templates
|
||||
$modules = ModuleQuery::getActivated();
|
||||
/** @var Module $module */
|
||||
foreach ($modules as $module) {
|
||||
$dir = $module->getAbsoluteTemplateBasePath() . DS . TemplateDefinition::EMAIL_SUBDIR . DS . 'default';
|
||||
|
||||
|
||||
if (file_exists($dir)) {
|
||||
$finder = Finder::create()
|
||||
->files()
|
||||
@@ -193,7 +194,7 @@ class MessageController extends AbstractCrudController
|
||||
->ignoreDotFiles(true)
|
||||
->sortByName()
|
||||
->name("*.$requiredExtension");
|
||||
|
||||
|
||||
foreach ($finder as $file) {
|
||||
$fileName = $file->getBasename();
|
||||
if (!in_array($fileName, $list)) {
|
||||
@@ -202,20 +203,20 @@ class MessageController extends AbstractCrudController
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
|
||||
protected function renderEditionTemplate()
|
||||
{
|
||||
return $this->render('message-edit', array(
|
||||
'message_id' => $this->getRequest()->get('message_id'),
|
||||
'layout_list' => $this->listDirectoryContent('tpl'),
|
||||
'html_template_list' => $this->listDirectoryContent('html'),
|
||||
'text_template_list' => $this->listDirectoryContent('txt'),
|
||||
'message_id' => $this->getRequest()->get('message_id'),
|
||||
'layout_list' => $this->listDirectoryContent('tpl'),
|
||||
'html_template_list' => $this->listDirectoryContent('html'),
|
||||
'text_template_list' => $this->listDirectoryContent('txt'),
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
protected function redirectToEditionTemplate()
|
||||
{
|
||||
return $this->generateRedirectFromRoute(
|
||||
@@ -225,47 +226,95 @@ class MessageController extends AbstractCrudController
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
protected function redirectToListTemplate()
|
||||
{
|
||||
return $this->generateRedirectFromRoute('admin.configuration.messages.default');
|
||||
}
|
||||
|
||||
|
||||
public function previewAction($messageId, $html = true)
|
||||
{
|
||||
if (null !== $response = $this->checkAuth(AdminResources::MESSAGE, [], AccessManager::VIEW)) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
|
||||
if (null === $message = MessageQuery::create()->findPk($messageId)) {
|
||||
$this->pageNotFound();
|
||||
}
|
||||
|
||||
|
||||
$parser = $this->getParser($this->getTemplateHelper()->getActiveMailTemplate());
|
||||
|
||||
|
||||
foreach ($this->getRequest()->query->all() as $key => $value) {
|
||||
$parser->assign($key, $value);
|
||||
}
|
||||
|
||||
|
||||
if ($html) {
|
||||
$content = $message->setLocale($this->getCurrentEditionLocale())->getHtmlMessageBody($parser);
|
||||
} else {
|
||||
$content = $message->setLocale($this->getCurrentEditionLocale())->getTextMessageBody($parser);
|
||||
}
|
||||
|
||||
|
||||
return new Response($content);
|
||||
}
|
||||
|
||||
|
||||
public function previewAsHtmlAction($messageId)
|
||||
{
|
||||
return $this->previewAction($messageId);
|
||||
}
|
||||
|
||||
|
||||
public function previewAsTextAction($messageId)
|
||||
{
|
||||
$response = $this->previewAction($messageId, false);
|
||||
$response->headers->add(["Content-Type" => "text/plain"]);
|
||||
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function sendSampleByEmailAction($messageId)
|
||||
{
|
||||
if (null !== $response = $this->checkAuth(AdminResources::MESSAGE, [], AccessManager::VIEW)) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
if (null !== $message = MessageQuery::create()->findPk($messageId)) {
|
||||
// Ajax submission: prevent CRSF control, as page is not refreshed
|
||||
$baseForm = $this->createForm(AdminForm::MESSAGE_SEND_SAMPLE, 'form', [], ['csrf_protection' => false]);
|
||||
|
||||
try {
|
||||
$form = $this->validateForm($baseForm, "POST");
|
||||
|
||||
$data = $form->getData();
|
||||
|
||||
$messageParameters = [];
|
||||
|
||||
foreach ($this->getRequest()->request->all() as $key => $value) {
|
||||
$messageParameters[$key] = $value;
|
||||
}
|
||||
|
||||
$this->getMailer()->sendEmailMessage(
|
||||
$message->getName(),
|
||||
[ConfigQuery::getStoreEmail() => ConfigQuery::getStoreName()],
|
||||
[ $data['recipient_email'] => $data['recipient_email'] ],
|
||||
$messageParameters,
|
||||
$this->getCurrentEditionLocale()
|
||||
);
|
||||
|
||||
return new Response(
|
||||
$this->getTranslator()->trans(
|
||||
"The message has been successfully sent to %recipient.",
|
||||
[ '%recipient' => $data['recipient_email'] ]
|
||||
)
|
||||
);
|
||||
} catch (\Exception $ex) {
|
||||
return new Response(
|
||||
$this->getTranslator()->trans(
|
||||
"Something goes wrong, the message was not sent to recipient. Error is : %err",
|
||||
[ '%err' => $ex->getMessage() ]
|
||||
)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return $this->pageNotFound();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ class OrderController extends BaseAdminController
|
||||
|
||||
$order = OrderQuery::create()->findPk($order_id);
|
||||
|
||||
$statusId = $this->getRequest()->request->get("status_id");
|
||||
$statusId = $this->getRequest()->get("status_id");
|
||||
$status = OrderStatusQuery::create()->findPk($statusId);
|
||||
|
||||
if (null === $order) {
|
||||
|
||||
@@ -329,7 +329,6 @@ class ProductController extends AbstractSeoCrudController
|
||||
$this->appendValue($combinationPseData, "isdefault", $saleElement->getIsDefault() > 0 ? 1 : 0);
|
||||
$this->appendValue($combinationPseData, "ean_code", $saleElement->getEanCode());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$defaultPseForm = $this->createForm(AdminForm::PRODUCT_DEFAULT_SALE_ELEMENT_UPDATE, "form", $defaultPseData);
|
||||
|
||||
@@ -81,7 +81,7 @@ class SaleController extends AbstractCrudController
|
||||
/** @var SaleProduct $saleProduct */
|
||||
foreach ($saleProducts as $saleProduct) {
|
||||
$categories[] = $saleProduct->getProduct()->getDefaultCategoryId();
|
||||
$products[] = $saleProduct->getProduct()->getId();
|
||||
$products[$saleProduct->getProduct()->getId()] = $saleProduct->getProduct()->getId();
|
||||
}
|
||||
|
||||
$dateFormat = SaleModificationForm::PHP_DATE_FORMAT;
|
||||
|
||||
@@ -185,7 +185,6 @@ class SessionController extends BaseAdminController
|
||||
$this->getSession()->set(self::ADMIN_TOKEN_SESSION_VAR_NAME, null);
|
||||
|
||||
return $this->generateSuccessRedirect($adminCreatePasswordForm);
|
||||
|
||||
} catch (FormValidationException $ex) {
|
||||
// Validation problem
|
||||
$message = $this->createStandardFormValidationErrorMessage($ex);
|
||||
|
||||
@@ -241,5 +241,4 @@ class StateController extends AbstractCrudController
|
||||
{
|
||||
return new StateToggleVisibilityEvent($this->getExistingObject());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -332,7 +332,6 @@ class TaxRuleController extends AbstractCrudController
|
||||
);
|
||||
|
||||
return $this->jsonResponse(json_encode($responseData));
|
||||
|
||||
} catch (FormValidationException $ex) {
|
||||
// Form cannot be validated
|
||||
$error_msg = $this->createStandardFormValidationErrorMessage($ex);
|
||||
@@ -411,7 +410,6 @@ class TaxRuleController extends AbstractCrudController
|
||||
|
||||
$taxRuleCountry = $taxRuleCountries->getNext();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$data = [
|
||||
|
||||
@@ -18,8 +18,10 @@ use Thelia\Core\Event\Template\TemplateCreateEvent;
|
||||
use Thelia\Core\Event\Template\TemplateDeleteAttributeEvent;
|
||||
use Thelia\Core\Event\Template\TemplateDeleteEvent;
|
||||
use Thelia\Core\Event\Template\TemplateDeleteFeatureEvent;
|
||||
use Thelia\Core\Event\Template\TemplateDuplicateEvent;
|
||||
use Thelia\Core\Event\Template\TemplateUpdateEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\HttpFoundation\Request;
|
||||
use Thelia\Core\Security\AccessManager;
|
||||
use Thelia\Core\Security\Resource\AdminResources;
|
||||
use Thelia\Form\Definition\AdminForm;
|
||||
@@ -157,13 +159,18 @@ class TemplateController extends AbstractCrudController
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
protected function redirectToEditionTemplate()
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param int $id
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
protected function redirectToEditionTemplate($request = null, $id = null)
|
||||
{
|
||||
return $this->generateRedirectFromRoute(
|
||||
"admin.configuration.templates.update",
|
||||
[
|
||||
'template_id' => $this->getRequest()->get('template_id'),
|
||||
'template_id' => $id ?: $this->getRequest()->get('template_id'),
|
||||
]
|
||||
);
|
||||
}
|
||||
@@ -195,6 +202,33 @@ class TemplateController extends AbstractCrudController
|
||||
return null;
|
||||
}
|
||||
|
||||
public function duplicateAction()
|
||||
{
|
||||
// Check current user authorization
|
||||
if (null !== $response = $this->checkAuth(AdminResources::TEMPLATE, array(), AccessManager::CREATE)) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$template_id = intval($this->getRequest()->get('template_id'));
|
||||
|
||||
if ($template_id > 0) {
|
||||
try {
|
||||
$event = new TemplateDuplicateEvent($template_id, $this->getCurrentEditionLocale());
|
||||
|
||||
$this->dispatch(TheliaEvents::TEMPLATE_DUPLICATE, $event);
|
||||
|
||||
if ($event->hasTemplate()) {
|
||||
$template_id = $event->getTemplate()->getId();
|
||||
}
|
||||
} catch (\Exception $ex) {
|
||||
// Any error
|
||||
return $this->errorPage($ex);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->redirectToEditionTemplate(null, $template_id);
|
||||
}
|
||||
|
||||
public function getAjaxFeaturesAction()
|
||||
{
|
||||
return $this->render(
|
||||
|
||||
@@ -126,18 +126,7 @@ class BaseFrontController extends BaseController
|
||||
// Add the template standard extension
|
||||
$templateName .= '.html';
|
||||
|
||||
$session = $this->getSession();
|
||||
|
||||
// Prepare common template variables
|
||||
$args = array_merge($args, array(
|
||||
'locale' => $session->getLang()->getLocale(),
|
||||
'lang_code' => $session->getLang()->getCode(),
|
||||
'lang_id' => $session->getLang()->getId(),
|
||||
'current_url' => $this->getRequest()->getUri()
|
||||
));
|
||||
|
||||
// Render the template.
|
||||
|
||||
$data = $this->getParser($templateDir)->render($templateName, $args);
|
||||
|
||||
return $data;
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
|
||||
namespace Thelia\Core\Archiver;
|
||||
|
||||
use Thelia\Core\Translation\Translator;
|
||||
|
||||
/**
|
||||
* Class AbstractArchiver
|
||||
* @author Jérôme Billiras <jbilliras@openstudio.fr>
|
||||
@@ -28,10 +30,10 @@ abstract class AbstractArchiver implements ArchiverInterface
|
||||
*/
|
||||
protected $archivePath;
|
||||
|
||||
public function __construct()
|
||||
public function __construct($checkIsAvailable = false)
|
||||
{
|
||||
if (!$this->isAvailable()) {
|
||||
throw new Exception(
|
||||
if ($checkIsAvailable && !$this->isAvailable()) {
|
||||
throw new \Exception(
|
||||
Translator::getInstance()->trans(
|
||||
"The archiver :name is not available. Please install the php extension :extension first.",
|
||||
[
|
||||
@@ -40,7 +42,7 @@ abstract class AbstractArchiver implements ArchiverInterface
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getArchivePath()
|
||||
|
||||
@@ -15,8 +15,8 @@ namespace Thelia\Core\DependencyInjection\Compiler;
|
||||
use Propel\Runtime\Propel;
|
||||
use ReflectionException;
|
||||
use ReflectionMethod;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Thelia\Core\Hook\BaseHook;
|
||||
use Thelia\Core\Hook\HookDefinition;
|
||||
@@ -26,8 +26,8 @@ use Thelia\Model\Base\IgnoredModuleHookQuery;
|
||||
use Thelia\Model\ConfigQuery;
|
||||
use Thelia\Model\Hook;
|
||||
use Thelia\Model\HookQuery;
|
||||
use Thelia\Model\ModuleHookQuery;
|
||||
use Thelia\Model\ModuleHook;
|
||||
use Thelia\Model\ModuleHookQuery;
|
||||
use Thelia\Model\ModuleQuery;
|
||||
|
||||
/**
|
||||
@@ -61,11 +61,11 @@ class RegisterHookListenersPass implements CompilerPassInterface
|
||||
}
|
||||
}
|
||||
|
||||
protected function logAlertMessage($message)
|
||||
protected function logAlertMessage($message, $failSafe = false)
|
||||
{
|
||||
Tlog::getInstance()->addAlert($message);
|
||||
|
||||
if ($this->debugEnabled) {
|
||||
if (!$failSafe && $this->debugEnabled) {
|
||||
throw new \InvalidArgumentException($message);
|
||||
}
|
||||
}
|
||||
@@ -190,7 +190,6 @@ class RegisterHookListenersPass implements CompilerPassInterface
|
||||
$moduleHook
|
||||
->setHookActive(false)
|
||||
->save();
|
||||
|
||||
} else {
|
||||
//$moduleHook->setTemplates($attributes['templates']);
|
||||
|
||||
@@ -226,6 +225,7 @@ class RegisterHookListenersPass implements CompilerPassInterface
|
||||
$hookId = 0;
|
||||
/** @var ModuleHook $moduleHook */
|
||||
foreach ($moduleHooks as $moduleHook) {
|
||||
|
||||
// check if class and method exists
|
||||
if (!$container->hasDefinition($moduleHook->getClassname())) {
|
||||
continue;
|
||||
@@ -236,7 +236,8 @@ class RegisterHookListenersPass implements CompilerPassInterface
|
||||
if (!$this->isValidHookMethod(
|
||||
$container->getDefinition($moduleHook->getClassname())->getClass(),
|
||||
$moduleHook->getMethod(),
|
||||
$hook->getBlock()
|
||||
$hook->getBlock(),
|
||||
true
|
||||
)
|
||||
) {
|
||||
$moduleHook->delete();
|
||||
@@ -346,9 +347,7 @@ class RegisterHookListenersPass implements CompilerPassInterface
|
||||
}
|
||||
|
||||
if (! $hook->getActivate()) {
|
||||
$this->logAlertMessage(sprintf("Hook %s is not activated.", $hookName));
|
||||
|
||||
return null;
|
||||
$this->logAlertMessage(sprintf("Hook %s is not activated.", $hookName), true);
|
||||
}
|
||||
|
||||
return $hook;
|
||||
@@ -360,10 +359,11 @@ class RegisterHookListenersPass implements CompilerPassInterface
|
||||
* @param string $className the namespace of the class
|
||||
* @param string $methodName the method name
|
||||
* @param bool $block tell if the hook is a block or a function
|
||||
* @param bool $failSafe
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isValidHookMethod($className, $methodName, $block)
|
||||
protected function isValidHookMethod($className, $methodName, $block, $failSafe = false)
|
||||
{
|
||||
try {
|
||||
$method = new ReflectionMethod($className, $methodName);
|
||||
@@ -380,7 +380,10 @@ class RegisterHookListenersPass implements CompilerPassInterface
|
||||
return false;
|
||||
}
|
||||
} catch (ReflectionException $ex) {
|
||||
$this->logAlertMessage(sprintf("Method %s does not exist in %s : %s", $methodName, $className, $ex));
|
||||
$this->logAlertMessage(
|
||||
sprintf("Method %s does not exist in %s : %s", $methodName, $className, $ex),
|
||||
$failSafe
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@ use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Thelia\Model\Module;
|
||||
use Thelia\Model\ModuleQuery;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -52,8 +54,9 @@ class RegisterRouterPass implements CompilerPassInterface
|
||||
$chainRouter->addMethodCall("add", array(new Reference($id), $priority));
|
||||
}
|
||||
if (defined("THELIA_INSTALL_MODE") === false) {
|
||||
$modules = \Thelia\Model\ModuleQuery::getActivated();
|
||||
$modules = ModuleQuery::getActivated();
|
||||
|
||||
/** @var Module $module */
|
||||
foreach ($modules as $module) {
|
||||
$moduleBaseDir = $module->getBaseDir();
|
||||
$routingConfigFilePath = $module->getAbsoluteBaseDir() . DS . "Config" . DS . "routing.xml";
|
||||
@@ -76,7 +79,7 @@ class RegisterRouterPass implements CompilerPassInterface
|
||||
|
||||
$container->setDefinition("router.".$moduleBaseDir, $definition);
|
||||
|
||||
$chainRouter->addMethodCall("add", array(new Reference("router.".$moduleBaseDir), 150));
|
||||
$chainRouter->addMethodCall("add", array(new Reference("router.".$moduleBaseDir), 150 + $module->getPosition()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ class CartDuplicationEvent extends CartEvent
|
||||
*/
|
||||
public function getDuplicatedCart()
|
||||
{
|
||||
return parent::getCart();
|
||||
return $this->getCart();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,5 +20,4 @@ namespace Thelia\Core\Event\Country;
|
||||
*/
|
||||
class CountryToggleVisibilityEvent extends CountryEvent
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -128,6 +128,4 @@ class ModuleHookCreateEvent extends ModuleHookEvent
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -10,36 +10,57 @@
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
|
||||
namespace Thelia\Core\Event\Loop;
|
||||
|
||||
use Thelia\Core\Template\Element\BaseLoop;
|
||||
|
||||
/**
|
||||
* Class LoopExtendsBuildArrayEvent
|
||||
*
|
||||
* @package Thelia\Core\Event\Loop
|
||||
* @author Julien Chanséaume <julien@thelia.net>
|
||||
*/
|
||||
class LoopExtendsBuildArrayEvent extends LoopExtendsEvent
|
||||
{
|
||||
/** @var array $array */
|
||||
/**
|
||||
* @var array Build array results
|
||||
*/
|
||||
protected $array;
|
||||
|
||||
/**
|
||||
* LoopExtendsBuildArrayEvent constructor.
|
||||
* @param array $array
|
||||
* Class constructor
|
||||
*
|
||||
* @param \Thelia\Core\Template\Element\BaseLoop $loop Loop object
|
||||
* @param array $array Build array base results
|
||||
*/
|
||||
public function __construct(BaseLoop $loop, array $array)
|
||||
{
|
||||
parent::__construct($loop);
|
||||
|
||||
$this->array = $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* Get build array results
|
||||
*
|
||||
* @return array Build array results
|
||||
*/
|
||||
public function getArray()
|
||||
{
|
||||
return $this->array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set build array results
|
||||
*
|
||||
* @param array $array
|
||||
*
|
||||
* @return $this Return $this, allow chaining
|
||||
*/
|
||||
public function setArray(array $array)
|
||||
{
|
||||
$this->array = $array;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,17 +25,28 @@ class ModuleDeleteEvent extends ModuleEvent
|
||||
protected $module_id;
|
||||
protected $delete_data;
|
||||
|
||||
public function __construct($module_id)
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $assume_delete;
|
||||
|
||||
public function __construct($module_id, $assume_delete = false)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->module_id = $module_id;
|
||||
$this->assume_delete = $assume_delete;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $module_id
|
||||
* @return $this
|
||||
*/
|
||||
public function setModuleId($module_id)
|
||||
{
|
||||
$this->module_id = $module_id;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -51,10 +62,33 @@ class ModuleDeleteEvent extends ModuleEvent
|
||||
return $this->delete_data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param boolean $delete_data
|
||||
* @return $this
|
||||
*/
|
||||
public function setDeleteData($delete_data)
|
||||
{
|
||||
$this->delete_data = $delete_data;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
*/
|
||||
public function getAssumeDelete()
|
||||
{
|
||||
return $this->assume_delete;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param boolean $assume_delete
|
||||
* @return $this
|
||||
*/
|
||||
public function setAssumeDelete($assume_delete)
|
||||
{
|
||||
$this->assume_delete = $assume_delete;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,13 +34,21 @@ class ModuleToggleActivationEvent extends ModuleEvent
|
||||
*/
|
||||
protected $recursive;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $assume_deactivate;
|
||||
|
||||
|
||||
/**
|
||||
* @param int $module_id
|
||||
*/
|
||||
public function __construct($module_id)
|
||||
public function __construct($module_id, $assume_deactivate = false)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->module_id = $module_id;
|
||||
$this->assume_deactivate = $assume_deactivate;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -73,7 +81,7 @@ class ModuleToggleActivationEvent extends ModuleEvent
|
||||
|
||||
/**
|
||||
* @param boolean $noCheck
|
||||
* @return $this;
|
||||
* @return $this
|
||||
*/
|
||||
public function setNoCheck($noCheck)
|
||||
{
|
||||
@@ -92,11 +100,29 @@ class ModuleToggleActivationEvent extends ModuleEvent
|
||||
|
||||
/**
|
||||
* @param boolean $recursive
|
||||
* @return $this;
|
||||
* @return $this
|
||||
*/
|
||||
public function setRecursive($recursive)
|
||||
{
|
||||
$this->recursive = $recursive;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
*/
|
||||
public function getAssumeDeactivate()
|
||||
{
|
||||
return $this->assume_deactivate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param boolean $assume_deactivate
|
||||
* @return $this
|
||||
*/
|
||||
public function setAssumeDeactivate($assume_deactivate)
|
||||
{
|
||||
$this->assume_deactivate = $assume_deactivate;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,6 +61,9 @@ class OrderEvent extends ActionEvent
|
||||
/** @var null|int */
|
||||
protected $cartItemId = null;
|
||||
|
||||
/** @var null|string */
|
||||
protected $transactionRef = null;
|
||||
|
||||
/**
|
||||
* @var Response
|
||||
*/
|
||||
@@ -352,4 +355,24 @@ class OrderEvent extends ActionEvent
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.4.0
|
||||
* @return null|string
|
||||
*/
|
||||
public function getTransactionRef()
|
||||
{
|
||||
return $this->transactionRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.4.0
|
||||
* @param null|string $transactionRef
|
||||
* @return $this
|
||||
*/
|
||||
public function setTransactionRef($transactionRef)
|
||||
{
|
||||
$this->transactionRef = $transactionRef;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,12 +17,23 @@ use Thelia\Model\Product;
|
||||
|
||||
class ProductCloneEvent extends ActionEvent
|
||||
{
|
||||
/** @var string */
|
||||
protected $ref;
|
||||
/** @var string */
|
||||
protected $lang;
|
||||
protected $originalProduct = array();
|
||||
protected $clonedProduct = array();
|
||||
/** @var Product */
|
||||
protected $originalProduct;
|
||||
/** @var Product */
|
||||
protected $clonedProduct;
|
||||
/** @var array */
|
||||
protected $types = array('images', 'documents');
|
||||
|
||||
/**
|
||||
* ProductCloneEvent constructor.
|
||||
* @param string $ref
|
||||
* @param string $lang the locale (such as fr_FR)
|
||||
* @param $originalProduct
|
||||
*/
|
||||
public function __construct(
|
||||
$ref,
|
||||
$lang,
|
||||
@@ -34,7 +45,7 @@ class ProductCloneEvent extends ActionEvent
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
* @return string
|
||||
*/
|
||||
public function getRef()
|
||||
{
|
||||
@@ -42,7 +53,7 @@ class ProductCloneEvent extends ActionEvent
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $ref
|
||||
* @param string $ref
|
||||
*/
|
||||
public function setRef($ref)
|
||||
{
|
||||
@@ -50,7 +61,7 @@ class ProductCloneEvent extends ActionEvent
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
* @return string the locale (such as fr_FR)
|
||||
*/
|
||||
public function getLang()
|
||||
{
|
||||
@@ -58,7 +69,7 @@ class ProductCloneEvent extends ActionEvent
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $lang
|
||||
* @param string $lang the locale (such as fr_FR)
|
||||
*/
|
||||
public function setLang($lang)
|
||||
{
|
||||
|
||||
@@ -14,34 +14,55 @@ namespace Thelia\Core\Event\ProductSaleElement;
|
||||
|
||||
class ProductSaleElementDeleteEvent extends ProductSaleElementEvent
|
||||
{
|
||||
/** @var int */
|
||||
protected $product_sale_element_id;
|
||||
/** @var int */
|
||||
protected $currency_id;
|
||||
|
||||
|
||||
/**
|
||||
* ProductSaleElementDeleteEvent constructor.
|
||||
* @param int $product_sale_element_id
|
||||
* @param int $currency_id
|
||||
*/
|
||||
public function __construct($product_sale_element_id, $currency_id)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->product_sale_element_id = $product_sale_element_id;
|
||||
$this->setCurrencyId($currency_id);
|
||||
$this->currency_id = $currency_id;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getProductSaleElementId()
|
||||
{
|
||||
return $this->product_sale_element_id;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param int $product_sale_element_id
|
||||
* @return $this
|
||||
*/
|
||||
public function setProductSaleElementId($product_sale_element_id)
|
||||
{
|
||||
$this->product_sale_element_id = $product_sale_element_id;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getCurrencyId()
|
||||
{
|
||||
return $this->currency_id;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param int $currency_id
|
||||
* @return $this
|
||||
*/
|
||||
public function setCurrencyId($currency_id)
|
||||
{
|
||||
$this->currency_id = $currency_id;
|
||||
|
||||
@@ -20,5 +20,4 @@ namespace Thelia\Core\Event\State;
|
||||
*/
|
||||
class StateToggleVisibilityEvent extends StateEvent
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -17,23 +17,36 @@ use Thelia\Model\Template;
|
||||
|
||||
class TemplateEvent extends ActionEvent
|
||||
{
|
||||
/**
|
||||
* @var Template
|
||||
*/
|
||||
protected $template = null;
|
||||
|
||||
public function __construct(Template $template = null)
|
||||
{
|
||||
$this->template = $template;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function hasTemplate()
|
||||
{
|
||||
return ! is_null($this->template);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Template
|
||||
*/
|
||||
public function getTemplate()
|
||||
{
|
||||
return $this->template;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Template $template
|
||||
* @return $this
|
||||
*/
|
||||
public function setTemplate($template)
|
||||
{
|
||||
$this->template = $template;
|
||||
|
||||
@@ -26,6 +26,10 @@ final class TheliaEvents
|
||||
* sent at the beginning
|
||||
*/
|
||||
const BOOT = "thelia.boot";
|
||||
/**
|
||||
* Kernel View Check Handle
|
||||
*/
|
||||
const VIEW_CHECK = "thelia.view_check";
|
||||
// -- END CORE EVENTS ---------------------------------------------------------
|
||||
// -- ADDRESS EVENTS ---------------------------------------------------------
|
||||
/**
|
||||
@@ -115,6 +119,8 @@ final class TheliaEvents
|
||||
const CATEGORY_REMOVE_CONTENT = "action.categoryRemoveContent";
|
||||
|
||||
const CATEGORY_UPDATE_SEO = "action.updateCategorySeo";
|
||||
|
||||
const VIEW_CATEGORY_ID_NOT_VISIBLE = "action.viewCategoryIdNotVisible";
|
||||
// -- END CATEGORIES EVENTS -----------------------------------------------
|
||||
|
||||
|
||||
@@ -137,6 +143,8 @@ final class TheliaEvents
|
||||
|
||||
const CONTENT_ADD_FOLDER = "action.contentAddFolder";
|
||||
const CONTENT_REMOVE_FOLDER = "action.contentRemoveFolder";
|
||||
|
||||
const VIEW_CONTENT_ID_NOT_VISIBLE = "action.viewContentIdNotVisible";
|
||||
// -- END CONTENT EVENTS ---------------------------------------------------------
|
||||
|
||||
|
||||
@@ -234,6 +242,12 @@ final class TheliaEvents
|
||||
* sent when a customer need a new password
|
||||
*/
|
||||
const LOST_PASSWORD = "action.lostPassword";
|
||||
|
||||
/**
|
||||
* Send the account ccreation confirmation email
|
||||
*/
|
||||
const SEND_ACCOUNT_CONFIRMATION_EMAIL = "action.customer.sendAccountConfirmationEmail";
|
||||
|
||||
// -- END CUSTOMER EVENTS ---------------------------------------------------------
|
||||
|
||||
|
||||
@@ -253,6 +267,8 @@ final class TheliaEvents
|
||||
const FOLDER_TOGGLE_VISIBILITY = "action.toggleFolderVisibility";
|
||||
const FOLDER_UPDATE_POSITION = "action.updateFolderPosition";
|
||||
const FOLDER_UPDATE_SEO = "action.updateFolderSeo";
|
||||
|
||||
const VIEW_FOLDER_ID_NOT_VISIBLE = "action.viewFolderIdNotVisible";
|
||||
// -- END FOLDER EVENTS ---------------------------------------------------------
|
||||
|
||||
|
||||
@@ -299,6 +315,7 @@ final class TheliaEvents
|
||||
const VIRTUAL_PRODUCT_ORDER_HANDLE = "action.virtualProduct.handleOrder";
|
||||
const VIRTUAL_PRODUCT_ORDER_DOWNLOAD_RESPONSE = "action.virtualProduct.downloadResponse";
|
||||
|
||||
const VIEW_PRODUCT_ID_NOT_VISIBLE = "action.viewProductIdNotVisible";
|
||||
// -- END PRODUCT EVENTS ---------------------------------------------------------
|
||||
|
||||
|
||||
@@ -437,6 +454,7 @@ final class TheliaEvents
|
||||
const ORDER_SEND_NOTIFICATION_EMAIL = "action.order.sendOrderNotificationEmail";
|
||||
|
||||
const ORDER_UPDATE_DELIVERY_REF = "action.order.updateDeliveryRef";
|
||||
const ORDER_UPDATE_TRANSACTION_REF = "action.order.updateTransactionRef";
|
||||
const ORDER_UPDATE_ADDRESS = "action.order.updateAddress";
|
||||
|
||||
const ORDER_PRODUCT_BEFORE_CREATE = "action.orderProduct.beforeCreate";
|
||||
@@ -694,6 +712,7 @@ final class TheliaEvents
|
||||
const TEMPLATE_CREATE = "action.createTemplate";
|
||||
const TEMPLATE_UPDATE = "action.updateTemplate";
|
||||
const TEMPLATE_DELETE = "action.deleteTemplate";
|
||||
const TEMPLATE_DUPLICATE = "action.duplicateTemplate";
|
||||
|
||||
const TEMPLATE_ADD_ATTRIBUTE = "action.templateAddAttribute";
|
||||
const TEMPLATE_DELETE_ATTRIBUTE = "action.templateDeleteAttribute";
|
||||
@@ -912,6 +931,8 @@ final class TheliaEvents
|
||||
const BEFORE_UPDATEBRAND = "action.before_updateBrand";
|
||||
const AFTER_UPDATEBRAND = "action.after_updateBrand";
|
||||
|
||||
const VIEW_BRAND_ID_NOT_VISIBLE = "action.viewBrandIdNotVisible";
|
||||
|
||||
// -- Import ----------------------------------------------
|
||||
|
||||
const IMPORT_CHANGE_POSITION = 'import.change.position';
|
||||
@@ -980,4 +1001,20 @@ final class TheliaEvents
|
||||
|
||||
const TRANSLATION_GET_STRINGS = 'action.translation.get_strings';
|
||||
const TRANSLATION_WRITE_FILE = 'action.translation.write_file';
|
||||
|
||||
// -- ORDER STATUS EVENTS -----------------------------------------------
|
||||
const BEFORE_CREATE_ORDER_STATUS = "action.before_createOrderStatus";
|
||||
const ORDER_STATUS_CREATE = "action.createOrderStatus";
|
||||
const AFTER_CREATE_ORDER_STATUS = "action.after_createOrderStatus";
|
||||
|
||||
const BEFORE_UPDATE_ORDER_STATUS = "action.before_updateOrderStatus";
|
||||
const ORDER_STATUS_UPDATE = "action.updateOrderStatus";
|
||||
const AFTER_UPDATE_ORDER_STATUS = "action.after_updateOrderStatus";
|
||||
|
||||
const BEFORE_DELETE_ORDER_STATUS = "action.before_deleteOrderStatus";
|
||||
const ORDER_STATUS_DELETE = "action.deleteOrderStatus";
|
||||
const AFTER_DELETE_ORDER_STATUS = "action.after_deleteOrderStatus";
|
||||
|
||||
const ORDER_STATUS_UPDATE_POSITION = "action.updateOrderStatusPosition";
|
||||
// -- END ORDER STATUS EVENTS -----------------------------------------------
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ use Thelia\Core\Security\Exception\AuthenticationException;
|
||||
use Thelia\Core\Security\SecurityContext;
|
||||
use Thelia\Core\Template\ParserInterface;
|
||||
use Thelia\Core\TheliaKernelEvents;
|
||||
use Thelia\Log\Tlog;
|
||||
use Thelia\Model\ConfigQuery;
|
||||
|
||||
/**
|
||||
@@ -89,6 +90,25 @@ class ErrorListener implements EventSubscriberInterface
|
||||
}
|
||||
}
|
||||
|
||||
public function logException(GetResponseForExceptionEvent $event)
|
||||
{
|
||||
// Log exception in the Thelia log
|
||||
$exception = $event->getException();
|
||||
|
||||
$logMessage = '';
|
||||
|
||||
do {
|
||||
$logMessage .=
|
||||
($logMessage ? PHP_EOL . 'Caused by' : 'Uncaught exception')
|
||||
. $event->getException()->getMessage()
|
||||
. PHP_EOL
|
||||
. "Stack Trace: " . $event->getException()->getTraceAsString()
|
||||
;
|
||||
} while (null !== $exception = $exception->getPrevious());
|
||||
|
||||
Tlog::getInstance()->error($logMessage);
|
||||
}
|
||||
|
||||
public function authenticationException(GetResponseForExceptionEvent $event)
|
||||
{
|
||||
$exception = $event->getException();
|
||||
@@ -107,6 +127,7 @@ class ErrorListener implements EventSubscriberInterface
|
||||
{
|
||||
return array(
|
||||
KernelEvents::EXCEPTION => [
|
||||
["logException", 0],
|
||||
["handleException", 0],
|
||||
['authenticationException', 100]
|
||||
],
|
||||
|
||||
@@ -275,9 +275,11 @@ class RequestListener implements EventSubscriberInterface
|
||||
) {
|
||||
$request->getSession()->setCurrency($find);
|
||||
$this->eventDispatcher->dispatch(TheliaEvents::CHANGE_DEFAULT_CURRENCY, new CurrencyChangeEvent($find, $request));
|
||||
} else {
|
||||
$defaultCurrency = Currency::getDefaultCurrency();
|
||||
$request->getSession()->setCurrency($defaultCurrency);
|
||||
$this->eventDispatcher->dispatch(TheliaEvents::CHANGE_DEFAULT_CURRENCY, new CurrencyChangeEvent($defaultCurrency, $request));
|
||||
}
|
||||
} else {
|
||||
$request->getSession()->setCurrency(Currency::getDefaultCurrency());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,6 @@ class ResponseListener implements EventSubscriberInterface
|
||||
$session = $event->getRequest()->getSession();
|
||||
|
||||
if (null !== $id = $session->get("cart_use_cookie")) {
|
||||
|
||||
$response = $event->getResponse();
|
||||
$cookieName = ConfigQuery::read("cart.cookie_name", 'thelia_cart');
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
namespace Thelia\Core\EventListener;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
@@ -20,6 +21,8 @@ use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Symfony\Component\HttpKernel\KernelEvents;
|
||||
use Symfony\Component\Routing\Router;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\Event\ViewCheckEvent;
|
||||
use Thelia\Core\HttpFoundation\Response;
|
||||
use Thelia\Core\Template\Exception\ResourceNotFoundException;
|
||||
use Thelia\Exception\OrderException;
|
||||
@@ -35,23 +38,23 @@ use Thelia\Exception\OrderException;
|
||||
|
||||
class ViewListener implements EventSubscriberInterface
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @var \Symfony\Component\DependencyInjection\ContainerInterface
|
||||
*/
|
||||
/** @var ContainerInterface */
|
||||
private $container;
|
||||
|
||||
/** @var EventDispatcherInterface */
|
||||
protected $eventDispatcher;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param ContainerInterface $container
|
||||
* @param EventDispatcherInterface $eventDispatcher
|
||||
*/
|
||||
public function __construct(ContainerInterface $container)
|
||||
public function __construct(ContainerInterface $container, EventDispatcherInterface $eventDispatcher)
|
||||
{
|
||||
$this->container = $container;
|
||||
$this->eventDispatcher = $eventDispatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Launch the parser defined on the constructor and get the result.
|
||||
*
|
||||
* The result is transform id needed into a Response object
|
||||
@@ -66,7 +69,13 @@ class ViewListener implements EventSubscriberInterface
|
||||
$request = $this->container->get('request_stack')->getCurrentRequest();
|
||||
$response = null;
|
||||
try {
|
||||
$content = $parser->render($request->attributes->get('_view').".html");
|
||||
$view = $request->attributes->get('_view');
|
||||
|
||||
$viewId = $request->attributes->get($view . '_id');
|
||||
|
||||
$this->eventDispatcher->dispatch(TheliaEvents::VIEW_CHECK, new ViewCheckEvent($view, $viewId));
|
||||
|
||||
$content = $parser->render($view . '.html');
|
||||
|
||||
if ($content instanceof Response) {
|
||||
$response = $content;
|
||||
@@ -98,15 +107,19 @@ class ViewListener implements EventSubscriberInterface
|
||||
{
|
||||
$request = $this->container->get('request_stack')->getCurrentRequest();
|
||||
|
||||
if (null === $request->attributes->get('_view')) {
|
||||
if (null === $view = $request->attributes->get('_view')) {
|
||||
$request->attributes->set('_view', $this->findView($request));
|
||||
}
|
||||
|
||||
if (null === $request->attributes->get($view . '_id')) {
|
||||
$request->attributes->set($view . '_id', $this->findViewId($request, $view));
|
||||
}
|
||||
}
|
||||
|
||||
public function findView(Request $request)
|
||||
{
|
||||
if (! $view = $request->query->get('view')) {
|
||||
$view = "index";
|
||||
$view = 'index';
|
||||
if ($request->request->has('view')) {
|
||||
$view = $request->request->get('view');
|
||||
}
|
||||
@@ -115,6 +128,17 @@ class ViewListener implements EventSubscriberInterface
|
||||
return $view;
|
||||
}
|
||||
|
||||
public function findViewId(Request $request, $view)
|
||||
{
|
||||
if (! $viewId = $request->query->get($view . '_id')) {
|
||||
$viewId = 0;
|
||||
if ($request->request->has($view . '_id')) {
|
||||
$viewId = $request->request->get($view . '_id');
|
||||
}
|
||||
}
|
||||
|
||||
return $viewId;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
|
||||
@@ -20,5 +20,4 @@ namespace Thelia\Core\Hook;
|
||||
*/
|
||||
class DefaultHook extends BaseHook
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
namespace Thelia\Core\Routing;
|
||||
|
||||
use Propel\Runtime\ActiveQuery\Criteria;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Exception\InvalidParameterException;
|
||||
use Symfony\Component\Routing\Exception\MethodNotAllowedException;
|
||||
@@ -26,7 +27,10 @@ use Thelia\Core\HttpFoundation\Request as TheliaRequest;
|
||||
use Thelia\Core\HttpKernel\Exception\RedirectException;
|
||||
use Thelia\Exception\UrlRewritingException;
|
||||
use Thelia\Model\ConfigQuery;
|
||||
use Thelia\Model\CustomerQuery;
|
||||
use Thelia\Model\Lang;
|
||||
use Thelia\Model\LangQuery;
|
||||
use Thelia\Model\RewritingUrlQuery;
|
||||
use Thelia\Rewriting\RewritingResolver;
|
||||
use Thelia\Tools\URL;
|
||||
|
||||
@@ -177,6 +181,11 @@ class RewritingRouter implements RouterInterface, RequestMatcherInterface
|
||||
if (null ==! $requestedLocale = $request->get('lang')) {
|
||||
if (null !== $requestedLang = LangQuery::create()->findOneByLocale($requestedLocale)) {
|
||||
if ($requestedLang->getLocale() != $rewrittenUrlData->locale) {
|
||||
// Save one redirection if requested locale is disabled.
|
||||
if (! $requestedLang->getActive()) {
|
||||
$requestedLang = Lang::getDefaultLanguage();
|
||||
}
|
||||
|
||||
$localizedUrl = $urlTool->retrieve(
|
||||
$rewrittenUrlData->view,
|
||||
$rewrittenUrlData->viewId,
|
||||
@@ -188,9 +197,33 @@ class RewritingRouter implements RouterInterface, RequestMatcherInterface
|
||||
}
|
||||
}
|
||||
|
||||
// If the rewritten URL locale is disabled, redirect to the URL in the default language
|
||||
if (null === $lang = LangQuery::create()
|
||||
->filterByActive(true)
|
||||
->filterByLocale($rewrittenUrlData->locale)
|
||||
->findOne()) {
|
||||
$lang = Lang::getDefaultLanguage();
|
||||
|
||||
$localizedUrl = $urlTool->retrieve(
|
||||
$rewrittenUrlData->view,
|
||||
$rewrittenUrlData->viewId,
|
||||
$lang->getLocale()
|
||||
)->toString();
|
||||
|
||||
$this->redirect($urlTool->absoluteUrl($localizedUrl), 301);
|
||||
}
|
||||
|
||||
/* is the URL redirected ? */
|
||||
if (null !== $rewrittenUrlData->redirectedToUrl) {
|
||||
$this->redirect($urlTool->absoluteUrl($rewrittenUrlData->redirectedToUrl), 301);
|
||||
$redirect = RewritingUrlQuery::create()
|
||||
->filterByView($rewrittenUrlData->view)
|
||||
->filterByViewId($rewrittenUrlData->viewId)
|
||||
->filterByViewLocale($rewrittenUrlData->locale)
|
||||
->filterByRedirected(null, Criteria::ISNULL)
|
||||
->findOne()
|
||||
;
|
||||
|
||||
$this->redirect($urlTool->absoluteUrl($redirect->getUrl()), 301);
|
||||
}
|
||||
|
||||
/* define GET arguments in request */
|
||||
|
||||
@@ -13,11 +13,14 @@
|
||||
namespace Thelia\Core\Security\Authentication;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Thelia\Core\Security\Exception\CustomerNotConfirmedException;
|
||||
use Thelia\Core\Security\UserProvider\UserProviderInterface;
|
||||
use Thelia\Core\Security\Exception\WrongPasswordException;
|
||||
use Thelia\Core\Security\Exception\UsernameNotFoundException;
|
||||
use Symfony\Component\Validator\Exception\ValidatorException;
|
||||
use Thelia\Form\BaseForm;
|
||||
use Thelia\Model\ConfigQuery;
|
||||
use Thelia\Model\Customer;
|
||||
|
||||
class UsernamePasswordFormAuthenticator implements AuthenticatorInterface
|
||||
{
|
||||
@@ -78,6 +81,14 @@ class UsernamePasswordFormAuthenticator implements AuthenticatorInterface
|
||||
if ($authOk !== true) {
|
||||
throw new WrongPasswordException(sprintf("Wrong password for user '%s'.", $username));
|
||||
}
|
||||
|
||||
if (ConfigQuery::isCustomerEmailConfirmationEnable() && $user instanceof Customer) {
|
||||
// Customer email confirmation feature is available since Thelia 2.3.4
|
||||
if ($user->getConfirmationToken() !== null && ! $user->getEnable()) {
|
||||
throw (new CustomerNotConfirmedException())->setUser($user);
|
||||
}
|
||||
}
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
|
||||
@@ -97,6 +97,8 @@ class AdminResources
|
||||
|
||||
const ORDER = "admin.order";
|
||||
|
||||
const ORDER_STATUS = "admin.configuration.order-status";
|
||||
|
||||
const PRODUCT = "admin.product";
|
||||
|
||||
const PROFILE = "admin.configuration.profile";
|
||||
|
||||
@@ -114,7 +114,7 @@ class CSVSerializer extends AbstractSerializer
|
||||
if ($this->headers !== null) {
|
||||
// Create tmp file with header
|
||||
$fd = fopen('php://temp', 'w+b');
|
||||
fputcsv($fd, $this->headers);
|
||||
fputcsv($fd, $this->headers, $this->delimiter, $this->enclosure);
|
||||
|
||||
// Copy file content into tmp file
|
||||
$fileObject->rewind();
|
||||
@@ -131,6 +131,8 @@ class CSVSerializer extends AbstractSerializer
|
||||
|
||||
// Remove last line feed
|
||||
$fileObject->ftruncate($fileObject->getSize() - 1);
|
||||
|
||||
clearstatcache(true, $fileObject->getPathname());
|
||||
}
|
||||
|
||||
public function unserialize(\SplFileObject $fileObject)
|
||||
|
||||
@@ -147,7 +147,6 @@ class ParamInitMiddleware implements HttpKernelInterface
|
||||
Tlog::getInstance()->warning("The domain URL for language ".$lang->getTitle()." (id ".$lang->getId().") is not defined.");
|
||||
|
||||
return Lang::getDefaultLanguage();
|
||||
|
||||
} else {
|
||||
// one domain for all languages, the lang has to be set into session
|
||||
return $lang;
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
namespace Thelia\Core\Template\Element;
|
||||
|
||||
use Propel\Runtime\ActiveQuery\Criteria;
|
||||
use Thelia\Core\Template\Loop\Argument\Argument;
|
||||
use Propel\Runtime\ActiveQuery\ModelCriteria;
|
||||
use Thelia\Model\Tools\ModelCriteriaTools;
|
||||
@@ -54,8 +55,13 @@ abstract class BaseI18nLoop extends BaseLoop
|
||||
*
|
||||
* @return mixed the locale
|
||||
*/
|
||||
protected function configureI18nProcessing(ModelCriteria $search, $columns = array('TITLE', 'CHAPO', 'DESCRIPTION', 'POSTSCRIPTUM'), $foreignTable = null, $foreignKey = 'ID', $forceReturn = false)
|
||||
{
|
||||
protected function configureI18nProcessing(
|
||||
ModelCriteria $search,
|
||||
$columns = array('TITLE', 'CHAPO', 'DESCRIPTION', 'POSTSCRIPTUM'),
|
||||
$foreignTable = null,
|
||||
$foreignKey = 'ID',
|
||||
$forceReturn = false
|
||||
) {
|
||||
/* manage translations */
|
||||
|
||||
$this->locale = ModelCriteriaTools::getI18n(
|
||||
@@ -69,4 +75,34 @@ abstract class BaseI18nLoop extends BaseLoop
|
||||
$this->getForceReturn()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add the search clause for an I18N column, taking care of the back/front context, as default_locale_i18n is
|
||||
* not defined in the backEnd I18N context.
|
||||
*
|
||||
* @param ModelCriteria $search
|
||||
* @param string $columnName the column to search into, such as TITLE
|
||||
* @param string $searchCriteria the search criteria, such as Criterial::LIKE, Criteria::EQUAL, etc.
|
||||
* @param string $searchTerm the searched term
|
||||
*/
|
||||
public function addSearchInI18nColumn($search, $columnName, $searchCriteria, $searchTerm)
|
||||
{
|
||||
if (! $this->getBackendContext()) {
|
||||
$search->where(
|
||||
"CASE WHEN NOT ISNULL(`requested_locale_i18n`.ID)
|
||||
THEN `requested_locale_i18n`.`$columnName`
|
||||
ELSE `default_locale_i18n`.`$columnName`
|
||||
END " . $searchCriteria . " ?",
|
||||
$searchTerm,
|
||||
\PDO::PARAM_STR
|
||||
);
|
||||
} else {
|
||||
$search->where(
|
||||
"`requested_locale_i18n`.`$columnName` $searchCriteria ?",
|
||||
$searchTerm,
|
||||
\PDO::PARAM_STR
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
22
core/lib/Thelia/Core/Template/Element/BaseLoop.php
Normal file → Executable file
22
core/lib/Thelia/Core/Template/Element/BaseLoop.php
Normal file → Executable file
@@ -86,6 +86,7 @@ abstract class BaseLoop
|
||||
protected $translator = null;
|
||||
|
||||
private static $cacheLoopResult = [];
|
||||
private static $cacheLoopPagination = [];
|
||||
private static $cacheCount = [];
|
||||
|
||||
/** @var array cache of event to dispatch */
|
||||
@@ -498,6 +499,10 @@ abstract class BaseLoop
|
||||
$hash = $this->args->getHash();
|
||||
|
||||
if (($isCaching = $this->isCaching()) && isset(self::$cacheLoopResult[$hash])) {
|
||||
if (isset(self::$cacheLoopPagination[$hash])) {
|
||||
$pagination = self::$cacheLoopPagination[$hash];
|
||||
}
|
||||
|
||||
return self::$cacheLoopResult[$hash];
|
||||
}
|
||||
|
||||
@@ -533,9 +538,15 @@ abstract class BaseLoop
|
||||
}
|
||||
|
||||
$parsedResults = $this->extendsParseResults($this->parseResults($loopResult));
|
||||
|
||||
|
||||
$loopResult->finalizeRows();
|
||||
|
||||
if ($isCaching) {
|
||||
self::$cacheLoopResult[$hash] = $parsedResults;
|
||||
|
||||
if ($pagination instanceof PropelModelPager) {
|
||||
self::$cacheLoopPagination[$hash] = clone $pagination;
|
||||
}
|
||||
}
|
||||
|
||||
return $parsedResults;
|
||||
@@ -708,10 +719,11 @@ abstract class BaseLoop
|
||||
|
||||
$eventName = $this->getDispatchEventName(TheliaEvents::LOOP_EXTENDS_BUILD_ARRAY);
|
||||
if (null !== $eventName) {
|
||||
$this->dispatcher->dispatch(
|
||||
$eventName,
|
||||
new LoopExtendsBuildArrayEvent($this, $search)
|
||||
);
|
||||
$event = new LoopExtendsBuildArrayEvent($this, $search);
|
||||
|
||||
$this->dispatcher->dispatch($eventName, $event);
|
||||
|
||||
$search = $event->getArray();
|
||||
}
|
||||
|
||||
return $search;
|
||||
|
||||
@@ -80,6 +80,20 @@ class LoopResult implements \Iterator, \JsonSerializable
|
||||
|
||||
$this->collection[] = $row;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust the collection once all results have been added.
|
||||
*/
|
||||
public function finalizeRows()
|
||||
{
|
||||
// Fix rows LOOP_TOTAL if parseResults() did not added all resultsCollection items to the collection array
|
||||
// see https://github.com/thelia/thelia/issues/2337
|
||||
if (true === $this->countable && $this->getResultDataCollectionCount() !== $realCount = $this->getCount()) {
|
||||
foreach ($this->collection as &$item) {
|
||||
$item->set('LOOP_TOTAL', $realCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getCount()
|
||||
{
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
|
||||
namespace Thelia\Core\Template\Element;
|
||||
|
||||
use Propel\Runtime\ActiveQuery\ModelCriteria;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Etienne Roudeix <eroudeix@openstudio.fr>
|
||||
@@ -28,5 +30,11 @@ interface SearchLoopInterface
|
||||
*/
|
||||
public function getSearchIn();
|
||||
|
||||
/**
|
||||
* @param ModelCriteria $search a query
|
||||
* @param string $searchTerm the searched term
|
||||
* @param array $searchIn available field to search in
|
||||
* @param string $searchCriteria the search criteria, such as Criterial::LIKE, Criteria::EQUAL, etc.
|
||||
*/
|
||||
public function doSearch(&$search, $searchTerm, $searchIn, $searchCriteria);
|
||||
}
|
||||
|
||||
@@ -143,13 +143,12 @@ class Argument
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is available from Thelia 2.2 version
|
||||
*
|
||||
* @param $name
|
||||
* @param null $default
|
||||
* @param bool $mandatory
|
||||
* @param bool $empty
|
||||
* @return Argument
|
||||
* @since 2.2
|
||||
*/
|
||||
public static function createAnyListTypeArgument($name, $default = null, $mandatory = false, $empty = true)
|
||||
{
|
||||
@@ -176,4 +175,46 @@ class Argument
|
||||
$empty
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param null $default
|
||||
* @param bool $mandatory
|
||||
* @param bool $empty
|
||||
* @return Argument
|
||||
* @since 2.4.0
|
||||
*/
|
||||
public static function createAlphaNumStringTypeArgument($name, $default = null, $mandatory = false, $empty = true)
|
||||
{
|
||||
return new Argument(
|
||||
$name,
|
||||
new TypeCollection(
|
||||
new Type\AlphaNumStringType()
|
||||
),
|
||||
$default,
|
||||
$mandatory,
|
||||
$empty
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param null $default
|
||||
* @param bool $mandatory
|
||||
* @param bool $empty
|
||||
* @return Argument
|
||||
* @since 2.4.0
|
||||
*/
|
||||
public static function createAlphaNumStringListTypeArgument($name, $default = null, $mandatory = false, $empty = true)
|
||||
{
|
||||
return new Argument(
|
||||
$name,
|
||||
new TypeCollection(
|
||||
new Type\AlphaNumStringListType()
|
||||
),
|
||||
$default,
|
||||
$mandatory,
|
||||
$empty
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ use Thelia\Core\Template\Element\LoopResult;
|
||||
use Thelia\Core\Template\Element\LoopResultRow;
|
||||
use Thelia\Core\Template\Element\PropelSearchLoopInterface;
|
||||
use Thelia\Core\Template\Element\SearchLoopInterface;
|
||||
use Thelia\Core\Template\Element\StandardI18nFieldsSearchTrait;
|
||||
use Thelia\Core\Template\Loop\Argument\Argument;
|
||||
use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
|
||||
use Thelia\Model\BrandQuery;
|
||||
@@ -46,6 +47,8 @@ use Thelia\Type\TypeCollection;
|
||||
*/
|
||||
class Brand extends BaseI18nLoop implements PropelSearchLoopInterface, SearchLoopInterface
|
||||
{
|
||||
use StandardI18nFieldsSearchTrait;
|
||||
|
||||
protected $timestampable = true;
|
||||
|
||||
/**
|
||||
@@ -90,28 +93,20 @@ class Brand extends BaseI18nLoop implements PropelSearchLoopInterface, SearchLoo
|
||||
*/
|
||||
public function getSearchIn()
|
||||
{
|
||||
return [
|
||||
"title"
|
||||
];
|
||||
return $this->getStandardI18nSearchFields();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BrandQuery $search
|
||||
* @param string $searchTerm
|
||||
* @param string $searchIn
|
||||
* @param array $searchIn
|
||||
* @param string $searchCriteria
|
||||
*/
|
||||
public function doSearch(&$search, $searchTerm, $searchIn, $searchCriteria)
|
||||
{
|
||||
$search->_and();
|
||||
|
||||
$search->where(
|
||||
"CASE WHEN NOT ISNULL(`requested_locale_i18n`.ID)
|
||||
THEN `requested_locale_i18n`.`TITLE`ELSE `default_locale_i18n`.`TITLE`
|
||||
END ".$searchCriteria." ?",
|
||||
$searchTerm,
|
||||
\PDO::PARAM_STR
|
||||
);
|
||||
$this->addStandardI18nSearch($search, $searchTerm, $searchCriteria);
|
||||
}
|
||||
|
||||
public function buildModelCriteria()
|
||||
@@ -153,14 +148,7 @@ class Brand extends BaseI18nLoop implements PropelSearchLoopInterface, SearchLoo
|
||||
$title = $this->getTitle();
|
||||
|
||||
if (!is_null($title)) {
|
||||
$search->where(
|
||||
"CASE WHEN NOT ISNULL(`requested_locale_i18n`.ID)
|
||||
THEN `requested_locale_i18n`.`TITLE`
|
||||
ELSE `default_locale_i18n`.`TITLE`
|
||||
END ".Criteria::LIKE." ?",
|
||||
"%".$title."%",
|
||||
\PDO::PARAM_STR
|
||||
);
|
||||
$this->addSearchInI18nColumn($search, 'TITLE', Criteria::LIKE, "%".$title."%");
|
||||
}
|
||||
|
||||
$current = $this->getCurrent();
|
||||
|
||||
@@ -18,6 +18,7 @@ use Thelia\Core\Template\Element\LoopResult;
|
||||
use Thelia\Core\Template\Element\LoopResultRow;
|
||||
use Thelia\Core\Template\Element\PropelSearchLoopInterface;
|
||||
use Thelia\Core\Template\Element\SearchLoopInterface;
|
||||
use Thelia\Core\Template\Element\StandardI18nFieldsSearchTrait;
|
||||
use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
|
||||
use Thelia\Core\Template\Loop\Argument\Argument;
|
||||
use Thelia\Model\CategoryQuery;
|
||||
@@ -59,9 +60,13 @@ use Thelia\Model\Category as CategoryModel;
|
||||
* @method bool|string getVisible()
|
||||
* @method int[] getExclude()
|
||||
* @method string[] getOrder()
|
||||
* @method int[] getTemplateId()
|
||||
* @method bool getProductCountVisibleOnly()
|
||||
*/
|
||||
class Category extends BaseI18nLoop implements PropelSearchLoopInterface, SearchLoopInterface
|
||||
{
|
||||
use StandardI18nFieldsSearchTrait;
|
||||
|
||||
protected $timestampable = true;
|
||||
protected $versionable = true;
|
||||
|
||||
@@ -82,11 +87,21 @@ class Category extends BaseI18nLoop implements PropelSearchLoopInterface, Search
|
||||
Argument::createBooleanTypeArgument('with_prev_next_info', false),
|
||||
Argument::createBooleanTypeArgument('need_count_child', false),
|
||||
Argument::createBooleanTypeArgument('need_product_count', false),
|
||||
Argument::createBooleanTypeArgument('product_count_visible_only', false),
|
||||
Argument::createBooleanOrBothTypeArgument('visible', 1),
|
||||
Argument::createIntListTypeArgument('template_id'),
|
||||
new Argument(
|
||||
'order',
|
||||
new TypeCollection(
|
||||
new Type\EnumListType(array('id', 'id_reverse', 'alpha', 'alpha_reverse', 'manual', 'manual_reverse', 'visible', 'visible_reverse', 'random'))
|
||||
new Type\EnumListType([
|
||||
'id', 'id_reverse',
|
||||
'alpha', 'alpha_reverse',
|
||||
'manual', 'manual_reverse',
|
||||
'visible', 'visible_reverse',
|
||||
'created', 'created_reverse',
|
||||
'updated', 'updated_reverse',
|
||||
'random'
|
||||
])
|
||||
),
|
||||
'manual'
|
||||
),
|
||||
@@ -99,22 +114,20 @@ class Category extends BaseI18nLoop implements PropelSearchLoopInterface, Search
|
||||
*/
|
||||
public function getSearchIn()
|
||||
{
|
||||
return [
|
||||
"title"
|
||||
];
|
||||
return $this->getStandardI18nSearchFields();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CategoryQuery $search
|
||||
* @param string $searchTerm
|
||||
* @param string $searchIn
|
||||
* @param array $searchIn
|
||||
* @param string $searchCriteria
|
||||
*/
|
||||
public function doSearch(&$search, $searchTerm, $searchIn, $searchCriteria)
|
||||
{
|
||||
$search->_and();
|
||||
|
||||
$search->where("CASE WHEN NOT ISNULL(`requested_locale_i18n`.ID) THEN `requested_locale_i18n`.`TITLE` ELSE `default_locale_i18n`.`TITLE` END ".$searchCriteria." ?", $searchTerm, \PDO::PARAM_STR);
|
||||
$this->addStandardI18nSearch($search, $searchTerm, $searchCriteria);
|
||||
}
|
||||
|
||||
public function buildModelCriteria()
|
||||
@@ -132,8 +145,11 @@ class Category extends BaseI18nLoop implements PropelSearchLoopInterface, Search
|
||||
|
||||
$parent = $this->getParent();
|
||||
|
||||
if (!is_null($parent)) {
|
||||
if (null !== $parent) {
|
||||
$search->filterByParent($parent, Criteria::IN);
|
||||
$positionOrderAllowed = true;
|
||||
} else {
|
||||
$positionOrderAllowed = false;
|
||||
}
|
||||
|
||||
$excludeParent = $this->getExcludeParent();
|
||||
@@ -190,6 +206,11 @@ class Category extends BaseI18nLoop implements PropelSearchLoopInterface, Search
|
||||
->endUse()
|
||||
;
|
||||
}
|
||||
$templateIdList = $this->getTemplateId();
|
||||
|
||||
if (!is_null($templateIdList)) {
|
||||
$search->filterByDefaultTemplateId($templateIdList, Criteria::IN);
|
||||
}
|
||||
|
||||
$orders = $this->getOrder();
|
||||
|
||||
@@ -219,6 +240,18 @@ class Category extends BaseI18nLoop implements PropelSearchLoopInterface, Search
|
||||
case "visible_reverse":
|
||||
$search->orderByVisible(Criteria::DESC);
|
||||
break;
|
||||
case "created":
|
||||
$search->addAscendingOrderByColumn('created_at');
|
||||
break;
|
||||
case "created_reverse":
|
||||
$search->addDescendingOrderByColumn('created_at');
|
||||
break;
|
||||
case "updated":
|
||||
$search->addAscendingOrderByColumn('updated_at');
|
||||
break;
|
||||
case "updated_reverse":
|
||||
$search->addDescendingOrderByColumn('updated_at');
|
||||
break;
|
||||
case "random":
|
||||
$search->clearOrderByColumns();
|
||||
$search->addAscendingOrderByColumn('RAND()');
|
||||
@@ -264,7 +297,11 @@ class Category extends BaseI18nLoop implements PropelSearchLoopInterface, Search
|
||||
}
|
||||
|
||||
if ($this->getNeedProductCount()) {
|
||||
$loopResultRow->set("PRODUCT_COUNT", $category->countAllProducts());
|
||||
if ($this->getProductCountVisibleOnly()) {
|
||||
$loopResultRow->set("PRODUCT_COUNT", $category->countAllProductsVisibleOnly());
|
||||
} else {
|
||||
$loopResultRow->set("PRODUCT_COUNT", $category->countAllProducts());
|
||||
}
|
||||
}
|
||||
|
||||
$isBackendContext = $this->getBackendContext();
|
||||
|
||||
@@ -49,32 +49,34 @@ class CategoryPath extends BaseI18nLoop implements ArraySearchLoopInterface
|
||||
{
|
||||
return new ArgumentCollection(
|
||||
Argument::createIntTypeArgument('category', null, true),
|
||||
Argument::createIntTypeArgument('depth'),
|
||||
Argument::createIntTypeArgument('depth', PHP_INT_MAX),
|
||||
Argument::createBooleanOrBothTypeArgument('visible', true, false)
|
||||
);
|
||||
}
|
||||
|
||||
public function buildArray()
|
||||
{
|
||||
$id = $this->getCategory();
|
||||
$originalId = $currentId = $this->getCategory();
|
||||
$visible = $this->getVisible();
|
||||
|
||||
$search = CategoryQuery::create();
|
||||
|
||||
$this->configureI18nProcessing($search, array('TITLE'));
|
||||
|
||||
$search->filterById($id);
|
||||
if ($visible !== BooleanOrBothType::ANY) {
|
||||
$search->filterByVisible($visible);
|
||||
}
|
||||
|
||||
$depth = $this->getDepth();
|
||||
|
||||
$results = array();
|
||||
|
||||
|
||||
$ids = array();
|
||||
|
||||
|
||||
do {
|
||||
$search = CategoryQuery::create();
|
||||
|
||||
$this->configureI18nProcessing($search, array('TITLE'));
|
||||
|
||||
$search->filterById($currentId);
|
||||
|
||||
if ($visible !== BooleanOrBothType::ANY) {
|
||||
$search->filterByVisible($visible);
|
||||
}
|
||||
|
||||
$category = $search->findOne();
|
||||
|
||||
|
||||
if ($category != null) {
|
||||
$results[] = array(
|
||||
"ID" => $category->getId(),
|
||||
@@ -82,29 +84,26 @@ class CategoryPath extends BaseI18nLoop implements ArraySearchLoopInterface
|
||||
"URL" => $category->getUrl($this->locale),
|
||||
"LOCALE" => $this->locale,
|
||||
);
|
||||
|
||||
$parent = $category->getParent();
|
||||
|
||||
if ($parent > 0) {
|
||||
|
||||
$currentId = $category->getParent();
|
||||
|
||||
if ($currentId > 0) {
|
||||
// Prevent circular refererences
|
||||
if (in_array($parent, $ids)) {
|
||||
throw new \LogicException(sprintf("Circular reference detected in category ID=%d hierarchy (category ID=%d appears more than one times in path)", $id, $parent));
|
||||
}
|
||||
|
||||
$ids[] = $parent;
|
||||
|
||||
$search = CategoryQuery::create();
|
||||
|
||||
$this->configureI18nProcessing($search, array('TITLE'));
|
||||
|
||||
$search->filterById($parent);
|
||||
if ($visible != BooleanOrBothType::ANY) {
|
||||
$search->filterByVisible($visible);
|
||||
if (in_array($currentId, $ids)) {
|
||||
throw new \LogicException(
|
||||
sprintf(
|
||||
"Circular reference detected in category ID=%d hierarchy (category ID=%d appears more than one times in path)",
|
||||
$originalId,
|
||||
$currentId
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$ids[] = $currentId;
|
||||
}
|
||||
}
|
||||
} while ($category != null && $parent > 0);
|
||||
|
||||
} while ($category != null && $currentId > 0 && --$depth > 0);
|
||||
|
||||
// Reverse list and build the final result
|
||||
return array_reverse($results);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ use Thelia\Core\Template\Element\LoopResult;
|
||||
use Thelia\Core\Template\Element\LoopResultRow;
|
||||
use Thelia\Core\Template\Element\PropelSearchLoopInterface;
|
||||
use Thelia\Core\Template\Element\SearchLoopInterface;
|
||||
use Thelia\Core\Template\Element\StandardI18nFieldsSearchTrait;
|
||||
use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
|
||||
use Thelia\Core\Template\Loop\Argument\Argument;
|
||||
use Thelia\Model\ContentFolderQuery;
|
||||
@@ -54,6 +55,8 @@ use Thelia\Type\BooleanOrBothType;
|
||||
*/
|
||||
class Content extends BaseI18nLoop implements PropelSearchLoopInterface, SearchLoopInterface
|
||||
{
|
||||
use StandardI18nFieldsSearchTrait;
|
||||
|
||||
protected $timestampable = true;
|
||||
protected $versionable = true;
|
||||
|
||||
@@ -77,18 +80,15 @@ class Content extends BaseI18nLoop implements PropelSearchLoopInterface, SearchL
|
||||
new TypeCollection(
|
||||
new Type\EnumListType(
|
||||
array(
|
||||
'alpha',
|
||||
'alpha-reverse',
|
||||
'manual',
|
||||
'manual_reverse',
|
||||
'id', 'id_reverse',
|
||||
'alpha', 'alpha-reverse', 'alpha_reverse',
|
||||
'manual', 'manual_reverse',
|
||||
'visible', 'visible_reverse',
|
||||
'random',
|
||||
'given_id',
|
||||
'created',
|
||||
'created_reverse',
|
||||
'updated',
|
||||
'updated_reverse',
|
||||
'position',
|
||||
'position_reverse'
|
||||
'created', 'created_reverse',
|
||||
'updated', 'updated_reverse',
|
||||
'position', 'position_reverse'
|
||||
)
|
||||
)
|
||||
),
|
||||
@@ -104,22 +104,20 @@ class Content extends BaseI18nLoop implements PropelSearchLoopInterface, SearchL
|
||||
*/
|
||||
public function getSearchIn()
|
||||
{
|
||||
return [
|
||||
"title"
|
||||
];
|
||||
return $this->getStandardI18nSearchFields();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContentQuery $search
|
||||
* @param string $searchTerm
|
||||
* @param string $searchIn
|
||||
* @param array $searchIn
|
||||
* @param string $searchCriteria
|
||||
*/
|
||||
public function doSearch(&$search, $searchTerm, $searchIn, $searchCriteria)
|
||||
{
|
||||
$search->_and();
|
||||
|
||||
$search->where("CASE WHEN NOT ISNULL(`requested_locale_i18n`.ID) THEN `requested_locale_i18n`.`TITLE` ELSE `default_locale_i18n`.`TITLE` END ".$searchCriteria." ?", $searchTerm, \PDO::PARAM_STR);
|
||||
$this->addStandardI18nSearch($search, $searchTerm, $searchCriteria);
|
||||
}
|
||||
|
||||
public function buildModelCriteria()
|
||||
@@ -140,8 +138,8 @@ class Content extends BaseI18nLoop implements PropelSearchLoopInterface, SearchL
|
||||
// Select the contents which have $folderDefault as the default folder.
|
||||
$search
|
||||
->useContentFolderQuery('FolderSelect')
|
||||
->filterByDefaultFolder(true)
|
||||
->filterByFolderId($folderDefault, Criteria::IN)
|
||||
->filterByDefaultFolder(true)
|
||||
->filterByFolderId($folderDefault, Criteria::IN)
|
||||
->endUse()
|
||||
;
|
||||
|
||||
@@ -155,7 +153,7 @@ class Content extends BaseI18nLoop implements PropelSearchLoopInterface, SearchL
|
||||
|
||||
$search
|
||||
->useContentFolderQuery('FolderSelect')
|
||||
->filterByFolderId($allFolderIDs, Criteria::IN)
|
||||
->filterByFolderId($allFolderIDs, Criteria::IN)
|
||||
->endUse()
|
||||
;
|
||||
|
||||
@@ -163,12 +161,18 @@ class Content extends BaseI18nLoop implements PropelSearchLoopInterface, SearchL
|
||||
$manualOrderAllowed = (1 == $depth && 1 == count($folderIdList));
|
||||
} else {
|
||||
$search
|
||||
->useContentFolderQuery('FolderSelect')
|
||||
->filterByDefaultFolder(true)
|
||||
->endUse()
|
||||
->leftJoinContentFolder('FolderSelect')
|
||||
->addJoinCondition('FolderSelect', '`FolderSelect`.DEFAULT_FOLDER = 1')
|
||||
;
|
||||
}
|
||||
|
||||
$search->withColumn(
|
||||
'CAST(CASE WHEN ISNULL(`FolderSelect`.POSITION) THEN \'' . PHP_INT_MAX . '\' ELSE `FolderSelect`.POSITION END AS SIGNED)',
|
||||
'position_delegate'
|
||||
);
|
||||
$search->withColumn('`FolderSelect`.FOLDER_ID', 'default_folder_id');
|
||||
$search->withColumn('`FolderSelect`.DEFAULT_FOLDER', 'is_default_folder');
|
||||
|
||||
$current = $this->getCurrent();
|
||||
|
||||
if ($current === true) {
|
||||
@@ -198,19 +202,39 @@ class Content extends BaseI18nLoop implements PropelSearchLoopInterface, SearchL
|
||||
$title = $this->getTitle();
|
||||
|
||||
if (!is_null($title)) {
|
||||
$search->where("CASE WHEN NOT ISNULL(`requested_locale_i18n`.ID) THEN `requested_locale_i18n`.`TITLE` ELSE `default_locale_i18n`.`TITLE` END ".Criteria::LIKE." ?", "%".$title."%", \PDO::PARAM_STR);
|
||||
$this->addSearchInI18nColumn($search, 'TITLE', Criteria::LIKE, "%".$title."%");
|
||||
}
|
||||
|
||||
$search->withColumn('`FolderSelect`.POSITION', 'position_delegate');
|
||||
$exclude = $this->getExclude();
|
||||
|
||||
if (!is_null($exclude)) {
|
||||
$search->filterById($exclude, Criteria::NOT_IN);
|
||||
}
|
||||
|
||||
$exclude_folder = $this->getExcludeFolder();
|
||||
|
||||
if (!is_null($exclude_folder)) {
|
||||
$search->filterByFolder(
|
||||
FolderQuery::create()->filterById($exclude_folder, Criteria::IN)->find(),
|
||||
Criteria::NOT_IN
|
||||
);
|
||||
}
|
||||
|
||||
$orders = $this->getOrder();
|
||||
|
||||
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;
|
||||
case "alpha-reverse":
|
||||
case "alpha_reverse":
|
||||
$search->addDescendingOrderByColumn('i18n_TITLE');
|
||||
break;
|
||||
case "manual":
|
||||
@@ -235,6 +259,12 @@ class Content extends BaseI18nLoop implements PropelSearchLoopInterface, SearchL
|
||||
$search->orderBy($givenIdMatched, Criteria::DESC);
|
||||
}
|
||||
break;
|
||||
case "visible":
|
||||
$search->orderByVisible(Criteria::ASC);
|
||||
break;
|
||||
case "visible_reverse":
|
||||
$search->orderByVisible(Criteria::DESC);
|
||||
break;
|
||||
case "random":
|
||||
$search->clearOrderByColumns();
|
||||
$search->addAscendingOrderByColumn('RAND()');
|
||||
@@ -260,20 +290,7 @@ class Content extends BaseI18nLoop implements PropelSearchLoopInterface, SearchL
|
||||
}
|
||||
}
|
||||
|
||||
$exclude = $this->getExclude();
|
||||
|
||||
if (!is_null($exclude)) {
|
||||
$search->filterById($exclude, Criteria::NOT_IN);
|
||||
}
|
||||
|
||||
$exclude_folder = $this->getExcludeFolder();
|
||||
|
||||
if (!is_null($exclude_folder)) {
|
||||
$search->filterByFolder(
|
||||
FolderQuery::create()->filterById($exclude_folder, Criteria::IN)->find(),
|
||||
Criteria::NOT_IN
|
||||
);
|
||||
}
|
||||
$search->groupById();
|
||||
|
||||
return $search;
|
||||
}
|
||||
@@ -283,7 +300,13 @@ class Content extends BaseI18nLoop implements PropelSearchLoopInterface, SearchL
|
||||
/** @var ContentModel $content */
|
||||
foreach ($loopResult->getResultDataCollection() as $content) {
|
||||
$loopResultRow = new LoopResultRow($content);
|
||||
$defaultFolderId = $content->getDefaultFolderId();
|
||||
|
||||
if ((bool) $content->getVirtualColumn('is_default_folder')) {
|
||||
$defaultFolderId = $content->getVirtualColumn('default_folder_id');
|
||||
} else {
|
||||
$defaultFolderId = $content->getDefaultFolderId();
|
||||
}
|
||||
|
||||
$loopResultRow->set("ID", $content->getId())
|
||||
->set("IS_TRANSLATED", $content->getVirtualColumn('IS_TRANSLATED'))
|
||||
->set("LOCALE", $this->locale)
|
||||
|
||||
@@ -118,6 +118,7 @@ class Country extends BaseI18nLoop implements PropelSearchLoopInterface
|
||||
|
||||
if (true === $withArea) {
|
||||
$search
|
||||
->distinct()
|
||||
->joinCountryArea('with_area', Criteria::LEFT_JOIN)
|
||||
->where('`with_area`.country_id ' . Criteria::ISNOTNULL);
|
||||
} elseif (false === $withArea) {
|
||||
|
||||
@@ -252,7 +252,9 @@ class Customer extends BaseLoop implements SearchLoopInterface, PropelSearchLoop
|
||||
->set("RESELLER", $customer->getReseller())
|
||||
->set("SPONSOR", $customer->getSponsor())
|
||||
->set("DISCOUNT", $customer->getDiscount())
|
||||
->set("NEWSLETTER", $customer->getVirtualColumn("is_registered_to_newsletter"));
|
||||
->set("NEWSLETTER", $customer->getVirtualColumn("is_registered_to_newsletter"))
|
||||
->set("CONFIRMATION_TOKEN", $customer->getConfirmationToken())
|
||||
;
|
||||
|
||||
if ($this->getWithPrevNextInfo()) {
|
||||
// Find previous and next category
|
||||
|
||||
@@ -123,6 +123,13 @@ class Feature extends BaseI18nLoop implements PropelSearchLoopInterface
|
||||
|
||||
/** @var ProductModel $product */
|
||||
foreach ($products as $product) {
|
||||
if (!$this->getBackendContext()) {
|
||||
$search
|
||||
->useFeatureProductQuery()
|
||||
->filterByProduct($product)
|
||||
->endUse()
|
||||
;
|
||||
}
|
||||
$tplId = $product->getTemplateId();
|
||||
|
||||
if (! is_null($tplId)) {
|
||||
|
||||
@@ -22,6 +22,8 @@ use Thelia\Core\Template\Loop\Argument\Argument;
|
||||
use Thelia\Model\FeatureAv;
|
||||
use Thelia\Model\FeatureAvQuery;
|
||||
use Thelia\Model\FeatureProductQuery;
|
||||
use Thelia\Model\Map\FeatureAvTableMap;
|
||||
use Thelia\Model\Map\FeatureProductTableMap;
|
||||
use Thelia\Type\TypeCollection;
|
||||
use Thelia\Type;
|
||||
|
||||
@@ -106,6 +108,24 @@ class FeatureAvailability extends BaseI18nLoop implements PropelSearchLoopInterf
|
||||
}
|
||||
}
|
||||
|
||||
// We do not consider here Free Text values, so be sure that the features values we will get
|
||||
// are not free text ones, e.g. are not defined as free-text feature values in the
|
||||
// feature_product table.
|
||||
// We are doig here something like
|
||||
// SELECT * FROM `feature_av`
|
||||
// WHERE feature_av.FEATURE_ID IN ('7')
|
||||
// AND feature_av.ID not in (
|
||||
// select feature_av_id from feature_product
|
||||
// where feature_id = `feature_av`.feature_id
|
||||
// and feature_av_id = `feature_av`.id
|
||||
// and free_text_value = 1
|
||||
// )
|
||||
$search->where(FeatureAvTableMap::ID . ' NOT IN (
|
||||
SELECT '. FeatureProductTableMap::FEATURE_AV_ID . '
|
||||
FROM ' .FeatureProductTableMap::TABLE_NAME. '
|
||||
WHERE ' . FeatureProductTableMap::FREE_TEXT_VALUE . ' = 1
|
||||
)');
|
||||
|
||||
return $search;
|
||||
}
|
||||
|
||||
@@ -113,26 +133,19 @@ class FeatureAvailability extends BaseI18nLoop implements PropelSearchLoopInterf
|
||||
{
|
||||
/** @var FeatureAv $featureAv */
|
||||
foreach ($loopResult->getResultDataCollection() as $featureAv) {
|
||||
$isFreeText = FeatureProductQuery::create()
|
||||
->filterByFeatureId($featureAv->getFeatureId())
|
||||
->filterByFeatureAvId($featureAv->getId())
|
||||
->findOneByFreeTextValue(true);
|
||||
$loopResultRow = new LoopResultRow($featureAv);
|
||||
$loopResultRow->set("ID", $featureAv->getId())
|
||||
->set("IS_TRANSLATED", $featureAv->getVirtualColumn('IS_TRANSLATED'))
|
||||
->set("LOCALE", $this->locale)
|
||||
->set("FEATURE_ID", $featureAv->getFeatureId())
|
||||
->set("TITLE", $featureAv->getVirtualColumn('i18n_TITLE'))
|
||||
->set("CHAPO", $featureAv->getVirtualColumn('i18n_CHAPO'))
|
||||
->set("DESCRIPTION", $featureAv->getVirtualColumn('i18n_DESCRIPTION'))
|
||||
->set("POSTSCRIPTUM", $featureAv->getVirtualColumn('i18n_POSTSCRIPTUM'))
|
||||
->set("POSITION", $featureAv->getPosition());
|
||||
$this->addOutputFields($loopResultRow, $featureAv);
|
||||
|
||||
if ($isFreeText === null) {
|
||||
$loopResultRow = new LoopResultRow($featureAv);
|
||||
$loopResultRow->set("ID", $featureAv->getId())
|
||||
->set("IS_TRANSLATED", $featureAv->getVirtualColumn('IS_TRANSLATED'))
|
||||
->set("LOCALE", $this->locale)
|
||||
->set("FEATURE_ID", $featureAv->getFeatureId())
|
||||
->set("TITLE", $featureAv->getVirtualColumn('i18n_TITLE'))
|
||||
->set("CHAPO", $featureAv->getVirtualColumn('i18n_CHAPO'))
|
||||
->set("DESCRIPTION", $featureAv->getVirtualColumn('i18n_DESCRIPTION'))
|
||||
->set("POSTSCRIPTUM", $featureAv->getVirtualColumn('i18n_POSTSCRIPTUM'))
|
||||
->set("POSITION", $featureAv->getPosition());
|
||||
$this->addOutputFields($loopResultRow, $featureAv);
|
||||
|
||||
$loopResult->addRow($loopResultRow);
|
||||
}
|
||||
$loopResult->addRow($loopResultRow);
|
||||
}
|
||||
|
||||
return $loopResult;
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
namespace Thelia\Core\Template\Loop;
|
||||
|
||||
use Symfony\Component\Cache\Adapter\AdapterInterface;
|
||||
use Thelia\Core\Template\Element\ArraySearchLoopInterface;
|
||||
use Thelia\Core\Template\Element\BaseLoop;
|
||||
use Thelia\Core\Template\Element\LoopResult;
|
||||
@@ -41,27 +42,25 @@ class Feed extends BaseLoop implements ArraySearchLoopInterface
|
||||
|
||||
public function buildArray()
|
||||
{
|
||||
$cachedir = THELIA_ROOT . 'cache/feeds';
|
||||
/** @var AdapterInterface $cacheAdapter */
|
||||
$cacheAdapter = $this->container->get('thelia.cache');
|
||||
|
||||
if (! is_dir($cachedir)) {
|
||||
if (! mkdir($cachedir)) {
|
||||
throw new \Exception(sprintf("Failed to create cache directory '%s'", $cachedir));
|
||||
}
|
||||
$cacheItem = $cacheAdapter->getItem('feed_' . md5($this->getUrl()));
|
||||
|
||||
if (!$cacheItem->isHit()) {
|
||||
$feed = new \SimplePie();
|
||||
$feed->set_feed_url($this->getUrl());
|
||||
|
||||
$feed->init();
|
||||
|
||||
$feed->handle_content_type();
|
||||
|
||||
$cacheItem->expiresAfter($this->getTimeout() * 60);
|
||||
$cacheItem->set($feed->get_items());
|
||||
$cacheAdapter->save($cacheItem);
|
||||
}
|
||||
|
||||
$feed = new \SimplePie();
|
||||
$feed->set_feed_url($this->getUrl());
|
||||
$feed->set_cache_location(THELIA_ROOT . 'cache/feeds');
|
||||
|
||||
$feed->init();
|
||||
|
||||
$feed->handle_content_type();
|
||||
|
||||
$feed->set_timeout($this->getTimeout());
|
||||
|
||||
$items = $feed->get_items();
|
||||
|
||||
return $items;
|
||||
return $cacheItem->get();
|
||||
}
|
||||
|
||||
public function parseResults(LoopResult $loopResult)
|
||||
|
||||
@@ -18,6 +18,7 @@ use Thelia\Core\Template\Element\LoopResult;
|
||||
use Thelia\Core\Template\Element\LoopResultRow;
|
||||
use Thelia\Core\Template\Element\PropelSearchLoopInterface;
|
||||
use Thelia\Core\Template\Element\SearchLoopInterface;
|
||||
use Thelia\Core\Template\Element\StandardI18nFieldsSearchTrait;
|
||||
use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
|
||||
use Thelia\Core\Template\Loop\Argument\Argument;
|
||||
use Thelia\Model\ContentQuery;
|
||||
@@ -42,9 +43,14 @@ use Thelia\Type\BooleanOrBothType;
|
||||
* @method string getTitle()
|
||||
* @method string[] getOrder()
|
||||
* @method bool getWithPrevNextInfo()
|
||||
* @method bool getNeedCountChild()
|
||||
* @method bool getNeedContentCount()
|
||||
* @method bool getContentCountVisible()
|
||||
*/
|
||||
class Folder extends BaseI18nLoop implements PropelSearchLoopInterface, SearchLoopInterface
|
||||
{
|
||||
use StandardI18nFieldsSearchTrait;
|
||||
|
||||
protected $timestampable = true;
|
||||
protected $versionable = true;
|
||||
|
||||
@@ -61,27 +67,28 @@ class Folder extends BaseI18nLoop implements PropelSearchLoopInterface, SearchLo
|
||||
Argument::createBooleanTypeArgument('not_empty', 0),
|
||||
Argument::createBooleanOrBothTypeArgument('visible', 1),
|
||||
Argument::createAnyTypeArgument('title'),
|
||||
Argument::createBooleanTypeArgument('need_count_child', true),
|
||||
Argument::createBooleanTypeArgument('need_content_count', true),
|
||||
new Argument(
|
||||
'order',
|
||||
new TypeCollection(
|
||||
new Type\EnumListType(
|
||||
[
|
||||
'alpha',
|
||||
'alpha_reverse',
|
||||
'manual',
|
||||
'manual_reverse',
|
||||
'id', 'id_reverse',
|
||||
'alpha', 'alpha_reverse',
|
||||
'manual', 'manual_reverse',
|
||||
'visible', 'visible_reverse',
|
||||
'random',
|
||||
'created',
|
||||
'created_reverse',
|
||||
'updated',
|
||||
'updated_reverse'
|
||||
'created', 'created_reverse',
|
||||
'updated', 'updated_reverse'
|
||||
]
|
||||
)
|
||||
),
|
||||
'manual'
|
||||
),
|
||||
Argument::createIntListTypeArgument('exclude'),
|
||||
Argument::createBooleanTypeArgument('with_prev_next_info', false)
|
||||
Argument::createBooleanTypeArgument('with_prev_next_info', false),
|
||||
Argument::createBooleanOrBothTypeArgument('content_count_visible', true)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -90,36 +97,20 @@ class Folder extends BaseI18nLoop implements PropelSearchLoopInterface, SearchLo
|
||||
*/
|
||||
public function getSearchIn()
|
||||
{
|
||||
return [
|
||||
"title"
|
||||
];
|
||||
return $this->getStandardI18nSearchFields();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param FolderQuery $search
|
||||
* @param string $searchTerm
|
||||
* @param string $searchIn
|
||||
* @param array $searchIn
|
||||
* @param string $searchCriteria
|
||||
*/
|
||||
public function doSearch(&$search, $searchTerm, $searchIn, $searchCriteria)
|
||||
{
|
||||
$search->_and();
|
||||
|
||||
$this->addTitleSearchWhereClause($search, $searchCriteria, $searchTerm);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param FolderQuery $search
|
||||
* @param string $criteria
|
||||
* @param string $value
|
||||
*/
|
||||
protected function addTitleSearchWhereClause($search, $criteria, $value)
|
||||
{
|
||||
$search->where(
|
||||
"CASE WHEN NOT ISNULL(`requested_locale_i18n`.ID) THEN `requested_locale_i18n`.`TITLE` ELSE `default_locale_i18n`.`TITLE` END ".$criteria." ?",
|
||||
$value,
|
||||
\PDO::PARAM_STR
|
||||
);
|
||||
$this->addStandardI18nSearch($search, $searchTerm, $searchCriteria);
|
||||
}
|
||||
|
||||
public function buildModelCriteria()
|
||||
@@ -140,7 +131,7 @@ class Folder extends BaseI18nLoop implements PropelSearchLoopInterface, SearchLo
|
||||
|
||||
$parent = $this->getParent();
|
||||
|
||||
if (!is_null($parent)) {
|
||||
if (null !== $parent) {
|
||||
$search->filterByParent($parent);
|
||||
}
|
||||
|
||||
@@ -171,7 +162,7 @@ class Folder extends BaseI18nLoop implements PropelSearchLoopInterface, SearchLo
|
||||
$title = $this->getTitle();
|
||||
|
||||
if (!is_null($title)) {
|
||||
$this->addTitleSearchWhereClause($search, Criteria::LIKE, '%'.$title.'%');
|
||||
$this->addSearchInI18nColumn($search, 'TITLE', Criteria::LIKE, "%".$title."%");
|
||||
}
|
||||
|
||||
$visible = $this->getVisible();
|
||||
@@ -184,6 +175,12 @@ class Folder extends BaseI18nLoop implements PropelSearchLoopInterface, SearchLo
|
||||
|
||||
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;
|
||||
@@ -196,6 +193,12 @@ class Folder extends BaseI18nLoop implements PropelSearchLoopInterface, SearchLo
|
||||
case "manual":
|
||||
$search->orderByPosition(Criteria::ASC);
|
||||
break;
|
||||
case "visible":
|
||||
$search->orderByVisible(Criteria::ASC);
|
||||
break;
|
||||
case "visible_reverse":
|
||||
$search->orderByVisible(Criteria::DESC);
|
||||
break;
|
||||
case "random":
|
||||
$search->clearOrderByColumns();
|
||||
$search->addAscendingOrderByColumn('RAND()');
|
||||
@@ -221,6 +224,15 @@ class Folder extends BaseI18nLoop implements PropelSearchLoopInterface, SearchLo
|
||||
|
||||
public function parseResults(LoopResult $loopResult)
|
||||
{
|
||||
$needCountChild = $this->getNeedCountChild();
|
||||
$needContentCount = $this->getNeedContentCount();
|
||||
|
||||
$contentCountVisiblility = $this->getContentCountVisible();
|
||||
|
||||
if ($contentCountVisiblility !== BooleanOrBothType::ANY) {
|
||||
$contentCountVisiblility = $contentCountVisiblility ? 1 : 0;
|
||||
}
|
||||
|
||||
/** @var \Thelia\Model\Folder $folder */
|
||||
foreach ($loopResult->getResultDataCollection() as $folder) {
|
||||
$loopResultRow = new LoopResultRow($folder);
|
||||
@@ -239,11 +251,18 @@ class Folder extends BaseI18nLoop implements PropelSearchLoopInterface, SearchLo
|
||||
->set("META_TITLE", $folder->getVirtualColumn('i18n_META_TITLE'))
|
||||
->set("META_DESCRIPTION", $folder->getVirtualColumn('i18n_META_DESCRIPTION'))
|
||||
->set("META_KEYWORDS", $folder->getVirtualColumn('i18n_META_KEYWORDS'))
|
||||
->set("CHILD_COUNT", $folder->countChild())
|
||||
->set("CONTENT_COUNT", $folder->countAllContents())
|
||||
->set("VISIBLE", $folder->getVisible() ? "1" : "0")
|
||||
->set("POSITION", $folder->getPosition());
|
||||
|
||||
|
||||
if ($needCountChild) {
|
||||
$loopResultRow->set("CHILD_COUNT", $folder->countChild());
|
||||
}
|
||||
|
||||
if ($needContentCount) {
|
||||
$loopResultRow->set("CONTENT_COUNT", $folder->countAllContents($contentCountVisiblility));
|
||||
}
|
||||
|
||||
$isBackendContext = $this->getBackendContext();
|
||||
|
||||
if ($this->getWithPrevNextInfo()) {
|
||||
@@ -286,4 +305,4 @@ class Folder extends BaseI18nLoop implements PropelSearchLoopInterface, SearchLo
|
||||
|
||||
return $loopResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ use Thelia\Type\BooleanOrBothType;
|
||||
* {@inheritdoc}
|
||||
* @method int getFolder()
|
||||
* @method bool|string getVisible()
|
||||
* @method int getDepth()
|
||||
* @method string[] getOrder()
|
||||
*/
|
||||
class FolderPath extends BaseI18nLoop implements ArraySearchLoopInterface
|
||||
@@ -40,30 +41,32 @@ class FolderPath extends BaseI18nLoop implements ArraySearchLoopInterface
|
||||
{
|
||||
return new ArgumentCollection(
|
||||
Argument::createIntTypeArgument('folder', null, true),
|
||||
Argument::createIntTypeArgument('depth'),
|
||||
Argument::createIntTypeArgument('depth', PHP_INT_MAX),
|
||||
Argument::createBooleanOrBothTypeArgument('visible', true, false)
|
||||
);
|
||||
}
|
||||
|
||||
public function buildArray()
|
||||
{
|
||||
$id = $this->getFolder();
|
||||
$originalId = $currentId = $this->getFolder();
|
||||
$visible = $this->getVisible();
|
||||
|
||||
$search = FolderQuery::create();
|
||||
|
||||
$this->configureI18nProcessing($search, array('TITLE'));
|
||||
|
||||
$search->filterById($id);
|
||||
if ($visible !== BooleanOrBothType::ANY) {
|
||||
$search->filterByVisible($visible);
|
||||
}
|
||||
|
||||
$depth = $this->getDepth();
|
||||
|
||||
$results = array();
|
||||
|
||||
$ids = array();
|
||||
|
||||
do {
|
||||
$search = FolderQuery::create();
|
||||
|
||||
$this->configureI18nProcessing($search, array('TITLE'));
|
||||
|
||||
$search->filterById($currentId);
|
||||
|
||||
if ($visible !== BooleanOrBothType::ANY) {
|
||||
$search->filterByVisible($visible);
|
||||
}
|
||||
|
||||
$folder = $search->findOne();
|
||||
|
||||
if ($folder != null) {
|
||||
@@ -73,28 +76,25 @@ class FolderPath extends BaseI18nLoop implements ArraySearchLoopInterface
|
||||
"URL" => $folder->getUrl($this->locale),
|
||||
"LOCALE" => $this->locale,
|
||||
);
|
||||
|
||||
$currentId = $folder->getParent();
|
||||
|
||||
$parent = $folder->getParent();
|
||||
|
||||
if ($parent > 0) {
|
||||
if ($currentId > 0) {
|
||||
// Prevent circular refererences
|
||||
if (in_array($parent, $ids)) {
|
||||
throw new \LogicException(sprintf("Circular reference detected in folder ID=%d hierarchy (folder ID=%d appears more than one times in path)", $id, $parent));
|
||||
if (in_array($currentId, $ids)) {
|
||||
throw new \LogicException(
|
||||
sprintf(
|
||||
"Circular reference detected in folder ID=%d hierarchy (folder ID=%d appears more than one times in path)",
|
||||
$originalId,
|
||||
$currentId
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$ids[] = $parent;
|
||||
|
||||
$search = FolderQuery::create();
|
||||
|
||||
$this->configureI18nProcessing($search, array('TITLE'));
|
||||
|
||||
$search->filterById($parent);
|
||||
if ($visible != BooleanOrBothType::ANY) {
|
||||
$search->filterByVisible($visible);
|
||||
}
|
||||
$ids[] = $currentId;
|
||||
}
|
||||
}
|
||||
} while ($folder != null && $parent > 0);
|
||||
} while ($folder != null && $currentId > 0 && --$depth > 0);
|
||||
|
||||
// Reverse list and build the final result
|
||||
return array_reverse($results);
|
||||
|
||||
@@ -47,6 +47,8 @@ use Thelia\Type\TypeCollection;
|
||||
* @method int[] getExclude()
|
||||
* @method bool|string getActive()
|
||||
* @method string[] getOrder()
|
||||
* @method bool|string getMandatory()
|
||||
* @method bool|string getHidden()
|
||||
*/
|
||||
class Module extends BaseI18nLoop implements PropelSearchLoopInterface
|
||||
{
|
||||
@@ -87,24 +89,26 @@ class Module extends BaseI18nLoop implements PropelSearchLoopInterface
|
||||
'order',
|
||||
new TypeCollection(
|
||||
new Type\EnumListType([
|
||||
'id',
|
||||
'id_reverse',
|
||||
'code',
|
||||
'code_reverse',
|
||||
'title',
|
||||
'title_reverse',
|
||||
'type',
|
||||
'type_reverse',
|
||||
'manual',
|
||||
'manual_reverse',
|
||||
'enabled',
|
||||
'enabled_reverse'
|
||||
'id',
|
||||
'id_reverse',
|
||||
'code',
|
||||
'code_reverse',
|
||||
'title',
|
||||
'title_reverse',
|
||||
'type',
|
||||
'type_reverse',
|
||||
'manual',
|
||||
'manual_reverse',
|
||||
'enabled',
|
||||
'enabled_reverse'
|
||||
])
|
||||
),
|
||||
'manual'
|
||||
),
|
||||
Argument::createIntListTypeArgument('exclude'),
|
||||
Argument::createBooleanOrBothTypeArgument('active', Type\BooleanOrBothType::ANY)
|
||||
Argument::createBooleanOrBothTypeArgument('active', Type\BooleanOrBothType::ANY),
|
||||
Argument::createBooleanOrBothTypeArgument('hidden', Type\BooleanOrBothType::ANY),
|
||||
Argument::createBooleanOrBothTypeArgument('mandatory', Type\BooleanOrBothType::ANY)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -169,6 +173,18 @@ class Module extends BaseI18nLoop implements PropelSearchLoopInterface
|
||||
$search->filterByActivate($active ? 1 : 0, Criteria::EQUAL);
|
||||
}
|
||||
|
||||
$hidden = $this->getHidden();
|
||||
|
||||
if ($hidden !== Type\BooleanOrBothType::ANY) {
|
||||
$search->filterByHidden($hidden ? 1 : 0, Criteria::EQUAL);
|
||||
}
|
||||
|
||||
$mandatory = $this->getMandatory();
|
||||
|
||||
if ($mandatory !== Type\BooleanOrBothType::ANY) {
|
||||
$search->filterByMandatory($mandatory ? 1 : 0, Criteria::EQUAL);
|
||||
}
|
||||
|
||||
$orders = $this->getOrder();
|
||||
|
||||
foreach ($orders as $order) {
|
||||
@@ -245,6 +261,8 @@ class Module extends BaseI18nLoop implements PropelSearchLoopInterface
|
||||
->set("VERSION", $module->getVersion())
|
||||
->set("CLASS", $module->getFullNamespace())
|
||||
->set("POSITION", $module->getPosition())
|
||||
->set("MANDATORY", $module->getMandatory())
|
||||
->set("HIDDEN", $module->getHidden())
|
||||
->set("EXISTS", $exists);
|
||||
|
||||
$hasConfigurationInterface = false;
|
||||
|
||||
@@ -93,6 +93,7 @@ class OrderCoupon extends BaseLoop implements PropelSearchLoopInterface
|
||||
|
||||
$loopResultRow->set("ID", $orderCoupon->getId())
|
||||
->set("CODE", $orderCoupon->getCode())
|
||||
->set("DISCOUNT_AMOUNT", $orderCoupon->getAmount())
|
||||
->set("TITLE", $orderCoupon->getTitle())
|
||||
->set("SHORT_DESCRIPTION", $orderCoupon->getShortDescription())
|
||||
->set("DESCRIPTION", $orderCoupon->getDescription())
|
||||
@@ -104,6 +105,7 @@ class OrderCoupon extends BaseLoop implements PropelSearchLoopInterface
|
||||
->set("FREE_SHIPPING_FOR_COUNTRIES_LIST", implode(',', $freeShippingForCountriesIds))
|
||||
->set("FREE_SHIPPING_FOR_MODULES_LIST", implode(',', $freeShippingForModulesIds))
|
||||
->set("PER_CUSTOMER_USAGE_COUNT", $orderCoupon->getPerCustomerUsageCount())
|
||||
->set("IS_USAGE_CANCELED", $orderCoupon->getUsageCanceled())
|
||||
;
|
||||
$this->addOutputFields($loopResultRow, $orderCoupon);
|
||||
|
||||
|
||||
@@ -30,9 +30,11 @@ use Thelia\Model\OrderStatus as OrderStatusModel;
|
||||
* Class OrderStatus
|
||||
* @package Thelia\Core\Template\Loop
|
||||
* @author Etienne Roudeix <eroudeix@openstudio.fr>
|
||||
* @author Gilles Bourgeat <gbourgeat@gmail.com>
|
||||
*
|
||||
* @method int[] getId()
|
||||
* @method string getCode()
|
||||
* @method string[] getOrder()
|
||||
*/
|
||||
class OrderStatus extends BaseI18nLoop implements PropelSearchLoopInterface
|
||||
{
|
||||
@@ -45,7 +47,17 @@ class OrderStatus extends BaseI18nLoop implements PropelSearchLoopInterface
|
||||
{
|
||||
return new ArgumentCollection(
|
||||
Argument::createIntListTypeArgument('id'),
|
||||
Argument::createAnyTypeArgument('code')
|
||||
Argument::createAnyTypeArgument('code'),
|
||||
Argument::createEnumListTypeArgument(
|
||||
'order',
|
||||
[
|
||||
'alpha',
|
||||
'alpha_reverse',
|
||||
'manual',
|
||||
'manual_reverse'
|
||||
],
|
||||
'manual'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -56,18 +68,33 @@ class OrderStatus extends BaseI18nLoop implements PropelSearchLoopInterface
|
||||
/* manage translations */
|
||||
$this->configureI18nProcessing($search);
|
||||
|
||||
$id = $this->getId();
|
||||
|
||||
if (null !== $id) {
|
||||
if (null !== $id = $this->getId()) {
|
||||
$search->filterById($id, Criteria::IN);
|
||||
}
|
||||
|
||||
$code = $this->getCode();
|
||||
|
||||
if (null !== $code) {
|
||||
if (null !== $code = $this->getCode()) {
|
||||
$search->filterByCode($code, Criteria::EQUAL);
|
||||
}
|
||||
|
||||
$orders = $this->getOrder();
|
||||
|
||||
foreach ($orders as $order) {
|
||||
switch ($order) {
|
||||
case "alpha":
|
||||
$search->addAscendingOrderByColumn('i18n_TITLE');
|
||||
break;
|
||||
case "alpha_reverse":
|
||||
$search->addDescendingOrderByColumn('i18n_TITLE');
|
||||
break;
|
||||
case "manual":
|
||||
$search->orderByPosition(Criteria::ASC);
|
||||
break;
|
||||
case "manual_reverse":
|
||||
$search->orderByPosition(Criteria::DESC);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $search;
|
||||
}
|
||||
|
||||
@@ -80,6 +107,9 @@ class OrderStatus extends BaseI18nLoop implements PropelSearchLoopInterface
|
||||
->set("IS_TRANSLATED", $orderStatus->getVirtualColumn('IS_TRANSLATED'))
|
||||
->set("LOCALE", $this->locale)
|
||||
->set("CODE", $orderStatus->getCode())
|
||||
->set("COLOR", $orderStatus->getColor())
|
||||
->set("POSITION", $orderStatus->getPosition())
|
||||
->set("PROTECTED_STATUS", $orderStatus->getProtectedStatus())
|
||||
->set("TITLE", $orderStatus->getVirtualColumn('i18n_TITLE'))
|
||||
->set("CHAPO", $orderStatus->getVirtualColumn('i18n_CHAPO'))
|
||||
->set("DESCRIPTION", $orderStatus->getVirtualColumn('i18n_DESCRIPTION'))
|
||||
|
||||
@@ -19,6 +19,7 @@ use Thelia\Core\Template\Element\LoopResult;
|
||||
use Thelia\Core\Template\Element\LoopResultRow;
|
||||
use Thelia\Core\Template\Element\PropelSearchLoopInterface;
|
||||
use Thelia\Core\Template\Element\SearchLoopInterface;
|
||||
use Thelia\Core\Template\Element\StandardI18nFieldsSearchTrait;
|
||||
use Thelia\Core\Template\Loop\Argument\Argument;
|
||||
use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
|
||||
use Thelia\Exception\TaxEngineException;
|
||||
@@ -26,6 +27,7 @@ use Thelia\Log\Tlog;
|
||||
use Thelia\Model\CategoryQuery;
|
||||
use Thelia\Model\ConfigQuery;
|
||||
use Thelia\Model\CurrencyQuery;
|
||||
use Thelia\Model\Currency as CurrencyModel;
|
||||
use Thelia\Model\Map\ProductPriceTableMap;
|
||||
use Thelia\Model\Map\ProductSaleElementsTableMap;
|
||||
use Thelia\Model\Map\ProductTableMap;
|
||||
@@ -75,12 +77,15 @@ use Thelia\Type\TypeCollection;
|
||||
* @method int[] getFeatureAvailability()
|
||||
* @method string[] getFeatureValues()
|
||||
* @method string[] getAttributeNonStrictMatch()
|
||||
* @method int[] getTemplateId()
|
||||
*/
|
||||
class Product extends BaseI18nLoop implements PropelSearchLoopInterface, SearchLoopInterface
|
||||
{
|
||||
protected $timestampable = true;
|
||||
protected $versionable = true;
|
||||
|
||||
use StandardI18nFieldsSearchTrait;
|
||||
|
||||
/**
|
||||
* @return ArgumentCollection
|
||||
*/
|
||||
@@ -111,6 +116,7 @@ class Product extends BaseI18nLoop implements PropelSearchLoopInterface, SearchL
|
||||
Argument::createBooleanOrBothTypeArgument('visible', 1),
|
||||
Argument::createIntTypeArgument('currency'),
|
||||
Argument::createAnyTypeArgument('title'),
|
||||
Argument::createIntListTypeArgument('template_id'),
|
||||
new Argument(
|
||||
'order',
|
||||
new TypeCollection(
|
||||
@@ -124,6 +130,7 @@ class Product extends BaseI18nLoop implements PropelSearchLoopInterface, SearchL
|
||||
'updated', 'updated_reverse',
|
||||
'ref', 'ref_reverse',
|
||||
'visible', 'visible_reverse',
|
||||
'position', 'position_reverse',
|
||||
'promo',
|
||||
'new',
|
||||
'random',
|
||||
@@ -172,10 +179,10 @@ class Product extends BaseI18nLoop implements PropelSearchLoopInterface, SearchL
|
||||
|
||||
public function getSearchIn()
|
||||
{
|
||||
return [
|
||||
"ref",
|
||||
"title",
|
||||
];
|
||||
return array_merge(
|
||||
[ 'ref' ],
|
||||
$this->getStandardI18nSearchFields()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -187,6 +194,7 @@ class Product extends BaseI18nLoop implements PropelSearchLoopInterface, SearchL
|
||||
public function doSearch(&$search, $searchTerm, $searchIn, $searchCriteria)
|
||||
{
|
||||
$search->_and();
|
||||
|
||||
foreach ($searchIn as $index => $searchInElement) {
|
||||
if ($index > 0) {
|
||||
$search->_or();
|
||||
@@ -195,18 +203,10 @@ class Product extends BaseI18nLoop implements PropelSearchLoopInterface, SearchL
|
||||
case "ref":
|
||||
$search->filterByRef($searchTerm, $searchCriteria);
|
||||
break;
|
||||
case "title":
|
||||
$search->where(
|
||||
"CASE WHEN NOT ISNULL(`requested_locale_i18n`.ID)
|
||||
THEN `requested_locale_i18n`.`TITLE`
|
||||
ELSE `default_locale_i18n`.`TITLE`
|
||||
END ".$searchCriteria." ?",
|
||||
$searchTerm,
|
||||
\PDO::PARAM_STR
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$this->addStandardI18nSearch($search, $searchTerm, $searchCriteria);
|
||||
}
|
||||
|
||||
public function parseResults(LoopResult $loopResult)
|
||||
@@ -232,7 +232,9 @@ class Product extends BaseI18nLoop implements PropelSearchLoopInterface, SearchL
|
||||
|
||||
$price = $product->getVirtualColumn('price');
|
||||
|
||||
if ($securityContext->hasCustomerUser() && $securityContext->getCustomerUser()->getDiscount() > 0) {
|
||||
if (!$this->getBackendContext()
|
||||
&& $securityContext->hasCustomerUser()
|
||||
&& $securityContext->getCustomerUser()->getDiscount() > 0) {
|
||||
$price = $price * (1-($securityContext->getCustomerUser()->getDiscount()/100));
|
||||
}
|
||||
|
||||
@@ -246,7 +248,9 @@ class Product extends BaseI18nLoop implements PropelSearchLoopInterface, SearchL
|
||||
}
|
||||
$promoPrice = $product->getVirtualColumn('promo_price');
|
||||
|
||||
if ($securityContext->hasCustomerUser() && $securityContext->getCustomerUser()->getDiscount() > 0) {
|
||||
if (!$this->getBackendContext()
|
||||
&& $securityContext->hasCustomerUser()
|
||||
&& $securityContext->getCustomerUser()->getDiscount() > 0) {
|
||||
$promoPrice = $promoPrice * (1-($securityContext->getCustomerUser()->getDiscount()/100));
|
||||
}
|
||||
try {
|
||||
@@ -258,7 +262,7 @@ class Product extends BaseI18nLoop implements PropelSearchLoopInterface, SearchL
|
||||
$taxedPromoPrice = null;
|
||||
}
|
||||
|
||||
$default_category_id = $product->getDefaultCategoryId();
|
||||
$defaultCategoryId = $this->getDefaultCategoryId($product);
|
||||
|
||||
$loopResultRow
|
||||
->set("WEIGHT", $product->getVirtualColumn('weight'))
|
||||
@@ -277,9 +281,12 @@ class Product extends BaseI18nLoop implements PropelSearchLoopInterface, SearchL
|
||||
->set("IS_NEW", $product->getVirtualColumn('is_new'))
|
||||
->set("PRODUCT_SALE_ELEMENT", $product->getVirtualColumn('pse_id'))
|
||||
->set("PSE_COUNT", $product->getVirtualColumn('pse_count'));
|
||||
|
||||
$this->associateValues($loopResultRow, $product, $defaultCategoryId);
|
||||
|
||||
$this->addOutputFields($loopResultRow, $product);
|
||||
|
||||
$loopResult->addRow($this->associateValues($loopResultRow, $product, $default_category_id));
|
||||
$loopResult->addRow($loopResultRow);
|
||||
}
|
||||
|
||||
return $loopResult;
|
||||
@@ -311,8 +318,7 @@ class Product extends BaseI18nLoop implements PropelSearchLoopInterface, SearchL
|
||||
$taxedPrice = null;
|
||||
}
|
||||
|
||||
// Find previous and next product, in the default category.
|
||||
$default_category_id = $product->getDefaultCategoryId();
|
||||
$defaultCategoryId = $this->getDefaultCategoryId($product);
|
||||
|
||||
$loopResultRow
|
||||
->set("BEST_PRICE", $price)
|
||||
@@ -321,7 +327,11 @@ class Product extends BaseI18nLoop implements PropelSearchLoopInterface, SearchL
|
||||
->set("IS_PROMO", $product->getVirtualColumn('main_product_is_promo'))
|
||||
->set("IS_NEW", $product->getVirtualColumn('main_product_is_new'));
|
||||
|
||||
$loopResult->addRow($this->associateValues($loopResultRow, $product, $default_category_id));
|
||||
$this->associateValues($loopResultRow, $product, $defaultCategoryId);
|
||||
|
||||
$this->addOutputFields($loopResultRow, $product);
|
||||
|
||||
$loopResult->addRow($loopResultRow);
|
||||
}
|
||||
|
||||
return $loopResult;
|
||||
@@ -330,10 +340,10 @@ class Product extends BaseI18nLoop implements PropelSearchLoopInterface, SearchL
|
||||
/**
|
||||
* @param LoopResultRow $loopResultRow the current result row
|
||||
* @param \Thelia\Model\Product $product
|
||||
* @param $default_category_id
|
||||
* @param $defaultCategoryId
|
||||
* @return mixed
|
||||
*/
|
||||
private function associateValues($loopResultRow, $product, $default_category_id)
|
||||
private function associateValues($loopResultRow, $product, $defaultCategoryId)
|
||||
{
|
||||
$display_initial_price = $product->getVirtualColumn('display_initial_price');
|
||||
|
||||
@@ -358,12 +368,12 @@ class Product extends BaseI18nLoop implements PropelSearchLoopInterface, SearchL
|
||||
->set("VIRTUAL", $product->getVirtual() ? "1" : "0")
|
||||
->set("VISIBLE", $product->getVisible() ? "1" : "0")
|
||||
->set("TEMPLATE", $product->getTemplateId())
|
||||
->set("DEFAULT_CATEGORY", $default_category_id)
|
||||
->set("DEFAULT_CATEGORY", $defaultCategoryId)
|
||||
->set("TAX_RULE_ID", $product->getTaxRuleId())
|
||||
->set("BRAND_ID", $product->getBrandId() ?: 0)
|
||||
->set("SHOW_ORIGINAL_PRICE", $display_initial_price);
|
||||
|
||||
$this->findNextPrev($loopResultRow, $product, $default_category_id);
|
||||
$this->findNextPrev($loopResultRow, $product, $defaultCategoryId);
|
||||
|
||||
return $loopResultRow;
|
||||
}
|
||||
@@ -371,23 +381,23 @@ class Product extends BaseI18nLoop implements PropelSearchLoopInterface, SearchL
|
||||
/**
|
||||
* @param LoopResultRow $loopResultRow
|
||||
* @param ProductModel $product
|
||||
* @param int $defaultFolderId
|
||||
* @param int $defaultCategoryId
|
||||
*/
|
||||
private function findNextPrev(LoopResultRow $loopResultRow, ProductModel $product, $defaultFolderId)
|
||||
private function findNextPrev(LoopResultRow $loopResultRow, ProductModel $product, $defaultCategoryId)
|
||||
{
|
||||
if ($this->getWithPrevNextInfo()) {
|
||||
$currentPosition = ProductCategoryQuery::create()
|
||||
->filterByCategoryId($defaultFolderId)
|
||||
->filterByCategoryId($defaultCategoryId)
|
||||
->filterByProductId($product->getId())
|
||||
->findOne()->getPosition();
|
||||
|
||||
// Find previous and next product
|
||||
$previousQuery = ProductCategoryQuery::create()
|
||||
->filterByCategoryId($defaultFolderId)
|
||||
->filterByCategoryId($defaultCategoryId)
|
||||
->filterByPosition($currentPosition, Criteria::LESS_THAN);
|
||||
|
||||
$nextQuery = ProductCategoryQuery::create()
|
||||
->filterByCategoryId($defaultFolderId)
|
||||
->filterByCategoryId($defaultCategoryId)
|
||||
->filterByPosition($currentPosition, Criteria::GREATER_THAN);
|
||||
|
||||
if (!$this->getBackendContext()) {
|
||||
@@ -500,7 +510,7 @@ class Product extends BaseI18nLoop implements PropelSearchLoopInterface, SearchL
|
||||
$currency = $this->getCurrentRequest()->getSession()->getCurrency();
|
||||
}
|
||||
|
||||
$defaultCurrency = CurrencyQuery::create()->findOneByByDefault(1);
|
||||
$defaultCurrency = CurrencyModel::getDefaultCurrency();
|
||||
$defaultCurrencySuffix = '_default_currency';
|
||||
|
||||
$priceToCompareAsSQL = '';
|
||||
@@ -571,7 +581,13 @@ class Product extends BaseI18nLoop implements PropelSearchLoopInterface, SearchL
|
||||
$title = $this->getTitle();
|
||||
|
||||
if (!is_null($title)) {
|
||||
$search->where("CASE WHEN NOT ISNULL(`requested_locale_i18n`.ID) THEN `requested_locale_i18n`.`TITLE` ELSE `default_locale_i18n`.`TITLE` END ".Criteria::LIKE." ?", "%".$title."%", \PDO::PARAM_STR);
|
||||
$this->addSearchInI18nColumn($search, 'TITLE', Criteria::LIKE, "%".$title."%");
|
||||
}
|
||||
|
||||
$templateIdList = $this->getTemplateId();
|
||||
|
||||
if (!is_null($templateIdList)) {
|
||||
$search->filterByTemplateId($templateIdList, Criteria::IN);
|
||||
}
|
||||
|
||||
$manualOrderAllowed = false;
|
||||
@@ -603,13 +619,17 @@ class Product extends BaseI18nLoop implements PropelSearchLoopInterface, SearchL
|
||||
$manualOrderAllowed = (1 == $depth && 1 == count($categoryIdList));
|
||||
} else {
|
||||
$search
|
||||
->useProductCategoryQuery('CategorySelect')
|
||||
->filterByDefaultCategory(true)
|
||||
->endUse()
|
||||
->leftJoinProductCategory('CategorySelect')
|
||||
->addJoinCondition('CategorySelect', '`CategorySelect`.DEFAULT_CATEGORY = 1')
|
||||
;
|
||||
}
|
||||
|
||||
$search->withColumn('`CategorySelect`.POSITION', 'position_delegate');
|
||||
$search->withColumn(
|
||||
'CASE WHEN ISNULL(`CategorySelect`.POSITION) THEN ' . PHP_INT_MAX . ' ELSE CAST(`CategorySelect`.POSITION as SIGNED) END',
|
||||
'position_delegate'
|
||||
);
|
||||
$search->withColumn('`CategorySelect`.CATEGORY_ID', 'default_category_id');
|
||||
$search->withColumn('`CategorySelect`.DEFAULT_CATEGORY', 'is_default_category');
|
||||
|
||||
$current = $this->getCurrent();
|
||||
|
||||
@@ -1080,6 +1100,12 @@ class Product extends BaseI18nLoop implements PropelSearchLoopInterface, SearchL
|
||||
case "updated_reverse":
|
||||
$search->addDescendingOrderByColumn('updated_at');
|
||||
break;
|
||||
case "position":
|
||||
$search->addAscendingOrderByColumn('position_delegate');
|
||||
break;
|
||||
case "position_reverse":
|
||||
$search->addDescendingOrderByColumn('position_delegate');
|
||||
break;
|
||||
case "given_id":
|
||||
if (null === $id) {
|
||||
throw new \InvalidArgumentException('Given_id order cannot be set without `id` argument');
|
||||
@@ -1099,4 +1125,21 @@ class Product extends BaseI18nLoop implements PropelSearchLoopInterface, SearchL
|
||||
|
||||
return $search;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default category id for a product
|
||||
*
|
||||
* @param \Thelia\Model\Product $product
|
||||
* @return null|int
|
||||
*/
|
||||
protected function getDefaultCategoryId($product)
|
||||
{
|
||||
$defaultCategoryId = null;
|
||||
if ((bool) $product->getVirtualColumn('is_default_category')) {
|
||||
$defaultCategoryId = $product->getVirtualColumn('default_category_id');
|
||||
} else {
|
||||
$defaultCategoryId = $product->getDefaultCategoryId();
|
||||
}
|
||||
return $defaultCategoryId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ use Thelia\Core\Template\Loop\Argument\Argument;
|
||||
use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
|
||||
use Thelia\Exception\TaxEngineException;
|
||||
use Thelia\Model\CurrencyQuery;
|
||||
use Thelia\Model\Currency as CurrencyModel;
|
||||
use Thelia\Model\Map\ProductSaleElementsTableMap;
|
||||
use Thelia\Model\ProductSaleElementsQuery;
|
||||
use Thelia\Type;
|
||||
@@ -150,7 +151,7 @@ class ProductSaleElements extends BaseLoop implements PropelSearchLoopInterface,
|
||||
$search->orderByQuantity(Criteria::DESC);
|
||||
break;
|
||||
case "min_price":
|
||||
$search->addAscendingOrderByColumn('price_FINAL_PRICE', Criteria::ASC);
|
||||
$search->addAscendingOrderByColumn('price_FINAL_PRICE');
|
||||
break;
|
||||
case "max_price":
|
||||
$search->addDescendingOrderByColumn('price_FINAL_PRICE');
|
||||
@@ -184,7 +185,7 @@ class ProductSaleElements extends BaseLoop implements PropelSearchLoopInterface,
|
||||
$currency = $this->getCurrentRequest()->getSession()->getCurrency();
|
||||
}
|
||||
|
||||
$defaultCurrency = CurrencyQuery::create()->findOneByByDefault(1);
|
||||
$defaultCurrency = CurrencyModel::getDefaultCurrency();
|
||||
$defaultCurrencySuffix = '_default_currency';
|
||||
|
||||
$search->joinProductPrice('price', Criteria::LEFT_JOIN)
|
||||
@@ -275,11 +276,32 @@ class ProductSaleElements extends BaseLoop implements PropelSearchLoopInterface,
|
||||
{
|
||||
return [
|
||||
"ref",
|
||||
"ean_code"
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ProductSaleElementsQuery $search
|
||||
* @param $searchTerm
|
||||
* @param $searchIn
|
||||
* @param $searchCriteria
|
||||
*/
|
||||
public function doSearch(&$search, $searchTerm, $searchIn, $searchCriteria)
|
||||
{
|
||||
$search->filterByRef($searchTerm, $searchCriteria);
|
||||
$search->_and();
|
||||
|
||||
foreach ($searchIn as $index => $searchInElement) {
|
||||
if ($index > 0) {
|
||||
$search->_or();
|
||||
}
|
||||
switch ($searchInElement) {
|
||||
case "ref":
|
||||
$search->filterByRef($searchTerm, $searchCriteria);
|
||||
break;
|
||||
case "ean_code":
|
||||
$search->filterByEanCode($searchTerm, $searchCriteria);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ use Thelia\Core\Template\Element\LoopResult;
|
||||
use Thelia\Core\Template\Element\LoopResultRow;
|
||||
use Thelia\Core\Template\Element\PropelSearchLoopInterface;
|
||||
use Thelia\Core\Template\Element\SearchLoopInterface;
|
||||
use Thelia\Core\Template\Element\StandardI18nFieldsSearchTrait;
|
||||
use Thelia\Core\Template\Loop\Argument\Argument;
|
||||
use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
|
||||
use Thelia\Model\SaleQuery;
|
||||
@@ -42,6 +43,8 @@ use Thelia\Type\BooleanOrBothType;
|
||||
*/
|
||||
class Sale extends BaseI18nLoop implements PropelSearchLoopInterface, SearchLoopInterface
|
||||
{
|
||||
use StandardI18nFieldsSearchTrait;
|
||||
|
||||
protected $timestampable = true;
|
||||
|
||||
/**
|
||||
@@ -89,17 +92,34 @@ class Sale extends BaseI18nLoop implements PropelSearchLoopInterface, SearchLoop
|
||||
*/
|
||||
public function getSearchIn()
|
||||
{
|
||||
return [
|
||||
"title"
|
||||
];
|
||||
return array_merge(
|
||||
[ "sale_label" ],
|
||||
$this->getStandardI18nSearchFields()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param SaleQuery $search
|
||||
* @param string $searchTerm
|
||||
* @param array $searchIn
|
||||
* @param string $searchCriteria
|
||||
*/
|
||||
public function doSearch(&$search, $searchTerm, $searchIn, $searchCriteria)
|
||||
{
|
||||
/** @var SaleQuery $search */
|
||||
$search->_and();
|
||||
|
||||
$search->where("CASE WHEN NOT ISNULL(`requested_locale_i18n`.ID) THEN `requested_locale_i18n`.`TITLE` ELSE `default_locale_i18n`.`TITLE` END ".$searchCriteria." ?", $searchTerm, \PDO::PARAM_STR);
|
||||
|
||||
foreach ($searchIn as $index => $searchInElement) {
|
||||
if ($index > 0) {
|
||||
$search->_or();
|
||||
}
|
||||
switch ($searchInElement) {
|
||||
case "sale_label":
|
||||
$this->addSearchInI18nColumn($search, 'SALE_LABEL', $searchCriteria, $searchTerm);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$this->addStandardI18nSearch($search, $searchTerm, $searchCriteria);
|
||||
}
|
||||
|
||||
public function buildModelCriteria()
|
||||
|
||||
@@ -133,6 +133,28 @@ class ParserContext implements \IteratorAggregate
|
||||
{
|
||||
$formErrorInformation = $this->getSession()->getFormErrorInformation();
|
||||
|
||||
// Get form field error details
|
||||
$formFieldErrors = [];
|
||||
|
||||
/** @var Form $field */
|
||||
foreach ($form->getForm()->getIterator() as $field) {
|
||||
$errors = $field->getErrors();
|
||||
|
||||
if (count($errors) > 0) {
|
||||
$formFieldErrors[$field->getName()] = [];
|
||||
|
||||
/** @var FormError $error */
|
||||
foreach ($errors as $error) {
|
||||
$formFieldErrors[$field->getName()][] = [
|
||||
'message' => $error->getMessage(),
|
||||
'template' => $error->getMessageTemplate(),
|
||||
'parameters' => $error->getMessageParameters(),
|
||||
'pluralization' => $error->getMessagePluralization()
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->set(get_class($form) . ":" . $form->getType(), $form);
|
||||
|
||||
// Set form error information
|
||||
@@ -142,7 +164,8 @@ class ParserContext implements \IteratorAggregate
|
||||
'errorMessage' => $form->getErrorMessage(),
|
||||
'method' => $this->requestStack->getCurrentRequest()->getMethod(),
|
||||
'timestamp' => time(),
|
||||
'validation_groups' => $form->getForm()->getConfig()->getOption('validation_groups')
|
||||
'validation_groups' => $form->getForm()->getConfig()->getOption('validation_groups'),
|
||||
'field_errors' => $formFieldErrors
|
||||
];
|
||||
|
||||
$this->getSession()->setFormErrorInformation($formErrorInformation);
|
||||
@@ -189,6 +212,26 @@ class ParserContext implements \IteratorAggregate
|
||||
} catch (\Exception $ex) {
|
||||
// Ignore the exception.
|
||||
}
|
||||
|
||||
// Manually set the form fields error information, if validateForm() did not the job,
|
||||
// which is the case when the user has been redirected.
|
||||
foreach ($formInfo['field_errors'] as $fieldName => $errors) {
|
||||
/** @var Form $field */
|
||||
$field = $form->getForm()->get($fieldName);
|
||||
|
||||
if (null !== $field && count($field->getErrors()) == 0) {
|
||||
foreach ($errors as $errorData) {
|
||||
$error = new FormError(
|
||||
$errorData['message'],
|
||||
$errorData['template'],
|
||||
$errorData['parameters'],
|
||||
$errorData['pluralization']
|
||||
);
|
||||
|
||||
$field->addError($error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$form->setError($formInfo['hasError']);
|
||||
|
||||
@@ -50,7 +50,7 @@ use Thelia\Model\ModuleQuery;
|
||||
|
||||
class Thelia extends Kernel
|
||||
{
|
||||
const THELIA_VERSION = '2.3.1';
|
||||
const THELIA_VERSION = '2.3.4';
|
||||
|
||||
public function __construct($environment, $debug)
|
||||
{
|
||||
@@ -136,6 +136,15 @@ class Thelia extends Kernel
|
||||
$canUpdate = true;
|
||||
Tlog::getInstance()->addWarning("Remove sql_mode ONLY_FULL_GROUP_BY. Please configure your MySQL server.");
|
||||
}
|
||||
|
||||
// remove STRICT_ALL_TABLES, the scheme has been fixed in version 2.4 of Thelia
|
||||
if (version_compare(Thelia::THELIA_VERSION, '2.4', '<')) {
|
||||
if (($key = array_search('STRICT_ALL_TABLES', $sessionSqlMode)) !== false) {
|
||||
unset($sessionSqlMode[$key]);
|
||||
$canUpdate = true;
|
||||
Tlog::getInstance()->addWarning("Remove sql_mode STRICT_ALL_TABLES. Please configure your MySQL server or update your Thelia on version 2.4 or higher.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -85,7 +85,6 @@ class CouponFactory
|
||||
|
||||
// Check coupon usage count
|
||||
if (! $couponModel->isUsageUnlimited()) {
|
||||
|
||||
if (null === $customer = $this->facade->getCustomer()) {
|
||||
throw new UnmatchableConditionException($couponCode);
|
||||
}
|
||||
|
||||
@@ -219,13 +219,10 @@ class CouponManager
|
||||
|
||||
/** @var CouponInterface $coupon */
|
||||
foreach ($coupons as $coupon) {
|
||||
|
||||
try {
|
||||
|
||||
if ($coupon->isMatching()) {
|
||||
$couponsKept[] = $coupon;
|
||||
}
|
||||
|
||||
} catch (UnmatchableConditionException $e) {
|
||||
// ignore unmatchable coupon
|
||||
continue;
|
||||
@@ -319,10 +316,8 @@ class CouponManager
|
||||
public function decrementQuantity(Coupon $coupon, $customerId = null)
|
||||
{
|
||||
if ($coupon->isUsageUnlimited()) {
|
||||
$ret = true;
|
||||
return true;
|
||||
} else {
|
||||
$ret = false;
|
||||
|
||||
try {
|
||||
$usageLeft = $coupon->getUsagesLeft($customerId);
|
||||
|
||||
@@ -355,15 +350,13 @@ class CouponManager
|
||||
->save()
|
||||
;
|
||||
|
||||
$ret = $usageLeft - $newCount;
|
||||
return $usageLeft - $newCount;
|
||||
} else {
|
||||
$usageLeft--;
|
||||
|
||||
$coupon->setMaxUsage($usageLeft);
|
||||
$coupon->setMaxUsage(--$usageLeft);
|
||||
|
||||
$coupon->save();
|
||||
|
||||
$ret = $usageLeft;
|
||||
return $usageLeft;
|
||||
}
|
||||
}
|
||||
} catch (\Exception $ex) {
|
||||
@@ -372,6 +365,58 @@ class CouponManager
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a coupon usage, for the case the related order is canceled.
|
||||
*
|
||||
* @param Coupon $coupon
|
||||
* @param int $customerId
|
||||
*/
|
||||
public function incrementQuantity(Coupon $coupon, $customerId = null)
|
||||
{
|
||||
if ($coupon->isUsageUnlimited()) {
|
||||
return true;
|
||||
} else {
|
||||
try {
|
||||
$usageLeft = $coupon->getUsagesLeft($customerId);
|
||||
|
||||
// If the coupon usage is per user, remove an entry from coupon customer usage count table
|
||||
if ($coupon->getPerCustomerUsageCount()) {
|
||||
if (null === $customerId) {
|
||||
throw new \LogicException("Customer should not be null at this time.");
|
||||
}
|
||||
|
||||
$ccc = CouponCustomerCountQuery::create()
|
||||
->filterByCouponId($coupon->getId())
|
||||
->filterByCustomerId($customerId)
|
||||
->findOne()
|
||||
;
|
||||
|
||||
if ($ccc !== null && $ccc->getCount() > 0) {
|
||||
$newCount = $ccc->getCount() - 1;
|
||||
|
||||
$ccc
|
||||
->setCount($newCount)
|
||||
->save();
|
||||
|
||||
return $usageLeft - $newCount;
|
||||
}
|
||||
} else {
|
||||
// Ad one usage to coupon
|
||||
$coupon->setMaxUsage(++$usageLeft);
|
||||
|
||||
$coupon->save();
|
||||
|
||||
return $usageLeft;
|
||||
}
|
||||
} catch (\Exception $ex) {
|
||||
// Just log the problem.
|
||||
Tlog::getInstance()->addError(sprintf("Failed to increment coupon %s: %s", $coupon->getCode(), $ex->getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ namespace Thelia\Coupon\Type;
|
||||
|
||||
use Thelia\Coupon\FacadeInterface;
|
||||
use Thelia\Model\CartItem;
|
||||
use Thelia\Model\Category;
|
||||
|
||||
/**
|
||||
* Allow to remove an amount from the checkout total
|
||||
@@ -27,7 +26,7 @@ abstract class AbstractRemove extends CouponAbstract implements AmountAndPercent
|
||||
/**
|
||||
* Set the value of specific coupon fields.
|
||||
*
|
||||
* @param Array $effects the Coupon effects params
|
||||
* @param array $effects the Coupon effects params
|
||||
*/
|
||||
abstract public function setFieldsValue($effects);
|
||||
|
||||
@@ -81,35 +80,6 @@ abstract class AbstractRemove extends CouponAbstract implements AmountAndPercent
|
||||
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function exec()
|
||||
{
|
||||
// This coupon subtracts the specified amount from the order total
|
||||
// for each product of the selected categories.
|
||||
$discount = 0;
|
||||
|
||||
$cartItems = $this->facade->getCart()->getCartItems();
|
||||
|
||||
/** @var CartItem $cartItem */
|
||||
foreach ($cartItems as $cartItem) {
|
||||
if (! $cartItem->getPromo() || $this->isAvailableOnSpecialOffers()) {
|
||||
$categories = $cartItem->getProduct()->getCategories();
|
||||
|
||||
/** @var Category $category */
|
||||
foreach ($categories as $category) {
|
||||
if (in_array($category->getId(), $this->category_list)) {
|
||||
$discount += $this->getCartItemDiscount($cartItem);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $discount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
|
||||
@@ -33,7 +33,7 @@ abstract class AbstractRemoveOnAttributeValues extends CouponAbstract implements
|
||||
|
||||
/**
|
||||
* Set the value of specific coupon fields.
|
||||
* @param Array $effects the Coupon effects params
|
||||
* @param array $effects the Coupon effects params
|
||||
*/
|
||||
abstract public function setFieldsValue($effects);
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace Thelia\Coupon\Type;
|
||||
use Thelia\Core\Translation\Translator;
|
||||
use Thelia\Coupon\FacadeInterface;
|
||||
use Thelia\Model\CartItem;
|
||||
use Thelia\Model\Category;
|
||||
|
||||
/**
|
||||
* Allow to remove an amount from the checkout total
|
||||
@@ -31,7 +32,7 @@ abstract class AbstractRemoveOnCategories extends CouponAbstract implements Amou
|
||||
/**
|
||||
* Set the value of specific coupon fields.
|
||||
*
|
||||
* @param Array $effects the Coupon effects params
|
||||
* @param array $effects the Coupon effects params
|
||||
*/
|
||||
abstract public function setFieldsValue($effects);
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user