Oubli dans la MAJ en 2.3.4 --> à vérifier s'il n'y a pas d'autres oublis

This commit is contained in:
2020-05-03 23:44:13 +02:00
parent 315320df7c
commit 28b21af6c8
8 changed files with 285 additions and 17 deletions

View File

@@ -114,6 +114,7 @@
<argument type="service" id="thelia.taxEngine" /> <argument type="service" id="thelia.taxEngine" />
<argument type="service" id="thelia.parser.context"/> <argument type="service" id="thelia.parser.context"/>
<argument type="service" id="event_dispatcher"/> <argument type="service" id="event_dispatcher"/>
<argument type="service" id="thelia.coupon.manager"/>
</service> </service>
<service id="smarty.plugin.adminUtilities" class="TheliaSmarty\Template\Plugins\AdminUtilities"> <service id="smarty.plugin.adminUtilities" class="TheliaSmarty\Template\Plugins\AdminUtilities">
@@ -139,6 +140,13 @@
<tag name="thelia.parser.register_plugin"/> <tag name="thelia.parser.register_plugin"/>
<argument type="service" id="event_dispatcher"/> <argument type="service" id="event_dispatcher"/>
</service> </service>
<service id="smarty.plugin.cache" class="TheliaSmarty\Template\Plugins\Cache">
<argument type="service" id="thelia.cache"/>
<argument type="service" id="request_stack"/>
<argument>%kernel.debug%</argument>
<tag name="thelia.parser.register_plugin"/>
</service>
</services> </services>
</config> </config>

View File

@@ -1,5 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<module> <module xmlns="http://thelia.net/schema/dic/module"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://thelia.net/schema/dic/module http://thelia.net/schema/dic/module/module-2_2.xsd">
<fullnamespace>TheliaSmarty\TheliaSmarty</fullnamespace> <fullnamespace>TheliaSmarty\TheliaSmarty</fullnamespace>
<descriptive locale="en_US"> <descriptive locale="en_US">
<title>Smarty template engine integration</title> <title>Smarty template engine integration</title>
@@ -7,12 +9,20 @@
<descriptive locale="fr_FR"> <descriptive locale="fr_FR">
<title>Intégration du moteur de template Smarty</title> <title>Intégration du moteur de template Smarty</title>
</descriptive> </descriptive>
<version>2.3.1</version> <languages>
<language>en_US</language>
<language>fr_FR</language>
</languages>
<version>2.3.4</version>
<authors>
<author> <author>
<name>Manuel Raynaud</name> <name>Manuel Raynaud</name>
<email>manu@raynaud.io</email> <email>manu@raynaud.io</email>
</author> </author>
</authors>
<type>classic</type> <type>classic</type>
<thelia>2.2.0</thelia> <thelia>2.2.0</thelia>
<stability>alpha</stability> <stability>alpha</stability>
<mandatory>1</mandatory>
<hidden>1</hidden>
</module> </module>

View File

@@ -54,6 +54,17 @@ class AdminUtilities extends AbstractSmartyPlugin
return $data; return $data;
} }
public function optionOffsetGenerator($params, &$smarty)
{
$label = $this->getParam($params, 'label', null);
if (null !== $level = $this->getParam($params, [ 'l', 'level'], null)) {
$label = str_repeat('&nbsp;', 4 * $level) . $label;
}
return $label;
}
public function generatePositionChangeBlock($params, &$smarty) public function generatePositionChangeBlock($params, &$smarty)
{ {
// The required permissions // The required permissions
@@ -155,6 +166,7 @@ class AdminUtilities extends AbstractSmartyPlugin
return array( return array(
new SmartyPluginDescriptor('function', 'admin_sortable_header', $this, 'generateSortableColumnHeader'), new SmartyPluginDescriptor('function', 'admin_sortable_header', $this, 'generateSortableColumnHeader'),
new SmartyPluginDescriptor('function', 'admin_position_block', $this, 'generatePositionChangeBlock'), new SmartyPluginDescriptor('function', 'admin_position_block', $this, 'generatePositionChangeBlock'),
new SmartyPluginDescriptor('function', 'option_offset', $this, 'optionOffsetGenerator'),
); );
} }
} }

View File

@@ -20,6 +20,8 @@ use Thelia\Core\HttpFoundation\Request;
use Thelia\Core\HttpFoundation\Session\Session; use Thelia\Core\HttpFoundation\Session\Session;
use Thelia\Core\Security\SecurityContext; use Thelia\Core\Security\SecurityContext;
use Thelia\Core\Template\ParserContext; use Thelia\Core\Template\ParserContext;
use Thelia\Coupon\CouponManager;
use Thelia\Coupon\Type\CouponInterface;
use Thelia\Log\Tlog; use Thelia\Log\Tlog;
use Thelia\Model\Base\BrandQuery; use Thelia\Model\Base\BrandQuery;
use Thelia\Model\Cart; use Thelia\Model\Cart;
@@ -33,6 +35,7 @@ use Thelia\Model\FolderQuery;
use Thelia\Model\MetaDataQuery; use Thelia\Model\MetaDataQuery;
use Thelia\Model\ModuleConfigQuery; use Thelia\Model\ModuleConfigQuery;
use Thelia\Model\ModuleQuery; use Thelia\Model\ModuleQuery;
use Thelia\Model\Order;
use Thelia\Model\OrderQuery; use Thelia\Model\OrderQuery;
use Thelia\Model\ProductQuery; use Thelia\Model\ProductQuery;
use Thelia\Model\Tools\ModelCriteriaTools; use Thelia\Model\Tools\ModelCriteriaTools;
@@ -40,6 +43,8 @@ use Thelia\TaxEngine\TaxEngine;
use Thelia\Tools\DateTimeFormat; use Thelia\Tools\DateTimeFormat;
use TheliaSmarty\Template\AbstractSmartyPlugin; use TheliaSmarty\Template\AbstractSmartyPlugin;
use TheliaSmarty\Template\SmartyPluginDescriptor; use TheliaSmarty\Template\SmartyPluginDescriptor;
use Thelia\Core\Event\Image\ImageEvent;
use Thelia\Core\Event\TheliaEvents;
/** /**
* Implementation of data access to main Thelia objects (users, cart, etc.) * Implementation of data access to main Thelia objects (users, cart, etc.)
@@ -64,6 +69,9 @@ class DataAccessFunctions extends AbstractSmartyPlugin
/** @var TaxEngine */ /** @var TaxEngine */
protected $taxEngine; protected $taxEngine;
/** @var CouponManager */
protected $couponManager;
private static $dataAccessCache = array(); private static $dataAccessCache = array();
public function __construct( public function __construct(
@@ -71,13 +79,15 @@ class DataAccessFunctions extends AbstractSmartyPlugin
SecurityContext $securityContext, SecurityContext $securityContext,
TaxEngine $taxEngine, TaxEngine $taxEngine,
ParserContext $parserContext, ParserContext $parserContext,
EventDispatcherInterface $dispatcher EventDispatcherInterface $dispatcher,
CouponManager $couponManager
) { ) {
$this->securityContext = $securityContext; $this->securityContext = $securityContext;
$this->parserContext = $parserContext; $this->parserContext = $parserContext;
$this->requestStack = $requestStack; $this->requestStack = $requestStack;
$this->dispatcher = $dispatcher; $this->dispatcher = $dispatcher;
$this->taxEngine = $taxEngine; $this->taxEngine = $taxEngine;
$this->couponManager = $couponManager;
} }
/** /**
@@ -306,6 +316,14 @@ class DataAccessFunctions extends AbstractSmartyPlugin
self::$dataAccessCache['currentCountry'] = $taxCountry; self::$dataAccessCache['currentCountry'] = $taxCountry;
} }
/** @var State $taxState */
if (array_key_exists('currentState', self::$dataAccessCache)) {
$taxState = self::$dataAccessCache['currentState'];
} else {
$taxState = $this->taxEngine->getDeliveryState();
self::$dataAccessCache['currentState'] = $taxState;
}
/** @var Cart $cart */ /** @var Cart $cart */
$cart = $this->getSession()->getSessionCart($this->dispatcher); $cart = $this->getSession()->getSessionCart($this->dispatcher);
@@ -325,17 +343,17 @@ class DataAccessFunctions extends AbstractSmartyPlugin
break; break;
case "total_price": case "total_price":
case "total_price_with_discount": case "total_price_with_discount":
$result = $cart->getTotalAmount(); $result = $cart->getTotalAmount(true);
break; break;
case "total_price_without_discount": case "total_price_without_discount":
$result = $cart->getTotalAmount(false); $result = $cart->getTotalAmount(false);
break; break;
case "total_taxed_price": case "total_taxed_price":
case "total_taxed_price_with_discount": case "total_taxed_price_with_discount":
$result = $cart->getTaxedAmount($taxCountry); $result = $cart->getTaxedAmount($taxCountry, true, $taxState);
break; break;
case "total_taxed_price_without_discount": case "total_taxed_price_without_discount":
$result = $cart->getTaxedAmount($taxCountry, false); $result = $cart->getTaxedAmount($taxCountry, false, $taxState);
break; break;
case "is_virtual": case "is_virtual":
case "contains_virtual_product": case "contains_virtual_product":
@@ -353,6 +371,31 @@ class DataAccessFunctions extends AbstractSmartyPlugin
return $result; return $result;
} }
public function couponDataAccess($params, &$smarty)
{
/** @var Order $order */
$order = $this->getSession()->getOrder();
$attribute = $this->getNormalizedParam($params, array('attribute', 'attrib', 'attr'));
switch ($attribute) {
case 'has_coupons':
return count($this->couponManager->getCouponsKept()) > 0;
case 'coupon_count':
return count($this->couponManager->getCouponsKept());
case 'coupon_list':
$orderCoupons = [];
/** @var CouponInterface $coupon */
foreach($this->couponManager->getCouponsKept() as $coupon) {
$orderCoupons[] = $coupon->getCode();
}
return $orderCoupons;
case 'is_delivery_free':
return $this->couponManager->isCouponRemovingPostage($order);
}
throw new \InvalidArgumentException(sprintf("%s has no '%s' attribute", 'Order', $attribute));
}
/** /**
* Provides access to an attribute of the current order * Provides access to an attribute of the current order
* *
@@ -362,6 +405,7 @@ class DataAccessFunctions extends AbstractSmartyPlugin
*/ */
public function orderDataAccess($params, &$smarty) public function orderDataAccess($params, &$smarty)
{ {
/** @var Order $order */
$order = $this->getSession()->getOrder(); $order = $this->getSession()->getOrder();
$attribute = $this->getNormalizedParam($params, array('attribute', 'attrib', 'attr')); $attribute = $this->getNormalizedParam($params, array('attribute', 'attrib', 'attr'));
switch ($attribute) { switch ($attribute) {
@@ -743,6 +787,134 @@ class DataAccessFunctions extends AbstractSmartyPlugin
return $return; return $return;
} }
/**
* Provides access to the uploaded store-related images (such as logo or favicon)
*
* @param array $params
* @param string $content
* @param \Smarty_Internal_Template $template
* @param boolean $repeat
* @return string|null
*/
public function storeMediaDataAccess($params, $content, \Smarty_Internal_Template $template, &$repeat)
{
$type = $this->getParam($params, 'type', null);
$allowedTypes = ['favicon', 'logo', 'banner'];
if ($type !== null && in_array($type, $allowedTypes)) {
switch ($type) {
case 'favicon':
$configKey = 'favicon_file';
$defaultImageName = 'favicon.png';
break;
case 'logo':
$configKey = 'logo_file';
$defaultImageName = 'logo.png';
break;
case 'banner':
$configKey = 'banner_file';
$defaultImageName = 'banner.jpg';
break;
}
$uploadDir = ConfigQuery::read('images_library_path');
if ($uploadDir === null) {
$uploadDir = THELIA_LOCAL_DIR . 'media' . DS . 'images';
} else {
$uploadDir = THELIA_ROOT . $uploadDir;
}
$uploadDir .= DS . 'store';
$imageFileName = ConfigQuery::read($configKey);
$skipImageTransform = false;
// If we couldn't find the image path in the config table or if it doesn't exist, we take the default image provided.
if ($imageFileName == null) {
$imageSourcePath = $uploadDir . DS . $defaultImageName;
} else {
$imageSourcePath = $uploadDir . DS . $imageFileName;
if (!file_exists($imageSourcePath)) {
Tlog::getInstance()->error(sprintf('Source image file %s does not exists.', $imageSourcePath));
$imageSourcePath = $uploadDir . DS . $defaultImageName;
}
if ($type == 'favicon') {
$extension = pathinfo($imageSourcePath, PATHINFO_EXTENSION);
if ($extension == 'ico') {
$mime_type = 'image/x-icon';
// If the media is a .ico favicon file, we skip the image transformations,
// as transformations on .ico file are not supported by Thelia.
$skipImageTransform = true;
} else {
$mime_type = 'image/png';
}
$template->assign('MEDIA_MIME_TYPE', $mime_type);
}
}
$event = new ImageEvent();
$event->setSourceFilepath($imageSourcePath)
->setCacheSubdirectory('store');
if (!$skipImageTransform) {
switch ($this->getParam($params, 'resize_mode', null)) {
case 'crop':
$resize_mode = \Thelia\Action\Image::EXACT_RATIO_WITH_CROP;
break;
case 'borders':
$resize_mode = \Thelia\Action\Image::EXACT_RATIO_WITH_BORDERS;
break;
case 'none':
default:
$resize_mode = \Thelia\Action\Image::KEEP_IMAGE_RATIO;
}
// Prepare transformations
$width = $this->getParam($params, 'width', null);
$height = $this->getParam($params, 'height', null);
$rotation = $this->getParam($params, 'rotation', null);
if (!is_null($width)) {
$event->setWidth($width);
}
if (!is_null($height)) {
$event->setHeight($height);
}
$event->setResizeMode($resize_mode);
if (!is_null($rotation)) {
$event->setRotation($rotation);
}
}
$this->dispatcher->dispatch(TheliaEvents::IMAGE_PROCESS, $event);
$template->assign('MEDIA_URL', $event->getFileUrl());
}
if (isset($content)) {
return $content;
}
return null;
}
/** /**
* @inheritdoc * @inheritdoc
*/ */
@@ -765,6 +937,9 @@ class DataAccessFunctions extends AbstractSmartyPlugin
new SmartyPluginDescriptor('function', 'stats', $this, 'statsAccess'), new SmartyPluginDescriptor('function', 'stats', $this, 'statsAccess'),
new SmartyPluginDescriptor('function', 'meta', $this, 'metaAccess'), new SmartyPluginDescriptor('function', 'meta', $this, 'metaAccess'),
new SmartyPluginDescriptor('function', 'module_config', $this, 'moduleConfigDataAccess'), new SmartyPluginDescriptor('function', 'module_config', $this, 'moduleConfigDataAccess'),
new SmartyPluginDescriptor('function', 'coupon', $this, 'couponDataAccess'),
new SmartyPluginDescriptor('block', 'local_media', $this, 'storeMediaDataAccess'),
); );
} }

View File

@@ -185,10 +185,10 @@ class Form extends AbstractSmartyPlugin
/** @var FormErrorIterator $errors */ /** @var FormErrorIterator $errors */
$errors = $fieldVars["errors"]; $errors = $fieldVars["errors"];
if ($errors) {
$template->assign("error", $errors->count() ? true : false); $template->assign("error", $errors->count() ? true : false);
$this->assignFieldErrorVars($template, $errors); $this->assignFieldErrorVars($template, $errors);
}
$attr = array(); $attr = array();

View File

@@ -151,7 +151,9 @@ class TheliaLoop extends AbstractSmartyPlugin
self::$pagination[$name] = null; self::$pagination[$name] = null;
$loopResults = $loop->exec(self::$pagination[$name]); // We have to clone the result, as exec() returns a cached LoopResult object, which may cause side effects
// if loops with the same argument set are nested (see https://github.com/thelia/thelia/issues/2213)
$loopResults = clone($loop->exec(self::$pagination[$name]));
$loopResults->rewind(); $loopResults->rewind();

View File

@@ -22,6 +22,9 @@ use TheliaSmarty\Template\AbstractSmartyPlugin;
use Thelia\Tools\TokenProvider; use Thelia\Tools\TokenProvider;
use Thelia\Tools\URL; use Thelia\Tools\URL;
use Thelia\Core\HttpFoundation\Request; use Thelia\Core\HttpFoundation\Request;
use Thelia\Model\RewritingUrlQuery;
use Thelia\Model\LangQuery;
use Thelia\Model\ConfigQuery;
class UrlGenerator extends AbstractSmartyPlugin class UrlGenerator extends AbstractSmartyPlugin
{ {
@@ -119,6 +122,35 @@ class UrlGenerator extends AbstractSmartyPlugin
$this->getArgsFromParam($params, array_merge(['noamp', 'path', 'file', 'target'], $excludeParams)), $this->getArgsFromParam($params, array_merge(['noamp', 'path', 'file', 'target'], $excludeParams)),
$mode $mode
); );
$request = $this->getRequest();
$requestedLangCodeOrLocale = $params["lang"];
$view = $request->attributes->get('_view', null);
$viewId = $view === null ? null : $request->query->get($view . '_id', null);
if (null !== $requestedLangCodeOrLocale) {
if (strlen($requestedLangCodeOrLocale) > 2) {
$lang = LangQuery::create()->findOneByLocale($requestedLangCodeOrLocale);
} else {
$lang = LangQuery::create()->findOneByCode($requestedLangCodeOrLocale);
}
if (ConfigQuery::isMultiDomainActivated()) {
$urlRewrite = RewritingUrlQuery::create()
->filterByView($view)
->filterByViewId($viewId)
->filterByViewLocale($lang->getLocale())
->findOneByRedirected(null)
;
$path = '';
if (null != $urlRewrite) {
$path = "/".$urlRewrite->getUrl();
}
$url = rtrim($lang->getUrl(), "/").$request->getBaseUrl().$path;
}
}
} }
return $this->applyNoAmpAndTarget($params, $url); return $this->applyNoAmpAndTarget($params, $url);
} }

View File

@@ -16,6 +16,7 @@ use \Smarty;
use \Symfony\Component\HttpFoundation\Request; use \Symfony\Component\HttpFoundation\Request;
use \Symfony\Component\EventDispatcher\EventDispatcherInterface; use \Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\RequestStack;
use Thelia\Core\HttpFoundation\Session\Session;
use Thelia\Core\Template\ParserInterface; use Thelia\Core\Template\ParserInterface;
use Thelia\Core\Template\Exception\ResourceNotFoundException; use Thelia\Core\Template\Exception\ResourceNotFoundException;
use Thelia\Core\Template\ParserContext; use Thelia\Core\Template\ParserContext;
@@ -25,6 +26,7 @@ use Imagine\Exception\InvalidArgumentException;
use Thelia\Core\Translation\Translator; use Thelia\Core\Translation\Translator;
use Thelia\Log\Tlog; use Thelia\Log\Tlog;
use Thelia\Model\ConfigQuery; use Thelia\Model\ConfigQuery;
use Thelia\Model\Lang;
/** /**
* *
@@ -58,6 +60,12 @@ class SmartyParser extends Smarty implements ParserInterface
/** @var int */ /** @var int */
protected $status = 200; protected $status = 200;
/** @var string */
protected $env;
/** @var bool */
protected $debug;
/** /**
* @param RequestStack $requestStack * @param RequestStack $requestStack
* @param EventDispatcherInterface $dispatcher * @param EventDispatcherInterface $dispatcher
@@ -80,15 +88,17 @@ class SmartyParser extends Smarty implements ParserInterface
$this->dispatcher = $dispatcher; $this->dispatcher = $dispatcher;
$this->parserContext = $parserContext; $this->parserContext = $parserContext;
$this->templateHelper = $templateHelper; $this->templateHelper = $templateHelper;
$this->env = $env;
$this->debug = $debug;
// Configure basic Smarty parameters // Configure basic Smarty parameters
$compile_dir = THELIA_ROOT . 'cache'. DS . $env . DS . 'smarty'.DS.'compile'; $compile_dir = THELIA_ROOT . 'cache'. DS . $env . DS . 'smarty' . DS . 'compile';
if (! is_dir($compile_dir)) { if (! is_dir($compile_dir)) {
@mkdir($compile_dir, 0777, true); @mkdir($compile_dir, 0777, true);
} }
$cache_dir = THELIA_ROOT . 'cache'. DS . $env . DS . 'smarty'.DS.'cache'; $cache_dir = THELIA_ROOT . 'cache'. DS . $env . DS . 'smarty' . DS . 'cache';
if (! is_dir($cache_dir)) { if (! is_dir($cache_dir)) {
@mkdir($cache_dir, 0777, true); @mkdir($cache_dir, 0777, true);
} }
@@ -392,6 +402,25 @@ class SmartyParser extends Smarty implements ParserInterface
throw new ResourceNotFoundException(Translator::getInstance()->trans("Template file %file cannot be found.", array('%file' => $realTemplateName))); throw new ResourceNotFoundException(Translator::getInstance()->trans("Template file %file cannot be found.", array('%file' => $realTemplateName)));
} }
// Prepare common template variables
/** @var Session $session */
$session = $this->getRequest()->getSession();
$lang = $session ? $session->getLang() : Lang::getDefaultLanguage();
$parameters = array_merge($parameters, [
'locale' => $lang->getLocale(),
'lang_code' => $lang->getCode(),
'lang_id' => $lang->getId(),
'current_url' => $this->getRequest()->getUri(),
'app' => (object) [
'environment' => $this->env,
'request' => $this->getRequest(),
'session' => $session,
'debug' => $this->debug
]
]);
return $this->internalRenderer('file', $realTemplateName, $parameters, $compressOutput); return $this->internalRenderer('file', $realTemplateName, $parameters, $compressOutput);
} }