Initial Commit
This commit is contained in:
40
local/modules/TheliaSmarty/CREDITS.md
Normal file
40
local/modules/TheliaSmarty/CREDITS.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# Credits
|
||||
|
||||
## Yii framework
|
||||
|
||||
TheliaSmarty module uses a function that comes from [Yii framework](http://www.yiiframework.com/)
|
||||
|
||||
License :
|
||||
|
||||
The Yii framework is free software. It is released under the terms of
|
||||
the following BSD License.
|
||||
|
||||
Copyright © 2008 by Yii Software LLC (http://www.yiisoft.com)
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Yii Software LLC nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace TheliaSmarty\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* Register parser plugins. These plugins shouild be tagged thelia.parser.register_plugin
|
||||
* in the configuration.
|
||||
*
|
||||
* @author Manuel Raynaud <manu@raynaud.io>
|
||||
*/
|
||||
class RegisterParserPluginPass implements CompilerPassInterface
|
||||
{
|
||||
/**
|
||||
* You can modify the container here before it is dumped to PHP code.
|
||||
*
|
||||
* @param ContainerBuilder $container
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
if (!$container->hasDefinition("thelia.parser")) {
|
||||
return;
|
||||
}
|
||||
|
||||
$smarty = $container->getDefinition("thelia.parser");
|
||||
|
||||
foreach ($container->findTaggedServiceIds("thelia.parser.register_plugin") as $id => $plugin) {
|
||||
$smarty->addMethodCall("addPlugins", array(new Reference($id)));
|
||||
}
|
||||
|
||||
$smarty->addMethodCall("registerPlugins");
|
||||
}
|
||||
}
|
||||
144
local/modules/TheliaSmarty/Config/config.xml
Normal file
144
local/modules/TheliaSmarty/Config/config.xml
Normal file
@@ -0,0 +1,144 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<config xmlns="http://thelia.net/schema/dic/config"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://thelia.net/schema/dic/config http://thelia.net/schema/dic/config/thelia-1.0.xsd">
|
||||
|
||||
|
||||
<services>
|
||||
<!-- Parser context -->
|
||||
|
||||
|
||||
|
||||
<!-- Parser configuration -->
|
||||
|
||||
<service id="thelia.parser" class="TheliaSmarty\Template\SmartyParser">
|
||||
<argument type="service" id="request_stack" />
|
||||
<argument type="service" id="event_dispatcher"/>
|
||||
<argument type="service" id="thelia.parser.context"/>
|
||||
<argument type="service" id="thelia.template_helper"/>
|
||||
<argument >%kernel.environment%</argument>
|
||||
<argument >%kernel.debug%</argument>
|
||||
</service>
|
||||
|
||||
<service id="thelia.parser.helper" class="TheliaSmarty\Template\SmartyHelper" />
|
||||
|
||||
<!-- URL maganement -->
|
||||
|
||||
|
||||
|
||||
<!-- The assets resolver -->
|
||||
<service id="thelia.parser.asset.resolver" class="TheliaSmarty\Template\Assets\SmartyAssetsResolver" >
|
||||
<argument type="service" id="assetic.asset.manager" />
|
||||
</service>
|
||||
|
||||
<!-- Smarty parser plugins -->
|
||||
|
||||
<service id="smarty.plugin.assets" class="TheliaSmarty\Template\Plugins\Assets" >
|
||||
<tag name="thelia.parser.register_plugin"/>
|
||||
|
||||
<argument type="service" id="assetic.asset.manager" />
|
||||
<argument type="service" id="thelia.parser.asset.resolver" />
|
||||
</service>
|
||||
|
||||
<service id="smarty.plugin.format" class="TheliaSmarty\Template\Plugins\Format">
|
||||
<argument type="service" id="request_stack"/>
|
||||
<tag name="thelia.parser.register_plugin"/>
|
||||
</service>
|
||||
|
||||
<service id="smarty.plugin.thelialoop" class="TheliaSmarty\Template\Plugins\TheliaLoop">
|
||||
<tag name="thelia.parser.register_plugin"/>
|
||||
<argument type="service" id="service_container" />
|
||||
<call method="setLoopList">
|
||||
<argument>%thelia.parser.loops%</argument>
|
||||
</call>
|
||||
</service>
|
||||
|
||||
<service id="smarty.plugin.cartpostage" class="TheliaSmarty\Template\Plugins\CartPostage">
|
||||
<tag name="thelia.parser.register_plugin"/>
|
||||
<argument type="service" id="service_container" />
|
||||
</service>
|
||||
|
||||
<service id="smarty.plugin.type" class="TheliaSmarty\Template\Plugins\Type">
|
||||
<tag name="thelia.parser.register_plugin"/>
|
||||
</service>
|
||||
|
||||
<service id="smarty.plugin.render" class="TheliaSmarty\Template\Plugins\Render">
|
||||
<argument type="service" id="controller_resolver" />
|
||||
<argument type="service" id="request_stack" />
|
||||
<argument type="service" id="service_container" />
|
||||
<tag name="thelia.parser.register_plugin"/>
|
||||
</service>
|
||||
|
||||
<service id="smart.plugin.form" class="TheliaSmarty\Template\Plugins\Form">
|
||||
<tag name="thelia.parser.register_plugin"/>
|
||||
|
||||
<argument type="service" id="thelia.form_factory" />
|
||||
<argument type="service" id="thelia.parser.context"/>
|
||||
<argument type="service" id="thelia.parser"/>
|
||||
|
||||
<call method="setFormDefinition">
|
||||
<argument>%thelia.parser.forms%</argument>
|
||||
</call>
|
||||
</service>
|
||||
|
||||
<service id="smarty.plugin.translation" class="TheliaSmarty\Template\Plugins\Translation" >
|
||||
<tag name="thelia.parser.register_plugin"/>
|
||||
<argument type="service" id="thelia.translator" />
|
||||
</service>
|
||||
|
||||
<service id="smarty.plugin.module" class="TheliaSmarty\Template\Plugins\Module">
|
||||
<argument>%kernel.debug%</argument>
|
||||
<argument type="service" id="request_stack"/>
|
||||
<tag name="thelia.parser.register_plugin"/>
|
||||
</service>
|
||||
|
||||
<service id="smarty.url.module" class="TheliaSmarty\Template\Plugins\UrlGenerator">
|
||||
<tag name="thelia.parser.register_plugin"/>
|
||||
<argument type="service" id="request_stack"/>
|
||||
<argument type="service" id="thelia.token_provider"/>
|
||||
<argument type="service" id="service_container" />
|
||||
</service>
|
||||
|
||||
<service id="smarty.plugin.security" class="TheliaSmarty\Template\Plugins\Security">
|
||||
<tag name="thelia.parser.register_plugin"/>
|
||||
<argument type="service" id="request_stack" />
|
||||
<argument type="service" id="event_dispatcher"/>
|
||||
<argument type="service" id="thelia.securityContext" />
|
||||
</service>
|
||||
|
||||
<service id="smarty.plugin.dataAccess" class="TheliaSmarty\Template\Plugins\DataAccessFunctions">
|
||||
<tag name="thelia.parser.register_plugin"/>
|
||||
<argument type="service" id="request_stack" />
|
||||
<argument type="service" id="thelia.securityContext" />
|
||||
<argument type="service" id="thelia.taxEngine" />
|
||||
<argument type="service" id="thelia.parser.context"/>
|
||||
<argument type="service" id="event_dispatcher"/>
|
||||
</service>
|
||||
|
||||
<service id="smarty.plugin.adminUtilities" class="TheliaSmarty\Template\Plugins\AdminUtilities">
|
||||
<tag name="thelia.parser.register_plugin"/>
|
||||
<argument type="service" id="thelia.securityContext" />
|
||||
<argument type="service" id="thelia.template_helper" />
|
||||
</service>
|
||||
|
||||
<service id="smarty.plugin.flashMessage" class="TheliaSmarty\Template\Plugins\FlashMessage">
|
||||
<tag name="thelia.parser.register_plugin"/>
|
||||
<argument type="service" id="request_stack" />
|
||||
<argument type="service" id="thelia.translator" />
|
||||
</service>
|
||||
|
||||
<service id="smarty.plugin.esi" class="TheliaSmarty\Template\Plugins\Esi">
|
||||
<tag name="thelia.parser.register_plugin"/>
|
||||
<argument type="service" id="fragment.renderer.esi" />
|
||||
<argument type="service" id="request_stack" />
|
||||
</service>
|
||||
|
||||
<service id="smarty.plugin.hook" class="TheliaSmarty\Template\Plugins\Hook">
|
||||
<argument>%kernel.debug%</argument>
|
||||
<tag name="thelia.parser.register_plugin"/>
|
||||
<argument type="service" id="event_dispatcher"/>
|
||||
</service>
|
||||
</services>
|
||||
|
||||
</config>
|
||||
18
local/modules/TheliaSmarty/Config/module.xml
Normal file
18
local/modules/TheliaSmarty/Config/module.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module>
|
||||
<fullnamespace>TheliaSmarty\TheliaSmarty</fullnamespace>
|
||||
<descriptive locale="en_US">
|
||||
<title>Smarty template engine integration</title>
|
||||
</descriptive>
|
||||
<descriptive locale="fr_FR">
|
||||
<title>Intégration du moteur de template Smarty</title>
|
||||
</descriptive>
|
||||
<version>2.3.1</version>
|
||||
<author>
|
||||
<name>Manuel Raynaud</name>
|
||||
<email>manu@raynaud.io</email>
|
||||
</author>
|
||||
<type>classic</type>
|
||||
<thelia>2.2.0</thelia>
|
||||
<stability>alpha</stability>
|
||||
</module>
|
||||
21
local/modules/TheliaSmarty/I18n/en_US.php
Normal file
21
local/modules/TheliaSmarty/I18n/en_US.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
'\'%type\' loop class should extends Thelia\Core\Template\Element\BaseLoop' => '\'%type\' loop class should extends Thelia\Core\Template\Element\BaseLoop',
|
||||
'A loop named \'%name\' already exists in the current scope.' => 'A loop named \'%name\' already exists in the current scope.',
|
||||
'Loop type \'%type\' is not defined.' => 'Loop type \'%type\' is not defined.',
|
||||
'Missing \'name\' parameter in loop arguments' => 'Missing \'name\' parameter in loop arguments',
|
||||
'Missing \'rel\' parameter in forHook arguments' => 'Missing \'rel\' parameter in forHook arguments',
|
||||
'Missing \'rel\' parameter in ifhook/elsehook arguments' => 'Missing \'rel\' parameter in ifhook/elsehook arguments',
|
||||
'Missing \'rel\' parameter in ifloop/elseloop arguments' => 'Missing \'rel\' parameter in ifloop/elseloop arguments',
|
||||
'Missing \'rel\' parameter in page loop' => 'Missing \'rel\' parameter in page loop',
|
||||
'Missing \'type\' parameter in loop arguments' => 'Missing \'type\' parameter in loop arguments',
|
||||
'Missing \'type\' parameter in {count} loop arguments' => 'Missing \'type\' parameter in {count} loop arguments',
|
||||
'Missing \'type\' parameter in {hasflash} function arguments' => 'Missing \'type\' parameter in {hasflash} function arguments',
|
||||
'No pagination currently defined for loop name \'%name\'' => 'No pagination currently defined for loop name \'%name\'',
|
||||
'Please specify either \'path\' or \'file\' parameter in {url} function.' => 'Please specify either \'path\' or \'file\' parameter in {url} function.',
|
||||
'Related hook name \'%name\' is not defined.' => 'Related hook name \'%name\' is not defined.',
|
||||
'Related loop name \'%name\'\' is not defined.' => 'Related loop name \'%name\'\' is not defined.',
|
||||
'Template file %file cannot be found.' => 'Template file %file cannot be found.',
|
||||
'The loop name \'%name\' is already defined in %className class' => 'The loop name \'%name\' is already defined in %className class',
|
||||
);
|
||||
21
local/modules/TheliaSmarty/I18n/fr_FR.php
Normal file
21
local/modules/TheliaSmarty/I18n/fr_FR.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'\'%type\' loop class should extends Thelia\Core\Template\Element\BaseLoop' => 'La loop "%type" doit étendre la class Thelia\Core\Template\Element\BaseLoop',
|
||||
'A loop named \'%name\' already exists in the current scope.' => 'une loop avec comme nom \'%name\' existe déjà dans le scope courant',
|
||||
'Loop type \'%type\' is not defined.' => 'La loop de type "%type" n\'est pas défini',
|
||||
'Missing \'name\' parameter in loop arguments' => 'Le paramètre \'name\' est manquant dans la liste des arguments',
|
||||
'Missing \'rel\' parameter in forHook arguments' => 'Le paramètre \'rel\' est manquant dans les arguments de forHook',
|
||||
'Missing \'rel\' parameter in ifhook/elsehook arguments' => 'Le paramètre \'rel\' est manquant des arguments ifhook/elsehook',
|
||||
'Missing \'rel\' parameter in ifloop/elseloop arguments' => 'Paramètre \'rel\' manquant dans la liste des arguments d\'une loop ifloop/elseloop',
|
||||
'Missing \'rel\' parameter in page loop' => 'Paramètre \'rel\' manquant dans la loop page',
|
||||
'Missing \'type\' parameter in loop arguments' => 'Le paramètre \'type\' est manquant dans la liste des arguments',
|
||||
'Missing \'type\' parameter in {count} loop arguments' => 'Le paramètre \'type\' dans la loop {count} est manquant',
|
||||
'Missing \'type\' parameter in {hasflash} function arguments' => 'Le paramètre \'type\' est manquant dans',
|
||||
'No pagination currently defined for loop name \'%name\'' => 'Il n\'y a pas de pagination définie pour la loop \'%name\'',
|
||||
'Please specify either \'path\' or \'file\' parameter in {url} function.' => 'Merci de spécifier le \'path\' ou le \'file\'.parameter dans la fonction {url}',
|
||||
'Related hook name \'%name\' is not defined.' => 'le hook ayat pour nom "%name" n\'est pas défini',
|
||||
'Related loop name \'%name\'\' is not defined.' => 'La loop ayant pour nom "%name" n\'est pas défini',
|
||||
'Template file %file cannot be found.' => 'Le fichier %s ne semble pas présent',
|
||||
'The loop name \'%name\' is already defined in %className class' => 'La loop "%name" est déjà définie dans la class %className',
|
||||
];
|
||||
21
local/modules/TheliaSmarty/I18n/tr_TR.php
Normal file
21
local/modules/TheliaSmarty/I18n/tr_TR.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'\'%type\' loop class should extends Thelia\Core\Template\Element\BaseLoop' => '\'%type\' döngü sınıfını genişleten Thelia\Core\Template\Element\BaseLoop',
|
||||
'A loop named \'%name\' already exists in the current scope.' => '\'%name\' adlı bir döngü geçerli etki alanında bulunmaktadır.',
|
||||
'Loop type \'%type\' is not defined.' => 'Döngü türü \'%type\' tanımlı değil.',
|
||||
'Missing \'name\' parameter in loop arguments' => 'Döngü değişkenlerde \'ad\' parametresi eksik',
|
||||
'Missing \'rel\' parameter in forHook arguments' => 'ForHook değişkenlerde \'rel\' parametresi eksik',
|
||||
'Missing \'rel\' parameter in ifhook/elsehook arguments' => 'İfhook/elsehook bağımsız değişkenleri \'rel\' parametresi eksik',
|
||||
'Missing \'rel\' parameter in ifloop/elseloop arguments' => 'İfloop/elseloop bağımsız değişkenleri \'rel\' parametresi eksik',
|
||||
'Missing \'rel\' parameter in page loop' => 'Sayfa döngü içinde \'rel\' parametresi eksik',
|
||||
'Missing \'type\' parameter in loop arguments' => '\'Tür\' parametresinde döngü bağımsız değişkenleri eksik',
|
||||
'Missing \'type\' parameter in {count} loop arguments' => '{count} döngü değişkenlerde \'type\' parametresi eksik',
|
||||
'Missing \'type\' parameter in {hasflash} function arguments' => '\'Tür\' parametresinde {hasflash} fonksiyon bağımsız değişkenleri eksik',
|
||||
'No pagination currently defined for loop name \'%name\'' => 'Şu anda döngü adı \'%name\' tanımlı hiçbir pagination',
|
||||
'Please specify either \'path\' or \'file\' parameter in {url} function.' => 'Lütfen \'yol\' ya da \'dosya\' parametre {url} işlevinde belirtin.',
|
||||
'Related hook name \'%name\' is not defined.' => 'İlgili kanca adı \'%name\' tanımlı değil.',
|
||||
'Related loop name \'%name\'\' is not defined.' => 'İlgili kanca adı \'%name\' tanımlı değil.',
|
||||
'Template file %file cannot be found.' => 'Şablon dosyası %file bulunamadı.',
|
||||
'The loop name \'%name\' is already defined in %className class' => 'Döngü adı \'%name\' zaten %className sınıfında tanımlanmış',
|
||||
];
|
||||
165
local/modules/TheliaSmarty/LICENSE.txt
Normal file
165
local/modules/TheliaSmarty/LICENSE.txt
Normal file
@@ -0,0 +1,165 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
2
local/modules/TheliaSmarty/Readme.md
Normal file
2
local/modules/TheliaSmarty/Readme.md
Normal file
@@ -0,0 +1,2 @@
|
||||
## Smarty for Thelia
|
||||
|
||||
97
local/modules/TheliaSmarty/Template/AbstractSmartyPlugin.php
Normal file
97
local/modules/TheliaSmarty/Template/AbstractSmartyPlugin.php
Normal file
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace TheliaSmarty\Template;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* The class all Smarty Thelia plugin shoud extend
|
||||
*
|
||||
* Class AbstractSmartyPlugin
|
||||
* @package Thelia\Core\Template\Smarty
|
||||
*/
|
||||
abstract class AbstractSmartyPlugin
|
||||
{
|
||||
/**
|
||||
* Explode a comma separated list in a array, trimming all array elements
|
||||
*
|
||||
* @param mixed $commaSeparatedValues
|
||||
* @return mixed:
|
||||
*/
|
||||
protected function explode($commaSeparatedValues)
|
||||
{
|
||||
if (null === $commaSeparatedValues) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$array = explode(',', $commaSeparatedValues);
|
||||
|
||||
if (array_walk(
|
||||
$array,
|
||||
function (&$item) {
|
||||
$item = strtoupper(trim($item));
|
||||
}
|
||||
)) {
|
||||
return $array;
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a function or block parameter value, and normalize it, trimming balnks and
|
||||
* making it lowercase
|
||||
*
|
||||
* @param array $params the parameters array
|
||||
* @param mixed $name as single parameter name, or an array of names. In this case, the first defined parameter is returned. Use this for aliases (context, ctx, c)
|
||||
* @param mixed $default the defaut value if parameter is missing (default to null)
|
||||
* @return mixed the parameter value, or the default value if it is not found.
|
||||
*/
|
||||
public function getNormalizedParam($params, $name, $default = null)
|
||||
{
|
||||
$value = $this->getParam($params, $name, $default);
|
||||
|
||||
if (is_string($value)) {
|
||||
$value = strtolower(trim($value));
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a function or block parameter value
|
||||
*
|
||||
* @param array $params the parameters array
|
||||
* @param mixed $name as single parameter name, or an array of names. In this case, the first defined parameter is returned. Use this for aliases (context, ctx, c)
|
||||
* @param mixed $default the defaut value if parameter is missing (default to null)
|
||||
* @return mixed the parameter value, or the default value if it is not found.
|
||||
*/
|
||||
public function getParam($params, $name, $default = null)
|
||||
{
|
||||
if (is_array($name)) {
|
||||
foreach ($name as $test) {
|
||||
if (isset($params[$test])) {
|
||||
return $params[$test];
|
||||
}
|
||||
}
|
||||
} elseif (isset($params[$name])) {
|
||||
return $params[$name];
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SmartyPluginDescriptor[] an array of SmartyPluginDescriptor
|
||||
*/
|
||||
abstract public function getPluginDescriptors();
|
||||
}
|
||||
@@ -0,0 +1,268 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace TheliaSmarty\Template\Assets;
|
||||
|
||||
use Thelia\Core\Template\Assets\AssetManagerInterface;
|
||||
use Thelia\Core\Template\Assets\AssetResolverInterface;
|
||||
use Thelia\Exception\TheliaProcessException;
|
||||
use TheliaSmarty\Template\SmartyParser;
|
||||
use Thelia\Core\Template\TemplateDefinition;
|
||||
use Thelia\Log\Tlog;
|
||||
|
||||
class SmartyAssetsManager
|
||||
{
|
||||
const ASSET_TYPE_AUTO = '';
|
||||
|
||||
private $assetsManager;
|
||||
private $assetsResolver;
|
||||
|
||||
private $web_root;
|
||||
private $path_relative_to_web_root;
|
||||
|
||||
private static $assetsDirectory = null;
|
||||
|
||||
/**
|
||||
* Creates a new SmartyAssetsManager instance
|
||||
*
|
||||
* @param AssetManagerInterface $assetsManager an asset manager instance
|
||||
* @param AssetResolverInterface $assetsResolver an asset resolver instance
|
||||
* @param string $web_root the disk path to the web root (with final /)
|
||||
* @param string $path_relative_to_web_root the path (relative to web root) where the assets will be generated
|
||||
*/
|
||||
public function __construct(
|
||||
AssetManagerInterface $assetsManager,
|
||||
AssetResolverInterface $assetsResolver,
|
||||
$web_root,
|
||||
$path_relative_to_web_root
|
||||
) {
|
||||
$this->web_root = $web_root;
|
||||
$this->path_relative_to_web_root = $path_relative_to_web_root;
|
||||
|
||||
$this->assetsManager = $assetsManager;
|
||||
$this->assetsResolver = $assetsResolver;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prepare current template assets
|
||||
*
|
||||
* @param string $assets_directory the assets directory in the template
|
||||
* @param \Smarty_Internal_Template $smarty the smarty parser
|
||||
*/
|
||||
public function prepareAssets($assets_directory, \Smarty_Internal_Template $smarty)
|
||||
{
|
||||
// Be sure to use the proper path separator
|
||||
if (DS != '/') {
|
||||
$assets_directory = str_replace('/', DS, $assets_directory);
|
||||
}
|
||||
|
||||
// Set the current template assets directory
|
||||
self::$assetsDirectory = $assets_directory;
|
||||
|
||||
/** @var SmartyParser $smartyParser */
|
||||
$smartyParser = $smarty->smarty;
|
||||
|
||||
$this->prepareTemplateAssets($smartyParser->getTemplateDefinition(), $assets_directory, $smartyParser);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare template assets
|
||||
*
|
||||
* @param TemplateDefinition $templateDefinition the template to process
|
||||
* @param string $assets_directory the assets directory in the template
|
||||
* @param \TheliaSmarty\Template\SmartyParser $smartyParser the current parser.
|
||||
*/
|
||||
protected function prepareTemplateAssets(
|
||||
TemplateDefinition $templateDefinition,
|
||||
$assets_directory,
|
||||
SmartyParser $smartyParser
|
||||
) {
|
||||
// Get the registered template directories for the current template path
|
||||
$templateDirectories = $smartyParser->getTemplateDirectories($templateDefinition->getType());
|
||||
|
||||
if (isset($templateDirectories[$templateDefinition->getName()])) {
|
||||
/* create assets foreach registered directory : main @ modules */
|
||||
foreach ($templateDirectories[$templateDefinition->getName()] as $key => $directory) {
|
||||
// This is the assets directory in the template's tree
|
||||
$tpl_path = $directory . DS . $assets_directory;
|
||||
|
||||
$asset_dir_absolute_path = realpath($tpl_path);
|
||||
|
||||
if (false !== $asset_dir_absolute_path) {
|
||||
// If we're processing template assets (not module assets),
|
||||
// we will use the $assets_directory as the assets parent dir.
|
||||
if (SmartyParser::TEMPLATE_ASSETS_KEY == $key && ! null !== $assets_directory) {
|
||||
$assetsWebDir = SmartyParser::TEMPLATE_ASSETS_KEY . DS . $assets_directory;
|
||||
} else {
|
||||
$assetsWebDir = $key;
|
||||
}
|
||||
|
||||
Tlog::getInstance()->addDebug(
|
||||
"Preparing assets: source assets directory $asset_dir_absolute_path, "
|
||||
. "web assets dir base: " . $this->web_root . $this->path_relative_to_web_root . ", "
|
||||
. "template: ".$templateDefinition->getPath().", "
|
||||
. "web asset key: $assetsWebDir (key=$key)"
|
||||
);
|
||||
|
||||
$this->assetsManager->prepareAssets(
|
||||
$asset_dir_absolute_path,
|
||||
$this->web_root . $this->path_relative_to_web_root,
|
||||
$templateDefinition->getPath(),
|
||||
$key . DS . $assets_directory
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve asset URL
|
||||
*
|
||||
* @param string $assetType js|css|image
|
||||
* @param array $params Parameters
|
||||
* - file File path in the default template
|
||||
* - source module asset
|
||||
* - filters filter to apply
|
||||
* - debug
|
||||
* - template if you want to load asset from another template
|
||||
* @param \Smarty_Internal_Template $template Smarty Template
|
||||
*
|
||||
* @param bool $allowFilters if false, the 'filters' parameter is ignored
|
||||
* @return string
|
||||
*/
|
||||
public function computeAssetUrl($assetType, $params, \Smarty_Internal_Template $template, $allowFilters = true)
|
||||
{
|
||||
$assetUrl = "";
|
||||
|
||||
$file = $params['file'];
|
||||
|
||||
// The 'file' parameter is mandatory
|
||||
if (empty($file)) {
|
||||
throw new \InvalidArgumentException(
|
||||
"The 'file' parameter is missing in an asset directive (type is '$assetType')"
|
||||
);
|
||||
}
|
||||
|
||||
$assetOrigin = isset($params['source']) ? $params['source'] : SmartyParser::TEMPLATE_ASSETS_KEY;
|
||||
$filters = $allowFilters && isset($params['filters']) ? $params['filters'] : '';
|
||||
$debug = isset($params['debug']) ? trim(strtolower($params['debug'])) == 'true' : false;
|
||||
$templateName = isset($params['template']) ? $params['template'] : false;
|
||||
$failsafe = isset($params['failsafe']) ? $params['failsafe'] : false;
|
||||
|
||||
Tlog::getInstance()->debug("Searching asset $file in source $assetOrigin, with template $templateName");
|
||||
|
||||
/** @var \TheliaSmarty\Template\SmartyParser $smartyParser */
|
||||
$smartyParser = $template->smarty;
|
||||
|
||||
if (false !== $templateName) {
|
||||
// We have to be sure that this external template assets have been properly prepared.
|
||||
// We will assume the following:
|
||||
// 1) this template have the same type as the current template,
|
||||
// 2) this template assets have the same structure as the current template
|
||||
// (which is in self::$assetsDirectory)
|
||||
$currentTemplate = $smartyParser->getTemplateDefinition();
|
||||
|
||||
$templateDefinition = new TemplateDefinition(
|
||||
$templateName,
|
||||
$currentTemplate->getType()
|
||||
);
|
||||
|
||||
/* Add this templates directory to the current list */
|
||||
$smartyParser->addTemplateDirectory(
|
||||
$templateDefinition->getType(),
|
||||
$templateDefinition->getName(),
|
||||
THELIA_TEMPLATE_DIR . $templateDefinition->getPath(),
|
||||
SmartyParser::TEMPLATE_ASSETS_KEY
|
||||
);
|
||||
|
||||
$this->prepareTemplateAssets($templateDefinition, self::$assetsDirectory, $smartyParser);
|
||||
}
|
||||
|
||||
$assetSource = $this->assetsResolver->resolveAssetSourcePath($assetOrigin, $templateName, $file, $smartyParser);
|
||||
|
||||
if (null !== $assetSource) {
|
||||
$assetUrl = $this->assetsResolver->resolveAssetURL(
|
||||
$assetOrigin,
|
||||
$file,
|
||||
$assetType,
|
||||
$smartyParser,
|
||||
$filters,
|
||||
$debug,
|
||||
self::$assetsDirectory,
|
||||
$templateName
|
||||
);
|
||||
} else {
|
||||
// Log the problem
|
||||
if ($failsafe) {
|
||||
// The asset URL will be ''
|
||||
Tlog::getInstance()->addWarning("Failed to find asset source file " . $params['file']);
|
||||
} else {
|
||||
throw new TheliaProcessException("Failed to find asset source file " . $params['file']);
|
||||
}
|
||||
}
|
||||
|
||||
return $assetUrl;
|
||||
}
|
||||
|
||||
public function processSmartyPluginCall(
|
||||
$assetType,
|
||||
$params,
|
||||
$content,
|
||||
\Smarty_Internal_Template $template,
|
||||
&$repeat
|
||||
) {
|
||||
// Opening tag (first call only)
|
||||
if ($repeat) {
|
||||
$isfailsafe = false;
|
||||
|
||||
$url = '';
|
||||
try {
|
||||
// Check if we're in failsafe mode
|
||||
if (isset($params['failsafe'])) {
|
||||
$isfailsafe = $params['failsafe'];
|
||||
}
|
||||
|
||||
$url = $this->computeAssetUrl($assetType, $params, $template);
|
||||
|
||||
if (empty($url)) {
|
||||
$message = sprintf("Failed to get real path of asset %s without exception", $params['file']);
|
||||
|
||||
Tlog::getInstance()->addWarning($message);
|
||||
|
||||
// In debug mode, throw exception
|
||||
if ($this->assetsManager->isDebugMode() && ! $isfailsafe) {
|
||||
throw new TheliaProcessException($message);
|
||||
}
|
||||
}
|
||||
} catch (\Exception $ex) {
|
||||
Tlog::getInstance()->addWarning(
|
||||
sprintf(
|
||||
"Failed to get real path of asset %s with exception: %s",
|
||||
$params['file'],
|
||||
$ex->getMessage()
|
||||
)
|
||||
);
|
||||
|
||||
// If we're in development mode, just retrow the exception, so that it will be displayed
|
||||
if ($this->assetsManager->isDebugMode() && ! $isfailsafe) {
|
||||
throw $ex;
|
||||
}
|
||||
}
|
||||
$template->assign('asset_url', $url);
|
||||
} elseif (isset($content)) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace TheliaSmarty\Template\Assets;
|
||||
|
||||
use Thelia\Core\Template\Assets\AssetManagerInterface;
|
||||
use Thelia\Core\Template\Assets\AssetResolverInterface;
|
||||
use Thelia\Core\Template\ParserInterface;
|
||||
use TheliaSmarty\Template\SmartyParser;
|
||||
use Thelia\Core\Template\TemplateDefinition;
|
||||
use Thelia\Log\Tlog;
|
||||
use Thelia\Model\ConfigQuery;
|
||||
use Thelia\Tools\URL;
|
||||
|
||||
class SmartyAssetsResolver implements AssetResolverInterface
|
||||
{
|
||||
private $path_relative_to_web_root;
|
||||
|
||||
private $assetsManager;
|
||||
|
||||
/**
|
||||
* Creates a new SmartyAssetsManager instance
|
||||
*
|
||||
* @param AssetManagerInterface $assetsManager an asset manager instance
|
||||
*/
|
||||
public function __construct(AssetManagerInterface $assetsManager)
|
||||
{
|
||||
$this->path_relative_to_web_root = ConfigQuery::read('asset_dir_from_web_root', 'assets');
|
||||
|
||||
$this->assetsManager = $assetsManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an asset URL
|
||||
*
|
||||
* @param string $source a module code, or SmartyParser::TEMPLATE_ASSETS_KEY
|
||||
* @param string $file the file path, relative to a template base directory (e.g. assets/css/style.css)
|
||||
* @param string $type the asset type, either 'css' or '
|
||||
* @param ParserInterface $parserInterface the current template parser
|
||||
* @param array $filters the filters to pass to the asset manager
|
||||
* @param bool $debug the debug mode
|
||||
* @param string $declaredAssetsDirectory if not null, this is the assets directory declared in the {declare_assets} function of a template.
|
||||
* @param mixed $sourceTemplateName A template name, of false. If provided, the assets will be searched in this template directory instead of the current one.
|
||||
* @return mixed
|
||||
*/
|
||||
public function resolveAssetURL($source, $file, $type, ParserInterface $parserInterface, $filters = [], $debug = false, $declaredAssetsDirectory = null, $sourceTemplateName = false)
|
||||
{
|
||||
$url = "";
|
||||
|
||||
// Normalize path separator
|
||||
$file = $this->fixPathSeparator($file);
|
||||
|
||||
$fileRoot = $this->resolveAssetSourcePath($source, $sourceTemplateName, $file, $parserInterface);
|
||||
|
||||
if (null !== $fileRoot) {
|
||||
$templateDefinition = $parserInterface->getTemplateDefinition($sourceTemplateName);
|
||||
|
||||
$url = $this->assetsManager->processAsset(
|
||||
$fileRoot . DS . $file,
|
||||
$fileRoot,
|
||||
THELIA_WEB_DIR . $this->path_relative_to_web_root,
|
||||
$templateDefinition->getPath(),
|
||||
$source, // $this->getBaseWebAssetDirectory($source, $declaredAssetsDirectory),
|
||||
URL::getInstance()->absoluteUrl($this->path_relative_to_web_root, null, URL::PATH_TO_FILE /* path only */),
|
||||
$type,
|
||||
$filters,
|
||||
$debug
|
||||
);
|
||||
} else {
|
||||
Tlog::getInstance()->addError("Asset $file (type $type) was not found.");
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return an asset source file path.
|
||||
*
|
||||
* A system of fallback enables file overriding. It will look for the template :
|
||||
* - in the current template in directory /modules/{module code}/
|
||||
* - in the module in the current template if it exists
|
||||
* - in the module in the default template
|
||||
*
|
||||
* @param string $source a module code, or or SmartyParser::TEMPLATE_ASSETS_KEY
|
||||
* @param string $templateName a template name, or false to use the current template
|
||||
* @param string $fileName the filename
|
||||
* @param ParserInterface $parserInterface the current template parser
|
||||
*
|
||||
* @return mixed the path to directory containing the file, or null if the file doesn't exists.
|
||||
*/
|
||||
public function resolveAssetSourcePath($source, $templateName, $fileName, ParserInterface $parserInterface)
|
||||
{
|
||||
$filePath = null;
|
||||
|
||||
$templateDefinition = $parserInterface->getTemplateDefinition(false);
|
||||
|
||||
// Get all possible directories to search
|
||||
$paths = $this->getPossibleAssetSources(
|
||||
$parserInterface->getTemplateDirectories($templateDefinition->getType()),
|
||||
$templateName ?: $templateDefinition->getName(),
|
||||
$source
|
||||
);
|
||||
|
||||
// Normalize path separator if required (e.g., / becomes \ on windows)
|
||||
$fileName = $this->fixPathSeparator($fileName);
|
||||
|
||||
/* Absolute paths are not allowed. This may be a mistake, such as '/assets/...' instead of 'assets/...'. Forgive it. */
|
||||
$fileName = ltrim($fileName, DS);
|
||||
|
||||
/* Navigating in the server's directory tree is not allowed :) */
|
||||
if (preg_match('!\.\.\\'.DS.'!', $fileName)) {
|
||||
// This time, we will not forgive.
|
||||
throw new \InvalidArgumentException("Relative paths are not allowed in assets names.");
|
||||
}
|
||||
|
||||
// Find the first occurrence of the file in the directories lists
|
||||
foreach ($paths as $path) {
|
||||
if ($this->filesExist($path, $fileName)) {
|
||||
// Got it !
|
||||
$filePath = $path;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $filePath;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Be sure that the pat separator of a pathname is always the platform path separator.
|
||||
*
|
||||
* @param string $path the iput path
|
||||
* @return string the fixed path
|
||||
*/
|
||||
protected function fixPathSeparator($path)
|
||||
{
|
||||
if (DS != '/') {
|
||||
$path = str_replace('/', DS, $path);
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a file(s) exists in a directory
|
||||
*
|
||||
* @param string $dir the directory path
|
||||
* @param string $file the file path. It can contain wildcard. eg: /path/*.css
|
||||
* @return bool true if file(s)
|
||||
*/
|
||||
protected function filesExist($dir, $file)
|
||||
{
|
||||
if (!file_exists($dir)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$full_path = rtrim($dir, DS) . DS . ltrim($file, DS);
|
||||
|
||||
try {
|
||||
$files = glob($full_path);
|
||||
|
||||
$files_found = ! empty($files);
|
||||
} catch (\Exception $ex) {
|
||||
Tlog::getInstance()->addError($ex->getMessage());
|
||||
|
||||
$files_found = false;
|
||||
}
|
||||
|
||||
return $files_found;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all possible directories from which the asset can be found.
|
||||
* It returns an array of directories ordered by priority.
|
||||
*
|
||||
* @param array $directories all directories source available for the template type
|
||||
* @param string $template the name of the template
|
||||
* @param string $source the module code or SmartyParser::TEMPLATE_ASSETS_KEY
|
||||
* @return array possible directories
|
||||
*/
|
||||
protected function getPossibleAssetSources($directories, $template, $source)
|
||||
{
|
||||
$paths = [];
|
||||
|
||||
if (SmartyParser::TEMPLATE_ASSETS_KEY !== $source) {
|
||||
// We're in a module.
|
||||
|
||||
// First look into the current template in the right scope : frontOffice, backOffice, ...
|
||||
// template should be overridden in : {template_path}/modules/{module_code}/{template_name}
|
||||
if (isset($directories[$template][SmartyParser::TEMPLATE_ASSETS_KEY])) {
|
||||
$paths[] =
|
||||
$directories[$template][SmartyParser::TEMPLATE_ASSETS_KEY]
|
||||
. DS
|
||||
. self::MODULE_OVERRIDE_DIRECTORY_NAME . DS
|
||||
. $source;
|
||||
}
|
||||
|
||||
// then in the implementation for the current template used in the module directory
|
||||
if (isset($directories[$template][$source])) {
|
||||
$paths[] = $directories[$template][$source];
|
||||
}
|
||||
|
||||
// then in the default theme in the module itself
|
||||
if (isset($directories[self::DEFAULT_TEMPLATE_NAME][$source])) {
|
||||
$paths[] = $directories[self::DEFAULT_TEMPLATE_NAME][$source];
|
||||
}
|
||||
} else {
|
||||
$paths[] = $directories[$template][SmartyParser::TEMPLATE_ASSETS_KEY];
|
||||
}
|
||||
|
||||
return $paths;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace TheliaSmarty\Template\Exception;
|
||||
|
||||
/**
|
||||
* Class SmartyPluginException
|
||||
* @package Thelia\Core\Template\Smarty\Exception
|
||||
* @author Manuel Raynaud <manu@raynaud.io>
|
||||
*/
|
||||
class SmartyPluginException extends \SmartyException
|
||||
{
|
||||
}
|
||||
160
local/modules/TheliaSmarty/Template/Plugins/AdminUtilities.php
Normal file
160
local/modules/TheliaSmarty/Template/Plugins/AdminUtilities.php
Normal file
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace TheliaSmarty\Template\Plugins;
|
||||
|
||||
use Thelia\Core\Security\SecurityContext;
|
||||
use Thelia\Core\Template\TemplateHelperInterface;
|
||||
use Thelia\Tools\URL;
|
||||
use TheliaSmarty\Template\AbstractSmartyPlugin;
|
||||
use TheliaSmarty\Template\SmartyPluginDescriptor;
|
||||
|
||||
/**
|
||||
* This class implements variour admin template utilities
|
||||
*
|
||||
* @author Franck Allimant <franck@cqfdev.fr>
|
||||
*/
|
||||
class AdminUtilities extends AbstractSmartyPlugin
|
||||
{
|
||||
private $securityContext;
|
||||
private $templateHelper;
|
||||
|
||||
public function __construct(SecurityContext $securityContext, TemplateHelperInterface $templateHelper)
|
||||
{
|
||||
$this->securityContext = $securityContext;
|
||||
$this->templateHelper = $templateHelper;
|
||||
}
|
||||
|
||||
protected function fetchSnippet($smarty, $templateName, $variablesArray)
|
||||
{
|
||||
$data = '';
|
||||
|
||||
$snippet_path = sprintf(
|
||||
'%s/%s/%s.html',
|
||||
THELIA_TEMPLATE_DIR,
|
||||
$this->templateHelper->getActiveAdminTemplate()->getPath(),
|
||||
$templateName
|
||||
);
|
||||
|
||||
if (false !== $snippet_content = file_get_contents($snippet_path)) {
|
||||
$smarty->assign($variablesArray);
|
||||
|
||||
$data = $smarty->fetch(sprintf('string:%s', $snippet_content));
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function generatePositionChangeBlock($params, &$smarty)
|
||||
{
|
||||
// The required permissions
|
||||
$resource = $this->getParam($params, 'resource');
|
||||
$module = $this->getParam($params, 'module');
|
||||
$access = $this->getParam($params, 'access');
|
||||
|
||||
// The base position change path
|
||||
$path = $this->getParam($params, 'path');
|
||||
|
||||
// The URL parameter the object ID is assigned
|
||||
$url_parameter = $this->getParam($params, 'url_parameter');
|
||||
|
||||
// The current object position
|
||||
$position = $this->getParam($params, 'position');
|
||||
|
||||
// The object ID
|
||||
$id = $this->getParam($params, 'id');
|
||||
|
||||
// The in place dition class
|
||||
$in_place_edit_class = $this->getParam($params, 'in_place_edit_class');
|
||||
|
||||
/*
|
||||
<a href="{url path='/admin/configuration/currencies/positionUp' currency_id=$ID}"><i class="icon-arrow-up"></i></a>
|
||||
<span class="currencyPositionChange" data-id="{$ID}">{$POSITION}</span>
|
||||
<a href="{url path='/admin/configuration/currencies/positionDown' currency_id=$ID}"><i class="icon-arrow-down"></i></a>
|
||||
*/
|
||||
|
||||
if ($this->securityContext->isGranted(
|
||||
array("ADMIN"),
|
||||
$resource === null ? array() : array($resource),
|
||||
$module === null ? array() : array($module),
|
||||
array($access)
|
||||
)
|
||||
) {
|
||||
return $this->fetchSnippet($smarty, 'includes/admin-utilities-position-block', array(
|
||||
'admin_utilities_go_up_url' => URL::getInstance()->absoluteUrl($path, array('mode' => 'up', $url_parameter => $id)),
|
||||
'admin_utilities_in_place_edit_class' => $in_place_edit_class,
|
||||
'admin_utilities_object_id' => $id,
|
||||
'admin_utilities_current_position' => $position,
|
||||
'admin_utilities_go_down_url' => URL::getInstance()->absoluteUrl($path, array('mode' => 'down', $url_parameter => $id))
|
||||
));
|
||||
} else {
|
||||
return $position;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the link of a sortable column header
|
||||
*
|
||||
* @param array $params
|
||||
* @param unknown $smarty
|
||||
* @return string no text is returned.
|
||||
*/
|
||||
public function generateSortableColumnHeader($params, &$smarty)
|
||||
{
|
||||
// The current order of the table
|
||||
$current_order = $this->getParam($params, 'current_order');
|
||||
|
||||
// The column ascending order
|
||||
$order = $this->getParam($params, 'order');
|
||||
|
||||
// The column descending order label
|
||||
$reverse_order = $this->getParam($params, 'reverse_order');
|
||||
|
||||
// The order change path
|
||||
$path = $this->getParam($params, 'path');
|
||||
|
||||
// The column label
|
||||
$label = $this->getParam($params, 'label');
|
||||
|
||||
// The request parameter
|
||||
$request_parameter_name = $this->getParam($params, 'request_parameter_name', 'order');
|
||||
|
||||
if ($current_order == $order) {
|
||||
$sort_direction = 'up';
|
||||
$order_change = $reverse_order;
|
||||
} elseif ($current_order == $reverse_order) {
|
||||
$sort_direction = 'down';
|
||||
$order_change = $order;
|
||||
} else {
|
||||
$order_change = $order;
|
||||
}
|
||||
|
||||
return $this->fetchSnippet($smarty, 'includes/admin-utilities-sortable-column-header', array(
|
||||
'admin_utilities_sort_direction' => $sort_direction,
|
||||
'admin_utilities_sorting_url' => URL::getInstance()->absoluteUrl($path, array($request_parameter_name => $order_change)),
|
||||
'admin_utilities_header_text' => $label
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the various smarty plugins handled by this class
|
||||
*
|
||||
* @return array of smarty plugin descriptors
|
||||
*/
|
||||
public function getPluginDescriptors()
|
||||
{
|
||||
return array(
|
||||
new SmartyPluginDescriptor('function', 'admin_sortable_header', $this, 'generateSortableColumnHeader'),
|
||||
new SmartyPluginDescriptor('function', 'admin_position_block', $this, 'generatePositionChangeBlock'),
|
||||
);
|
||||
}
|
||||
}
|
||||
106
local/modules/TheliaSmarty/Template/Plugins/Assets.php
Normal file
106
local/modules/TheliaSmarty/Template/Plugins/Assets.php
Normal file
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace TheliaSmarty\Template\Plugins;
|
||||
|
||||
use Thelia\Core\Template\Assets\AssetManagerInterface;
|
||||
use Thelia\Core\Template\Assets\AssetResolverInterface;
|
||||
use Thelia\Model\ConfigQuery;
|
||||
use TheliaSmarty\Template\AbstractSmartyPlugin;
|
||||
use TheliaSmarty\Template\Assets\SmartyAssetsManager;
|
||||
use TheliaSmarty\Template\SmartyPluginDescriptor;
|
||||
|
||||
class Assets extends AbstractSmartyPlugin
|
||||
{
|
||||
public $assetManager;
|
||||
|
||||
public function __construct(AssetManagerInterface $assetsManager, AssetResolverInterface $assetsResolver)
|
||||
{
|
||||
$asset_dir_from_web_root = ConfigQuery::read('asset_dir_from_web_root', 'assets');
|
||||
|
||||
$this->assetManager = new SmartyAssetsManager(
|
||||
$assetsManager,
|
||||
$assetsResolver,
|
||||
THELIA_WEB_DIR,
|
||||
$asset_dir_from_web_root
|
||||
);
|
||||
}
|
||||
|
||||
public function declareAssets($params, \Smarty_Internal_Template $template)
|
||||
{
|
||||
if (false !== $asset_dir = $this->getParam($params, 'directory', false)) {
|
||||
$this->assetManager->prepareAssets($asset_dir, $template);
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException('declare_assets: parameter "directory" is required');
|
||||
}
|
||||
|
||||
public function blockJavascripts($params, $content, \Smarty_Internal_Template $template, &$repeat)
|
||||
{
|
||||
return $this->assetManager->processSmartyPluginCall('js', $params, $content, $template, $repeat);
|
||||
}
|
||||
|
||||
public function blockImages($params, $content, \Smarty_Internal_Template $template, &$repeat)
|
||||
{
|
||||
return $this
|
||||
->assetManager
|
||||
->processSmartyPluginCall(SmartyAssetsManager::ASSET_TYPE_AUTO, $params, $content, $template, $repeat);
|
||||
}
|
||||
|
||||
public function blockStylesheets($params, $content, \Smarty_Internal_Template $template, &$repeat)
|
||||
{
|
||||
return $this->assetManager->processSmartyPluginCall('css', $params, $content, $template, $repeat);
|
||||
}
|
||||
|
||||
public function functionImage($params, \Smarty_Internal_Template $template)
|
||||
{
|
||||
return $this->assetManager->computeAssetUrl(SmartyAssetsManager::ASSET_TYPE_AUTO, $params, $template);
|
||||
}
|
||||
|
||||
public function functionAsset($params, \Smarty_Internal_Template $template)
|
||||
{
|
||||
return $this->assetManager->computeAssetUrl(SmartyAssetsManager::ASSET_TYPE_AUTO, $params, $template, false);
|
||||
}
|
||||
|
||||
public function functionJavascript($params, \Smarty_Internal_Template $template)
|
||||
{
|
||||
return $this->assetManager->computeAssetUrl(SmartyAssetsManager::ASSET_TYPE_AUTO, $params, $template);
|
||||
}
|
||||
|
||||
public function functionStylesheet($params, \Smarty_Internal_Template $template)
|
||||
{
|
||||
return $this->assetManager->computeAssetUrl('css', $params, $template);
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the various smarty plugins hendled by this class
|
||||
*
|
||||
* @return array an array of smarty plugin descriptors
|
||||
*/
|
||||
public function getPluginDescriptors()
|
||||
{
|
||||
return array(
|
||||
new SmartyPluginDescriptor('block', 'stylesheets', $this, 'blockStylesheets'),
|
||||
new SmartyPluginDescriptor('block', 'javascripts', $this, 'blockJavascripts'),
|
||||
new SmartyPluginDescriptor('block', 'images', $this, 'blockImages'),
|
||||
|
||||
new SmartyPluginDescriptor('function', 'asset', $this, 'functionAsset'),
|
||||
new SmartyPluginDescriptor('function', 'image', $this, 'functionImage'),
|
||||
new SmartyPluginDescriptor('function', 'javascript', $this, 'functionJavascript'),
|
||||
new SmartyPluginDescriptor('function', 'stylesheet', $this, 'functionStylesheet'),
|
||||
|
||||
new SmartyPluginDescriptor('function', 'declare_assets', $this, 'declareAssets')
|
||||
);
|
||||
}
|
||||
}
|
||||
251
local/modules/TheliaSmarty/Template/Plugins/CartPostage.php
Normal file
251
local/modules/TheliaSmarty/Template/Plugins/CartPostage.php
Normal file
@@ -0,0 +1,251 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace TheliaSmarty\Template\Plugins;
|
||||
|
||||
use Propel\Runtime\ActiveQuery\Criteria;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Thelia\Core\Event\Delivery\DeliveryPostageEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\HttpFoundation\Request;
|
||||
use Thelia\Model\Address;
|
||||
use Thelia\Model\AddressQuery;
|
||||
use Thelia\Model\ConfigQuery;
|
||||
use Thelia\Model\Country;
|
||||
use Thelia\Model\CountryQuery;
|
||||
use Thelia\Model\Customer;
|
||||
use Thelia\Model\ModuleQuery;
|
||||
use Thelia\Module\BaseModule;
|
||||
use Thelia\Module\DeliveryModuleInterface;
|
||||
use Thelia\Module\Exception\DeliveryException;
|
||||
use TheliaSmarty\Template\AbstractSmartyPlugin;
|
||||
use TheliaSmarty\Template\SmartyPluginDescriptor;
|
||||
|
||||
/**
|
||||
* Class CartPostage
|
||||
* @package Thelia\Core\Template\Smarty\Plugins
|
||||
*/
|
||||
class CartPostage extends AbstractSmartyPlugin
|
||||
{
|
||||
/**
|
||||
* @var \Thelia\Core\HttpFoundation\Request The Request
|
||||
* @deprecated since 2.3, please use requestStack
|
||||
*/
|
||||
protected $request;
|
||||
|
||||
/** @var RequestStack */
|
||||
protected $requestStack;
|
||||
|
||||
/** @var EventDispatcherInterface */
|
||||
protected $dispatcher;
|
||||
|
||||
/** @var ContainerInterface Service Container */
|
||||
protected $container = null;
|
||||
|
||||
/** @var integer $countryId the id of country */
|
||||
protected $countryId = null;
|
||||
|
||||
/** @var integer $deliveryId the id of the cheapest delivery */
|
||||
protected $deliveryId = null;
|
||||
|
||||
/** @var float $postage the postage amount with taxes */
|
||||
protected $postage = null;
|
||||
|
||||
/** @var float $postageTax the postage tax amount */
|
||||
protected $postageTax = null;
|
||||
|
||||
/** @var string $postageTaxRuleTitle the postage tax rule title */
|
||||
protected $postageTaxRuleTitle = null;
|
||||
|
||||
/** @var boolean $isCustomizable indicate if customer can change the country */
|
||||
protected $isCustomizable = true;
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*/
|
||||
public function __construct(ContainerInterface $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
|
||||
$this->requestStack = $container->get('request_stack');
|
||||
|
||||
$this->request = $this->getCurrentRequest();
|
||||
|
||||
$this->dispatcher = $container->get('event_dispatcher');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get postage amount for cart
|
||||
*
|
||||
* @param array $params Block parameters
|
||||
* @param mixed $content Block content
|
||||
* @param \Smarty_Internal_Template $template Template
|
||||
* @param bool $repeat Control how many times
|
||||
* the block is displayed
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function postage($params, $content, $template, &$repeat)
|
||||
{
|
||||
if (!$repeat) {
|
||||
return (null !== $this->countryId) ? $content : "";
|
||||
}
|
||||
|
||||
$customer = $this->getCurrentRequest()->getSession()->getCustomerUser();
|
||||
/** @var Address $address */
|
||||
/** @var Country $country */
|
||||
list($address, $country, $state) = $this->getDeliveryInformation($customer);
|
||||
|
||||
if (null !== $country) {
|
||||
$this->countryId = $country->getId();
|
||||
// try to get the cheapest delivery for this country
|
||||
$this->getCheapestDelivery($address, $country);
|
||||
}
|
||||
|
||||
$template->assign('country_id', $this->countryId);
|
||||
$template->assign('delivery_id', $this->deliveryId);
|
||||
$template->assign('postage', $this->postage ?: 0.0);
|
||||
$template->assign('postage_tax', $this->postageTax ?: 0.0);
|
||||
$template->assign('postage_title', $this->postageTaxRuleTitle ?: 0.0);
|
||||
$template->assign('is_customizable', $this->isCustomizable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the delivery country for a customer
|
||||
*
|
||||
* The rules :
|
||||
* - the country of the delivery address of the customer related to the
|
||||
* cart if it exists
|
||||
* - the country saved in cookie if customer have changed
|
||||
* the default country
|
||||
* - the default country for the shop if it exists
|
||||
*
|
||||
*
|
||||
* @param \Thelia\Model\Customer $customer
|
||||
* @return \Thelia\Model\Country
|
||||
*/
|
||||
protected function getDeliveryInformation(Customer $customer = null)
|
||||
{
|
||||
$address = null;
|
||||
// get the selected delivery address
|
||||
if (null !== $addressId = $this->getCurrentRequest()->getSession()->getOrder()->getChoosenDeliveryAddress()) {
|
||||
if (null !== $address = AddressQuery::create()->findPk($addressId)) {
|
||||
$this->isCustomizable = false;
|
||||
return [$address, $address->getCountry(), null];
|
||||
}
|
||||
}
|
||||
|
||||
// get country from customer addresses
|
||||
if (null !== $customer) {
|
||||
$address = AddressQuery::create()
|
||||
->filterByCustomerId($customer->getId())
|
||||
->filterByIsDefault(1)
|
||||
->findOne()
|
||||
;
|
||||
|
||||
if (null !== $address) {
|
||||
$this->isCustomizable = false;
|
||||
|
||||
return [$address, $address->getCountry(), null];
|
||||
}
|
||||
}
|
||||
|
||||
// get country from cookie
|
||||
$cookieName = ConfigQuery::read('front_cart_country_cookie_name', 'fcccn');
|
||||
if ($this->getCurrentRequest()->cookies->has($cookieName)) {
|
||||
$cookieVal = $this->getCurrentRequest()->cookies->getInt($cookieName, 0);
|
||||
if (0 !== $cookieVal) {
|
||||
$country = CountryQuery::create()->findPk($cookieVal);
|
||||
if (null !== $country) {
|
||||
return [null, $country, null];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get default country for store.
|
||||
try {
|
||||
$country = Country::getDefaultCountry();
|
||||
|
||||
return [null, $country, null];
|
||||
} catch (\LogicException $e) {
|
||||
;
|
||||
}
|
||||
|
||||
return [null, null, null];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the cheapest delivery for country
|
||||
*
|
||||
* @param Address $address
|
||||
* @param \Thelia\Model\Country $country
|
||||
* @return DeliveryModuleInterface
|
||||
*/
|
||||
protected function getCheapestDelivery(Address $address = null, Country $country = null)
|
||||
{
|
||||
$cart = $this->getCurrentRequest()->getSession()->getSessionCart();
|
||||
|
||||
$deliveryModules = ModuleQuery::create()
|
||||
->filterByActivate(1)
|
||||
->filterByType(BaseModule::DELIVERY_MODULE_TYPE, Criteria::EQUAL)
|
||||
->find()
|
||||
;
|
||||
|
||||
/** @var \Thelia\Model\Module $deliveryModule */
|
||||
foreach ($deliveryModules as $deliveryModule) {
|
||||
$moduleInstance = $deliveryModule->getDeliveryModuleInstance($this->container);
|
||||
|
||||
try {
|
||||
$deliveryPostageEvent = new DeliveryPostageEvent($moduleInstance, $cart, $address, $country, $state);
|
||||
$this->dispatcher->dispatch(
|
||||
TheliaEvents::MODULE_DELIVERY_GET_POSTAGE,
|
||||
$deliveryPostageEvent
|
||||
);
|
||||
|
||||
if ($deliveryPostageEvent->isValidModule()) {
|
||||
$postage = $deliveryPostageEvent->getPostage();
|
||||
|
||||
if (null === $this->postage || $this->postage > $postage->getAmount()) {
|
||||
$this->postage = $postage->getAmount();
|
||||
$this->postageTax = $postage->getAmountTax();
|
||||
$this->postageTaxRuleTitle = $postage->getTaxRuleTitle();
|
||||
$this->deliveryId = $deliveryModule->getId();
|
||||
}
|
||||
}
|
||||
} catch (DeliveryException $ex) {
|
||||
// Module is not available
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the various smarty plugins handled by this class
|
||||
*
|
||||
* @return \TheliaSmarty\Template\SmartyPluginDescriptor[] smarty plugin descriptors
|
||||
*/
|
||||
public function getPluginDescriptors()
|
||||
{
|
||||
return array(
|
||||
new SmartyPluginDescriptor('block', 'postage', $this, 'postage')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null|Request
|
||||
*/
|
||||
protected function getCurrentRequest()
|
||||
{
|
||||
return $this->requestStack->getCurrentRequest();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,786 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace TheliaSmarty\Template\Plugins;
|
||||
|
||||
use Propel\Runtime\ActiveQuery\ModelCriteria;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Thelia\Core\HttpFoundation\Request;
|
||||
use Thelia\Core\HttpFoundation\Session\Session;
|
||||
use Thelia\Core\Security\SecurityContext;
|
||||
use Thelia\Core\Template\ParserContext;
|
||||
use Thelia\Log\Tlog;
|
||||
use Thelia\Model\Base\BrandQuery;
|
||||
use Thelia\Model\Cart;
|
||||
use Thelia\Model\CategoryQuery;
|
||||
use Thelia\Model\ConfigQuery;
|
||||
use Thelia\Model\ContentQuery;
|
||||
use Thelia\Model\Country;
|
||||
use Thelia\Model\CountryQuery;
|
||||
use Thelia\Model\CurrencyQuery;
|
||||
use Thelia\Model\FolderQuery;
|
||||
use Thelia\Model\MetaDataQuery;
|
||||
use Thelia\Model\ModuleConfigQuery;
|
||||
use Thelia\Model\ModuleQuery;
|
||||
use Thelia\Model\OrderQuery;
|
||||
use Thelia\Model\ProductQuery;
|
||||
use Thelia\Model\Tools\ModelCriteriaTools;
|
||||
use Thelia\TaxEngine\TaxEngine;
|
||||
use Thelia\Tools\DateTimeFormat;
|
||||
use TheliaSmarty\Template\AbstractSmartyPlugin;
|
||||
use TheliaSmarty\Template\SmartyPluginDescriptor;
|
||||
|
||||
/**
|
||||
* Implementation of data access to main Thelia objects (users, cart, etc.)
|
||||
*
|
||||
* @author Franck Allimant <franck@cqfdev.fr>
|
||||
*
|
||||
*/
|
||||
class DataAccessFunctions extends AbstractSmartyPlugin
|
||||
{
|
||||
/** @var SecurityContext */
|
||||
private $securityContext;
|
||||
|
||||
/** @var ParserContext */
|
||||
protected $parserContext;
|
||||
|
||||
/** @var RequestStack */
|
||||
protected $requestStack;
|
||||
|
||||
/** @var EventDispatcherInterface */
|
||||
protected $dispatcher;
|
||||
|
||||
/** @var TaxEngine */
|
||||
protected $taxEngine;
|
||||
|
||||
private static $dataAccessCache = array();
|
||||
|
||||
public function __construct(
|
||||
RequestStack $requestStack,
|
||||
SecurityContext $securityContext,
|
||||
TaxEngine $taxEngine,
|
||||
ParserContext $parserContext,
|
||||
EventDispatcherInterface $dispatcher
|
||||
) {
|
||||
$this->securityContext = $securityContext;
|
||||
$this->parserContext = $parserContext;
|
||||
$this->requestStack = $requestStack;
|
||||
$this->dispatcher = $dispatcher;
|
||||
$this->taxEngine = $taxEngine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides access to the current logged administrator attributes using the accessors.
|
||||
*
|
||||
* @param array $params
|
||||
* @param \Smarty $smarty
|
||||
* @return string the value of the requested attribute
|
||||
*/
|
||||
public function adminDataAccess($params, &$smarty)
|
||||
{
|
||||
return $this->dataAccess("Admin User", $params, $this->securityContext->getAdminUser());
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides access to the current logged customer attributes thought the accessor
|
||||
*
|
||||
* @param array $params
|
||||
* @param \Smarty $smarty
|
||||
* @return string the value of the requested attribute
|
||||
*/
|
||||
public function customerDataAccess($params, &$smarty)
|
||||
{
|
||||
return $this->dataAccess("Customer User", $params, $this->securityContext->getCustomerUser());
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides access to an attribute of the current product
|
||||
*
|
||||
* @param array $params
|
||||
* @param \Smarty $smarty
|
||||
* @return string the value of the requested attribute
|
||||
*/
|
||||
public function productDataAccess($params, &$smarty)
|
||||
{
|
||||
$productId = $this->getRequest()->get('product_id');
|
||||
|
||||
if ($productId !== null) {
|
||||
return $this->dataAccessWithI18n(
|
||||
"Product",
|
||||
$params,
|
||||
ProductQuery::create()->filterByPrimaryKey($productId)
|
||||
);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides access to an attribute of the current category
|
||||
*
|
||||
* @param array $params
|
||||
* @param \Smarty $smarty
|
||||
* @return string the value of the requested attribute
|
||||
*/
|
||||
public function categoryDataAccess($params, &$smarty)
|
||||
{
|
||||
$categoryId = $this->getRequest()->get('category_id');
|
||||
|
||||
if ($categoryId === null) {
|
||||
$productId = $this->getRequest()->get('product_id');
|
||||
|
||||
if ($productId !== null) {
|
||||
if (null !== $product = ProductQuery::create()->findPk($productId)) {
|
||||
$categoryId = $product->getDefaultCategoryId();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($categoryId !== null) {
|
||||
return $this->dataAccessWithI18n(
|
||||
"Category",
|
||||
$params,
|
||||
CategoryQuery::create()->filterByPrimaryKey($categoryId)
|
||||
);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides access to an attribute of the current content
|
||||
*
|
||||
* @param array $params
|
||||
* @param \Smarty $smarty
|
||||
* @return string the value of the requested attribute
|
||||
*/
|
||||
public function contentDataAccess($params, &$smarty)
|
||||
{
|
||||
$contentId = $this->getRequest()->get('content_id');
|
||||
|
||||
if ($contentId !== null) {
|
||||
return $this->dataAccessWithI18n(
|
||||
"Content",
|
||||
$params,
|
||||
ContentQuery::create()->filterByPrimaryKey($contentId)
|
||||
);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides access to an attribute of the current folder
|
||||
*
|
||||
* @param array $params
|
||||
* @param \Smarty $smarty
|
||||
* @return string the value of the requested attribute
|
||||
*/
|
||||
public function folderDataAccess($params, &$smarty)
|
||||
{
|
||||
$folderId = $this->getRequest()->get('folder_id');
|
||||
|
||||
if ($folderId === null) {
|
||||
$contentId = $this->getRequest()->get('content_id');
|
||||
|
||||
if ($contentId !== null) {
|
||||
if (null !== $content = ContentQuery::create()->findPk($contentId)) {
|
||||
$folderId = $content->getDefaultFolderId();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($folderId !== null) {
|
||||
return $this->dataAccessWithI18n(
|
||||
"Folder",
|
||||
$params,
|
||||
FolderQuery::create()->filterByPrimaryKey($folderId)
|
||||
);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides access to an attribute of the current brand
|
||||
*
|
||||
* @param array $params
|
||||
* @param \Smarty $smarty
|
||||
* @return string the value of the requested attribute
|
||||
*/
|
||||
public function brandDataAccess($params, &$smarty)
|
||||
{
|
||||
$brandId = $this->getRequest()->get('brand_id');
|
||||
|
||||
if ($brandId === null) {
|
||||
$productId = $this->getRequest()->get('product_id');
|
||||
|
||||
if ($productId !== null) {
|
||||
if (null !== $product = ProductQuery::create()->findPk($productId)) {
|
||||
$brandId = $product->getBrandId();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($brandId !== null) {
|
||||
return $this->dataAccessWithI18n(
|
||||
"Brand",
|
||||
$params,
|
||||
BrandQuery::create()->filterByPrimaryKey($brandId)
|
||||
);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Provides access to an attribute of the current currency
|
||||
*
|
||||
* @param array $params
|
||||
* @param \Smarty $smarty
|
||||
* @return string the value of the requested attribute
|
||||
*/
|
||||
public function currencyDataAccess($params, $smarty)
|
||||
{
|
||||
$currency = $this->getSession()->getCurrency();
|
||||
|
||||
if ($currency) {
|
||||
return $this->dataAccessWithI18n(
|
||||
"Currency",
|
||||
$params,
|
||||
CurrencyQuery::create()->filterByPrimaryKey($currency->getId()),
|
||||
array("NAME")
|
||||
);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides access to an attribute of the default country
|
||||
*
|
||||
* @param array $params
|
||||
* @param \Smarty $smarty
|
||||
* @return string the value of the requested attribute
|
||||
*/
|
||||
public function countryDataAccess($params, $smarty)
|
||||
{
|
||||
switch ($params["ask"]) {
|
||||
case "default":
|
||||
return $this->dataAccessWithI18n(
|
||||
"defaultCountry",
|
||||
$params,
|
||||
CountryQuery::create()->filterByByDefault(1)->limit(1)
|
||||
);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides access to an attribute of the cart
|
||||
*
|
||||
* @param array $params
|
||||
* @param \Smarty $smarty
|
||||
* @return string the value of the requested attribute
|
||||
*/
|
||||
public function cartDataAccess($params, $smarty)
|
||||
{
|
||||
/** @var Country $taxCountry */
|
||||
if (array_key_exists('currentCountry', self::$dataAccessCache)) {
|
||||
$taxCountry = self::$dataAccessCache['currentCountry'];
|
||||
} else {
|
||||
$taxCountry = $this->taxEngine->getDeliveryCountry();
|
||||
self::$dataAccessCache['currentCountry'] = $taxCountry;
|
||||
}
|
||||
|
||||
/** @var Cart $cart */
|
||||
$cart = $this->getSession()->getSessionCart($this->dispatcher);
|
||||
|
||||
$result = "";
|
||||
switch ($params["attr"]) {
|
||||
case "count_product":
|
||||
case "product_count":
|
||||
$result = $cart->getCartItems()->count();
|
||||
break;
|
||||
case "count_item":
|
||||
case "item_count":
|
||||
$count_allitem = 0;
|
||||
foreach ($cart->getCartItems() as $cartItem) {
|
||||
$count_allitem += $cartItem->getQuantity();
|
||||
}
|
||||
$result = $count_allitem;
|
||||
break;
|
||||
case "total_price":
|
||||
case "total_price_with_discount":
|
||||
$result = $cart->getTotalAmount();
|
||||
break;
|
||||
case "total_price_without_discount":
|
||||
$result = $cart->getTotalAmount(false);
|
||||
break;
|
||||
case "total_taxed_price":
|
||||
case "total_taxed_price_with_discount":
|
||||
$result = $cart->getTaxedAmount($taxCountry);
|
||||
break;
|
||||
case "total_taxed_price_without_discount":
|
||||
$result = $cart->getTaxedAmount($taxCountry, false);
|
||||
break;
|
||||
case "is_virtual":
|
||||
case "contains_virtual_product":
|
||||
$result = $cart->isVirtual();
|
||||
break;
|
||||
case "total_vat":
|
||||
case 'total_tax_amount':
|
||||
$result = $cart->getTotalVAT($taxCountry);
|
||||
break;
|
||||
case "weight":
|
||||
$result = $cart->getWeight();
|
||||
break;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides access to an attribute of the current order
|
||||
*
|
||||
* @param array $params
|
||||
* @param \Smarty $smarty
|
||||
* @return string the value of the requested attribute
|
||||
*/
|
||||
public function orderDataAccess($params, &$smarty)
|
||||
{
|
||||
$order = $this->getSession()->getOrder();
|
||||
$attribute = $this->getNormalizedParam($params, array('attribute', 'attrib', 'attr'));
|
||||
switch ($attribute) {
|
||||
case 'untaxed_postage':
|
||||
return $order->getUntaxedPostage();
|
||||
case 'postage':
|
||||
return $order->getPostage();
|
||||
case 'postage_tax':
|
||||
return $order->getPostageTax();
|
||||
case 'discount':
|
||||
return $order->getDiscount();
|
||||
case 'delivery_address':
|
||||
return $order->getChoosenDeliveryAddress();
|
||||
case 'invoice_address':
|
||||
return $order->getChoosenInvoiceAddress();
|
||||
case 'delivery_module':
|
||||
return $order->getDeliveryModuleId();
|
||||
case 'payment_module':
|
||||
return $order->getPaymentModuleId();
|
||||
case 'has_virtual_product':
|
||||
return $order->hasVirtualProduct();
|
||||
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException(sprintf("%s has no '%s' attribute", 'Order', $attribute));
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides access to an attribute of the current language
|
||||
*
|
||||
* @param array $params
|
||||
* @param \Smarty $smarty
|
||||
* @return string the value of the requested attribute
|
||||
*/
|
||||
|
||||
public function langDataAccess($params, $smarty)
|
||||
{
|
||||
return $this->dataAccess("Lang", $params, $this->getSession()->getLang());
|
||||
}
|
||||
|
||||
public function configDataAccess($params, $smarty)
|
||||
{
|
||||
$key = $this->getParam($params, 'key', false);
|
||||
|
||||
if ($key === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$default = $this->getParam($params, 'default', '');
|
||||
|
||||
return ConfigQuery::read($key, $default);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides access to a module configuration value
|
||||
*
|
||||
* @param array $params
|
||||
* @param \Smarty $smarty
|
||||
* @return string the value of the configuration value
|
||||
*/
|
||||
|
||||
public function moduleConfigDataAccess($params, $smarty)
|
||||
{
|
||||
$key = $this->getParam($params, 'key', false);
|
||||
$moduleCode = $this->getParam($params, 'module', false);
|
||||
$locale = $this->getParam($params, 'locale');
|
||||
|
||||
if (null === $locale) {
|
||||
$locale = $this->getSession()->getLang()->getLocale();
|
||||
}
|
||||
|
||||
if ($key === false || $moduleCode === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$default = $this->getParam($params, 'default', '');
|
||||
|
||||
if (null !== $module = ModuleQuery::create()->findOneByCode($moduleCode)) {
|
||||
return ModuleConfigQuery::create()
|
||||
->getConfigValue(
|
||||
$module->getId(),
|
||||
$key,
|
||||
$default,
|
||||
$locale
|
||||
);
|
||||
} else {
|
||||
Tlog::getInstance()->addWarning(
|
||||
sprintf(
|
||||
"Module code '%s' not found in module-config Smarty function",
|
||||
$moduleCode
|
||||
)
|
||||
);
|
||||
|
||||
$value = $default;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides access to sales statistics
|
||||
*
|
||||
* @param array $params
|
||||
* @param \Smarty $smarty
|
||||
* @return string the value of the requested attribute
|
||||
*/
|
||||
|
||||
public function statsAccess($params, $smarty)
|
||||
{
|
||||
if (false === array_key_exists("key", $params)) {
|
||||
throw new \InvalidArgumentException(sprintf("missing key attribute in stats access function"));
|
||||
}
|
||||
if (false === array_key_exists("startDate", $params) || $params['startDate'] === '') {
|
||||
throw new \InvalidArgumentException(sprintf("missing startDate attribute in stats access function"));
|
||||
}
|
||||
if (false === array_key_exists("endDate", $params) || $params['endDate'] === '') {
|
||||
throw new \InvalidArgumentException(sprintf("missing endDate attribute in stats access function"));
|
||||
}
|
||||
|
||||
if (false !== array_key_exists("includeShipping", $params) && $params['includeShipping'] == 'false') {
|
||||
$includeShipping = false;
|
||||
} else {
|
||||
$includeShipping = true;
|
||||
}
|
||||
|
||||
if ($params['startDate'] == 'today') {
|
||||
$startDate = new \DateTime();
|
||||
$startDate->setTime(0, 0, 0);
|
||||
} elseif ($params['startDate'] == 'yesterday') {
|
||||
$startDate = new \DateTime();
|
||||
$startDate->setTime(0, 0, 0);
|
||||
$startDate->modify('-1 day');
|
||||
} elseif ($params['startDate'] == 'this_month') {
|
||||
$startDate = new \DateTime();
|
||||
$startDate->modify('first day of this month');
|
||||
$startDate->setTime(0, 0, 0);
|
||||
} elseif ($params['startDate'] == 'last_month') {
|
||||
$startDate = new \DateTime();
|
||||
$startDate->modify('first day of last month');
|
||||
$startDate->setTime(0, 0, 0);
|
||||
} elseif ($params['startDate'] == 'this_year') {
|
||||
$startDate = new \DateTime();
|
||||
$startDate->modify('first day of January this year');
|
||||
$startDate->setTime(0, 0, 0);
|
||||
} elseif ($params['startDate'] == 'last_year') {
|
||||
$startDate = new \DateTime();
|
||||
$startDate->modify('first day of January last year');
|
||||
$startDate->setTime(0, 0, 0);
|
||||
} else {
|
||||
try {
|
||||
$startDate = new \DateTime($params['startDate']);
|
||||
} catch (\Exception $e) {
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf("invalid startDate attribute '%s' in stats access function", $params['startDate'])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ($params['endDate'] == 'today') {
|
||||
$endDate = new \DateTime();
|
||||
$endDate->setTime(0, 0, 0);
|
||||
} elseif ($params['endDate'] == 'yesterday') {
|
||||
$endDate = new \DateTime();
|
||||
$endDate->setTime(0, 0, 0);
|
||||
$endDate->modify('-1 day');
|
||||
} elseif ($params['endDate'] == 'this_month') {
|
||||
$endDate = new \DateTime();
|
||||
$endDate->modify('last day of this month');
|
||||
$endDate->setTime(0, 0, 0);
|
||||
} elseif ($params['endDate'] == 'last_month') {
|
||||
$endDate = new \DateTime();
|
||||
$endDate->modify('last day of last month');
|
||||
$endDate->setTime(0, 0, 0);
|
||||
} elseif ($params['endDate'] == 'this_year') {
|
||||
$endDate = new \DateTime();
|
||||
$endDate->modify('last day of December this year');
|
||||
$endDate->setTime(0, 0, 0);
|
||||
} elseif ($params['endDate'] == 'last_year') {
|
||||
$endDate = new \DateTime();
|
||||
$endDate->modify('last day of December last year');
|
||||
$endDate->setTime(0, 0, 0);
|
||||
} else {
|
||||
try {
|
||||
$endDate = new \DateTime($params['endDate']);
|
||||
} catch (\Exception $e) {
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf("invalid endDate attribute '%s' in stats access function", $params['endDate'])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
switch ($params['key']) {
|
||||
case 'sales':
|
||||
return OrderQuery::getSaleStats($startDate, $endDate, $includeShipping);
|
||||
break;
|
||||
case 'orders':
|
||||
return OrderQuery::getOrderStats($startDate, $endDate, array(1,2,3,4));
|
||||
break;
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf("invalid key attribute '%s' in stats access function", $params['key'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve meta data associated to an element
|
||||
*
|
||||
* params should contain at least key an id attributes. Thus it will return
|
||||
* an array of associated data.
|
||||
*
|
||||
* If meta argument is specified then it will return an unique value.
|
||||
*
|
||||
* @param array $params
|
||||
* @param \Smarty $smarty
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return string|array|null
|
||||
*/
|
||||
public function metaAccess($params, $smarty)
|
||||
{
|
||||
$meta = $this->getParam($params, 'meta', null);
|
||||
$key = $this->getParam($params, 'key', null);
|
||||
$id = $this->getParam($params, 'id', null);
|
||||
|
||||
$cacheKey = sprintf('meta_%s_%s_%s', $meta, $key, $id);
|
||||
|
||||
$out = null;
|
||||
|
||||
if (array_key_exists($cacheKey, self::$dataAccessCache)) {
|
||||
return self::$dataAccessCache[$cacheKey];
|
||||
}
|
||||
|
||||
if ($key !== null && $id !== null) {
|
||||
if ($meta === null) {
|
||||
$out = MetaDataQuery::getAllVal($key, (int) $id);
|
||||
} else {
|
||||
$out = MetaDataQuery::getVal($meta, $key, (int) $id);
|
||||
}
|
||||
} else {
|
||||
throw new \InvalidArgumentException("key and id arguments are required in meta access function");
|
||||
}
|
||||
|
||||
self::$dataAccessCache[$cacheKey] = $out;
|
||||
|
||||
if (!empty($params['out'])) {
|
||||
$smarty->assign($params['out'], $out);
|
||||
|
||||
return $out !== null ? true : false;
|
||||
} else {
|
||||
if (is_array($out)) {
|
||||
throw new \InvalidArgumentException('The argument "out" is required if the meta value is an array');
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $objectLabel
|
||||
* @param $params
|
||||
* @param ModelCriteria $search
|
||||
* @param array $columns
|
||||
* @param null $foreignTable
|
||||
* @param string $foreignKey
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function dataAccessWithI18n(
|
||||
$objectLabel,
|
||||
$params,
|
||||
ModelCriteria $search,
|
||||
$columns = array('TITLE', 'CHAPO', 'DESCRIPTION', 'POSTSCRIPTUM'),
|
||||
$foreignTable = null,
|
||||
$foreignKey = 'ID'
|
||||
) {
|
||||
if (array_key_exists('data_' . $objectLabel, self::$dataAccessCache)) {
|
||||
$data = self::$dataAccessCache['data_' . $objectLabel];
|
||||
} else {
|
||||
$lang = $this->getNormalizedParam($params, array('lang'));
|
||||
if ($lang === null) {
|
||||
$lang = $this->getSession()->getLang()->getId();
|
||||
}
|
||||
|
||||
ModelCriteriaTools::getI18n(
|
||||
false,
|
||||
$lang,
|
||||
$search,
|
||||
$this->getSession()->getLang()->getLocale(),
|
||||
$columns,
|
||||
$foreignTable,
|
||||
$foreignKey,
|
||||
true
|
||||
);
|
||||
|
||||
$data = $search->findOne();
|
||||
|
||||
self::$dataAccessCache['data_' . $objectLabel] = $data;
|
||||
}
|
||||
|
||||
if ($data !== null) {
|
||||
$noGetterData = array();
|
||||
|
||||
foreach ($columns as $column) {
|
||||
$noGetterData[$column] = $data->getVirtualColumn('i18n_' . $column);
|
||||
}
|
||||
|
||||
return $this->dataAccess($objectLabel, $params, $data, $noGetterData);
|
||||
} else {
|
||||
throw new NotFoundHttpException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $objectLabel
|
||||
* @param $params
|
||||
* @param $data
|
||||
* @param array $noGetterData
|
||||
*
|
||||
* @return string
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
protected function dataAccess($objectLabel, $params, $data, $noGetterData = array())
|
||||
{
|
||||
$attribute = $this->getNormalizedParam($params, array('attribute', 'attrib', 'attr'));
|
||||
|
||||
if (!empty($attribute)) {
|
||||
if (null != $data) {
|
||||
$keyAttribute = strtoupper($attribute);
|
||||
if (array_key_exists($keyAttribute, $noGetterData)) {
|
||||
return $noGetterData[$keyAttribute];
|
||||
}
|
||||
|
||||
$getter = sprintf("get%s", $this->underscoreToCamelcase($attribute));
|
||||
if (method_exists($data, $getter)) {
|
||||
$return = $data->$getter();
|
||||
|
||||
if ($return instanceof \DateTime) {
|
||||
if (array_key_exists("format", $params)) {
|
||||
$format = $params["format"];
|
||||
} else {
|
||||
$format = DateTimeFormat::getInstance($this->getRequest())->getFormat(
|
||||
array_key_exists("output", $params) ? $params["output"] : null
|
||||
);
|
||||
}
|
||||
|
||||
$return = $return->format($format);
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException(sprintf("%s has no '%s' attribute", $objectLabel, $attribute));
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Transcode an underscored string into a camel-cased string, eg. default_folder into DefaultFolder
|
||||
*
|
||||
* @param string $str the string to convert from underscore to camel-case
|
||||
*
|
||||
* @return string the camel cased string.
|
||||
*/
|
||||
private function underscoreToCamelcase($str)
|
||||
{
|
||||
// Split string in words.
|
||||
$words = explode('_', strtolower($str));
|
||||
|
||||
$return = '';
|
||||
|
||||
foreach ($words as $word) {
|
||||
$return .= ucfirst(trim($word));
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getPluginDescriptors()
|
||||
{
|
||||
return array(
|
||||
new SmartyPluginDescriptor('function', 'admin', $this, 'adminDataAccess'),
|
||||
new SmartyPluginDescriptor('function', 'customer', $this, 'customerDataAccess'),
|
||||
new SmartyPluginDescriptor('function', 'product', $this, 'productDataAccess'),
|
||||
new SmartyPluginDescriptor('function', 'category', $this, 'categoryDataAccess'),
|
||||
new SmartyPluginDescriptor('function', 'content', $this, 'contentDataAccess'),
|
||||
new SmartyPluginDescriptor('function', 'folder', $this, 'folderDataAccess'),
|
||||
new SmartyPluginDescriptor('function', 'brand', $this, 'brandDataAccess'),
|
||||
new SmartyPluginDescriptor('function', 'currency', $this, 'currencyDataAccess'),
|
||||
new SmartyPluginDescriptor('function', 'country', $this, 'countryDataAccess'),
|
||||
new SmartyPluginDescriptor('function', 'lang', $this, 'langDataAccess'),
|
||||
new SmartyPluginDescriptor('function', 'cart', $this, 'cartDataAccess'),
|
||||
new SmartyPluginDescriptor('function', 'order', $this, 'orderDataAccess'),
|
||||
new SmartyPluginDescriptor('function', 'config', $this, 'configDataAccess'),
|
||||
new SmartyPluginDescriptor('function', 'stats', $this, 'statsAccess'),
|
||||
new SmartyPluginDescriptor('function', 'meta', $this, 'metaAccess'),
|
||||
new SmartyPluginDescriptor('function', 'module_config', $this, 'moduleConfigDataAccess'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Request
|
||||
*/
|
||||
protected function getRequest()
|
||||
{
|
||||
return $this->requestStack->getCurrentRequest();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Session
|
||||
*/
|
||||
protected function getSession()
|
||||
{
|
||||
return $this->getRequest()->getSession();
|
||||
}
|
||||
}
|
||||
73
local/modules/TheliaSmarty/Template/Plugins/Esi.php
Normal file
73
local/modules/TheliaSmarty/Template/Plugins/Esi.php
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace TheliaSmarty\Template\Plugins;
|
||||
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Component\HttpKernel\Fragment\EsiFragmentRenderer;
|
||||
use Thelia\Core\Template\Smarty\Plugins\an;
|
||||
use TheliaSmarty\Template\AbstractSmartyPlugin;
|
||||
use TheliaSmarty\Template\SmartyPluginDescriptor;
|
||||
|
||||
/**
|
||||
* Class Esi
|
||||
* @package Thelia\Core\Template\Smarty\Plugins
|
||||
* @author Manuel Raynaud <manu@raynaud.io>
|
||||
*/
|
||||
class Esi extends AbstractSmartyPlugin
|
||||
{
|
||||
/** @var EsiFragmentRenderer */
|
||||
protected $esiFragmentRender;
|
||||
|
||||
/** @var RequestStack */
|
||||
protected $requestStack;
|
||||
|
||||
public function __construct(EsiFragmentRenderer $esiFragmentRenderer, RequestStack $requestStack)
|
||||
{
|
||||
$this->esiFragmentRender = $esiFragmentRenderer;
|
||||
$this->requestStack = $requestStack;
|
||||
}
|
||||
|
||||
public function renderEsi($params, $template = null)
|
||||
{
|
||||
$path = $this->getParam($params, 'path');
|
||||
$alt = $this->getParam($params, 'alt');
|
||||
$ignore_errors = $this->getParam($params, 'ignore_errors');
|
||||
$comment = $this->getParam($params, 'comment');
|
||||
|
||||
if (null === $path) {
|
||||
return;
|
||||
}
|
||||
|
||||
$response = $this->esiFragmentRender->render($path, $this->requestStack->getCurrentRequest(), array(
|
||||
'alt' => $alt,
|
||||
'ignore_errors' => $ignore_errors,
|
||||
'comment' => $comment
|
||||
));
|
||||
|
||||
if (!$response->isSuccessful()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $response->getContent();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array an array of SmartyPluginDescriptor
|
||||
*/
|
||||
public function getPluginDescriptors()
|
||||
{
|
||||
return array(
|
||||
new SmartyPluginDescriptor('function', 'render_esi', $this, 'renderEsi')
|
||||
);
|
||||
}
|
||||
}
|
||||
155
local/modules/TheliaSmarty/Template/Plugins/FlashMessage.php
Normal file
155
local/modules/TheliaSmarty/Template/Plugins/FlashMessage.php
Normal file
@@ -0,0 +1,155 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace TheliaSmarty\Template\Plugins;
|
||||
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Thelia\Core\HttpFoundation\Session\Session;
|
||||
use Thelia\Core\Template\Element\FlashMessage as FlashMessageBag;
|
||||
use TheliaSmarty\Template\AbstractSmartyPlugin;
|
||||
use TheliaSmarty\Template\SmartyPluginDescriptor;
|
||||
use Thelia\Core\Translation\Translator;
|
||||
|
||||
/**
|
||||
* Plugin for smarty defining blocks allowing to get flash message
|
||||
* A flash message is a variable, array, object stored in session under the flashMessage key
|
||||
* ex $SESSION['flashMessage']['myType']
|
||||
*
|
||||
* blocks :
|
||||
*
|
||||
* ```
|
||||
* {flash type="myType"}
|
||||
* <div class="alert alert-success">{$MESSAGE}</div>
|
||||
* {/flash}
|
||||
* ```
|
||||
* Class Form
|
||||
*
|
||||
* @package Thelia\Core\Template\Smarty\Plugins
|
||||
* @author Guillaume MOREL <gmorel@openstudio.fr>
|
||||
* @author Julien Chanséaume <jchanseaume@openstudio.fr>
|
||||
*/
|
||||
class FlashMessage extends AbstractSmartyPlugin
|
||||
{
|
||||
/** @var RequestStack Request service */
|
||||
protected $requestStack;
|
||||
|
||||
/** @var FlashMessageBag $results */
|
||||
protected $results;
|
||||
|
||||
/** @var Translator */
|
||||
protected $translator;
|
||||
|
||||
public function __construct(RequestStack $requestStack, Translator $translator)
|
||||
{
|
||||
$this->requestStack = $requestStack;
|
||||
$this->translator = $translator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the count function: executes a loop and return the number of items found
|
||||
*
|
||||
* @param array $params parameters array
|
||||
* @param \Smarty_Internal_Template $template
|
||||
*
|
||||
* @return int the item count
|
||||
* @throws \InvalidArgumentException if a parameter is missing
|
||||
*
|
||||
*/
|
||||
public function hasFlashMessage(
|
||||
$params,
|
||||
/** @noinspection PhpUnusedParameterInspection */
|
||||
$template
|
||||
) {
|
||||
$type = $this->getParam($params, 'type', null);
|
||||
|
||||
if (null == $type) {
|
||||
throw new \InvalidArgumentException(
|
||||
$this->translator->trans("Missing 'type' parameter in {hasflash} function arguments")
|
||||
);
|
||||
}
|
||||
|
||||
return $this->getSession()->getFlashBag()->has($type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get FlashMessage
|
||||
* And clean session from this key
|
||||
*
|
||||
* @param array $params Block parameters
|
||||
* @param mixed $content Block content
|
||||
* @param \Smarty_Internal_Template $template Template
|
||||
* @param bool $repeat Control how many times
|
||||
* the block is displayed
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getFlashMessage($params, $content, \Smarty_Internal_Template $template, &$repeat)
|
||||
{
|
||||
$type = $this->getParam($params, 'type', false);
|
||||
|
||||
if (null === $content) {
|
||||
$this->results = new FlashMessageBag();
|
||||
|
||||
if (false === $type) {
|
||||
$this->results->addAll($this->getSession()->getFlashBag()->all());
|
||||
} else {
|
||||
$this->results->add(
|
||||
$type,
|
||||
$this->getSession()->getFlashBag()->get($type, [])
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->results->isEmpty()) {
|
||||
$repeat = false;
|
||||
}
|
||||
} else {
|
||||
$this->results->next();
|
||||
}
|
||||
|
||||
if ($this->results->valid()) {
|
||||
$message = $this->results->current();
|
||||
$template->assign("TYPE", $message["type"]);
|
||||
$template->assign("MESSAGE", $message["message"]);
|
||||
|
||||
$repeat = true;
|
||||
}
|
||||
|
||||
if ($content !== null) {
|
||||
if ($this->results->isEmpty()) {
|
||||
$content = "";
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array an array of SmartyPluginDescriptor
|
||||
*/
|
||||
public function getPluginDescriptors()
|
||||
{
|
||||
return [
|
||||
new SmartyPluginDescriptor("function", "hasflash", $this, "hasFlashMessage"),
|
||||
new SmartyPluginDescriptor("block", "flash", $this, "getFlashMessage")
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Session
|
||||
*/
|
||||
protected function getSession()
|
||||
{
|
||||
return $this->requestStack->getCurrentRequest()->getSession();
|
||||
}
|
||||
}
|
||||
1029
local/modules/TheliaSmarty/Template/Plugins/Form.php
Normal file
1029
local/modules/TheliaSmarty/Template/Plugins/Form.php
Normal file
File diff suppressed because it is too large
Load Diff
496
local/modules/TheliaSmarty/Template/Plugins/Format.php
Normal file
496
local/modules/TheliaSmarty/Template/Plugins/Format.php
Normal file
@@ -0,0 +1,496 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace TheliaSmarty\Template\Plugins;
|
||||
|
||||
use CommerceGuys\Addressing\Model\Address;
|
||||
use IntlDateFormatter;
|
||||
use Symfony\Component\DependencyInjection\Container;
|
||||
use Thelia\Core\HttpFoundation\Session\Session;
|
||||
use Thelia\Model\AddressQuery;
|
||||
use Thelia\Model\OrderAddressQuery;
|
||||
use Thelia\Tools\AddressFormat;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use TheliaSmarty\Template\AbstractSmartyPlugin;
|
||||
use TheliaSmarty\Template\Exception\SmartyPluginException;
|
||||
use TheliaSmarty\Template\SmartyPluginDescriptor;
|
||||
use Thelia\Tools\DateTimeFormat;
|
||||
use Thelia\Tools\MoneyFormat;
|
||||
use Thelia\Tools\NumberFormat;
|
||||
|
||||
/**
|
||||
*
|
||||
* format_date and format_date smarty function.
|
||||
*
|
||||
* Class Format
|
||||
* @package Thelia\Core\Template\Smarty\Plugins
|
||||
* @author Manuel Raynaud <manu@raynaud.io>
|
||||
* @author Benjamin Perche <benjamin@thelia.net>
|
||||
*/
|
||||
class Format extends AbstractSmartyPlugin
|
||||
{
|
||||
private static $dateKeys = ["day", "month", "year"];
|
||||
private static $timeKeys = ["hour", "minute", "second"];
|
||||
|
||||
/** @var RequestStack */
|
||||
protected $requestStack;
|
||||
|
||||
public function __construct(RequestStack $requestStack)
|
||||
{
|
||||
$this->requestStack = $requestStack;
|
||||
}
|
||||
|
||||
/**
|
||||
* return date in expected format
|
||||
*
|
||||
* available parameters :
|
||||
* date => DateTime object (mandatory)
|
||||
* format => expected format
|
||||
* output => list of default system format. Values available :
|
||||
* date => date format
|
||||
* time => time format
|
||||
* datetime => datetime format (default)
|
||||
*
|
||||
* ex :
|
||||
* {format_date date=$dateTimeObject format="Y-m-d H:i:s"} will output the format with specific format
|
||||
* {format_date date=$dateTimeObject format="l F j" locale="fr_FR"} will output the format with specific format (see date() function)
|
||||
* {format_date date=$dateTimeObject output="date"} will output the date using the default date system format
|
||||
* {format_date date=$dateTimeObject} will output with the default datetime system format
|
||||
*
|
||||
* @param array $params
|
||||
* @param null $template
|
||||
* @throws \TheliaSmarty\Template\Exception\SmartyPluginException
|
||||
* @return string
|
||||
*/
|
||||
public function formatDate($params, $template = null)
|
||||
{
|
||||
$date = $this->getParam($params, "date", false);
|
||||
|
||||
if ($date === false) {
|
||||
// Check if we have a timestamp
|
||||
$timestamp = $this->getParam($params, "timestamp", false);
|
||||
|
||||
if ($timestamp === false) {
|
||||
// No timestamp => error
|
||||
throw new SmartyPluginException("Either date or timestamp is a mandatory parameter in format_date function");
|
||||
} else {
|
||||
$date = new \DateTime();
|
||||
$date->setTimestamp($timestamp);
|
||||
}
|
||||
} elseif (is_array($date)) {
|
||||
$keys = array_keys($date);
|
||||
|
||||
$isDate = $this->arrayContains(static::$dateKeys, $keys);
|
||||
$isTime = $this->arrayContains(static::$timeKeys, $keys);
|
||||
|
||||
// If this is not a date, fallback on today
|
||||
// If this is not a time, fallback on midnight
|
||||
$dateFormat = $isDate ? sprintf("%d-%d-%d", $date["year"], $date["month"], $date["day"]) : (new \DateTime())->format("Y-m-d");
|
||||
$timeFormat = $isTime ? sprintf("%d:%d:%d", $date["hour"], $date["minute"], $date["second"]) : "0:0:0";
|
||||
|
||||
$date = new \DateTime(sprintf("%s %s", $dateFormat, $timeFormat));
|
||||
}
|
||||
|
||||
if (!($date instanceof \DateTime)) {
|
||||
try {
|
||||
$date = new \DateTime($date);
|
||||
} catch (\Exception $e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
$format = $this->getParam($params, "format", false);
|
||||
|
||||
if ($format === false) {
|
||||
$format = DateTimeFormat::getInstance($this->requestStack->getCurrentRequest())->getFormat($this->getParam($params, "output", null));
|
||||
}
|
||||
|
||||
$locale = $this->getParam($params, 'locale', false);
|
||||
|
||||
if (false === $locale) {
|
||||
$value = $date->format($format);
|
||||
} else {
|
||||
$value = $this->formatDateWithLocale($date, $locale, $format);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
private function formatDateWithLocale(\DateTime $date, $locale, $format)
|
||||
{
|
||||
if (false === strpos($format, '%')) {
|
||||
$formatter = new IntlDateFormatter($locale, IntlDateFormatter::FULL, IntlDateFormatter::FULL);
|
||||
|
||||
$icuFormat = $this->convertDatePhpToIcu($format);
|
||||
$formatter->setPattern($icuFormat);
|
||||
|
||||
$localizedDate = $formatter->format($date);
|
||||
} else {
|
||||
// for backward compatibility
|
||||
if (function_exists('setlocale')) {
|
||||
// Save the current locale
|
||||
$systemLocale = setlocale(LC_TIME, 0);
|
||||
setlocale(LC_TIME, $locale);
|
||||
$localizedDate = strftime($format, $date->getTimestamp());
|
||||
// Restore the locale
|
||||
setlocale(LC_TIME, $systemLocale);
|
||||
} else {
|
||||
// setlocale() function not available => error
|
||||
throw new SmartyPluginException("The setlocale() function is not available on your system.");
|
||||
}
|
||||
}
|
||||
|
||||
return $localizedDate;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* display numbers in expected format
|
||||
*
|
||||
* available parameters :
|
||||
* number => int or float number
|
||||
* decimals => how many decimals format expected
|
||||
* dec_point => separator for the decimal point
|
||||
* thousands_sep => thousands separator
|
||||
*
|
||||
* ex : {format_number number="1246.12" decimals="1" dec_point="," thousands_sep=" "} will output "1 246,1"
|
||||
*
|
||||
* @param $params
|
||||
* @param null $template
|
||||
* @throws \TheliaSmarty\Template\Exception\SmartyPluginException
|
||||
* @return string the expected number formatted
|
||||
*/
|
||||
public function formatNumber($params, $template = null)
|
||||
{
|
||||
$number = $this->getParam($params, "number", false);
|
||||
|
||||
if ($number === false || $number === '') {
|
||||
return "";
|
||||
}
|
||||
|
||||
return NumberFormat::getInstance($this->requestStack->getCurrentRequest())->format(
|
||||
$number,
|
||||
$this->getParam($params, "decimals", null),
|
||||
$this->getParam($params, "dec_point", null),
|
||||
$this->getParam($params, "thousands_sep", null)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* display a amount in expected format
|
||||
*
|
||||
* available parameters :
|
||||
* number => int or float number
|
||||
* decimals => how many decimals format expected
|
||||
* dec_point => separator for the decimal point
|
||||
* thousands_sep => thousands separator
|
||||
* symbol => Currency symbol
|
||||
*
|
||||
* ex : {format_money number="1246.12" decimals="1" dec_point="," thousands_sep=" " symbol="€"} will output "1 246,1 €"
|
||||
*
|
||||
* @param $params
|
||||
* @param null $template
|
||||
* @throws \TheliaSmarty\Template\Exception\SmartyPluginException
|
||||
* @return string the expected number formatted
|
||||
*/
|
||||
public function formatMoney($params, $template = null)
|
||||
{
|
||||
$number = $this->getParam($params, "number", false);
|
||||
|
||||
if ($number === false || $number === '') {
|
||||
return "";
|
||||
}
|
||||
|
||||
if ($this->getParam($params, "symbol", null) === null) {
|
||||
return MoneyFormat::getInstance($this->requestStack->getCurrentRequest())->formatByCurrency(
|
||||
$number,
|
||||
$this->getParam($params, "decimals", null),
|
||||
$this->getParam($params, "dec_point", null),
|
||||
$this->getParam($params, "thousands_sep", null),
|
||||
$this->getParam($params, "currency_id", null)
|
||||
);
|
||||
}
|
||||
|
||||
return MoneyFormat::getInstance($this->requestStack->getCurrentRequest())->format(
|
||||
$number,
|
||||
$this->getParam($params, "decimals", null),
|
||||
$this->getParam($params, "dec_point", null),
|
||||
$this->getParam($params, "thousands_sep", null),
|
||||
$this->getParam($params, "symbol", null)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* return two-dimensional arrays in string
|
||||
*
|
||||
* available parameters :
|
||||
* values => array 2D ['key A' => ['value 1', 'value 2'], 'key B' => ['value 3', 'value 4']]
|
||||
* separators => ['key value separator', 'value value separator', 'key key separator']
|
||||
*
|
||||
* ex :
|
||||
* {format_array_2d values=['Colors' => ['Green', 'Yellow', 'Red'], 'Material' => ['Wood']] separators=[' : ', ' / ', ' | ']}
|
||||
* will output the format with specific format : "Colors : Green / Yellow / Red | Material : Wood"
|
||||
*
|
||||
* @param $params
|
||||
* @return string
|
||||
*/
|
||||
public function formatTwoDimensionalArray($params)
|
||||
{
|
||||
$output = '';
|
||||
$values = $this->getParam($params, "values", null);
|
||||
$separators = $this->getParam($params, "separators", [' : ', ' / ', ' | ']);
|
||||
|
||||
if (!is_array($values)) {
|
||||
return $output;
|
||||
}
|
||||
|
||||
foreach ($values as $key => $value) {
|
||||
if ($output !== '') {
|
||||
$output .= $separators[2];
|
||||
}
|
||||
|
||||
$output .= $key . $separators[0];
|
||||
|
||||
if (!is_array($value)) {
|
||||
$output .= $value;
|
||||
continue;
|
||||
}
|
||||
|
||||
$output .= implode($separators[1], $value);
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
protected function arrayContains(array $expected, array $hayStack)
|
||||
{
|
||||
foreach ($expected as $value) {
|
||||
if (!in_array($value, $hayStack)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function comes from [Yii framework](http://www.yiiframework.com/)
|
||||
*
|
||||
*
|
||||
* Converts a date format pattern from [php date() function format][] to [ICU format][].
|
||||
*
|
||||
* The conversion is limited to date patterns that do not use escaped characters.
|
||||
* Patterns like `jS \o\f F Y` which will result in a date like `1st of December 2014` may not be converted correctly
|
||||
* because of the use of escaped characters.
|
||||
*
|
||||
* Pattern constructs that are not supported by the ICU format will be removed.
|
||||
*
|
||||
* [php date() function format]: http://php.net/manual/en/function.date.php
|
||||
* [ICU format]: http://userguide.icu-project.org/formatparse/datetime#TOC-Date-Time-Format-Syntax
|
||||
*
|
||||
* @param string $pattern date format pattern in php date()-function format.
|
||||
* @return string The converted date format pattern.
|
||||
*/
|
||||
protected function convertDatePhpToIcu($pattern)
|
||||
{
|
||||
// http://php.net/manual/en/function.date.php
|
||||
return strtr(
|
||||
$pattern,
|
||||
[
|
||||
// Day
|
||||
'd' => 'dd', // Day of the month, 2 digits with leading zeros 01 to 31
|
||||
'D' => 'eee', // A textual representation of a day, three letters Mon through Sun
|
||||
'j' => 'd', // Day of the month without leading zeros 1 to 31
|
||||
'l' => 'eeee', // A full textual representation of the day of the week Sunday through Saturday
|
||||
'N' => 'e', // ISO-8601 numeric representation of the day of the week, 1 (for Monday) through 7 (for Sunday)
|
||||
'S' => '', // English ordinal suffix for the day of the month, 2 characters st, nd, rd or th. Works well with j
|
||||
'w' => '', // Numeric representation of the day of the week 0 (for Sunday) through 6 (for Saturday)
|
||||
'z' => 'D', // The day of the year (starting from 0) 0 through 365
|
||||
// Week
|
||||
'W' => 'w', // ISO-8601 week number of year, weeks starting on Monday (added in PHP 4.1.0) Example: 42 (the 42nd week in the year)
|
||||
// Month
|
||||
'F' => 'MMMM', // A full textual representation of a month, January through December
|
||||
'm' => 'MM', // Numeric representation of a month, with leading zeros 01 through 12
|
||||
'M' => 'MMM', // A short textual representation of a month, three letters Jan through Dec
|
||||
'n' => 'M', // Numeric representation of a month, without leading zeros 1 through 12, not supported by ICU but we fallback to "with leading zero"
|
||||
't' => '', // Number of days in the given month 28 through 31
|
||||
// Year
|
||||
'L' => '', // Whether it's a leap year, 1 if it is a leap year, 0 otherwise.
|
||||
'o' => 'Y', // ISO-8601 year number. This has the same value as Y, except that if the ISO week number (W) belongs to the previous or next year, that year is used instead.
|
||||
'Y' => 'yyyy', // A full numeric representation of a year, 4 digits Examples: 1999 or 2003
|
||||
'y' => 'yy', // A two digit representation of a year Examples: 99 or 03
|
||||
// Time
|
||||
'a' => 'a', // Lowercase Ante meridiem and Post meridiem, am or pm
|
||||
'A' => 'a', // Uppercase Ante meridiem and Post meridiem, AM or PM, not supported by ICU but we fallback to lowercase
|
||||
'B' => '', // Swatch Internet time 000 through 999
|
||||
'g' => 'h', // 12-hour format of an hour without leading zeros 1 through 12
|
||||
'G' => 'H', // 24-hour format of an hour without leading zeros 0 to 23h
|
||||
'h' => 'hh', // 12-hour format of an hour with leading zeros, 01 to 12 h
|
||||
'H' => 'HH', // 24-hour format of an hour with leading zeros, 00 to 23 h
|
||||
'i' => 'mm', // Minutes with leading zeros 00 to 59
|
||||
's' => 'ss', // Seconds, with leading zeros 00 through 59
|
||||
'u' => '', // Microseconds. Example: 654321
|
||||
// Timezone
|
||||
'e' => 'VV', // Timezone identifier. Examples: UTC, GMT, Atlantic/Azores
|
||||
'I' => '', // Whether or not the date is in daylight saving time, 1 if Daylight Saving Time, 0 otherwise.
|
||||
'O' => 'xx', // Difference to Greenwich time (GMT) in hours, Example: +0200
|
||||
'P' => 'xxx', // Difference to Greenwich time (GMT) with colon between hours and minutes, Example: +02:00
|
||||
'T' => 'zzz', // Timezone abbreviation, Examples: EST, MDT ...
|
||||
'Z' => '', // Timezone offset in seconds. The offset for timezones west of UTC is always negative, and for those east of UTC is always positive. -43200 through 50400
|
||||
// Full Date/Time
|
||||
'c' => 'yyyy-MM-dd\'T\'HH:mm:ssxxx', // ISO 8601 date, e.g. 2004-02-12T15:19:21+00:00
|
||||
'r' => 'eee, dd MMM yyyy HH:mm:ss xx', // RFC 2822 formatted date, Example: Thu, 21 Dec 2000 16:01:07 +0200
|
||||
'U' => '', // Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT)
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* display an address in expected format
|
||||
*
|
||||
* available parameters :
|
||||
* address => the id of the address to display
|
||||
* order_address => the id of the order address to display
|
||||
* from_country_id => the country id
|
||||
* dec_point => separator for the decimal point
|
||||
* thousands_sep => thousands separator
|
||||
* symbol => Currency symbol
|
||||
*
|
||||
* ex : {format_money number="1246.12" decimals="1" dec_point="," thousands_sep=" " symbol="€"} will output "1 246,1 €"
|
||||
*
|
||||
* @param $params
|
||||
* @param null $template
|
||||
* @throws \TheliaSmarty\Template\Exception\SmartyPluginException
|
||||
* @return string the expected number formatted
|
||||
*/
|
||||
public function formatAddress($params, $template = null)
|
||||
{
|
||||
$postal = filter_var(
|
||||
$this->getParam($params, "postal", null),
|
||||
FILTER_VALIDATE_BOOLEAN
|
||||
);
|
||||
|
||||
$html = filter_var(
|
||||
$this->getParam($params, "html", true),
|
||||
FILTER_VALIDATE_BOOLEAN
|
||||
);
|
||||
|
||||
$htmlTag = $this->getParam($params, "html_tag", "p");
|
||||
$originCountry = $this->getParam($params, "origin_country", null);
|
||||
$locale = $this->getParam($params, "locale", $this->getSession()->getLang()->getLocale());
|
||||
|
||||
// extract html attributes
|
||||
$htmlAttributes = [];
|
||||
foreach ($params as $k => $v) {
|
||||
if (strpos($k, 'html_') !== false && $k !== 'html_tag') {
|
||||
$htmlAttributes[substr($k, 5)] = $v;
|
||||
}
|
||||
}
|
||||
|
||||
// get address or order address
|
||||
$address = null;
|
||||
if (null !== $id = $this->getParam($params, "address", null)) {
|
||||
if (null === $address = AddressQuery::create()->findPk($id)) {
|
||||
return '';
|
||||
}
|
||||
} elseif (null !== $id = $this->getParam($params, "order_address", null)) {
|
||||
if (null === $address = OrderAddressQuery::create()->findPk($id)) {
|
||||
return '';
|
||||
}
|
||||
} else {
|
||||
// try to parse arguments to build address
|
||||
$address = $this->getAddressFormParams($params);
|
||||
}
|
||||
|
||||
if (null === $address) {
|
||||
throw new SmartyPluginException(
|
||||
"Either address, order_address or full list of address fields should be provided"
|
||||
);
|
||||
}
|
||||
|
||||
$addressFormat = AddressFormat::getInstance();
|
||||
if ($postal) {
|
||||
if ($address instanceof Address) {
|
||||
$formattedAddress = $addressFormat->postalLabelFormat($address, $locale, $originCountry);
|
||||
} else {
|
||||
$formattedAddress = $addressFormat->postalLabelFormatTheliaAddress($address, $locale, $originCountry);
|
||||
}
|
||||
} else {
|
||||
if ($address instanceof Address) {
|
||||
$formattedAddress = $addressFormat->format($address, $locale, $html, $htmlTag, $htmlAttributes);
|
||||
} else {
|
||||
$formattedAddress = $addressFormat->formatTheliaAddress($address, $locale, $html, $htmlTag, $htmlAttributes);
|
||||
}
|
||||
}
|
||||
|
||||
return $formattedAddress;
|
||||
}
|
||||
|
||||
protected function getAddressFormParams($params)
|
||||
{
|
||||
// Check if there is arguments
|
||||
$addressArgs = [
|
||||
'country_code',
|
||||
'administrative_area',
|
||||
'locality',
|
||||
'dependent_locality',
|
||||
'postal_code',
|
||||
'sorting_code',
|
||||
'address_line1',
|
||||
'address_line2',
|
||||
'organization',
|
||||
'recipient',
|
||||
'locale'
|
||||
];
|
||||
$valid = false;
|
||||
|
||||
$address = new Address();
|
||||
|
||||
foreach ($addressArgs as $arg) {
|
||||
if (null !== $argVal = $this->getParam($params, $arg, null)) {
|
||||
$valid = true;
|
||||
$functionName = 'with' . Container::camelize($arg);
|
||||
$address = $address->$functionName($argVal);
|
||||
}
|
||||
}
|
||||
|
||||
if (false === $valid) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $address;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SmartyPluginDescriptor[]
|
||||
*/
|
||||
public function getPluginDescriptors()
|
||||
{
|
||||
return array(
|
||||
new SmartyPluginDescriptor("function", "format_date", $this, "formatDate"),
|
||||
new SmartyPluginDescriptor("function", "format_number", $this, "formatNumber"),
|
||||
new SmartyPluginDescriptor("function", "format_money", $this, "formatMoney"),
|
||||
new SmartyPluginDescriptor("function", "format_array_2d", $this, "formatTwoDimensionalArray"),
|
||||
new SmartyPluginDescriptor("function", "format_address", $this, "formatAddress"),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Session
|
||||
*/
|
||||
protected function getSession()
|
||||
{
|
||||
return $this->requestStack->getCurrentRequest()->getSession();
|
||||
}
|
||||
}
|
||||
476
local/modules/TheliaSmarty/Template/Plugins/Hook.php
Normal file
476
local/modules/TheliaSmarty/Template/Plugins/Hook.php
Normal file
@@ -0,0 +1,476 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace TheliaSmarty\Template\Plugins;
|
||||
|
||||
use Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher;
|
||||
use Thelia\Core\Event\Hook\HookRenderBlockEvent;
|
||||
use Thelia\Core\Event\Hook\HookRenderEvent;
|
||||
use Thelia\Core\Hook\Fragment;
|
||||
use Thelia\Core\Hook\FragmentBag;
|
||||
use TheliaSmarty\Template\Plugins\Module;
|
||||
use TheliaSmarty\Template\AbstractSmartyPlugin;
|
||||
use TheliaSmarty\Template\SmartyParser;
|
||||
use TheliaSmarty\Template\SmartyPluginDescriptor;
|
||||
use Thelia\Core\Template\TemplateDefinition;
|
||||
use Thelia\Core\Translation\Translator;
|
||||
use Thelia\Model\ModuleQuery;
|
||||
|
||||
/**
|
||||
* Plugin for smarty defining blocks and functions for using Hooks.
|
||||
*
|
||||
* Class Hook
|
||||
* @package Thelia\Core\Template\Smarty\Plugins
|
||||
* @author Julien Chanséaume <jchanseaume@openstudio.fr>
|
||||
*/
|
||||
class Hook extends AbstractSmartyPlugin
|
||||
{
|
||||
private $dispatcher;
|
||||
|
||||
/** @var Translator */
|
||||
protected $translator;
|
||||
|
||||
/** @var Module */
|
||||
protected $smartyPluginModule = null;
|
||||
|
||||
/** @var array */
|
||||
protected $hookResults = array();
|
||||
|
||||
/** @var array */
|
||||
protected $varstack = array();
|
||||
|
||||
/** @var bool debug */
|
||||
protected $debug = false;
|
||||
|
||||
public function __construct($debug, ContainerAwareEventDispatcher $dispatcher)
|
||||
{
|
||||
$this->debug = $debug;
|
||||
$this->dispatcher = $dispatcher;
|
||||
$this->translator = $dispatcher->getContainer()->get("thelia.translator");
|
||||
$this->hookResults = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the content of the hook
|
||||
*
|
||||
* {hook name="hook_code" var1="value1" var2="value2" ... }
|
||||
*
|
||||
* This function create an event, feed it with the custom variables passed to the function (var1, var2, ...) and
|
||||
* dispatch it to the hooks that respond to it.
|
||||
*
|
||||
* The name of the event is `hook.{context}.{hook_code}` where :
|
||||
* * context : the id of the context of the smarty render : 1: frontoffice, 2: backoffice, 3: email, 4: pdf
|
||||
* * hook_code : the code of the hook
|
||||
*
|
||||
* The event collects all the fragments of text rendered in each modules functions that listen to this event.
|
||||
* Finally, this fragments are concatenated and injected in the template
|
||||
*
|
||||
* @param array $params the params passed in the smarty function
|
||||
* @param \TheliaSmarty\Template\SmartyParser $smarty the smarty parser
|
||||
*
|
||||
* @return string the contents generated by modules
|
||||
*/
|
||||
public function processHookFunction($params, &$smarty)
|
||||
{
|
||||
$hookName = $this->getParam($params, 'name');
|
||||
$module = intval($this->getParam($params, 'module', 0));
|
||||
$moduleCode = $this->getParam($params, 'modulecode', "");
|
||||
|
||||
$type = $smarty->getTemplateDefinition()->getType();
|
||||
|
||||
$event = new HookRenderEvent($hookName, $params);
|
||||
|
||||
$event->setArguments($this->getArgumentsFromParams($params));
|
||||
|
||||
$eventName = sprintf('hook.%s.%s', $type, $hookName);
|
||||
|
||||
// this is a hook specific to a module
|
||||
if (0 === $module && "" !== $moduleCode) {
|
||||
if (null !== $mod = ModuleQuery::create()->findOneByCode($moduleCode)) {
|
||||
$module = $mod->getId();
|
||||
}
|
||||
}
|
||||
if (0 !== $module) {
|
||||
$eventName .= '.' . $module;
|
||||
}
|
||||
|
||||
$this->getDispatcher()->dispatch($eventName, $event);
|
||||
|
||||
$content = trim($event->dump());
|
||||
|
||||
if ($this->debug && $smarty->getRequest()->get('SHOW_HOOK')) {
|
||||
$content = self::showHook($hookName, $params) . $content;
|
||||
}
|
||||
|
||||
$this->hookResults[$hookName] = $content;
|
||||
|
||||
// support for compatibility with module_include
|
||||
if ($type === TemplateDefinition::BACK_OFFICE) {
|
||||
$content .= $this->moduleIncludeCompat($params, $smarty);
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the plugin function module_include for backward compatibility.
|
||||
*
|
||||
* @param array $params the params passed in the smarty function
|
||||
* @param \TheliaSmarty\Template\SmartyParser $smarty the smarty parser
|
||||
*
|
||||
* @return string the contents generated by module_include function
|
||||
*/
|
||||
protected function moduleIncludeCompat($params, &$smarty)
|
||||
{
|
||||
$plugin = $this->getSmartyPluginModule();
|
||||
$params = array(
|
||||
"location" => $this->getParam($params, 'location', null),
|
||||
"module" => $this->getParam($params, 'modulecode', null),
|
||||
"countvar" => $this->getParam($params, 'countvar', null)
|
||||
);
|
||||
|
||||
return $plugin->theliaModule($params, $smarty);
|
||||
}
|
||||
|
||||
/**
|
||||
* get the smarty plugin Module
|
||||
*
|
||||
* @return Module the smarty plugin Module
|
||||
*/
|
||||
protected function getSmartyPluginModule()
|
||||
{
|
||||
if (null === $this->smartyPluginModule) {
|
||||
$this->smartyPluginModule = $this->dispatcher->getContainer()->get("smarty.plugin.module");
|
||||
}
|
||||
|
||||
return $this->smartyPluginModule;
|
||||
}
|
||||
|
||||
protected function showHook($hookName, $params)
|
||||
{
|
||||
$content = '<div style="background-color: #C82D26; color: #fff; border-color: #000000; border: solid;">' . $hookName;
|
||||
|
||||
foreach ($params as $name => $value) {
|
||||
if ($name !== 'location' && $name !== "name") {
|
||||
$type = '';
|
||||
if (is_object($value)) {
|
||||
$value = get_class($value);
|
||||
$type = 'object';
|
||||
} elseif (is_array($value)) {
|
||||
$value = implode(',', $value);
|
||||
$type = 'array';
|
||||
} elseif (is_int($value)) {
|
||||
$type = 'float';
|
||||
} elseif (is_int($value)) {
|
||||
$type = 'int';
|
||||
} elseif (is_string($value)) {
|
||||
$value = (strlen($value) > 30) ? substr($value, 0, 30) . '...' : $value;
|
||||
$type = 'string';
|
||||
}
|
||||
|
||||
if ($type !== '') {
|
||||
$type = '<span style="background-color: #FF7D00; color: #fff">' . $type . '</span> ';
|
||||
}
|
||||
|
||||
$content .= '<span style="background-color: #008000; color: #fff; margin-left: 6px;">' . $name . ' = ' . $type . $value . '</span>';
|
||||
}
|
||||
}
|
||||
|
||||
return $content . '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the content of the hook block.
|
||||
*
|
||||
* {hookblock name="hook_code" var1="value1" var2="value2" ... }
|
||||
*
|
||||
* This function create an event, feed it with the custom variables passed to the function (var1, var2, ...) and
|
||||
* dispatch it to the hooks that respond to it.
|
||||
*
|
||||
* The name of the event is `hook.{context}.{hook_code}` where :
|
||||
* * context : the id of the context of the smarty render : 1: frontoffice, 2: backoffice, 3: email, 4: pdf
|
||||
* * hook_code : the code of the hook
|
||||
*
|
||||
* The event collects all the fragments generated by modules that listen to this event and add it to a fragmentBag.
|
||||
* This fragmentBag is not used directly. This is the forhook block that iterates over the fragmentBag to inject
|
||||
* data in the template.
|
||||
*
|
||||
* @param array $params
|
||||
* @param string $content
|
||||
* @param \TheliaSmarty\Template\SmartyParser $smarty
|
||||
* @param bool $repeat
|
||||
*
|
||||
* @return string the generated content
|
||||
*/
|
||||
public function processHookBlock($params, $content, $smarty, &$repeat)
|
||||
{
|
||||
$hookName = $this->getParam($params, 'name');
|
||||
$module = intval($this->getParam($params, 'module', 0));
|
||||
// explicit definition of variable that can be returned
|
||||
$fields = preg_replace(
|
||||
'|[^a-zA-Z0-9,\-_]|',
|
||||
'',
|
||||
$this->getParam($params, 'fields', '')
|
||||
);
|
||||
$fields = ('' !== $fields) ? explode(",", $fields) : [];
|
||||
|
||||
if (!$repeat) {
|
||||
if ($this->debug && $smarty->getRequest()->get('SHOW_HOOK')) {
|
||||
$content = self::showHook($hookName, $params) . $content;
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
$type = $smarty->getTemplateDefinition()->getType();
|
||||
|
||||
$event = new HookRenderBlockEvent($hookName, $params, $fields);
|
||||
|
||||
$event->setArguments($this->getArgumentsFromParams($params));
|
||||
|
||||
$eventName = sprintf('hook.%s.%s', $type, $hookName);
|
||||
|
||||
// this is a hook specific to a module
|
||||
if (0 !== $module) {
|
||||
$eventName .= '.' . $module;
|
||||
}
|
||||
|
||||
$this->getDispatcher()->dispatch($eventName, $event);
|
||||
|
||||
// save results so we can use it in forHook block
|
||||
$this->hookResults[$hookName] = $event->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a {forhook rel="hookname"} ... {/forhook}
|
||||
*
|
||||
* The forhook iterates over the results return by a hookblock :
|
||||
*
|
||||
* {hookblock name="product.additional"}
|
||||
* {forhook rel="product.additional"}
|
||||
* <div id="{$id}">
|
||||
* <h2>{$title}</h2>
|
||||
* <p>{$content}</p>
|
||||
* </div>
|
||||
* {/forhook}
|
||||
* {/hookblock}
|
||||
*
|
||||
* @param array $params
|
||||
* @param string $content
|
||||
* @param \TheliaSmarty\Template\SmartyParser $smarty
|
||||
* @param bool $repeat
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
* @return string the generated content
|
||||
*/
|
||||
public function processForHookBlock($params, $content, $smarty, &$repeat)
|
||||
{
|
||||
$rel = $this->getParam($params, 'rel');
|
||||
if (null == $rel) {
|
||||
throw new \InvalidArgumentException(
|
||||
$this->translator->trans("Missing 'rel' parameter in forHook arguments")
|
||||
);
|
||||
}
|
||||
|
||||
/** @var FragmentBag $fragments */
|
||||
$fragments = null;
|
||||
|
||||
// first call
|
||||
if ($content === null) {
|
||||
if (!array_key_exists($rel, $this->hookResults)) {
|
||||
throw new \InvalidArgumentException(
|
||||
$this->translator->trans("Related hook name '%name' is not defined.", ['%name' => $rel])
|
||||
);
|
||||
}
|
||||
|
||||
$fragments = $this->hookResults[$rel];
|
||||
$fragments->rewind();
|
||||
|
||||
if ($fragments->isEmpty()) {
|
||||
$repeat = false;
|
||||
}
|
||||
} else {
|
||||
$fragments = $this->hookResults[$rel];
|
||||
$fragments->next();
|
||||
}
|
||||
|
||||
if ($fragments->valid()) {
|
||||
/** @var Fragment $fragment */
|
||||
$fragment = $fragments->current();
|
||||
|
||||
// On first iteration, save variables that may be overwritten by this hook
|
||||
if (!isset($this->varstack[$rel])) {
|
||||
$saved_vars = array();
|
||||
|
||||
$varlist = $fragment->getVars();
|
||||
|
||||
foreach ($varlist as $var) {
|
||||
$saved_vars[$var] = $smarty->getTemplateVars($var);
|
||||
}
|
||||
|
||||
$this->varstack[$rel] = $saved_vars;
|
||||
}
|
||||
|
||||
foreach ($fragment->getVarVal() as $var => $val) {
|
||||
$smarty->assign($var, $val);
|
||||
}
|
||||
// continue iteration
|
||||
$repeat = true;
|
||||
}
|
||||
|
||||
// end
|
||||
if (!$repeat) {
|
||||
// Restore previous variables values before terminating
|
||||
if (isset($this->varstack[$rel])) {
|
||||
foreach ($this->varstack[$rel] as $var => $value) {
|
||||
$smarty->assign($var, $value);
|
||||
}
|
||||
|
||||
unset($this->varstack[$rel]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($content !== null) {
|
||||
if ($fragments->isEmpty()) {
|
||||
$content = "";
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Process {elsehook rel="hookname"} ... {/elsehook} block
|
||||
*
|
||||
* @param array $params hook parameters
|
||||
* @param string $content hook text content
|
||||
* @param \Smarty_Internal_Template $template the Smarty object
|
||||
* @param boolean $repeat repeat indicator (see Smarty doc.)
|
||||
*
|
||||
* @return string the hook output
|
||||
*/
|
||||
public function elseHook(
|
||||
$params,
|
||||
$content,
|
||||
/** @noinspection PhpUnusedParameterInspection */ $template,
|
||||
&$repeat
|
||||
) {
|
||||
// When encountering close tag, check if hook has results.
|
||||
if ($repeat === false) {
|
||||
return $this->checkEmptyHook($params) ? $content : '';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Process {ifhook rel="hookname"} ... {/ifhook} block
|
||||
*
|
||||
* @param array $params hook parameters
|
||||
* @param string $content hook text content
|
||||
* @param \Smarty_Internal_Template $template the Smarty object
|
||||
* @param boolean $repeat repeat indicator (see Smarty doc.)
|
||||
*
|
||||
* @return string the hook output
|
||||
*/
|
||||
public function ifHook($params, $content, /** @noinspection PhpUnusedParameterInspection */ $template, &$repeat)
|
||||
{
|
||||
// When encountering close tag, check if hook has results.
|
||||
if ($repeat === false) {
|
||||
return $this->checkEmptyHook($params) ? '' : $content;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a hook has returned results. The hook should have been executed before, or an
|
||||
* InvalidArgumentException is thrown
|
||||
*
|
||||
* @param array $params
|
||||
*
|
||||
* @return boolean true if the hook is empty
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
protected function checkEmptyHook($params)
|
||||
{
|
||||
$hookName = $this->getParam($params, 'rel');
|
||||
|
||||
if (null == $hookName) {
|
||||
throw new \InvalidArgumentException(
|
||||
$this->translator->trans("Missing 'rel' parameter in ifhook/elsehook arguments")
|
||||
);
|
||||
}
|
||||
|
||||
if (!isset($this->hookResults[$hookName])) {
|
||||
throw new \InvalidArgumentException(
|
||||
$this->translator->trans("Related hook name '%name' is not defined.", ['%name' => $hookName])
|
||||
);
|
||||
}
|
||||
|
||||
return (is_string($this->hookResults[$hookName]) && '' === $this->hookResults[$hookName]
|
||||
|| !is_string($this->hookResults[$hookName]) && $this->hookResults[$hookName]->isEmpty()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean the params of the params passed to the hook function or block to feed the arguments of the event
|
||||
* with relevant arguments.
|
||||
*
|
||||
* @param $params
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getArgumentsFromParams($params)
|
||||
{
|
||||
$args = array();
|
||||
$excludes = array("name", "before", "separator", "after", "fields");
|
||||
|
||||
if (is_array($params)) {
|
||||
foreach ($params as $key => $value) {
|
||||
if (!in_array($key, $excludes)) {
|
||||
$args[$key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the various smarty plugins handled by this class
|
||||
*
|
||||
* @return array an array of smarty plugin descriptors
|
||||
*/
|
||||
public function getPluginDescriptors()
|
||||
{
|
||||
return array(
|
||||
new SmartyPluginDescriptor('function', 'hook', $this, 'processHookFunction'),
|
||||
new SmartyPluginDescriptor('block', 'hookblock', $this, 'processHookBlock'),
|
||||
new SmartyPluginDescriptor('block', 'forhook', $this, 'processForHookBlock'),
|
||||
new SmartyPluginDescriptor('block', 'elsehook', $this, 'elseHook'),
|
||||
new SmartyPluginDescriptor('block', 'ifhook', $this, 'ifHook'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the event dispatcher,
|
||||
*
|
||||
* @return \Symfony\Component\EventDispatcher\EventDispatcher
|
||||
*/
|
||||
public function getDispatcher()
|
||||
{
|
||||
return $this->dispatcher;
|
||||
}
|
||||
}
|
||||
104
local/modules/TheliaSmarty/Template/Plugins/Module.php
Normal file
104
local/modules/TheliaSmarty/Template/Plugins/Module.php
Normal file
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace TheliaSmarty\Template\Plugins;
|
||||
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Thelia\Core\Template\Smarty\Plugins\an;
|
||||
use TheliaSmarty\Template\SmartyPluginDescriptor;
|
||||
use TheliaSmarty\Template\AbstractSmartyPlugin;
|
||||
use Thelia\Model\ModuleQuery;
|
||||
|
||||
class Module extends AbstractSmartyPlugin
|
||||
{
|
||||
/** @var bool application debug mode */
|
||||
protected $debug;
|
||||
|
||||
/** @var RequestStack */
|
||||
protected $requestStack;
|
||||
|
||||
public function __construct($debug, RequestStack $requestStack)
|
||||
{
|
||||
$this->debug = $debug;
|
||||
$this->requestStack = $requestStack;
|
||||
}
|
||||
/**
|
||||
* Process theliaModule template inclusion function
|
||||
*
|
||||
* This function accepts two parameters:
|
||||
*
|
||||
* - location : this is the location in the admin template. Example: folder-edit'. The function will search for
|
||||
* AdminIncludes/<location>.html file, and fetch it as a Smarty template.
|
||||
* - countvar : this is the name of a template variable where the number of found modules includes will be assigned.
|
||||
*
|
||||
* @param array $params
|
||||
* @param \Smarty_Internal_Template $template
|
||||
* @internal param \Thelia\Core\Template\Smarty\Plugins\unknown $smarty
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function theliaModule($params, \Smarty_Internal_Template $template)
|
||||
{
|
||||
$content = null;
|
||||
$count = 0;
|
||||
if (false !== $location = $this->getParam($params, 'location', false)) {
|
||||
if ($this->debug === true && $this->requestStack->getCurrentRequest()->get('SHOW_INCLUDE')) {
|
||||
echo sprintf('<div style="background-color: #C82D26; color: #fff; border-color: #000000; border: solid;">%s</div>', $location);
|
||||
}
|
||||
|
||||
$moduleLimit = $this->getParam($params, 'module', null);
|
||||
|
||||
$modules = ModuleQuery::getActivated();
|
||||
|
||||
/** @var \Thelia\Model\Module $module */
|
||||
foreach ($modules as $module) {
|
||||
if (null !== $moduleLimit && $moduleLimit != $module->getCode()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$file = $module->getAbsoluteAdminIncludesPath() . DS . $location . '.html';
|
||||
|
||||
if (file_exists($file)) {
|
||||
$output = trim(file_get_contents($file));
|
||||
|
||||
if (! empty($output)) {
|
||||
$content .= $output;
|
||||
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (false !== $countvarname = $this->getParam($params, 'countvar', false)) {
|
||||
$template->assign($countvarname, $count);
|
||||
}
|
||||
|
||||
if (! empty($content)) {
|
||||
return $template->fetch(sprintf("string:%s", $content));
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the various smarty plugins hendled by this class
|
||||
*
|
||||
* @return an array of smarty plugin descriptors
|
||||
*/
|
||||
public function getPluginDescriptors()
|
||||
{
|
||||
return array(
|
||||
new SmartyPluginDescriptor('function', 'module_include', $this, 'theliaModule'),
|
||||
);
|
||||
}
|
||||
}
|
||||
167
local/modules/TheliaSmarty/Template/Plugins/Render.php
Normal file
167
local/modules/TheliaSmarty/Template/Plugins/Render.php
Normal file
@@ -0,0 +1,167 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace TheliaSmarty\Template\Plugins;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Container;
|
||||
use Symfony\Component\HttpFoundation\ParameterBag;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Thelia\Core\Controller\ControllerResolver;
|
||||
use TheliaSmarty\Template\AbstractSmartyPlugin;
|
||||
use TheliaSmarty\Template\Exception\SmartyPluginException;
|
||||
use TheliaSmarty\Template\SmartyPluginDescriptor;
|
||||
|
||||
/**
|
||||
* Class Render
|
||||
* @package TheliaSmarty\Template\Plugins
|
||||
* @author Benjamin Perche <bperche@openstudio.fr>
|
||||
*/
|
||||
class Render extends AbstractSmartyPlugin
|
||||
{
|
||||
/** @var ControllerResolver */
|
||||
protected $controllerResolver;
|
||||
|
||||
/** @var RequestStack */
|
||||
protected $requestStack;
|
||||
|
||||
/** @var Container */
|
||||
protected $container;
|
||||
|
||||
/**
|
||||
* @param ControllerResolver $controllerResolver
|
||||
* @param RequestStack $requestStack
|
||||
* @param Container $container
|
||||
*/
|
||||
public function __construct(ControllerResolver $controllerResolver, RequestStack $requestStack, Container $container)
|
||||
{
|
||||
$this->controllerResolver = $controllerResolver;
|
||||
$this->requestStack = $requestStack;
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $params
|
||||
* @return mixed|string
|
||||
* @throws SmartyPluginException
|
||||
*/
|
||||
public function processRender($params)
|
||||
{
|
||||
if (null === $params["action"]) {
|
||||
throw new SmartyPluginException(
|
||||
"You must declare the 'action' parameter in the 'render' smarty function"
|
||||
);
|
||||
}
|
||||
|
||||
$request = $this->prepareRequest($params);
|
||||
|
||||
$this->requestStack->push($request);
|
||||
|
||||
$controller = $this->controllerResolver->getController($request);
|
||||
$controllerParameters = $this->controllerResolver->getArguments($request, $controller);
|
||||
|
||||
$response = call_user_func_array($controller, $controllerParameters);
|
||||
|
||||
$this->requestStack->pop();
|
||||
|
||||
if ($response instanceof Response) {
|
||||
return $response->getContent();
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
protected function prepareRequest(array $params)
|
||||
{
|
||||
// Get action
|
||||
$action = $this->popParameter($params, "action");
|
||||
|
||||
// Then get and filter query, request and method
|
||||
$query = $this->popParameter($params, "query");
|
||||
$query = $this->filterArrayStrParam($query);
|
||||
$request = $this->popParameter($params, "request");
|
||||
$request = $this->filterArrayStrParam($request);
|
||||
$method = strtoupper($this->popParameter($params, "method", "GET"));
|
||||
|
||||
// Then build the request
|
||||
$requestObject = clone $this->requestStack->getCurrentRequest();
|
||||
$requestObject->query = new ParameterBag($query);
|
||||
$requestObject->request = new ParameterBag($request);
|
||||
$requestObject->attributes = new ParameterBag(["_controller" => $action]);
|
||||
|
||||
// Apply the method
|
||||
if (!empty($request) && "GET" === $method) {
|
||||
$requestObject->setMethod("POST");
|
||||
} else {
|
||||
$requestObject->setMethod($method);
|
||||
}
|
||||
|
||||
// Then all the attribute parameters
|
||||
foreach ($params as $key => $attribute) {
|
||||
$requestObject->attributes->set($key, $attribute);
|
||||
}
|
||||
|
||||
return $requestObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $param
|
||||
* @return array
|
||||
*
|
||||
* If $param is an array, return it.
|
||||
* Else parser it to translate a=b&c=d&e[]=f&g[h]=i to
|
||||
* ["a"=>"b","c"=>"d","e"=>["f"],"g"=>["h"=>"i"]
|
||||
*/
|
||||
protected function filterArrayStrParam($param)
|
||||
{
|
||||
if (is_array($param)) {
|
||||
return $param;
|
||||
}
|
||||
|
||||
parse_str($param, $param);
|
||||
|
||||
if (false === $param) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $param;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $params
|
||||
* @param $name
|
||||
* @param null $default
|
||||
* @return mixed
|
||||
*
|
||||
* Get a parameter then unset it
|
||||
*/
|
||||
protected function popParameter(array $params, $name, $default = null)
|
||||
{
|
||||
$param = $this->getParam($params, $name, $default);
|
||||
|
||||
if (array_key_exists($name, $params)) {
|
||||
unset($params[$name]);
|
||||
}
|
||||
|
||||
return $param;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SmartyPluginDescriptor[] an array of SmartyPluginDescriptor
|
||||
*/
|
||||
public function getPluginDescriptors()
|
||||
{
|
||||
return array(
|
||||
new SmartyPluginDescriptor('function', 'render', $this, 'processRender'),
|
||||
);
|
||||
}
|
||||
}
|
||||
146
local/modules/TheliaSmarty/Template/Plugins/Security.php
Normal file
146
local/modules/TheliaSmarty/Template/Plugins/Security.php
Normal file
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace TheliaSmarty\Template\Plugins;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Thelia\Core\HttpFoundation\Session\Session;
|
||||
use Thelia\Core\Security\Exception\AuthorizationException;
|
||||
use TheliaSmarty\Template\SmartyPluginDescriptor;
|
||||
use TheliaSmarty\Template\AbstractSmartyPlugin;
|
||||
use Thelia\Core\Security\SecurityContext;
|
||||
use Thelia\Core\Security\Exception\AuthenticationException;
|
||||
use Thelia\Exception\OrderException;
|
||||
use Thelia\Model\AddressQuery;
|
||||
use Thelia\Model\ModuleQuery;
|
||||
|
||||
class Security extends AbstractSmartyPlugin
|
||||
{
|
||||
/** @var EventDispatcherInterface */
|
||||
protected $dispatcher;
|
||||
|
||||
/** @var RequestStack */
|
||||
protected $requestStack;
|
||||
|
||||
/** @var SecurityContext */
|
||||
private $securityContext;
|
||||
|
||||
public function __construct(RequestStack $requestStack, EventDispatcherInterface $dispatcher, SecurityContext $securityContext)
|
||||
{
|
||||
$this->securityContext = $securityContext;
|
||||
$this->requestStack = $requestStack;
|
||||
$this->dispatcher = $dispatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process security check function
|
||||
*
|
||||
* @param array $params
|
||||
* @param \Smarty $smarty
|
||||
* @return string no text is returned.
|
||||
* @throws \Thelia\Core\Security\Exception\AuthenticationException
|
||||
* @throws AuthenticationException
|
||||
* @throws AuthorizationException
|
||||
*/
|
||||
public function checkAuthFunction($params, &$smarty)
|
||||
{
|
||||
$roles = $this->explode($this->getParam($params, 'role'));
|
||||
$resources = $this->explode($this->getParam($params, 'resource'));
|
||||
$modules = $this->explode($this->getParam($params, 'module'));
|
||||
$accesses = $this->explode($this->getParam($params, 'access'));
|
||||
|
||||
if (! $this->securityContext->isGranted($roles, $resources, $modules, $accesses)) {
|
||||
if (null === $this->securityContext->checkRole($roles)) {
|
||||
// The current user is not logged-in.
|
||||
$ex = new AuthenticationException(
|
||||
sprintf(
|
||||
"User not granted for roles '%s', to access resources '%s' with %s.",
|
||||
implode(',', $roles),
|
||||
implode(',', $resources),
|
||||
implode(',', $accesses)
|
||||
)
|
||||
);
|
||||
|
||||
$loginTpl = $this->getParam($params, 'login_tpl');
|
||||
|
||||
if (null != $loginTpl) {
|
||||
$ex->setLoginTemplate($loginTpl);
|
||||
}
|
||||
} else {
|
||||
// We have a logged-in user, who do not have the proper permission. Issue an AuthorizationException.
|
||||
$ex = new AuthorizationException(
|
||||
sprintf(
|
||||
"User not granted for roles '%s', to access resources '%s' with %s.",
|
||||
implode(',', $roles),
|
||||
implode(',', $resources),
|
||||
implode(',', $accesses)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
throw $ex;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
public function checkCartNotEmptyFunction($params, &$smarty)
|
||||
{
|
||||
$cart = $this->getSession()->getSessionCart($this->dispatcher);
|
||||
if ($cart===null || $cart->countCartItems() == 0) {
|
||||
throw new OrderException('Cart must not be empty', OrderException::CART_EMPTY, array('empty' => 1));
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
public function checkValidDeliveryFunction($params, &$smarty)
|
||||
{
|
||||
$order = $this->getSession()->getOrder();
|
||||
/* Does address and module still exists ? We assume address owner can't change neither module type */
|
||||
if ($order !== null) {
|
||||
$checkAddress = AddressQuery::create()->findPk($order->getChoosenDeliveryAddress());
|
||||
$checkModule = ModuleQuery::create()->findPk($order->getDeliveryModuleId());
|
||||
} else {
|
||||
$checkAddress = $checkModule = null;
|
||||
}
|
||||
|
||||
if (null === $order || null == $checkAddress || null === $checkModule) {
|
||||
throw new OrderException('Delivery must be defined', OrderException::UNDEFINED_DELIVERY, array('missing' => 1));
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the various smarty plugins handled by this class
|
||||
*
|
||||
* @return array an array of smarty plugin descriptors
|
||||
*/
|
||||
public function getPluginDescriptors()
|
||||
{
|
||||
return array(
|
||||
new SmartyPluginDescriptor('function', 'check_auth', $this, 'checkAuthFunction'),
|
||||
new SmartyPluginDescriptor('function', 'check_cart_not_empty', $this, 'checkCartNotEmptyFunction'),
|
||||
new SmartyPluginDescriptor('function', 'check_valid_delivery', $this, 'checkValidDeliveryFunction'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Session
|
||||
*/
|
||||
protected function getSession()
|
||||
{
|
||||
return $this->requestStack->getCurrentRequest()->getSession();
|
||||
}
|
||||
}
|
||||
461
local/modules/TheliaSmarty/Template/Plugins/TheliaLoop.php
Normal file
461
local/modules/TheliaSmarty/Template/Plugins/TheliaLoop.php
Normal file
@@ -0,0 +1,461 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace TheliaSmarty\Template\Plugins;
|
||||
|
||||
use Propel\Runtime\Util\PropelModelPager;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Thelia\Core\HttpFoundation\Request;
|
||||
use Thelia\Core\Security\SecurityContext;
|
||||
use Thelia\Core\Template\Element\BaseLoop;
|
||||
use Thelia\Core\Template\Element\LoopResult;
|
||||
use TheliaSmarty\Template\AbstractSmartyPlugin;
|
||||
use TheliaSmarty\Template\SmartyPluginDescriptor;
|
||||
|
||||
use Thelia\Core\Template\Element\Exception\ElementNotFoundException;
|
||||
use Thelia\Core\Template\Element\Exception\InvalidElementException;
|
||||
use Thelia\Core\Translation\Translator;
|
||||
|
||||
class TheliaLoop extends AbstractSmartyPlugin
|
||||
{
|
||||
/** @var PropelModelPager[] */
|
||||
protected static $pagination = null;
|
||||
|
||||
protected $loopDefinition = array();
|
||||
|
||||
/**
|
||||
* @var Request
|
||||
* @deprecated since 2.3, please use requestStack
|
||||
*/
|
||||
protected $request;
|
||||
|
||||
/** @var EventDispatcherInterface */
|
||||
protected $dispatcher;
|
||||
|
||||
/** @var SecurityContext */
|
||||
protected $securityContext;
|
||||
|
||||
/** @var Translator */
|
||||
protected $translator;
|
||||
|
||||
/** @var ContainerInterface Service Container */
|
||||
protected $container = null;
|
||||
|
||||
/** @var LoopResult[] */
|
||||
protected $loopstack = array();
|
||||
|
||||
protected $varstack = array();
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*/
|
||||
public function __construct(ContainerInterface $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
$this->request = $container->get('request_stack')->getCurrentRequest();
|
||||
$this->dispatcher = $container->get('event_dispatcher');
|
||||
$this->securityContext = $container->get('thelia.securityContext');
|
||||
$this->translator = $container->get("thelia.translator");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $loopName
|
||||
* @return PropelModelPager
|
||||
* @throws \InvalidArgumentException if no pagination was found for loop
|
||||
*/
|
||||
public static function getPagination($loopName)
|
||||
{
|
||||
if (array_key_exists($loopName, self::$pagination)) {
|
||||
return self::$pagination[$loopName];
|
||||
} else {
|
||||
throw new \InvalidArgumentException(
|
||||
Translator::getInstance()->trans("No pagination currently defined for loop name '%name'", ['%name' => $loopName ])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the count function: executes a loop and return the number of items found
|
||||
*
|
||||
* @param array $params parameters array
|
||||
* @param \Smarty_Internal_Template $template
|
||||
*
|
||||
* @return int the item count
|
||||
* @throws \InvalidArgumentException if a parameter is missing
|
||||
*
|
||||
*/
|
||||
public function theliaCount($params, /** @noinspection PhpUnusedParameterInspection */ $template)
|
||||
{
|
||||
$type = $this->getParam($params, 'type');
|
||||
|
||||
if (null == $type) {
|
||||
throw new \InvalidArgumentException(
|
||||
$this->translator->trans("Missing 'type' parameter in {count} loop arguments")
|
||||
);
|
||||
}
|
||||
|
||||
$loop = $this->createLoopInstance($params);
|
||||
|
||||
return $loop->count();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process {loop name="loop name" type="loop type" ... } ... {/loop} block
|
||||
*
|
||||
* @param array $params
|
||||
* @param string $content
|
||||
* @param \Smarty_Internal_Template $template
|
||||
* @param boolean $repeat
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return void|string
|
||||
*/
|
||||
public function theliaLoop($params, $content, $template, &$repeat)
|
||||
{
|
||||
$name = $this->getParam($params, 'name');
|
||||
|
||||
if (null == $name) {
|
||||
throw new \InvalidArgumentException(
|
||||
$this->translator->trans("Missing 'name' parameter in loop arguments")
|
||||
);
|
||||
}
|
||||
|
||||
$type = $this->getParam($params, 'type');
|
||||
|
||||
if (null == $type) {
|
||||
throw new \InvalidArgumentException(
|
||||
$this->translator->trans("Missing 'type' parameter in loop arguments")
|
||||
);
|
||||
}
|
||||
|
||||
if ($content === null) {
|
||||
// Check if a loop with the same name exists in the current scope, and abort if it's the case.
|
||||
if (array_key_exists($name, $this->varstack)) {
|
||||
throw new \InvalidArgumentException(
|
||||
$this->translator->trans("A loop named '%name' already exists in the current scope.", ['%name' => $name])
|
||||
);
|
||||
}
|
||||
|
||||
$loop = $this->createLoopInstance($params);
|
||||
|
||||
self::$pagination[$name] = null;
|
||||
|
||||
$loopResults = $loop->exec(self::$pagination[$name]);
|
||||
|
||||
$loopResults->rewind();
|
||||
|
||||
$this->loopstack[$name] = $loopResults;
|
||||
|
||||
// No results ? The loop is terminated, do not evaluate loop text.
|
||||
if ($loopResults->isEmpty()) {
|
||||
$repeat = false;
|
||||
}
|
||||
} else {
|
||||
$loopResults = $this->loopstack[$name];
|
||||
|
||||
$loopResults->next();
|
||||
}
|
||||
|
||||
if ($loopResults->valid()) {
|
||||
$loopResultRow = $loopResults->current();
|
||||
|
||||
// On first iteration, save variables that may be overwritten by this loop
|
||||
if (! isset($this->varstack[$name])) {
|
||||
$saved_vars = array();
|
||||
|
||||
$varlist = $loopResultRow->getVars();
|
||||
|
||||
foreach ($varlist as $var) {
|
||||
$saved_vars[$var] = $template->getTemplateVars($var);
|
||||
}
|
||||
|
||||
$this->varstack[$name] = $saved_vars;
|
||||
}
|
||||
|
||||
foreach ($loopResultRow->getVarVal() as $var => $val) {
|
||||
$template->assign($var, $val);
|
||||
}
|
||||
|
||||
$repeat = true;
|
||||
}
|
||||
|
||||
// Loop is terminated. Cleanup.
|
||||
if (! $repeat) {
|
||||
// Restore previous variables values before terminating
|
||||
if (isset($this->varstack[$name])) {
|
||||
foreach ($this->varstack[$name] as $var => $value) {
|
||||
$template->assign($var, $value);
|
||||
}
|
||||
|
||||
unset($this->varstack[$name]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($content !== null) {
|
||||
if ($loopResults->isEmpty()) {
|
||||
$content = "";
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Process {elseloop rel="loopname"} ... {/elseloop} block
|
||||
*
|
||||
* @param array $params loop parameters
|
||||
* @param string $content loop text content
|
||||
* @param \Smarty_Internal_Template $template the Smarty object
|
||||
* @param boolean $repeat repeat indicator (see Smarty doc.)
|
||||
* @return string the loop output
|
||||
*/
|
||||
public function theliaElseloop($params, $content, /** @noinspection PhpUnusedParameterInspection */ $template, &$repeat)
|
||||
{
|
||||
//Block the smarty interpretation in the elseloop
|
||||
if ($content === null) {
|
||||
if (! $this->checkEmptyLoop($params)) {
|
||||
$repeat = false;
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process {ifloop rel="loopname"} ... {/ifloop} block
|
||||
*
|
||||
* @param array $params loop parameters
|
||||
* @param string $content loop text content
|
||||
* @param \Smarty_Internal_Template $template the Smarty object
|
||||
* @param boolean $repeat repeat indicator (see Smarty doc.)
|
||||
* @return string the loop output
|
||||
*/
|
||||
public function theliaIfLoop($params, $content, /** @noinspection PhpUnusedParameterInspection */ $template, &$repeat)
|
||||
{
|
||||
// When encountering close tag, check if loop has results.
|
||||
if ($repeat === false) {
|
||||
return $this->checkEmptyLoop($params) ? '' : $content;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Process {pageloop rel="loopname"} ... {/pageloop} block
|
||||
*
|
||||
* @param array $params loop parameters
|
||||
* @param string $content loop text content
|
||||
* @param \Smarty_Internal_Template $template the Smarty object
|
||||
* @param boolean $repeat repeat indicator (see Smarty doc.)
|
||||
* @return string the loop output
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function theliaPageLoop($params, $content, $template, &$repeat)
|
||||
{
|
||||
$loopName = $this->getParam($params, 'rel');
|
||||
|
||||
if (null == $loopName) {
|
||||
throw new \InvalidArgumentException($this->translator->trans("Missing 'rel' parameter in page loop"));
|
||||
}
|
||||
|
||||
// Find pagination
|
||||
$pagination = self::getPagination($loopName);
|
||||
|
||||
if ($pagination === null || $pagination->getNbResults() == 0) {
|
||||
// No need to paginate
|
||||
return '';
|
||||
}
|
||||
|
||||
$startPage = intval($this->getParam($params, 'start-page', 1));
|
||||
$displayedPageCount = intval($this->getParam($params, 'limit', 10));
|
||||
|
||||
if (intval($displayedPageCount) == 0) {
|
||||
$displayedPageCount = PHP_INT_MAX;
|
||||
}
|
||||
|
||||
$totalPageCount = $pagination->getLastPage();
|
||||
|
||||
if ($content === null) {
|
||||
// The current page
|
||||
$currentPage = $pagination->getPage();
|
||||
|
||||
// Get the start page.
|
||||
if ($totalPageCount > $displayedPageCount) {
|
||||
$startPage = $currentPage - round($displayedPageCount / 2);
|
||||
|
||||
if ($startPage <= 0) {
|
||||
$startPage = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// This is the iterative page number, the one we're going to increment in this loop
|
||||
$iterationPage = $startPage;
|
||||
|
||||
// The last displayed page number
|
||||
$endPage = $startPage + $displayedPageCount - 1;
|
||||
|
||||
if ($endPage > $totalPageCount) {
|
||||
$endPage = $totalPageCount;
|
||||
}
|
||||
|
||||
// The first displayed page number
|
||||
$template->assign('START', $startPage);
|
||||
// The previous page number
|
||||
$template->assign('PREV', $currentPage > 1 ? $currentPage-1 : $currentPage);
|
||||
// The next page number
|
||||
$template->assign('NEXT', $currentPage < $totalPageCount ? $currentPage+1 : $totalPageCount);
|
||||
// The last displayed page number
|
||||
$template->assign('END', $endPage);
|
||||
// The overall last page
|
||||
$template->assign('LAST', $totalPageCount);
|
||||
} else {
|
||||
$iterationPage = $template->getTemplateVars('PAGE');
|
||||
|
||||
$iterationPage++;
|
||||
}
|
||||
|
||||
if ($iterationPage <= $template->getTemplateVars('END')) {
|
||||
// The iterative page number
|
||||
$template->assign('PAGE', $iterationPage);
|
||||
|
||||
// The overall current page number
|
||||
$template->assign('CURRENT', $pagination->getPage());
|
||||
|
||||
$repeat = true;
|
||||
}
|
||||
|
||||
if ($content !== null) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a loop has returned results. The loop shoud have been executed before, or an
|
||||
* InvalidArgumentException is thrown
|
||||
*
|
||||
* @param array $params
|
||||
*
|
||||
* @return boolean true if the loop is empty
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
protected function checkEmptyLoop($params)
|
||||
{
|
||||
$loopName = $this->getParam($params, 'rel');
|
||||
|
||||
if (null == $loopName) {
|
||||
throw new \InvalidArgumentException(
|
||||
$this->translator->trans("Missing 'rel' parameter in ifloop/elseloop arguments")
|
||||
);
|
||||
}
|
||||
|
||||
if (! isset($this->loopstack[$loopName])) {
|
||||
throw new \InvalidArgumentException(
|
||||
$this->translator->trans("Related loop name '%name'' is not defined.", ['%name' => $loopName])
|
||||
);
|
||||
}
|
||||
|
||||
return $this->loopstack[$loopName]->isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $smartyParams
|
||||
*
|
||||
* @return BaseLoop
|
||||
* @throws \Thelia\Core\Template\Element\Exception\InvalidElementException
|
||||
* @throws \Thelia\Core\Template\Element\Exception\ElementNotFoundException
|
||||
*/
|
||||
protected function createLoopInstance($smartyParams)
|
||||
{
|
||||
$type = strtolower($smartyParams['type']);
|
||||
|
||||
if (! isset($this->loopDefinition[$type])) {
|
||||
throw new ElementNotFoundException(
|
||||
$this->translator->trans("Loop type '%type' is not defined.", ['%type' => $type])
|
||||
);
|
||||
}
|
||||
|
||||
$class = new \ReflectionClass($this->loopDefinition[$type]);
|
||||
|
||||
if ($class->isSubclassOf("Thelia\Core\Template\Element\BaseLoop") === false) {
|
||||
throw new InvalidElementException(
|
||||
$this->translator->trans("'%type' loop class should extends Thelia\Core\Template\Element\BaseLoop", ['%type' => $type])
|
||||
);
|
||||
}
|
||||
|
||||
$loop = $class->newInstance(
|
||||
$this->container
|
||||
);
|
||||
|
||||
$loop->initializeArgs($smartyParams);
|
||||
|
||||
return $loop;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Injects an associative array containing information for loop execution
|
||||
*
|
||||
* key is loop name
|
||||
* value is the class implementing/extending base loop classes
|
||||
*
|
||||
* ex :
|
||||
*
|
||||
* $loop = array(
|
||||
* "product" => "Thelia\Loop\Product",
|
||||
* "category" => "Thelia\Loop\Category",
|
||||
* "myLoop" => "My\Own\Loop"
|
||||
* );
|
||||
*
|
||||
* @param array $loopDefinition
|
||||
* @throws \InvalidArgumentException if loop name already exists
|
||||
*/
|
||||
public function setLoopList(array $loopDefinition)
|
||||
{
|
||||
foreach ($loopDefinition as $name => $className) {
|
||||
if (array_key_exists($name, $this->loopDefinition)) {
|
||||
throw new \InvalidArgumentException(
|
||||
$this->translator->trans("The loop name '%name' is already defined in %className class", [
|
||||
'%name' => $name,
|
||||
'%className' => $className
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
$this->loopDefinition[$name] = $className;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the various smarty plugins hendled by this class
|
||||
*
|
||||
* @return \TheliaSmarty\Template\SmartyPluginDescriptor[] smarty plugin descriptors
|
||||
*/
|
||||
public function getPluginDescriptors()
|
||||
{
|
||||
return array(
|
||||
|
||||
new SmartyPluginDescriptor('function', 'count', $this, 'theliaCount'),
|
||||
new SmartyPluginDescriptor('block', 'loop', $this, 'theliaLoop'),
|
||||
new SmartyPluginDescriptor('block', 'elseloop', $this, 'theliaElseloop'),
|
||||
new SmartyPluginDescriptor('block', 'ifloop', $this, 'theliaIfLoop'),
|
||||
new SmartyPluginDescriptor('block', 'pageloop', $this, 'theliaPageLoop'),
|
||||
);
|
||||
}
|
||||
}
|
||||
125
local/modules/TheliaSmarty/Template/Plugins/Translation.php
Normal file
125
local/modules/TheliaSmarty/Template/Plugins/Translation.php
Normal file
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace TheliaSmarty\Template\Plugins;
|
||||
|
||||
use Thelia\Core\Translation\Translator;
|
||||
use TheliaSmarty\Template\SmartyPluginDescriptor;
|
||||
use TheliaSmarty\Template\AbstractSmartyPlugin;
|
||||
use Symfony\Component\Translation\TranslatorInterface;
|
||||
|
||||
class Translation extends AbstractSmartyPlugin
|
||||
{
|
||||
/** @var Translator */
|
||||
protected $translator;
|
||||
|
||||
protected $defaultTranslationDomain = '';
|
||||
protected $defaultLocale = null;
|
||||
|
||||
|
||||
protected $protectedParams = [
|
||||
'l',
|
||||
'd',
|
||||
'js',
|
||||
'locale',
|
||||
'default',
|
||||
'fallback'
|
||||
];
|
||||
|
||||
public function __construct(TranslatorInterface $translator)
|
||||
{
|
||||
$this->translator = $translator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default translation domain
|
||||
*
|
||||
* @param array $params
|
||||
* @param \Smarty_Internal_Template $smarty
|
||||
* @return string
|
||||
*/
|
||||
public function setDefaultTranslationDomain($params, &$smarty)
|
||||
{
|
||||
$this->defaultTranslationDomain = $this->getParam($params, 'domain');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default locale
|
||||
*
|
||||
* @param array $params
|
||||
* @param \Smarty_Internal_Template $smarty
|
||||
* @return string
|
||||
*/
|
||||
public function setDefaultLocale($params, &$smarty)
|
||||
{
|
||||
$this->defaultLocale = $this->getParam($params, 'locale');
|
||||
}
|
||||
|
||||
/**
|
||||
* Process translate function
|
||||
*
|
||||
* @param array $params
|
||||
* @param \Smarty_Internal_Template $smarty
|
||||
* @return string
|
||||
*/
|
||||
public function translate($params, &$smarty)
|
||||
{
|
||||
// All parameters other than 'l' and 'd' and 'js' are supposed to be variables. Build an array of var => value pairs
|
||||
// and pass it to the translator
|
||||
$vars = array();
|
||||
|
||||
foreach ($params as $name => $value) {
|
||||
if (!in_array($name, $this->protectedParams)) {
|
||||
$vars["%$name"] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$str = $this->translator->trans(
|
||||
$this->getParam($params, 'l'),
|
||||
$vars,
|
||||
$this->getParam($params, 'd', $this->defaultTranslationDomain),
|
||||
$this->getParam($params, 'locale', $this->defaultLocale),
|
||||
$this->getBoolean($this->getParam($params, 'default', true), true),
|
||||
$this->getBoolean($this->getParam($params, 'fallback', true), true)
|
||||
);
|
||||
|
||||
if ($this->getParam($params, 'js', 0)) {
|
||||
$str = preg_replace("/(['\"])/", "\\\\$1", $str);
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
protected function getBoolean($value, $default = false)
|
||||
{
|
||||
$val = filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
|
||||
if (null === $val) {
|
||||
$val = $default;
|
||||
}
|
||||
|
||||
return $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the various smarty plugins handled by this class
|
||||
*
|
||||
* @return \TheliaSmarty\Template\SmartyPluginDescriptor[] an array of smarty plugin descriptors
|
||||
*/
|
||||
public function getPluginDescriptors()
|
||||
{
|
||||
return array(
|
||||
new SmartyPluginDescriptor('function', 'intl', $this, 'translate'),
|
||||
new SmartyPluginDescriptor('function', 'default_translation_domain', $this, 'setDefaultTranslationDomain'),
|
||||
new SmartyPluginDescriptor('function', 'default_locale', $this, 'setDefaultLocale'),
|
||||
);
|
||||
}
|
||||
}
|
||||
47
local/modules/TheliaSmarty/Template/Plugins/Type.php
Normal file
47
local/modules/TheliaSmarty/Template/Plugins/Type.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace TheliaSmarty\Template\Plugins;
|
||||
|
||||
use Thelia\Core\Template\Smarty\Plugins\an;
|
||||
use TheliaSmarty\Template\SmartyPluginDescriptor;
|
||||
use TheliaSmarty\Template\AbstractSmartyPlugin;
|
||||
|
||||
class Type extends AbstractSmartyPlugin
|
||||
{
|
||||
public function assertTypeModifier($value, $option)
|
||||
{
|
||||
$typeClass = "\\Thelia\\Type\\$option";
|
||||
if (!class_exists($typeClass)) {
|
||||
throw new \InvalidArgumentException(sprintf("Invalid type name `%s` in `assertType` modifier", $option));
|
||||
}
|
||||
|
||||
$typeInstance = new $typeClass();
|
||||
if (!$typeInstance->isValid($value)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the various smarty plugins handled by this class
|
||||
*
|
||||
* @return an array of smarty plugin descriptors
|
||||
*/
|
||||
public function getPluginDescriptors()
|
||||
{
|
||||
return array(
|
||||
new SmartyPluginDescriptor('modifier', 'assertType', $this, 'assertTypeModifier'),
|
||||
);
|
||||
}
|
||||
}
|
||||
363
local/modules/TheliaSmarty/Template/Plugins/UrlGenerator.php
Normal file
363
local/modules/TheliaSmarty/Template/Plugins/UrlGenerator.php
Normal file
@@ -0,0 +1,363 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace TheliaSmarty\Template\Plugins;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Component\Routing\Router;
|
||||
use Thelia\Core\HttpFoundation\Session\Session;
|
||||
use TheliaSmarty\Template\SmartyParser;
|
||||
use TheliaSmarty\Template\SmartyPluginDescriptor;
|
||||
use TheliaSmarty\Template\AbstractSmartyPlugin;
|
||||
use Thelia\Tools\TokenProvider;
|
||||
use Thelia\Tools\URL;
|
||||
use Thelia\Core\HttpFoundation\Request;
|
||||
|
||||
class UrlGenerator extends AbstractSmartyPlugin
|
||||
{
|
||||
/** @var RequestStack */
|
||||
protected $requestStack;
|
||||
|
||||
/** @var TokenProvider */
|
||||
protected $tokenProvider;
|
||||
|
||||
/** @var ContainerInterface */
|
||||
private $container;
|
||||
|
||||
/**
|
||||
* @param RequestStack $requestStack
|
||||
* @param TokenProvider $tokenProvider
|
||||
* @param ContainerInterface $container Needed to get all router.
|
||||
*/
|
||||
public function __construct(RequestStack $requestStack, TokenProvider $tokenProvider, ContainerInterface $container)
|
||||
{
|
||||
$this->requestStack = $requestStack;
|
||||
$this->tokenProvider = $tokenProvider;
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process url generator function
|
||||
*
|
||||
* @param array $params
|
||||
* @param \Smarty $smarty
|
||||
* @return string no text is returned.
|
||||
*/
|
||||
public function generateUrlFunction($params, &$smarty)
|
||||
{
|
||||
// the path to process
|
||||
$current = $this->getParam($params, 'current', false);
|
||||
$path = $this->getParam($params, 'path', null);
|
||||
// Do not invoke index.php in URL (get a static file in web space
|
||||
$file = $this->getParam($params, 'file', null);
|
||||
$routeId = $this->getParam($params, 'route_id', null);
|
||||
// select default router
|
||||
if ($this->getRequest()->fromAdmin()) {
|
||||
$defaultRouter = 'admin';
|
||||
} elseif ($this->getRequest()->fromFront()) {
|
||||
$defaultRouter = 'front';
|
||||
} else {
|
||||
$defaultRouter = null;
|
||||
}
|
||||
$routerId = $this->getParam($params, 'router', $defaultRouter);
|
||||
|
||||
if ($current) {
|
||||
$path = $this->getRequest()->getPathInfo();
|
||||
unset($params["current"]); // Delete the current param, so it isn't included in the url
|
||||
|
||||
// build the query variables
|
||||
$params = array_merge(
|
||||
$this->getRequest()->query->all(),
|
||||
$params
|
||||
);
|
||||
}
|
||||
|
||||
if ($routeId !== null && $routerId !== null) {
|
||||
$routerId = 'router.' . $routerId;
|
||||
|
||||
// test if the router exists
|
||||
if (!$this->container->has($routerId)) {
|
||||
throw new \InvalidArgumentException(
|
||||
'The router "' . $routerId . '" not found.'
|
||||
);
|
||||
}
|
||||
// get url by router and id
|
||||
/** @var Router $router */
|
||||
$router = $this->container->get($routerId);
|
||||
|
||||
$url = $router->generate(
|
||||
$routeId,
|
||||
$this->getArgsFromParam($params, ['route_id', 'router']),
|
||||
Router::ABSOLUTE_URL
|
||||
);
|
||||
} else {
|
||||
if ($file !== null) {
|
||||
$path = $file;
|
||||
$mode = URL::PATH_TO_FILE;
|
||||
} elseif ($path !== null) {
|
||||
$mode = URL::WITH_INDEX_PAGE;
|
||||
} else {
|
||||
throw new \InvalidArgumentException(
|
||||
"Please specify either 'path', 'file' or router and route_id on parameters in {url} function."
|
||||
);
|
||||
}
|
||||
|
||||
$excludeParams = $this->resolvePath($params, $path, $smarty);
|
||||
|
||||
$url = URL::getInstance()->absoluteUrl(
|
||||
$path,
|
||||
$this->getArgsFromParam($params, array_merge(['noamp', 'path', 'file', 'target'], $excludeParams)),
|
||||
$mode
|
||||
);
|
||||
}
|
||||
return $this->applyNoAmpAndTarget($params, $url);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* find placeholders in the path and replace them by the given value
|
||||
*
|
||||
* @param $params
|
||||
* @param $path
|
||||
* @param $smarty
|
||||
* @return array the placeholders found
|
||||
*/
|
||||
protected function resolvePath(&$params, &$path, $smarty)
|
||||
{
|
||||
$placeholder = [];
|
||||
|
||||
foreach ($params as $key => $value) {
|
||||
if (false !== strpos($path, "%$key")) {
|
||||
$placeholder["%$key"] = SmartyParser::theliaEscape($value, $smarty);
|
||||
unset($params[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
$path = strtr($path, $placeholder);
|
||||
$keys = array_keys($placeholder);
|
||||
array_walk($keys, function(&$item, $key) {
|
||||
$item = str_replace('%', '', $item);
|
||||
});
|
||||
|
||||
return $keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process view url generator function
|
||||
*
|
||||
* @param array $params
|
||||
* @param \Smarty $smarty
|
||||
* @return string no text is returned.
|
||||
*/
|
||||
public function generateFrontViewUrlFunction($params, &$smarty)
|
||||
{
|
||||
return $this->generateViewUrlFunction($params, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process administration view url generator function
|
||||
*
|
||||
* @param array $params
|
||||
* @param \Smarty $smarty
|
||||
* @return string no text is returned.
|
||||
*/
|
||||
public function generateAdminViewUrlFunction($params, &$smarty)
|
||||
{
|
||||
return $this->generateViewUrlFunction($params, true);
|
||||
}
|
||||
|
||||
|
||||
public function navigateToUrlFunction($params, &$smarty)
|
||||
{
|
||||
$to = $this->getParam($params, 'to', null);
|
||||
|
||||
$toMethod = $this->getNavigateToMethod($to);
|
||||
|
||||
$url = URL::getInstance()->absoluteUrl(
|
||||
$this->$toMethod(),
|
||||
$this->getArgsFromParam($params, ['noamp', 'to', 'target']),
|
||||
URL::WITH_INDEX_PAGE
|
||||
);
|
||||
|
||||
return $this->applyNoAmpAndTarget($params, $url);
|
||||
}
|
||||
|
||||
protected function generateViewUrlFunction($params, $forAdmin)
|
||||
{
|
||||
// the view name (without .html)
|
||||
$view = $this->getParam($params, 'view');
|
||||
|
||||
$args = $this->getArgsFromParam($params, array('view', 'noamp', 'target'));
|
||||
|
||||
$url = $forAdmin ? URL::getInstance()->adminViewUrl($view, $args) : URL::getInstance()->viewUrl($view, $args);
|
||||
|
||||
return $this->applyNoAmpAndTarget($params, $url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get URL parameters array from parameters.
|
||||
*
|
||||
* @param array $params Smarty function params
|
||||
* @param array $exclude Smarty function exclude params
|
||||
* @return array the parameters array (either emply, of valued)
|
||||
*/
|
||||
private function getArgsFromParam($params, $exclude = array())
|
||||
{
|
||||
$pairs = array();
|
||||
|
||||
foreach ($params as $name => $value) {
|
||||
if (in_array($name, $exclude)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$pairs[$name] = $value;
|
||||
}
|
||||
|
||||
return $pairs;
|
||||
}
|
||||
|
||||
public function generateUrlWithToken($params, &$smarty)
|
||||
{
|
||||
/**
|
||||
* Compute the url
|
||||
*/
|
||||
$url = $this->generateUrlFunction($params, $smarty);
|
||||
|
||||
$urlTokenParam = $this->getParam($params, "url_param", "_token");
|
||||
|
||||
/**
|
||||
* Add the token
|
||||
*/
|
||||
$token = $this->tokenProvider->assignToken();
|
||||
|
||||
$newUrl = URL::getInstance()->absoluteUrl(
|
||||
$url,
|
||||
[
|
||||
$urlTokenParam => $token
|
||||
]
|
||||
);
|
||||
|
||||
return $this->applyNoAmpAndTarget($params, $newUrl);
|
||||
}
|
||||
|
||||
protected function applyNoAmpAndTarget($params, $url)
|
||||
{
|
||||
$noamp = $this->getParam($params, 'noamp', null); // Do not change & in &
|
||||
$target = $this->getParam($params, 'target', null);
|
||||
|
||||
if (!$noamp) {
|
||||
$url = str_replace('&', '&', $url);
|
||||
}
|
||||
|
||||
if ($target != null) {
|
||||
$url .= '#'.$target;
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the _previous_url request attribute, to define the previous URL, or
|
||||
* prevent saving the current URL as the previous one.
|
||||
*
|
||||
* @param array $params
|
||||
* @param \Smarty_Internal_Template $smarty
|
||||
*/
|
||||
public function setPreviousUrlFunction($params, &$smarty)
|
||||
{
|
||||
$ignore_current = $this->getParam($params, 'ignore_current', false);
|
||||
|
||||
if ($ignore_current !== false) {
|
||||
$this->getRequest()->attributes->set('_previous_url', 'dont-save');
|
||||
} else {
|
||||
$this->getRequest()->attributes->set('_previous_url', $this->generateUrlFunction($params, $smarty));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the various smarty plugins handled by this class
|
||||
*
|
||||
* @return array an array of smarty plugin descriptors
|
||||
*/
|
||||
public function getPluginDescriptors()
|
||||
{
|
||||
return array(
|
||||
new SmartyPluginDescriptor('function', 'url', $this, 'generateUrlFunction'),
|
||||
new SmartyPluginDescriptor('function', 'token_url', $this, 'generateUrlWithToken'),
|
||||
new SmartyPluginDescriptor('function', 'viewurl', $this, 'generateFrontViewUrlFunction'),
|
||||
new SmartyPluginDescriptor('function', 'admin_viewurl', $this, 'generateAdminViewUrlFunction'),
|
||||
new SmartyPluginDescriptor('function', 'navigate', $this, 'navigateToUrlFunction'),
|
||||
new SmartyPluginDescriptor('function', 'set_previous_url', $this, 'setPreviousUrlFunction')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array sur le format "to_value" => "method_name"
|
||||
*/
|
||||
protected function getNavigateToValues()
|
||||
{
|
||||
return array(
|
||||
"current" => "getCurrentUrl",
|
||||
"previous" => "getPreviousUrl",
|
||||
"index" => "getIndexUrl",
|
||||
);
|
||||
}
|
||||
|
||||
protected function getNavigateToMethod($to)
|
||||
{
|
||||
if ($to === null) {
|
||||
throw new \InvalidArgumentException("Missing 'to' parameter in `navigate` substitution.");
|
||||
}
|
||||
|
||||
$navigateToValues = $this->getNavigateToValues();
|
||||
|
||||
if (!array_key_exists($to, $navigateToValues)) {
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf("Incorrect value `%s` for parameter `to` in `navigate` substitution.", $to)
|
||||
);
|
||||
}
|
||||
|
||||
return $navigateToValues[$to];
|
||||
}
|
||||
|
||||
protected function getCurrentUrl()
|
||||
{
|
||||
return $this->getRequest()->getUri();
|
||||
}
|
||||
|
||||
protected function getPreviousUrl()
|
||||
{
|
||||
return URL::getInstance()->absoluteUrl($this->getSession()->getReturnToUrl());
|
||||
}
|
||||
|
||||
protected function getIndexUrl()
|
||||
{
|
||||
return URL::getInstance()->getIndexPage();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Request
|
||||
*/
|
||||
protected function getRequest()
|
||||
{
|
||||
return $this->requestStack->getCurrentRequest();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Session
|
||||
*/
|
||||
protected function getSession()
|
||||
{
|
||||
return $this->getRequest()->getSession();
|
||||
}
|
||||
}
|
||||
178
local/modules/TheliaSmarty/Template/SmartyHelper.php
Normal file
178
local/modules/TheliaSmarty/Template/SmartyHelper.php
Normal file
@@ -0,0 +1,178 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace TheliaSmarty\Template;
|
||||
|
||||
use Thelia\Core\Template\ParserHelperInterface;
|
||||
|
||||
/**
|
||||
* Helper class for smarty templates
|
||||
*
|
||||
* Class SmartyHelper
|
||||
* @package Thelia\Core\Template\Smarty
|
||||
* @author Julien Chanséaume <jchanseaume@openstudio.fr>
|
||||
*/
|
||||
class SmartyHelper implements ParserHelperInterface
|
||||
{
|
||||
/**
|
||||
* Parse a string and get all smarty function and block with theirs arguments.
|
||||
* some smarty functions are not supported : if, for, ...
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param string $content the template content
|
||||
* @param array $functions the only functions we want to parse
|
||||
*
|
||||
* @return array array of functions with 2 index name and attributes an array of name, value
|
||||
*/
|
||||
public function getFunctionsDefinition($content, array $functions = array())
|
||||
{
|
||||
$strlen = strlen($content);
|
||||
|
||||
// init
|
||||
$buffer = '';
|
||||
$name = '';
|
||||
$attributeName = '';
|
||||
$waitfor = '';
|
||||
|
||||
$inFunction = false;
|
||||
$hasName = false;
|
||||
$inAttribute = false;
|
||||
$inInnerFunction = false;
|
||||
|
||||
$ldelim = '{';
|
||||
$rdelim = '}';
|
||||
$skipFunctions = array("if", "for");
|
||||
$skipCharacters = array("\t", "\r", "\n");
|
||||
|
||||
$store = array();
|
||||
$attributes = array();
|
||||
|
||||
for ($pos = 0; $pos < $strlen; $pos++) {
|
||||
$char = $content[$pos];
|
||||
|
||||
if (in_array($char, $skipCharacters)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$inFunction) {
|
||||
if ($char === $ldelim) {
|
||||
$inFunction = true;
|
||||
$inInnerFunction = false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// get function name
|
||||
if (!$hasName) {
|
||||
if ($char === " " || $char === $rdelim) {
|
||||
$name = $buffer;
|
||||
// we catch this name ?
|
||||
$hasName = $inFunction = (!in_array($name, $skipFunctions) && (0 === count($functions) || in_array($name, $functions)));
|
||||
$buffer = "";
|
||||
continue;
|
||||
} else {
|
||||
// skip {
|
||||
if (in_array($char, array("/", "$", "#", "'", "\""))) {
|
||||
$inFunction = false;
|
||||
} else {
|
||||
$buffer .= $char;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// inner Function ?
|
||||
if ($char === $ldelim) {
|
||||
$inInnerFunction = true;
|
||||
$buffer .= $char;
|
||||
continue;
|
||||
}
|
||||
|
||||
// end ?
|
||||
if ($char === $rdelim) {
|
||||
if ($inInnerFunction) {
|
||||
$inInnerFunction = false;
|
||||
$buffer .= $char;
|
||||
} else {
|
||||
if ($inAttribute) {
|
||||
if ("" === $attributeName) {
|
||||
$attributes[trim($buffer)] = "";
|
||||
} else {
|
||||
$attributes[$attributeName] = $buffer;
|
||||
}
|
||||
$inAttribute = false;
|
||||
}
|
||||
$store[] = array(
|
||||
"name" => $name,
|
||||
"attributes" => $attributes
|
||||
);
|
||||
$inFunction = false;
|
||||
$inAttribute = false;
|
||||
$inInnerFunction = false;
|
||||
$hasName = false;
|
||||
$name = "";
|
||||
$buffer = "";
|
||||
$waitfor = "";
|
||||
$attributes = array();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// attributes
|
||||
if (!$inAttribute) {
|
||||
if ($char !== " ") {
|
||||
$inAttribute = true;
|
||||
$buffer = $char;
|
||||
$attributeName = "";
|
||||
}
|
||||
} else {
|
||||
if ("" === $attributeName) {
|
||||
if (in_array($char, array(" ", "="))) {
|
||||
$attributeName = trim($buffer);
|
||||
if (" " === $char) {
|
||||
$attributes[$attributeName] = "";
|
||||
$inAttribute = false;
|
||||
}
|
||||
$buffer = "";
|
||||
} else {
|
||||
$buffer .= $char;
|
||||
}
|
||||
} else {
|
||||
if ("" === $waitfor) {
|
||||
if (in_array($char, array("'", "\""))) {
|
||||
$waitfor = $char;
|
||||
} else {
|
||||
$waitfor = " ";
|
||||
$buffer .= $char;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if ($inInnerFunction) {
|
||||
$buffer .= $char;
|
||||
} else {
|
||||
// end of attribute ?
|
||||
if ($char === $waitfor) {
|
||||
$attributes[$attributeName] = $buffer;
|
||||
$inAttribute = false;
|
||||
$waitfor = "";
|
||||
} else {
|
||||
$buffer .= $char;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $store;
|
||||
}
|
||||
}
|
||||
485
local/modules/TheliaSmarty/Template/SmartyParser.php
Normal file
485
local/modules/TheliaSmarty/Template/SmartyParser.php
Normal file
@@ -0,0 +1,485 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace TheliaSmarty\Template;
|
||||
|
||||
use \Smarty;
|
||||
use \Symfony\Component\HttpFoundation\Request;
|
||||
use \Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Thelia\Core\Template\ParserInterface;
|
||||
use Thelia\Core\Template\Exception\ResourceNotFoundException;
|
||||
use Thelia\Core\Template\ParserContext;
|
||||
use Thelia\Core\Template\TemplateHelperInterface;
|
||||
use Thelia\Core\Template\TemplateDefinition;
|
||||
use Imagine\Exception\InvalidArgumentException;
|
||||
use Thelia\Core\Translation\Translator;
|
||||
use Thelia\Log\Tlog;
|
||||
use Thelia\Model\ConfigQuery;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Franck Allimant <franck@cqfdev.fr>
|
||||
* @author Etienne Roudeix <eroudeix@openstudio.fr>
|
||||
*/
|
||||
class SmartyParser extends Smarty implements ParserInterface
|
||||
{
|
||||
public $plugins = array();
|
||||
|
||||
/** @var EventDispatcherInterface */
|
||||
protected $dispatcher;
|
||||
|
||||
/** @var ParserContext */
|
||||
protected $parserContext;
|
||||
|
||||
/** @var TemplateHelperInterface */
|
||||
protected $templateHelper;
|
||||
|
||||
/** @var RequestStack */
|
||||
protected $requestStack;
|
||||
|
||||
protected $backOfficeTemplateDirectories = array();
|
||||
protected $frontOfficeTemplateDirectories = array();
|
||||
|
||||
protected $templateDirectories = array();
|
||||
|
||||
/** @var TemplateDefinition */
|
||||
protected $templateDefinition;
|
||||
|
||||
/** @var int */
|
||||
protected $status = 200;
|
||||
|
||||
/**
|
||||
* @param RequestStack $requestStack
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
* @param ParserContext $parserContext
|
||||
* @param TemplateHelperInterface $templateHelper
|
||||
* @param string $env
|
||||
* @param bool $debug
|
||||
*/
|
||||
public function __construct(
|
||||
RequestStack $requestStack,
|
||||
EventDispatcherInterface $dispatcher,
|
||||
ParserContext $parserContext,
|
||||
TemplateHelperInterface $templateHelper,
|
||||
$env = "prod",
|
||||
$debug = false
|
||||
) {
|
||||
parent::__construct();
|
||||
|
||||
$this->requestStack = $requestStack;
|
||||
$this->dispatcher = $dispatcher;
|
||||
$this->parserContext = $parserContext;
|
||||
$this->templateHelper = $templateHelper;
|
||||
|
||||
// Configure basic Smarty parameters
|
||||
|
||||
$compile_dir = THELIA_ROOT . 'cache'. DS . $env . DS . 'smarty'.DS.'compile';
|
||||
if (! is_dir($compile_dir)) {
|
||||
@mkdir($compile_dir, 0777, true);
|
||||
}
|
||||
|
||||
$cache_dir = THELIA_ROOT . 'cache'. DS . $env . DS . 'smarty'.DS.'cache';
|
||||
if (! is_dir($cache_dir)) {
|
||||
@mkdir($cache_dir, 0777, true);
|
||||
}
|
||||
|
||||
$this->setCompileDir($compile_dir);
|
||||
$this->setCacheDir($cache_dir);
|
||||
$this->inheritance_merge_compiled_includes = false;
|
||||
|
||||
// Prevent smarty ErrorException: Notice: Undefined index bla bla bla...
|
||||
$this->error_reporting = E_ALL ^ E_NOTICE;
|
||||
|
||||
// The default HTTP status
|
||||
$this->status = 200;
|
||||
|
||||
$this->registerFilter('output', array($this, "trimWhitespaces"));
|
||||
$this->registerFilter('variable', array(__CLASS__, "theliaEscape"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current request or null if no request exists
|
||||
*
|
||||
* @return Request|null
|
||||
*/
|
||||
public function getRequest()
|
||||
{
|
||||
return $this->requestStack->getCurrentRequest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim whitespaces from the HTML output, preserving required ones in pre, textarea, javascript.
|
||||
* This methois uses 3 levels of trimming :
|
||||
*
|
||||
* - 0 : whitespaces are not trimmed, code remains as is.
|
||||
* - 1 : only blank lines are trimmed, code remains indented and human-readable (the default)
|
||||
* - 2 or more : all unnecessary whitespace are removed. Code is very hard to read.
|
||||
*
|
||||
* The trim level is defined by the configuration variable html_output_trim_level
|
||||
*
|
||||
* @param string $source the HTML source
|
||||
* @param \Smarty_Internal_Template $template
|
||||
* @return string
|
||||
*/
|
||||
public function trimWhitespaces($source, /** @noinspection PhpUnusedParameterInspection */ \Smarty_Internal_Template $template)
|
||||
{
|
||||
$compressionMode = ConfigQuery::read('html_output_trim_level', 1);
|
||||
|
||||
if ($compressionMode == 0) {
|
||||
return $source;
|
||||
}
|
||||
|
||||
$store = array();
|
||||
$_store = 0;
|
||||
$_offset = 0;
|
||||
|
||||
// Unify Line-Breaks to \n
|
||||
$source = preg_replace("/\015\012|\015|\012/", "\n", $source);
|
||||
|
||||
// capture Internet Explorer Conditional Comments
|
||||
if ($compressionMode == 1) {
|
||||
$expressions = array(
|
||||
// remove spaces between attributes (but not in attribute values!)
|
||||
'#(([a-z0-9]\s*=\s*(["\'])[^\3]*?\3)|<[a-z0-9_]+)\s+([a-z/>])#is' => '\1 \4',
|
||||
'/(^[\n]*|[\n]+)[\s\t]*[\n]+/' => "\n"
|
||||
);
|
||||
} elseif ($compressionMode >= 2) {
|
||||
if (preg_match_all('#<!--\[[^\]]+\]>.*?<!\[[^\]]+\]-->#is', $source, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) {
|
||||
foreach ($matches as $match) {
|
||||
$store[] = $match[0][0];
|
||||
$_length = strlen($match[0][0]);
|
||||
$replace = '@!@SMARTY:' . $_store . ':SMARTY@!@';
|
||||
$source = substr_replace($source, $replace, $match[0][1] - $_offset, $_length);
|
||||
|
||||
$_offset += $_length - strlen($replace);
|
||||
$_store++;
|
||||
}
|
||||
}
|
||||
|
||||
// Strip all HTML-Comments
|
||||
// yes, even the ones in <script> - see http://stackoverflow.com/a/808850/515124
|
||||
$source = preg_replace('#<!--.*?-->#ms', '', $source);
|
||||
|
||||
$expressions = array(
|
||||
// replace multiple spaces between tags by a single space
|
||||
// can't remove them entirely, becaue that might break poorly implemented CSS display:inline-block elements
|
||||
'#(:SMARTY@!@|>)\s+(?=@!@SMARTY:|<)#s' => '\1 \2',
|
||||
// remove spaces between attributes (but not in attribute values!)
|
||||
'#(([a-z0-9]\s*=\s*(["\'])[^\3]*?\3)|<[a-z0-9_]+)\s+([a-z/>])#is' => '\1 \4',
|
||||
// note: for some very weird reason trim() seems to remove spaces inside attributes.
|
||||
// maybe a \0 byte or something is interfering?
|
||||
'#^\s+<#Ss' => '<',
|
||||
'#>\s+$#Ss' => '>',
|
||||
|
||||
);
|
||||
} else {
|
||||
$expressions = array();
|
||||
}
|
||||
|
||||
// capture html elements not to be messed with
|
||||
$_offset = 0;
|
||||
if (preg_match_all('#<(script|pre|textarea)[^>]*>.*?</\\1>#is', $source, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) {
|
||||
foreach ($matches as $match) {
|
||||
$store[] = $match[0][0];
|
||||
$_length = strlen($match[0][0]);
|
||||
$replace = '@!@SMARTY:' . $_store . ':SMARTY@!@';
|
||||
$source = substr_replace($source, $replace, $match[0][1] - $_offset, $_length);
|
||||
|
||||
$_offset += $_length - strlen($replace);
|
||||
$_store++;
|
||||
}
|
||||
}
|
||||
|
||||
$source = preg_replace(array_keys($expressions), array_values($expressions), $source);
|
||||
|
||||
// capture html elements not to be messed with
|
||||
$_offset = 0;
|
||||
if (preg_match_all('#@!@SMARTY:([0-9]+):SMARTY@!@#is', $source, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) {
|
||||
foreach ($matches as $match) {
|
||||
$store[] = $match[0][0];
|
||||
$_length = strlen($match[0][0]);
|
||||
$replace = array_shift($store);
|
||||
$source = substr_replace($source, $replace, $match[0][1] + $_offset, $_length);
|
||||
|
||||
$_offset += strlen($replace) - $_length;
|
||||
$_store++;
|
||||
}
|
||||
}
|
||||
|
||||
return $source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a template directory to the current template list
|
||||
*
|
||||
* @param int $templateType the template type (a TemplateDefinition type constant)
|
||||
* @param string $templateName the template name
|
||||
* @param string $templateDirectory path to the template directory
|
||||
* @param string $key ???
|
||||
* @param boolean $addAtBeginning if true, the template definition should be added at the beginning of the template directory list
|
||||
*/
|
||||
public function addTemplateDirectory($templateType, $templateName, $templateDirectory, $key, $addAtBeginning = false)
|
||||
{
|
||||
Tlog::getInstance()->addDebug("Adding template directory $templateDirectory, type:$templateType name:$templateName, key: $key");
|
||||
|
||||
if (true === $addAtBeginning && isset($this->templateDirectories[$templateType][$templateName])) {
|
||||
// When using array_merge, the key was set to 0. Use + instead.
|
||||
$this->templateDirectories[$templateType][$templateName] =
|
||||
[ $key => $templateDirectory ] + $this->templateDirectories[$templateType][$templateName]
|
||||
;
|
||||
} else {
|
||||
$this->templateDirectories[$templateType][$templateName][$key] = $templateDirectory;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the registered template directories for a given template type
|
||||
*
|
||||
* @param int $templateType
|
||||
* @throws InvalidArgumentException
|
||||
* @return mixed:
|
||||
*/
|
||||
public function getTemplateDirectories($templateType)
|
||||
{
|
||||
if (! isset($this->templateDirectories[$templateType])) {
|
||||
throw new InvalidArgumentException("Failed to get template type %", $templateType);
|
||||
}
|
||||
|
||||
return $this->templateDirectories[$templateType];
|
||||
}
|
||||
|
||||
public static function theliaEscape($content, /** @noinspection PhpUnusedParameterInspection */ $smarty)
|
||||
{
|
||||
if (is_scalar($content)) {
|
||||
return htmlspecialchars($content, ENT_QUOTES, Smarty::$_CHARSET);
|
||||
} else {
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TemplateDefinition $templateDefinition
|
||||
* @param bool $useFallback
|
||||
*/
|
||||
public function setTemplateDefinition(TemplateDefinition $templateDefinition, $useFallback = false)
|
||||
{
|
||||
$this->templateDefinition = $templateDefinition;
|
||||
|
||||
/* init template directories */
|
||||
$this->setTemplateDir(array());
|
||||
|
||||
/* define config directory */
|
||||
$configDirectory = THELIA_TEMPLATE_DIR . $this->getTemplatePath() . DS . 'configs';
|
||||
$this->addConfigDir($configDirectory, self::TEMPLATE_ASSETS_KEY);
|
||||
|
||||
/* add modules template directories */
|
||||
$this->addTemplateDirectory(
|
||||
$templateDefinition->getType(),
|
||||
$templateDefinition->getName(),
|
||||
THELIA_TEMPLATE_DIR . $this->getTemplatePath(),
|
||||
self::TEMPLATE_ASSETS_KEY,
|
||||
true
|
||||
);
|
||||
|
||||
$type = $templateDefinition->getType();
|
||||
$name = $templateDefinition->getName();
|
||||
|
||||
/* do not pass array directly to addTemplateDir since we cant control on keys */
|
||||
if (isset($this->templateDirectories[$type][$name])) {
|
||||
foreach ($this->templateDirectories[$type][$name] as $key => $directory) {
|
||||
$this->addTemplateDir($directory, $key);
|
||||
$this->addConfigDir($directory . DS . 'configs', $key);
|
||||
}
|
||||
}
|
||||
|
||||
// fallback on default template
|
||||
if ($useFallback && 'default' !== $name) {
|
||||
if (isset($this->templateDirectories[$type]['default'])) {
|
||||
foreach ($this->templateDirectories[$type]['default'] as $key => $directory) {
|
||||
if (null === $this->getTemplateDir($key)) {
|
||||
$this->addTemplateDir($directory, $key);
|
||||
$this->addConfigDir($directory . DS . 'configs', $key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get template definition
|
||||
*
|
||||
* @param bool $webAssetTemplate Allow to load asset from another template
|
||||
* If the name of the template if provided
|
||||
*
|
||||
* @return TemplateDefinition
|
||||
*/
|
||||
public function getTemplateDefinition($webAssetTemplate = false)
|
||||
{
|
||||
$ret = clone $this->templateDefinition;
|
||||
|
||||
if (false !== $webAssetTemplate) {
|
||||
$customPath = str_replace($ret->getName(), $webAssetTemplate, $ret->getPath());
|
||||
$ret->setName($webAssetTemplate);
|
||||
$ret->setPath($customPath);
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string the template path
|
||||
*/
|
||||
public function getTemplatePath()
|
||||
{
|
||||
return $this->templateDefinition->getPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a rendered template, either from file or from a string
|
||||
*
|
||||
* @param string $resourceType either 'string' (rendering from a string) or 'file' (rendering a file)
|
||||
* @param string $resourceContent the resource content (a text, or a template file name)
|
||||
* @param array $parameters an associative array of names / value pairs
|
||||
* @param bool $compressOutput if true, te output is compressed using trimWhitespaces. If false, no compression occurs
|
||||
*
|
||||
* @return string the rendered template text
|
||||
*/
|
||||
protected function internalRenderer($resourceType, $resourceContent, array $parameters, $compressOutput = true)
|
||||
{
|
||||
// If we have to diable the output compression, just unregister the output filter temporarly
|
||||
if ($compressOutput == false) {
|
||||
$this->unregisterFilter('output', array($this, "trimWhitespaces"));
|
||||
}
|
||||
|
||||
// Assign the parserContext variables
|
||||
foreach ($this->parserContext as $var => $value) {
|
||||
$this->assign($var, $value);
|
||||
}
|
||||
|
||||
$this->assign($parameters);
|
||||
|
||||
$output = $this->fetch(sprintf("%s:%s", $resourceType, $resourceContent));
|
||||
|
||||
if ($compressOutput == false) {
|
||||
$this->registerFilter('output', array($this, "trimWhitespaces"));
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a rendered template file
|
||||
*
|
||||
* @param string $realTemplateName the template name (from the template directory)
|
||||
* @param array $parameters an associative array of names / value pairs
|
||||
* @return string the rendered template text
|
||||
* @param bool $compressOutput if true, te output is compressed using trimWhitespaces. If false, no compression occurs
|
||||
* @throws ResourceNotFoundException if the template cannot be found
|
||||
*/
|
||||
public function render($realTemplateName, array $parameters = array(), $compressOutput = true)
|
||||
{
|
||||
if (false === $this->templateExists($realTemplateName) || false === $this->checkTemplate($realTemplateName)) {
|
||||
throw new ResourceNotFoundException(Translator::getInstance()->trans("Template file %file cannot be found.", array('%file' => $realTemplateName)));
|
||||
}
|
||||
|
||||
return $this->internalRenderer('file', $realTemplateName, $parameters, $compressOutput);
|
||||
}
|
||||
|
||||
private function checkTemplate($fileName)
|
||||
{
|
||||
$templates = $this->getTemplateDir();
|
||||
|
||||
$found = true;
|
||||
|
||||
/** @noinspection PhpUnusedLocalVariableInspection */
|
||||
foreach ($templates as $key => $value) {
|
||||
$absolutePath = rtrim(realpath(dirname($value.$fileName)), "/");
|
||||
$templateDir = rtrim(realpath($value), "/");
|
||||
if (!empty($absolutePath) && strpos($absolutePath, $templateDir) !== 0) {
|
||||
$found = false;
|
||||
}
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a rendered template text
|
||||
*
|
||||
* @param string $templateText the template text
|
||||
* @param array $parameters an associative array of names / value pairs
|
||||
* @param bool $compressOutput if true, te output is compressed using trimWhitespaces. If false, no compression occurs
|
||||
* @return string the rendered template text
|
||||
*/
|
||||
public function renderString($templateText, array $parameters = array(), $compressOutput = true)
|
||||
{
|
||||
return $this->internalRenderer('string', $templateText, $parameters, $compressOutput);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return int the status of the response
|
||||
*/
|
||||
public function getStatus()
|
||||
{
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* status HTTP of the response
|
||||
*
|
||||
* @param int $status
|
||||
*/
|
||||
public function setStatus($status)
|
||||
{
|
||||
$this->status = $status;
|
||||
}
|
||||
|
||||
public function addPlugins(AbstractSmartyPlugin $plugin)
|
||||
{
|
||||
$this->plugins[] = $plugin;
|
||||
}
|
||||
|
||||
public function registerPlugins()
|
||||
{
|
||||
/** @var AbstractSmartyPlugin $register_plugin */
|
||||
foreach ($this->plugins as $register_plugin) {
|
||||
$plugins = $register_plugin->getPluginDescriptors();
|
||||
|
||||
if (!is_array($plugins)) {
|
||||
$plugins = array($plugins);
|
||||
}
|
||||
|
||||
/** @var SmartyPluginDescriptor $plugin */
|
||||
foreach ($plugins as $plugin) {
|
||||
$this->registerPlugin(
|
||||
$plugin->getType(),
|
||||
$plugin->getName(),
|
||||
array(
|
||||
$plugin->getClass(),
|
||||
$plugin->getMethod()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Thelia\Core\Template\TemplateHelperInterface the parser template helper instance
|
||||
*/
|
||||
public function getTemplateHelper()
|
||||
{
|
||||
return $this->templateHelper;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace TheliaSmarty\Template;
|
||||
|
||||
use TheliaSmarty\Template\AbstractSmartyPlugin;
|
||||
|
||||
/**
|
||||
* Class allowing to describe a smarty plugin
|
||||
*
|
||||
* Class SmartyPluginDescriptor
|
||||
* @package Thelia\Core\Template\Smarty
|
||||
*/
|
||||
class SmartyPluginDescriptor
|
||||
{
|
||||
/**
|
||||
* @var string Smarty plugin type (block, function, etc.)
|
||||
*/
|
||||
protected $type;
|
||||
|
||||
/**
|
||||
* @var string Smarty plugin name. This name will be used in Smarty templates.
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* @var AbstractSmartyPlugin plugin implmentation class
|
||||
*/
|
||||
protected $class;
|
||||
|
||||
/**
|
||||
* @var string plugin implmentation method in $class
|
||||
*/
|
||||
protected $method;
|
||||
|
||||
public function __construct($type, $name, $class, $method)
|
||||
{
|
||||
$this->type = $type;
|
||||
$this->name = $name;
|
||||
$this->class = $class;
|
||||
$this->method = $method;
|
||||
}
|
||||
|
||||
public function setType($type)
|
||||
{
|
||||
$this->type = $type;
|
||||
}
|
||||
|
||||
public function getType()
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function setClass($class)
|
||||
{
|
||||
$this->class = $class;
|
||||
}
|
||||
|
||||
public function getClass()
|
||||
{
|
||||
return $this->class;
|
||||
}
|
||||
|
||||
public function setMethod($method)
|
||||
{
|
||||
$this->method = $method;
|
||||
}
|
||||
|
||||
public function getMethod()
|
||||
{
|
||||
return $this->method;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace TheliaSmarty\Tests\Template\Plugin\Controller;
|
||||
|
||||
use Thelia\Controller\Front\BaseFrontController;
|
||||
use Thelia\Core\HttpFoundation\Response;
|
||||
|
||||
/**
|
||||
* Class TestController
|
||||
* @package TheliaSmarty\Tests\Template\Plugin\Controller
|
||||
* @author Benjamin Perche <bperche@openstudio.fr>
|
||||
*/
|
||||
class TestController extends BaseFrontController
|
||||
{
|
||||
public function testAction()
|
||||
{
|
||||
return new Response("world");
|
||||
}
|
||||
|
||||
public function testParamsAction($paramA, $paramB)
|
||||
{
|
||||
return new Response($paramA.$paramB);
|
||||
}
|
||||
|
||||
public function testMethodAction()
|
||||
{
|
||||
return $this->getRequest()->getMethod();
|
||||
}
|
||||
|
||||
public function testQueryAction()
|
||||
{
|
||||
return $this->getRequest()->query->get("foo");
|
||||
}
|
||||
|
||||
public function testRequestAction()
|
||||
{
|
||||
return $this->getRequest()->request->get("foo").$this->getRequest()->getMethod();
|
||||
}
|
||||
}
|
||||
186
local/modules/TheliaSmarty/Tests/Template/Plugin/FormTest.php
Normal file
186
local/modules/TheliaSmarty/Tests/Template/Plugin/FormTest.php
Normal file
@@ -0,0 +1,186 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace TheliaSmarty\Tests\Template\Plugin;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\Form\Extension\Core\CoreExtension;
|
||||
use Symfony\Component\Form\FormFactoryBuilder;
|
||||
use Symfony\Component\Validator\ValidatorBuilder;
|
||||
use TheliaSmarty\Template\Plugins\Form;
|
||||
|
||||
/**
|
||||
* Class FormTest
|
||||
* @package TheliaSmarty\Tests\Template\Plugin
|
||||
* @author Benjamin Perche <benjamin@thelia.net>
|
||||
*/
|
||||
class FormTest extends SmartyPluginTestCase
|
||||
{
|
||||
/**
|
||||
* @var Form
|
||||
*/
|
||||
protected $plugin;
|
||||
|
||||
/**
|
||||
* @return \TheliaSmarty\Template\AbstractSmartyPlugin
|
||||
*/
|
||||
protected function getPlugin(ContainerBuilder $container)
|
||||
{
|
||||
$this->plugin = new Form(
|
||||
$container->get("thelia.form_factory"),
|
||||
$container->get("thelia.parser.context"),
|
||||
$container->get("thelia.parser")
|
||||
);
|
||||
|
||||
$this->plugin->setFormDefinition($container->get("thelia.parser.forms"));
|
||||
|
||||
return $this->plugin;
|
||||
}
|
||||
|
||||
public function testSimpleStackedForm()
|
||||
{
|
||||
$parserContext = $this->getParserContext();
|
||||
$this->assertNull($parserContext->popCurrentForm());
|
||||
|
||||
// First, initialize form
|
||||
// eq: {form name="thelia.empty"}
|
||||
$repeat = true;
|
||||
$this->plugin->generateForm(
|
||||
["name" => "thelia.empty"],
|
||||
"",
|
||||
$this->getMock("\\Smarty_Internal_Template", [], [], '', false),
|
||||
$repeat
|
||||
);
|
||||
|
||||
// Here, the current form is present
|
||||
$this->assertInstanceOf("Thelia\\Form\\EmptyForm", $parserContext->getCurrentForm());
|
||||
$this->assertInstanceOf("Thelia\\Form\\EmptyForm", $form = $parserContext->popCurrentForm());
|
||||
// But not after we have pop
|
||||
$this->assertNull($parserContext->popCurrentForm());
|
||||
|
||||
// So we re-push it into the stack
|
||||
$parserContext->pushCurrentForm($form);
|
||||
|
||||
// And run the ending form tag
|
||||
// eq: {/form}
|
||||
$repeat = false;
|
||||
$this->plugin->generateForm(
|
||||
["name" => "thelia.empty"],
|
||||
"",
|
||||
$this->getMock("\\Smarty_Internal_Template", [], [], '', false),
|
||||
$repeat
|
||||
);
|
||||
|
||||
// There is no more form in the stack
|
||||
$this->assertNull($parserContext->popCurrentForm());
|
||||
|
||||
// Let's even predict an exception
|
||||
$this->setExpectedException(
|
||||
"TheliaSmarty\\Template\\Exception\\SmartyPluginException",
|
||||
"There is currently no defined form"
|
||||
);
|
||||
|
||||
$parserContext->getCurrentForm();
|
||||
}
|
||||
|
||||
public function testMultipleStackedForms()
|
||||
{
|
||||
$parserContext = $this->getParserContext();
|
||||
$this->assertNull($parserContext->popCurrentForm());
|
||||
|
||||
// First form:
|
||||
// eq: {form name="thelia.empty"}
|
||||
$repeat = true;
|
||||
$this->plugin->generateForm(
|
||||
["name" => "thelia.empty"],
|
||||
"",
|
||||
$this->getMock("\\Smarty_Internal_Template", [], [], '', false),
|
||||
$repeat
|
||||
);
|
||||
|
||||
$this->assertInstanceOf("Thelia\\Form\\EmptyForm", $parserContext->getCurrentForm());
|
||||
|
||||
// Then next one:
|
||||
// eq: {form name="thelia.api.empty"}
|
||||
$repeat = true;
|
||||
$this->plugin->generateForm(
|
||||
["name" => "thelia.api.empty"],
|
||||
"",
|
||||
$this->getMock("\\Smarty_Internal_Template", [], [], '', false),
|
||||
$repeat
|
||||
);
|
||||
|
||||
$this->assertInstanceOf("Thelia\\Form\\Api\\ApiEmptyForm", $parserContext->getCurrentForm());
|
||||
|
||||
// Third form:
|
||||
// eq: {form name="thelia.empty.2"}
|
||||
$repeat = true;
|
||||
$this->plugin->generateForm(
|
||||
["name" => "thelia.empty.2"],
|
||||
"",
|
||||
$this->getMock("\\Smarty_Internal_Template", [], [], '', false),
|
||||
$repeat
|
||||
);
|
||||
|
||||
$this->assertInstanceOf("Thelia\\Form\\EmptyForm", $parserContext->getCurrentForm());
|
||||
|
||||
// Then, Let's close forms
|
||||
// eq: {/form} {* related to {form name="thelia.empty.2"} *}
|
||||
$repeat = false;
|
||||
$this->plugin->generateForm(
|
||||
["name" => "thelia.empty.2"],
|
||||
"",
|
||||
$this->getMock("\\Smarty_Internal_Template", [], [], '', false),
|
||||
$repeat
|
||||
);
|
||||
|
||||
$this->assertInstanceOf("Thelia\\Form\\Api\\ApiEmptyForm", $parserContext->getCurrentForm());
|
||||
|
||||
// Then, Let's close forms
|
||||
// eq: {/form} {* related to {form name="thelia.api.empty"} *}
|
||||
$repeat = false;
|
||||
$this->plugin->generateForm(
|
||||
["name" => "thelia.api.empty"],
|
||||
"",
|
||||
$this->getMock("\\Smarty_Internal_Template", [], [], '', false),
|
||||
$repeat
|
||||
);
|
||||
|
||||
$this->assertInstanceOf("Thelia\\Form\\EmptyForm", $parserContext->getCurrentForm());
|
||||
|
||||
// Then close the first form:
|
||||
// eq: {/form} {* related to {form name="thelia.empty"} *}
|
||||
$repeat = false;
|
||||
$this->plugin->generateForm(
|
||||
["name" => "thelia.empty"],
|
||||
"",
|
||||
$this->getMock("\\Smarty_Internal_Template", [], [], '', false),
|
||||
$repeat
|
||||
);
|
||||
|
||||
// The exception
|
||||
$this->setExpectedException(
|
||||
"TheliaSmarty\\Template\\Exception\\SmartyPluginException",
|
||||
"There is currently no defined form"
|
||||
);
|
||||
|
||||
$parserContext->getCurrentForm();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Thelia\Core\Template\ParserContext
|
||||
*/
|
||||
protected function getParserContext()
|
||||
{
|
||||
return $this->container->get("thelia.parser.context");
|
||||
}
|
||||
}
|
||||
234
local/modules/TheliaSmarty/Tests/Template/Plugin/FormatTest.php
Normal file
234
local/modules/TheliaSmarty/Tests/Template/Plugin/FormatTest.php
Normal file
@@ -0,0 +1,234 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace TheliaSmarty\Tests\Template\Plugin;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Thelia\Core\HttpFoundation\Request;
|
||||
use Thelia\Model\AddressQuery;
|
||||
use Thelia\Model\CountryQuery;
|
||||
use Thelia\Model\CurrencyQuery;
|
||||
use Thelia\Model\StateQuery;
|
||||
use TheliaSmarty\Template\Plugins\Format;
|
||||
|
||||
/**
|
||||
* Class FormatTest
|
||||
* @package TheliaSmarty\Tests\Template\Plugin
|
||||
* @author Gilles Bourgeat <gbourgeat@openstudio.fr>
|
||||
* @author Baixas Alban <abaixas@openstudio.fr>
|
||||
*/
|
||||
class FormatTest extends SmartyPluginTestCase
|
||||
{
|
||||
/** @var RequestStack */
|
||||
protected $requestStack;
|
||||
|
||||
public function testFormatTwoDimensionalArray()
|
||||
{
|
||||
$requestStack = new RequestStack();
|
||||
$requestStack->push(new Request());
|
||||
|
||||
$plugin = new Format($requestStack);
|
||||
|
||||
$params['values'] = [
|
||||
'Colors' => ['Green', 'Yellow', 'Red'],
|
||||
'Material' => ['Wood']
|
||||
];
|
||||
|
||||
$output = $plugin->formatTwoDimensionalArray($params);
|
||||
|
||||
$this->assertEquals(
|
||||
"Colors : Green / Yellow / Red | Material : Wood",
|
||||
$output
|
||||
);
|
||||
}
|
||||
|
||||
public function testFormatMoneyNotForceCurrency()
|
||||
{
|
||||
// new format_money method, thelia >= 2.3
|
||||
$data = $this->render("testFormatMoney.html", [
|
||||
'number' => 9.9999
|
||||
]);
|
||||
|
||||
$this->assertEquals("10.00 €", $data);
|
||||
}
|
||||
|
||||
public function testFormatMoneyForceCurrency()
|
||||
{
|
||||
/********************/
|
||||
/*** Test for EUR ***/
|
||||
/********************/
|
||||
$currency = CurrencyQuery::create()->findOneByCode('EUR');
|
||||
|
||||
// new format_money method, thelia >= 2.3
|
||||
$data = $this->render("testFormatMoney.html", [
|
||||
'number' => 9.9999,
|
||||
'currency' => $currency->getId()
|
||||
]);
|
||||
|
||||
$this->assertEquals("10.00 " . $currency->getSymbol(), $data);
|
||||
|
||||
// old format_money method, thelia < 2.3
|
||||
$data = $this->render("testFormatMoney.html", [
|
||||
'number' => 9.9999,
|
||||
'currency_symbol' => $currency->getSymbol()
|
||||
]);
|
||||
|
||||
$this->assertEquals("10.00 " . $currency->getSymbol(), $data);
|
||||
|
||||
/********************/
|
||||
/*** Test for USD ***/
|
||||
/********************/
|
||||
$currency = CurrencyQuery::create()->findOneByCode('USD');
|
||||
|
||||
// new format_money method, thelia >= 2.3
|
||||
$data = $this->render("testFormatMoney.html", [
|
||||
'number' => 9.9999,
|
||||
'currency' => $currency->getId()
|
||||
]);
|
||||
|
||||
$this->assertEquals($currency->getSymbol() . "10.00", $data);
|
||||
|
||||
// old format_money method, thelia < 2.3
|
||||
$data = $this->render("testFormatMoney.html", [
|
||||
'number' => 9.9999,
|
||||
'currency_symbol' => $currency->getSymbol()
|
||||
]);
|
||||
|
||||
$this->assertEquals($currency->getSymbol() . "10.00", $data);
|
||||
|
||||
/********************/
|
||||
/*** Test for GBP ***/
|
||||
/********************/
|
||||
$currency = CurrencyQuery::create()->findOneByCode('GBP');
|
||||
|
||||
// new format_money method, thelia >= 2.3
|
||||
$data = $this->render("testFormatMoney.html", [
|
||||
'number' => 9.9999,
|
||||
'currency' => $currency->getId()
|
||||
]);
|
||||
|
||||
$this->assertEquals($currency->getSymbol() . "10.00", $data);
|
||||
|
||||
// old format_money method, thelia < 2.3
|
||||
$data = $this->render("testFormatMoney.html", [
|
||||
'number' => 9.9999,
|
||||
'currency_symbol' => $currency->getSymbol()
|
||||
]);
|
||||
|
||||
$this->assertEquals($currency->getSymbol() . "10.00", $data);
|
||||
}
|
||||
|
||||
public function testFormatAddress()
|
||||
{
|
||||
// Test for address in France
|
||||
$countryFR = CountryQuery::create()->filterByIsoalpha2('FR')->findOne();
|
||||
$address = AddressQuery::create()->findOne();
|
||||
$address
|
||||
->setCountryId($countryFR->getId())
|
||||
->save();
|
||||
|
||||
$data = $this->renderString(
|
||||
'{format_address address=$address locale="fr_FR"}',
|
||||
[
|
||||
'address' => $address->getId()
|
||||
]
|
||||
);
|
||||
|
||||
$title = $address->getCustomerTitle()
|
||||
->setLocale('fr_FR')
|
||||
->getShort();
|
||||
|
||||
$expected = [
|
||||
'<p >',
|
||||
sprintf('<span class="recipient">%s %s %s</span><br>', $title, $address->getLastname(), $address->getFirstname()),
|
||||
sprintf('<span class="address-line1">%s</span><br>', $address->getAddress1()),
|
||||
sprintf('<span class="postal-code">%s</span> <span class="locality">%s</span><br>', $address->getZipcode(), $address->getCity()),
|
||||
'<span class="country">France</span>',
|
||||
'</p>'
|
||||
];
|
||||
|
||||
$this->assertEquals($data, implode("\n", $expected));
|
||||
|
||||
// Test for address in USA
|
||||
$stateDC = StateQuery::create()->filterByIsocode('DC')->findOne();
|
||||
$countryUS = $stateDC->getCountry();
|
||||
$address
|
||||
->setCountryId($countryUS->getId())
|
||||
->setStateId($stateDC->getId())
|
||||
->save();
|
||||
|
||||
$data = $this->renderString(
|
||||
'{format_address address=$address locale="en_US"}',
|
||||
[
|
||||
'address' => $address->getId()
|
||||
]
|
||||
);
|
||||
|
||||
$title = $address->getCustomerTitle()
|
||||
->setLocale('en_US')
|
||||
->getShort();
|
||||
|
||||
$expected = [
|
||||
'<p >',
|
||||
sprintf('<span class="recipient">%s %s %s</span><br>', $title, $address->getLastname(), $address->getFirstname()),
|
||||
sprintf('<span class="address-line1">%s</span><br>', $address->getAddress1()),
|
||||
sprintf(
|
||||
'<span class="locality">%s</span>, <span class="administrative-area">%s</span> <span class="postal-code">%s</span><br>',
|
||||
$address->getCity(),
|
||||
$stateDC->getIsocode(),
|
||||
$address->getZipcode()
|
||||
),
|
||||
'<span class="country">United States</span>',
|
||||
'</p>'
|
||||
];
|
||||
|
||||
$this->assertEquals($data, implode("\n", $expected));
|
||||
|
||||
// Test html tag
|
||||
$data = $this->renderString(
|
||||
'{format_address html_tag="address" html_class="a_class" html_id="an_id" address=$address}',
|
||||
['address' => $address->getId()]
|
||||
);
|
||||
|
||||
$this->assertTrue(strpos($data, '<address class="a_class" id="an_id">') !== false);
|
||||
|
||||
// Test plain text
|
||||
$data = $this->renderString(
|
||||
'{format_address html="0" address=$address locale="en_US"}',
|
||||
[
|
||||
'address' => $address->getId()
|
||||
]
|
||||
);
|
||||
|
||||
$expected = [
|
||||
sprintf('%s %s %s', $title, $address->getLastname(), $address->getFirstname()),
|
||||
sprintf('%s', $address->getAddress1()),
|
||||
sprintf('%s, %s %s', $address->getCity(), $stateDC->getIsocode(), $address->getZipcode()),
|
||||
'United States',
|
||||
];
|
||||
$this->assertEquals($data, implode("\n", $expected));
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ContainerBuilder $container
|
||||
* @return \TheliaSmarty\Template\AbstractSmartyPlugin
|
||||
*/
|
||||
protected function getPlugin(ContainerBuilder $container)
|
||||
{
|
||||
$this->requestStack = $container->get("request_stack");
|
||||
|
||||
return new Format($this->requestStack);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace TheliaSmarty\Tests\Template\Plugin;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use TheliaSmarty\Template\Plugins\Render;
|
||||
use Thelia\Core\Controller\ControllerResolver;
|
||||
|
||||
/**
|
||||
* Class RenderTest
|
||||
* @package TheliaSmarty\Tests\Template\Plugin
|
||||
* @author Benjamin Perche <bperche@openstudio.fr>
|
||||
*/
|
||||
class RenderTest extends SmartyPluginTestCase
|
||||
{
|
||||
public function testRenderWithoutParams()
|
||||
{
|
||||
$data = $this->render("test.html");
|
||||
|
||||
$this->assertEquals("Hello, world!", $data);
|
||||
}
|
||||
|
||||
public function testRenderWithParams()
|
||||
{
|
||||
$data = $this->render("testParams.html");
|
||||
|
||||
$this->assertEquals("Hello, world!", $data);
|
||||
}
|
||||
|
||||
public function testMethodParameter()
|
||||
{
|
||||
$data = $this->render("testMethod.html");
|
||||
|
||||
$this->assertEquals("PUT", $data);
|
||||
}
|
||||
|
||||
public function testQueryArrayParamater()
|
||||
{
|
||||
$this->smarty->assign("query", ["foo" => "bar"]);
|
||||
$data = $this->render("testQueryArray.html");
|
||||
|
||||
$this->assertEquals("bar", $data);
|
||||
}
|
||||
|
||||
public function testQueryStringParamater()
|
||||
{
|
||||
$data = $this->render("testQueryString.html");
|
||||
|
||||
$this->assertEquals("bar", $data);
|
||||
}
|
||||
|
||||
public function testRequestParamater()
|
||||
{
|
||||
$data = $this->render("testRequest.html");
|
||||
|
||||
$this->assertEquals("barPOSTbazPUT", $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \TheliaSmarty\Template\AbstractSmartyPlugin
|
||||
*/
|
||||
protected function getPlugin(ContainerBuilder $container)
|
||||
{
|
||||
return new Render(
|
||||
new ControllerResolver($container),
|
||||
$container->get("request_stack"),
|
||||
$container
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace TheliaSmarty\Tests\Template\Plugin;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\Form\Extension\Core\CoreExtension;
|
||||
use Symfony\Component\Form\FormFactoryBuilder;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Component\Validator\ValidatorBuilder;
|
||||
use Thelia\Core\Form\TheliaFormFactory;
|
||||
use Thelia\Core\Form\TheliaFormValidator;
|
||||
use Thelia\Core\HttpFoundation\Request;
|
||||
use Thelia\Core\HttpFoundation\Session\Session;
|
||||
use Thelia\Core\Template\ParserContext;
|
||||
use Thelia\Core\Template\TheliaTemplateHelper;
|
||||
use Thelia\Core\Translation\Translator;
|
||||
use Thelia\Tests\ContainerAwareTestCase;
|
||||
use TheliaSmarty\Template\SmartyParser;
|
||||
|
||||
/**
|
||||
* Class SmartyPluginTestCase
|
||||
* @package TheliaSmarty\Tests\Template\Plugin
|
||||
* @author Benjamin Perche <bperche@openstudio.fr>
|
||||
*/
|
||||
abstract class SmartyPluginTestCase extends ContainerAwareTestCase
|
||||
{
|
||||
/** @var SmartyParser */
|
||||
protected $smarty;
|
||||
|
||||
/**
|
||||
* @param ContainerBuilder $container
|
||||
* Use this method to build the container with the services that you need.
|
||||
*/
|
||||
protected function buildContainer(ContainerBuilder $container)
|
||||
{
|
||||
/** @var Request $request */
|
||||
$request = $container->get("request_stack")->getCurrentRequest();
|
||||
if (null === $request->getSession()) {
|
||||
$request->setSession(new Session());
|
||||
}
|
||||
|
||||
$requestStack = new RequestStack();
|
||||
$requestStack->push($request);
|
||||
|
||||
$container->set("thelia.parser.forms", [
|
||||
"thelia.empty" => "Thelia\\Form\\EmptyForm",
|
||||
"thelia.empty.2" => "Thelia\\Form\\EmptyForm",
|
||||
"thelia.api.empty" => "Thelia\\Form\\Api\\ApiEmptyForm",
|
||||
]);
|
||||
|
||||
$container->set("thelia.form_factory_builder", (new FormFactoryBuilder())->addExtension(new CoreExtension()));
|
||||
$container->set("thelia.forms.validator_builder", new ValidatorBuilder());
|
||||
|
||||
$container->set(
|
||||
"thelia.form_factory",
|
||||
new TheliaFormFactory($requestStack, $container, $container->get("thelia.parser.forms"))
|
||||
);
|
||||
|
||||
$container->set("thelia.parser.context", new ParserContext(
|
||||
$requestStack,
|
||||
$container->get("thelia.form_factory"),
|
||||
new TheliaFormValidator(new Translator($container), 'dev')
|
||||
));
|
||||
|
||||
$this->smarty = new SmartyParser(
|
||||
$requestStack,
|
||||
$container->get("event_dispatcher"),
|
||||
$container->get("thelia.parser.context"),
|
||||
$templateHelper = new TheliaTemplateHelper()
|
||||
);
|
||||
|
||||
$container->set("thelia.parser", $this->smarty);
|
||||
|
||||
$this->smarty->addPlugins($this->getPlugin($container));
|
||||
$this->smarty->registerPlugins();
|
||||
}
|
||||
|
||||
protected function render($template, $data = [])
|
||||
{
|
||||
return $this->internalRender('file', __DIR__.DS."fixtures".DS.$template, $data);
|
||||
}
|
||||
|
||||
protected function renderString($template, $data = [])
|
||||
{
|
||||
return $this->internalRender('string', $template, $data);
|
||||
}
|
||||
|
||||
protected function internalRender($resourceType, $resourceContent, array $data)
|
||||
{
|
||||
foreach ($data as $key => $value) {
|
||||
$this->smarty->assign($key, $value);
|
||||
}
|
||||
|
||||
return $this->smarty->fetch(sprintf("%s:%s", $resourceType, $resourceContent));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerBuilder $container
|
||||
* @return \TheliaSmarty\Template\AbstractSmartyPlugin
|
||||
*/
|
||||
abstract protected function getPlugin(ContainerBuilder $container);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
Hello, {render action="TheliaSmarty\Tests\Template\Plugin:Test:test"}!
|
||||
@@ -0,0 +1 @@
|
||||
{if $currency}{format_money number=$number currency_id=$currency}{else}{format_money number=$number symbol=$currency_symbol}{/if}
|
||||
@@ -0,0 +1 @@
|
||||
{render action="TheliaSmarty\Tests\Template\Plugin:Test:testMethod" method="PUT"}
|
||||
@@ -0,0 +1 @@
|
||||
{render action="TheliaSmarty\Tests\Template\Plugin:Test:testParams" paramA="Hello, " paramB="world!"}
|
||||
@@ -0,0 +1 @@
|
||||
{render action="TheliaSmarty\Tests\Template\Plugin:Test:testQuery" query=$query}
|
||||
@@ -0,0 +1 @@
|
||||
{render action="TheliaSmarty\Tests\Template\Plugin:Test:testQuery" query="foo=bar"}
|
||||
@@ -0,0 +1 @@
|
||||
{render action="TheliaSmarty\Tests\Template\Plugin:Test:testRequest" request="foo=bar"}{render action="TheliaSmarty\Tests\Template\Plugin:Test:testRequest" request="foo=baz" method="put"}
|
||||
128
local/modules/TheliaSmarty/Tests/Template/SmartyHelperTest.php
Normal file
128
local/modules/TheliaSmarty/Tests/Template/SmartyHelperTest.php
Normal file
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace TheliaSmarty\Tests\Template;
|
||||
|
||||
use TheliaSmarty\Template\SmartyHelper;
|
||||
|
||||
/**
|
||||
* Class SmartyHelperTest
|
||||
* @package Thelia\Tests\Core\Smarty
|
||||
* @author Julien Chanséaume <jchanseaume@openstudio.fr>
|
||||
*/
|
||||
class SmartyHelperTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @var SmartyHelper
|
||||
*/
|
||||
protected static $smartyParserHelper;
|
||||
|
||||
public static function setUpBeforeClass()
|
||||
{
|
||||
self::$smartyParserHelper = new SmartyHelper();
|
||||
}
|
||||
|
||||
public function testFunctionsDefinition()
|
||||
{
|
||||
$content = <<<EOT
|
||||
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||
quis nostrud {hook name="test"} exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||
EOT;
|
||||
|
||||
$functions = self::$smartyParserHelper->getFunctionsDefinition($content);
|
||||
|
||||
$this->assertCount(1, $functions);
|
||||
$this->assertArrayHasKey("name", $functions[0]);
|
||||
$this->assertEquals("hook", $functions[0]["name"]);
|
||||
$this->assertArrayHasKey("attributes", $functions[0]);
|
||||
$this->assertArrayHasKey("name", $functions[0]["attributes"]);
|
||||
$this->assertEquals("test", $functions[0]["attributes"]["name"]);
|
||||
}
|
||||
|
||||
public function testfunctionsDefinitionVar()
|
||||
{
|
||||
$content = <<<'EOT'
|
||||
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||
quis nostrud {hook name=$test} exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||
cillum dolore {function name="{$test}"} eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||
EOT;
|
||||
|
||||
$functions = self::$smartyParserHelper->getFunctionsDefinition($content);
|
||||
|
||||
$this->assertCount(2, $functions);
|
||||
|
||||
$this->assertArrayHasKey("name", $functions[0]);
|
||||
$this->assertEquals("hook", $functions[0]["name"]);
|
||||
$this->assertArrayHasKey("attributes", $functions[0]);
|
||||
$this->assertArrayHasKey("name", $functions[0]["attributes"]);
|
||||
$this->assertEquals("\$test", $functions[0]["attributes"]["name"]);
|
||||
|
||||
$this->assertArrayHasKey("name", $functions[1]);
|
||||
$this->assertEquals("function", $functions[1]["name"]);
|
||||
$this->assertArrayHasKey("attributes", $functions[1]);
|
||||
$this->assertArrayHasKey("name", $functions[1]["attributes"]);
|
||||
$this->assertEquals("{\$test}", $functions[1]["attributes"]["name"]);
|
||||
}
|
||||
|
||||
public function testfunctionsDefinitionInnerFunction()
|
||||
{
|
||||
$content = <<<'EOT'
|
||||
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||
quis nostrud {hook name={intl l="test"}} exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||
cillum dolore {hook name={intl l="test"}} eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||
EOT;
|
||||
|
||||
$functions = self::$smartyParserHelper->getFunctionsDefinition($content);
|
||||
|
||||
$this->assertCount(2, $functions);
|
||||
|
||||
for ($i = 0; $i <= 1; $i++) {
|
||||
$this->assertArrayHasKey("name", $functions[$i]);
|
||||
$this->assertEquals("hook", $functions[$i]["name"]);
|
||||
$this->assertArrayHasKey("attributes", $functions[$i]);
|
||||
$this->assertArrayHasKey("name", $functions[$i]["attributes"]);
|
||||
$this->assertEquals("{intl l=\"test\"}", $functions[$i]["attributes"]["name"]);
|
||||
}
|
||||
}
|
||||
|
||||
public function testfunctionsDefinitionSpecificFunction()
|
||||
{
|
||||
$content = <<<'EOT'
|
||||
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||
quis nostrud {hook name="hello world" } exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||
cillum dolore {function name={intl l="test"}} eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||
EOT;
|
||||
|
||||
$functions = self::$smartyParserHelper->getFunctionsDefinition($content, array("hook"));
|
||||
|
||||
$this->assertCount(1, $functions);
|
||||
|
||||
$this->assertArrayHasKey("name", $functions[0]);
|
||||
$this->assertEquals("hook", $functions[0]["name"]);
|
||||
$this->assertArrayHasKey("attributes", $functions[0]);
|
||||
$this->assertArrayHasKey("name", $functions[0]["attributes"]);
|
||||
$this->assertEquals("hello world", $functions[0]["attributes"]["name"]);
|
||||
}
|
||||
}
|
||||
33
local/modules/TheliaSmarty/TheliaSmarty.php
Normal file
33
local/modules/TheliaSmarty/TheliaSmarty.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace TheliaSmarty;
|
||||
|
||||
use Thelia\Module\BaseModule;
|
||||
use TheliaSmarty\Compiler\RegisterParserPluginPass;
|
||||
|
||||
class TheliaSmarty extends BaseModule
|
||||
{
|
||||
/*
|
||||
* You may now override BaseModuleInterface methods, such as:
|
||||
* install, destroy, preActivation, postActivation, preDeactivation, postDeactivation
|
||||
*
|
||||
* Have fun !
|
||||
*/
|
||||
|
||||
public static function getCompilers()
|
||||
{
|
||||
return [
|
||||
new RegisterParserPluginPass()
|
||||
];
|
||||
}
|
||||
}
|
||||
11
local/modules/TheliaSmarty/composer.json
Normal file
11
local/modules/TheliaSmarty/composer.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "thelia/smarty-module",
|
||||
"license": "LGPL-3.0+",
|
||||
"type": "thelia-module",
|
||||
"require": {
|
||||
"thelia/installer": "~1.1"
|
||||
},
|
||||
"extra": {
|
||||
"installer-name": "TheliaSmarty"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user