Inital commit
This commit is contained in:
165
core/LICENSE.txt
Normal file
165
core/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.
|
||||
38
core/Readme.md
Normal file
38
core/Readme.md
Normal file
@@ -0,0 +1,38 @@
|
||||
Readme
|
||||
======
|
||||
|
||||
## This is the repository of Thelia core. All the pull requests on this repo will be ignored.
|
||||
### If you want to create a project, please take a look at [thelia/thelia-project](https://github.com/thelia/thelia-project)
|
||||
### If you want to contribute to Thelia, please take a look at [thelia/thelia](https://github.com/thelia/thelia)
|
||||
|
||||
Thelia
|
||||
------
|
||||
[](https://travis-ci.org/thelia/thelia) [](https://packagist.org/packages/thelia/thelia) [](https://scrutinizer-ci.com/g/thelia/thelia/)
|
||||
|
||||
[Thelia](http://thelia.net/) is an open source tool for creating e-business websites and managing online content. This software is published under LGPL.
|
||||
|
||||
This is the new major version of Thelia.
|
||||
|
||||
You can download this version and have a try or take a look at the source code (or anything you wish, respecting LGPL). See http://thelia.net/ web site for more information.
|
||||
|
||||
A repository containing all thelia modules is available at this address : https://github.com/thelia-modules
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
* php 5.5
|
||||
* Required extensions :
|
||||
* PDO_Mysql
|
||||
* openssl
|
||||
* intl
|
||||
* gd
|
||||
* curl
|
||||
* calendar
|
||||
* dom
|
||||
* fileinfo
|
||||
* safe_mode off
|
||||
* memory_limit at least 128M, preferably 256.
|
||||
* post_max_size 20M
|
||||
* upload_max_filesize 2M
|
||||
* apache 2
|
||||
* mysql
|
||||
53
core/Thelia
Executable file
53
core/Thelia
Executable file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
if (php_sapi_name() != 'cli') {
|
||||
throw new \Exception('this script can only be launched with cli sapi');
|
||||
}
|
||||
set_time_limit(0);
|
||||
|
||||
// allow cache to be cleared by php client or web
|
||||
umask(0002);
|
||||
|
||||
$bootstrapToggle = false;
|
||||
$bootstraped = false;
|
||||
|
||||
// Autoload bootstrap
|
||||
|
||||
foreach ($argv as $arg) {
|
||||
if ($arg === '-b') {
|
||||
$bootstrapToggle = true;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($bootstrapToggle) {
|
||||
require __DIR__ . DIRECTORY_SEPARATOR . $arg;
|
||||
|
||||
$bootstraped = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$bootstraped) {
|
||||
if (isset($bootstrapFile)) {
|
||||
require $bootstrapFile;
|
||||
} elseif (is_file($file = __DIR__ . '/vendor/autoload.php')) {
|
||||
require $file;
|
||||
} else {
|
||||
echo "No autoload file found. Please use the -b argument to include yours";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
use Thelia\Core\Thelia;
|
||||
use Thelia\Core\Application;
|
||||
use Thelia\Command\Output\TheliaConsoleOutput;
|
||||
use Symfony\Component\Console\Input\ArgvInput;
|
||||
|
||||
$input = new ArgvInput();
|
||||
$env = $input->getParameterOption(array('--env', '-e'), getenv('THELIA_ENV') ?: 'dev');
|
||||
$debug = getenv('THELIA_DEBUG') !== '0' && !$input->hasParameterOption(array('--no-debug', '')) && $env !== 'prod';
|
||||
|
||||
$thelia = new Thelia($env, $debug);
|
||||
$application = new Application($thelia);
|
||||
$application->getContainer()->get('thelia.translator');
|
||||
$application->run($input, new TheliaConsoleOutput());
|
||||
@@ -10,27 +10,83 @@
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
// Check php version
|
||||
|
||||
if (version_compare(phpversion(), "5.4", "<")) {
|
||||
die(sprintf(
|
||||
"Thelia needs at least php 5.4, but you are using php %s. Please upgrade before using Thelia.\n",
|
||||
phpversion()
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Thelia essential definitions
|
||||
*/
|
||||
define('DS' , DIRECTORY_SEPARATOR);
|
||||
define('THELIA_ROOT' , rtrim(realpath(dirname(__DIR__)), DS) . DS);
|
||||
define('THELIA_LOCAL_DIR' , THELIA_ROOT . 'local' . DS);
|
||||
define('THELIA_CONF_DIR' , THELIA_LOCAL_DIR . 'config' . DS);
|
||||
define('THELIA_MODULE_DIR' , THELIA_LOCAL_DIR . 'modules' . DS);
|
||||
define('THELIA_WEB_DIR' , THELIA_ROOT . 'web' . DS);
|
||||
define('THELIA_CACHE_DIR' , THELIA_ROOT . 'cache' . DS);
|
||||
define('THELIA_LOG_DIR' , THELIA_ROOT . 'log' . DS);
|
||||
define('THELIA_TEMPLATE_DIR' , THELIA_ROOT . 'templates' . DS);
|
||||
|
||||
$loader = require __DIR__ . "/vendor/autoload.php";
|
||||
if (!defined('DS')) {
|
||||
define('DS', DIRECTORY_SEPARATOR);
|
||||
}
|
||||
|
||||
if (!defined('THELIA_ROOT')) {
|
||||
define('THELIA_ROOT', rtrim(realpath(dirname(__DIR__)), DS) . DS);
|
||||
}
|
||||
|
||||
if (!defined('THELIA_LIB')) {
|
||||
define('THELIA_LIB', THELIA_ROOT . 'core' . DS . 'lib' . DS . 'Thelia' . DS);
|
||||
}
|
||||
|
||||
if (!defined('THELIA_VENDOR')) {
|
||||
define('THELIA_VENDOR', THELIA_ROOT . 'core' . DS . 'vendor' . DS);
|
||||
}
|
||||
|
||||
if (!defined('THELIA_LOCAL_DIR')) {
|
||||
define('THELIA_LOCAL_DIR', THELIA_ROOT . 'local' . DS);
|
||||
}
|
||||
|
||||
if (!defined('THELIA_CONF_DIR')) {
|
||||
define('THELIA_CONF_DIR', THELIA_LOCAL_DIR . 'config' . DS);
|
||||
}
|
||||
|
||||
if (!defined('THELIA_MODULE_DIR')) {
|
||||
define('THELIA_MODULE_DIR', THELIA_LOCAL_DIR . 'modules' . DS);
|
||||
}
|
||||
|
||||
if (!defined('THELIA_WEB_DIR')) {
|
||||
define('THELIA_WEB_DIR', THELIA_ROOT . 'web' . DS);
|
||||
}
|
||||
|
||||
if (!defined('THELIA_CACHE_DIR')) {
|
||||
define('THELIA_CACHE_DIR', THELIA_ROOT . 'cache' . DS);
|
||||
}
|
||||
|
||||
if (!defined('THELIA_LOG_DIR')) {
|
||||
define('THELIA_LOG_DIR', THELIA_ROOT . 'log' . DS);
|
||||
}
|
||||
|
||||
if (!defined('THELIA_TEMPLATE_DIR')) {
|
||||
define('THELIA_TEMPLATE_DIR', THELIA_ROOT . 'templates' . DS);
|
||||
}
|
||||
|
||||
if (!defined('THELIA_SETUP_DIRECTORY')) {
|
||||
define('THELIA_SETUP_DIRECTORY', THELIA_ROOT . 'setup' . DS);
|
||||
}
|
||||
|
||||
if (!defined('THELIA_SETUP_WIZARD_DIRECTORY')) {
|
||||
define('THELIA_SETUP_WIZARD_DIRECTORY', THELIA_ROOT . 'web' . DS . 'install' . DS);
|
||||
}
|
||||
|
||||
if (!file_exists(THELIA_CONF_DIR . 'database.yml') && !defined('THELIA_INSTALL_MODE')) {
|
||||
$sapi = php_sapi_name();
|
||||
if (substr($sapi, 0, 3) == 'cli') {
|
||||
define('THELIA_INSTALL_MODE', true);
|
||||
} else {
|
||||
} elseif (file_exists(THELIA_ROOT . DS . 'web' . DS . 'install')) {
|
||||
$request = \Thelia\Core\HttpFoundation\Request::createFromGlobals();
|
||||
header('Location: '.$request->getUriForPath('/install'));
|
||||
} else {
|
||||
header($_SERVER['SERVER_PROTOCOL'] . ' 500 Thelia is not installed', true, 500);
|
||||
die(sprintf(
|
||||
"Thelia is not installed. <a href=\"%s\" target=\"_blank\">More information</a>\n",
|
||||
"http://doc.thelia.net/en/documentation/installation/index.html#using-cli-tools"
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
79
core/composer.json
Normal file
79
core/composer.json
Normal file
@@ -0,0 +1,79 @@
|
||||
{
|
||||
"name": "thelia/core",
|
||||
"description": "Core of Thelia ecommerce CMS.",
|
||||
"license": "LGPL-3.0+",
|
||||
"homepage": "http://thelia.net/",
|
||||
"support": {
|
||||
"forum": "http://thelia.net/forum",
|
||||
"wiki": "http://doc.thelia.net"
|
||||
},
|
||||
"repositories": [
|
||||
{
|
||||
"type": "vcs",
|
||||
"url": "https://github.com/thelia/Propel2"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.4",
|
||||
"ircmaxell/password-compat": "1.0.*",
|
||||
"psr/log": "1.0",
|
||||
"symfony/config": "2.8.*",
|
||||
"symfony/console": "2.8.*",
|
||||
"symfony/dependency-injection": "2.8.*",
|
||||
"symfony/event-dispatcher": "2.8.*",
|
||||
"symfony/http-kernel": "2.8.*",
|
||||
"symfony/routing": "2.8.*",
|
||||
"symfony/filesystem": "2.8.*",
|
||||
"symfony/yaml": "2.8.*",
|
||||
"symfony/translation": "2.8.*",
|
||||
"symfony-cmf/routing": "1.3.*",
|
||||
"symfony/validator": "2.8.*",
|
||||
"symfony/options-resolver": "2.8.*",
|
||||
"symfony/security": "2.8.*",
|
||||
"symfony/expression-language": "2.8.*",
|
||||
"symfony/process": "2.8.*",
|
||||
"symfony/dom-crawler": "2.8.*",
|
||||
"symfony/property-access": "2.8.*",
|
||||
"symfony/serializer": "2.8.*",
|
||||
"ensepar/html2pdf": "1.0.1",
|
||||
"symfony/finder": "2.8.*",
|
||||
"symfony/browser-kit": "2.8.*",
|
||||
"symfony/http-foundation": "2.8.*",
|
||||
"symfony/form": "2.8.*",
|
||||
"symfony/class-loader": "2.8.*",
|
||||
"symfony/icu": "1.0",
|
||||
"stack/builder": "1.0.*",
|
||||
"thelia/currency-converter": "~1.0",
|
||||
"doctrine/cache": "1.5.*",
|
||||
"kriswallsmith/assetic": "1.3.*",
|
||||
"ptachoire/cssembed": "1.0.*",
|
||||
"simplepie/simplepie": "1.3.*",
|
||||
"imagine/imagine": "0.6.*",
|
||||
"swiftmailer/swiftmailer": "5.4.*",
|
||||
"oyejorge/less.php": "1.7.*",
|
||||
"michelf/php-markdown": "1.6.*",
|
||||
"smarty/smarty": "3.1.20",
|
||||
"ramsey/array_column": "~1.1",
|
||||
"propel/propel": "dev-thelia-2.3",
|
||||
"commerceguys/addressing": "0.8.*",
|
||||
"symfony/cache": "~3.1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"fzaninotto/faker": "1.5.*",
|
||||
"thelia/hooktest-module": "~1.1",
|
||||
"thelia/hooktest-template": "~1.1",
|
||||
"phpunit/phpunit": "4.8.*"
|
||||
},
|
||||
"bin": [
|
||||
"Thelia"
|
||||
],
|
||||
"minimum-stability": "stable",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Thelia\\": "lib/Thelia/"
|
||||
},
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -11,8 +11,10 @@
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Thelia\Action;
|
||||
|
||||
use Propel\Runtime\Exception\PropelException;
|
||||
use Propel\Runtime\Propel;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Core\Event\Address\AddressCreateOrUpdateEvent;
|
||||
use Thelia\Core\Event\Address\AddressEvent;
|
||||
@@ -23,23 +25,22 @@ use Thelia\Model\Map\AddressTableMap;
|
||||
/**
|
||||
* Class Address
|
||||
* @package Thelia\Action
|
||||
* @author Manuel Raynaud <mraynaud@openstudio.fr>
|
||||
* @author Manuel Raynaud <manu@raynaud.io>
|
||||
*/
|
||||
class Address extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
|
||||
public function create(AddressCreateOrUpdateEvent $event)
|
||||
public function create(AddressCreateOrUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$address = new AddressModel();
|
||||
$address->setCustomer($event->getCustomer());
|
||||
$this->createOrUpdate($address, $event);
|
||||
$this->createOrUpdate($address, $event, $dispatcher);
|
||||
}
|
||||
|
||||
public function update(AddressCreateOrUpdateEvent $event)
|
||||
public function update(AddressCreateOrUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$addressModel = $event->getAddress();
|
||||
|
||||
$this->createOrUpdate($addressModel, $event);
|
||||
$this->createOrUpdate($addressModel, $event, $dispatcher);
|
||||
}
|
||||
|
||||
public function delete(AddressEvent $event)
|
||||
@@ -56,9 +57,9 @@ class Address extends BaseAction implements EventSubscriberInterface
|
||||
$address->makeItDefault();
|
||||
}
|
||||
|
||||
protected function createOrUpdate(AddressModel $addressModel, AddressCreateOrUpdateEvent $event)
|
||||
protected function createOrUpdate(AddressModel $addressModel, AddressCreateOrUpdateEvent $event, $dispatcher)
|
||||
{
|
||||
$addressModel->setDispatcher($event->getDispatcher());
|
||||
$addressModel->setDispatcher($dispatcher);
|
||||
$con = Propel::getWriteConnection(AddressTableMap::DATABASE_NAME);
|
||||
$con->beginTransaction();
|
||||
try {
|
||||
@@ -73,6 +74,7 @@ class Address extends BaseAction implements EventSubscriberInterface
|
||||
->setZipcode($event->getZipcode())
|
||||
->setCity($event->getCity())
|
||||
->setCountryId($event->getCountry())
|
||||
->setStateId($event->getState())
|
||||
->setCellphone($event->getCellphone())
|
||||
->setPhone($event->getPhone())
|
||||
->setCompany($event->getCompany())
|
||||
@@ -85,33 +87,14 @@ class Address extends BaseAction implements EventSubscriberInterface
|
||||
|
||||
$event->setAddress($addressModel);
|
||||
$con->commit();
|
||||
|
||||
} catch (PropelException $e) {
|
||||
$con->rollback();
|
||||
throw $e;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of event names this subscriber wants to listen to.
|
||||
*
|
||||
* The array keys are event names and the value can be:
|
||||
*
|
||||
* * The method name to call (priority defaults to 0)
|
||||
* * An array composed of the method name to call and the priority
|
||||
* * An array of arrays composed of the method names to call and respective
|
||||
* priorities, or 0 if unset
|
||||
*
|
||||
* For instance:
|
||||
*
|
||||
* * array('eventName' => 'methodName')
|
||||
* * array('eventName' => array('methodName', $priority))
|
||||
* * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
|
||||
*
|
||||
* @return array The event names to listen to
|
||||
*
|
||||
* @api
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
|
||||
@@ -12,26 +12,45 @@
|
||||
|
||||
namespace Thelia\Action;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Core\Event\Administrator\AdministratorEvent;
|
||||
use Thelia\Core\Event\Administrator\AdministratorUpdatePasswordEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Mailer\MailerFactory;
|
||||
use Thelia\Model\Admin as AdminModel;
|
||||
use Thelia\Model\AdminQuery;
|
||||
use Thelia\Model\ConfigQuery;
|
||||
use Thelia\Tools\TokenProvider;
|
||||
|
||||
class Administrator extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
/** @var MailerFactory */
|
||||
protected $mailer;
|
||||
|
||||
/** @var TokenProvider */
|
||||
protected $tokenProvider;
|
||||
|
||||
public function __construct(MailerFactory $mailer, TokenProvider $tokenProvider)
|
||||
{
|
||||
$this->mailer = $mailer;
|
||||
$this->tokenProvider = $tokenProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AdministratorEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function create(AdministratorEvent $event)
|
||||
public function create(AdministratorEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$administrator = new AdminModel();
|
||||
|
||||
$administrator
|
||||
->setDispatcher($event->getDispatcher())
|
||||
->setDispatcher($dispatcher)
|
||||
->setFirstname($event->getFirstname())
|
||||
->setLastname($event->getLastname())
|
||||
->setEmail($event->getEmail())
|
||||
->setLogin($event->getLogin())
|
||||
->setPassword($event->getPassword())
|
||||
->setProfileId($event->getProfile())
|
||||
@@ -45,16 +64,18 @@ class Administrator extends BaseAction implements EventSubscriberInterface
|
||||
|
||||
/**
|
||||
* @param AdministratorEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function update(AdministratorEvent $event)
|
||||
public function update(AdministratorEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $administrator = AdminQuery::create()->findPk($event->getId())) {
|
||||
|
||||
$administrator
|
||||
->setDispatcher($event->getDispatcher())
|
||||
->setDispatcher($dispatcher)
|
||||
->setFirstname($event->getFirstname())
|
||||
->setLastname($event->getLastname())
|
||||
->setLogin($event->getLogin())
|
||||
->setEmail($event->getEmail())
|
||||
->setProfileId($event->getProfile())
|
||||
->setLocale($event->getLocale())
|
||||
;
|
||||
@@ -75,7 +96,6 @@ class Administrator extends BaseAction implements EventSubscriberInterface
|
||||
public function delete(AdministratorEvent $event)
|
||||
{
|
||||
if (null !== $administrator = AdminQuery::create()->findPk($event->getId())) {
|
||||
|
||||
$administrator
|
||||
->delete()
|
||||
;
|
||||
@@ -87,12 +107,40 @@ class Administrator extends BaseAction implements EventSubscriberInterface
|
||||
public function updatePassword(AdministratorUpdatePasswordEvent $event)
|
||||
{
|
||||
$admin = $event->getAdmin();
|
||||
$admin->setPassword($event->getPassword())
|
||||
|
||||
$admin
|
||||
->setPassword($event->getPassword())
|
||||
->setPasswordRenewToken(null)
|
||||
->save();
|
||||
}
|
||||
|
||||
public function createPassword(AdministratorEvent $event)
|
||||
{
|
||||
$admin = $event->getAdministrator();
|
||||
|
||||
$email = $admin->getEmail();
|
||||
|
||||
if (! empty($email)) {
|
||||
$renewToken = $this->tokenProvider->getToken();
|
||||
|
||||
$admin
|
||||
->setPasswordRenewToken($renewToken)
|
||||
->save();
|
||||
|
||||
$this->mailer->sendEmailMessage(
|
||||
'new_admin_password',
|
||||
[ ConfigQuery::getStoreEmail() => ConfigQuery::getStoreName() ],
|
||||
[ $email => $admin->getFirstname() . ' ' . $admin->getLastname() ],
|
||||
[
|
||||
'token' => $renewToken,
|
||||
'admin' => $admin
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
@@ -100,7 +148,8 @@ class Administrator extends BaseAction implements EventSubscriberInterface
|
||||
TheliaEvents::ADMINISTRATOR_CREATE => array('create', 128),
|
||||
TheliaEvents::ADMINISTRATOR_UPDATE => array('update', 128),
|
||||
TheliaEvents::ADMINISTRATOR_DELETE => array('delete', 128),
|
||||
TheliaEvents::ADMINISTRATOR_UPDATEPASSWORD => array('updatePassword', 128)
|
||||
TheliaEvents::ADMINISTRATOR_UPDATEPASSWORD => array('updatePassword', 128),
|
||||
TheliaEvents::ADMINISTRATOR_CREATEPASSWORD => array('createPassword', 128)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
65
core/lib/Thelia/Action/Api.php
Normal file
65
core/lib/Thelia/Action/Api.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?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 Thelia\Action;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Core\Event\Api\ApiCreateEvent;
|
||||
use Thelia\Core\Event\Api\ApiDeleteEvent;
|
||||
use Thelia\Core\Event\Api\ApiUpdateEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Model\Api as ApiModel;
|
||||
|
||||
/**
|
||||
* Class Api
|
||||
* @package Thelia\Action
|
||||
* @author Manuel Raynaud <manu@raynaud.io>
|
||||
*/
|
||||
class Api extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
public function createApi(ApiCreateEvent $event)
|
||||
{
|
||||
$api = new ApiModel();
|
||||
|
||||
$api->setLabel($event->getLabel())
|
||||
->setProfileId($event->getProfile())
|
||||
->save()
|
||||
;
|
||||
}
|
||||
|
||||
public function deleteApi(ApiDeleteEvent $event)
|
||||
{
|
||||
$api = $event->getApi();
|
||||
|
||||
$api->delete();
|
||||
}
|
||||
|
||||
public function updateApi(ApiUpdateEvent $event)
|
||||
{
|
||||
$api = $event->getApi();
|
||||
|
||||
$api->setProfileId($event->getProfile())
|
||||
->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return [
|
||||
TheliaEvents::API_CREATE => ['createApi', 128],
|
||||
TheliaEvents::API_DELETE => ['deleteApi', 128],
|
||||
TheliaEvents::API_UPDATE => ['updateApi', 128],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -11,52 +11,73 @@
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Thelia\Action;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Core\Event\Area\AreaAddCountryEvent;
|
||||
use Thelia\Core\Event\Area\AreaCreateEvent;
|
||||
use Thelia\Core\Event\Area\AreaDeleteEvent;
|
||||
use Thelia\Core\Event\Area\AreaRemoveCountryEvent;
|
||||
use Thelia\Core\Event\Area\AreaUpdateEvent;
|
||||
use Thelia\Core\Event\Area\AreaUpdatePostageEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Model\AreaQuery;
|
||||
use Thelia\Model\CountryQuery;
|
||||
|
||||
use Thelia\Model\Area as AreaModel;
|
||||
use Thelia\Model\AreaQuery;
|
||||
use Thelia\Model\CountryArea;
|
||||
use Thelia\Model\CountryAreaQuery;
|
||||
|
||||
/**
|
||||
* Class Area
|
||||
* @package Thelia\Action
|
||||
* @author Manuel Raynaud <mraynaud@openstudio.fr>
|
||||
* @author Manuel Raynaud <manu@raynaud.io>
|
||||
*/
|
||||
class Area extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
|
||||
public function addCountry(AreaAddCountryEvent $event)
|
||||
{
|
||||
if (null !== $country = CountryQuery::create()->findPk($event->getCountryId())) {
|
||||
$country->setDispatcher($event->getDispatcher());
|
||||
$country->setAreaId($event->getAreaId())
|
||||
->save();
|
||||
$countryIds = $event->getCountryId();
|
||||
|
||||
$event->setArea($country->getArea());
|
||||
$areaId = $event->getAreaId();
|
||||
|
||||
foreach ($countryIds as $countryId) {
|
||||
$countryArea = new CountryArea();
|
||||
|
||||
$country = explode('-', $countryId);
|
||||
if (count($country) === 1) {
|
||||
$country[1] = null;
|
||||
}
|
||||
if ($country[1] == 0) {
|
||||
$country[1] = null;
|
||||
}
|
||||
|
||||
$countryArea
|
||||
->setAreaId($areaId)
|
||||
->setCountryId($country[0])
|
||||
->setStateId($country[1])
|
||||
->save()
|
||||
;
|
||||
}
|
||||
|
||||
$event->setArea(AreaQuery::create()->findPk($areaId));
|
||||
}
|
||||
|
||||
public function removeCountry(AreaRemoveCountryEvent $event)
|
||||
{
|
||||
if (null !== $country = CountryQuery::create()->findPk($event->getCountryId())) {
|
||||
$event->setArea($country->getArea());
|
||||
CountryAreaQuery::create()
|
||||
->filterByCountryId($event->getCountryId())
|
||||
->filterByStateId($event->getStateId())
|
||||
->filterByAreaId($event->getAreaId())
|
||||
->delete();
|
||||
|
||||
$country->setDispatcher($event->getDispatcher());
|
||||
$country->setAreaId(null)
|
||||
->save();
|
||||
if (null !== $area = AreaQuery::create()->findPk($event->getAreaId())) {
|
||||
$event->setArea($area);
|
||||
}
|
||||
}
|
||||
|
||||
public function updatePostage(AreaUpdatePostageEvent $event)
|
||||
public function updatePostage(AreaUpdatePostageEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $area = AreaQuery::create()->findPk($event->getAreaId())) {
|
||||
$area->setDispatcher($event->getDispatcher());
|
||||
$area->setDispatcher($dispatcher);
|
||||
$area
|
||||
->setPostage($event->getPostage())
|
||||
->save();
|
||||
@@ -65,47 +86,42 @@ class Area extends BaseAction implements EventSubscriberInterface
|
||||
}
|
||||
}
|
||||
|
||||
public function delete(AreaDeleteEvent $event)
|
||||
public function delete(AreaDeleteEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $area = AreaQuery::create()->findPk($event->getAreaId())) {
|
||||
$area->setDispatcher($event->getDispatcher());
|
||||
$area->setDispatcher($dispatcher);
|
||||
$area->delete();
|
||||
|
||||
$event->setArea($area);
|
||||
}
|
||||
}
|
||||
|
||||
public function create(AreaCreateEvent $event)
|
||||
public function create(AreaCreateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$area = new AreaModel();
|
||||
|
||||
$area
|
||||
->setDispatcher($event->getDispatcher())
|
||||
->setDispatcher($dispatcher)
|
||||
->setName($event->getAreaName())
|
||||
->save();
|
||||
|
||||
$event->setArea($area);
|
||||
}
|
||||
|
||||
public function update(AreaUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $area = AreaQuery::create()->findPk($event->getAreaId())) {
|
||||
$area
|
||||
->setDispatcher($dispatcher)
|
||||
->setName($event->getAreaName())
|
||||
->save();
|
||||
|
||||
$event->setArea($area);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of event names this subscriber wants to listen to.
|
||||
*
|
||||
* The array keys are event names and the value can be:
|
||||
*
|
||||
* * The method name to call (priority defaults to 0)
|
||||
* * An array composed of the method name to call and the priority
|
||||
* * An array of arrays composed of the method names to call and respective
|
||||
* priorities, or 0 if unset
|
||||
*
|
||||
* For instance:
|
||||
*
|
||||
* * array('eventName' => 'methodName')
|
||||
* * array('eventName' => array('methodName', $priority))
|
||||
* * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
|
||||
*
|
||||
* @return array The event names to listen to
|
||||
*
|
||||
* @api
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
@@ -114,7 +130,8 @@ class Area extends BaseAction implements EventSubscriberInterface
|
||||
TheliaEvents::AREA_REMOVE_COUNTRY => array('removeCountry', 128),
|
||||
TheliaEvents::AREA_POSTAGE_UPDATE => array('updatePostage', 128),
|
||||
TheliaEvents::AREA_DELETE => array('delete', 128),
|
||||
TheliaEvents::AREA_CREATE => array('create', 128)
|
||||
TheliaEvents::AREA_CREATE => array('create', 128),
|
||||
TheliaEvents::AREA_UPDATE => array('update', 128)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,13 +12,11 @@
|
||||
|
||||
namespace Thelia\Action;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
|
||||
use Thelia\Model\AttributeQuery;
|
||||
use Thelia\Model\Attribute as AttributeModel;
|
||||
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
|
||||
use Thelia\Core\Event\Attribute\AttributeUpdateEvent;
|
||||
use Thelia\Core\Event\Attribute\AttributeCreateEvent;
|
||||
use Thelia\Core\Event\Attribute\AttributeDeleteEvent;
|
||||
@@ -34,17 +32,17 @@ class Attribute extends BaseAction implements EventSubscriberInterface
|
||||
* Create a new attribute entry
|
||||
*
|
||||
* @param AttributeCreateEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function create(AttributeCreateEvent $event)
|
||||
public function create(AttributeCreateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$attribute = new AttributeModel();
|
||||
|
||||
$attribute
|
||||
->setDispatcher($event->getDispatcher())
|
||||
|
||||
->setDispatcher($dispatcher)
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
|
||||
->save()
|
||||
;
|
||||
|
||||
@@ -60,14 +58,14 @@ class Attribute extends BaseAction implements EventSubscriberInterface
|
||||
* Change a product attribute
|
||||
*
|
||||
* @param AttributeUpdateEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function update(AttributeUpdateEvent $event)
|
||||
public function update(AttributeUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
|
||||
if (null !== $attribute = AttributeQuery::create()->findPk($event->getAttributeId())) {
|
||||
|
||||
$attribute
|
||||
->setDispatcher($event->getDispatcher())
|
||||
->setDispatcher($dispatcher)
|
||||
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
@@ -85,14 +83,14 @@ class Attribute extends BaseAction implements EventSubscriberInterface
|
||||
* Delete a product attribute entry
|
||||
*
|
||||
* @param AttributeDeleteEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function delete(AttributeDeleteEvent $event)
|
||||
public function delete(AttributeDeleteEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
|
||||
if (null !== ($attribute = AttributeQuery::create()->findPk($event->getAttributeId()))) {
|
||||
|
||||
$attribute
|
||||
->setDispatcher($event->getDispatcher())
|
||||
->setDispatcher($dispatcher)
|
||||
->delete()
|
||||
;
|
||||
|
||||
@@ -103,11 +101,13 @@ class Attribute extends BaseAction implements EventSubscriberInterface
|
||||
/**
|
||||
* Changes position, selecting absolute ou relative change.
|
||||
*
|
||||
* @param CategoryChangePositionEvent $event
|
||||
* @param UpdatePositionEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function updatePosition(UpdatePositionEvent $event)
|
||||
public function updatePosition(UpdatePositionEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$this->genericUpdatePosition(AttributeQuery::create(), $event);
|
||||
$this->genericUpdatePosition(AttributeQuery::create(), $event, $dispatcher);
|
||||
}
|
||||
|
||||
protected function doAddToAllTemplates(AttributeModel $attribute)
|
||||
@@ -115,7 +115,6 @@ class Attribute extends BaseAction implements EventSubscriberInterface
|
||||
$templates = TemplateQuery::create()->find();
|
||||
|
||||
foreach ($templates as $template) {
|
||||
|
||||
$attribute_template = new AttributeTemplate();
|
||||
|
||||
if (null === AttributeTemplateQuery::create()->filterByAttribute($attribute)->filterByTemplate($template)->findOne()) {
|
||||
@@ -140,7 +139,7 @@ class Attribute extends BaseAction implements EventSubscriberInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
|
||||
@@ -12,13 +12,11 @@
|
||||
|
||||
namespace Thelia\Action;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
|
||||
use Thelia\Model\AttributeAvQuery;
|
||||
use Thelia\Model\AttributeAv as AttributeAvModel;
|
||||
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
|
||||
use Thelia\Core\Event\Attribute\AttributeAvUpdateEvent;
|
||||
use Thelia\Core\Event\Attribute\AttributeAvCreateEvent;
|
||||
use Thelia\Core\Event\Attribute\AttributeAvDeleteEvent;
|
||||
@@ -30,13 +28,15 @@ class AttributeAv extends BaseAction implements EventSubscriberInterface
|
||||
* Create a new attribute entry
|
||||
*
|
||||
* @param AttributeAvCreateEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function create(AttributeAvCreateEvent $event)
|
||||
public function create(AttributeAvCreateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$attribute = new AttributeAvModel();
|
||||
|
||||
$attribute
|
||||
->setDispatcher($event->getDispatcher())
|
||||
->setDispatcher($dispatcher)
|
||||
|
||||
->setAttributeId($event->getAttributeId())
|
||||
->setLocale($event->getLocale())
|
||||
@@ -51,15 +51,15 @@ class AttributeAv extends BaseAction implements EventSubscriberInterface
|
||||
/**
|
||||
* Change a product attribute
|
||||
*
|
||||
* @param \Thelia\Core\Event\Attribute\AttributeAvUpdateEvent $event
|
||||
* @param AttributeAvUpdateEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function update(AttributeAvUpdateEvent $event)
|
||||
public function update(AttributeAvUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
|
||||
if (null !== $attribute = AttributeAvQuery::create()->findPk($event->getAttributeAvId())) {
|
||||
|
||||
$attribute
|
||||
->setDispatcher($event->getDispatcher())
|
||||
->setDispatcher($dispatcher)
|
||||
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
@@ -77,14 +77,14 @@ class AttributeAv extends BaseAction implements EventSubscriberInterface
|
||||
* Delete a product attribute entry
|
||||
*
|
||||
* @param AttributeAvDeleteEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function delete(AttributeAvDeleteEvent $event)
|
||||
public function delete(AttributeAvDeleteEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
|
||||
if (null !== ($attribute = AttributeAvQuery::create()->findPk($event->getAttributeAvId()))) {
|
||||
|
||||
$attribute
|
||||
->setDispatcher($event->getDispatcher())
|
||||
->setDispatcher($dispatcher)
|
||||
->delete()
|
||||
;
|
||||
|
||||
@@ -95,15 +95,17 @@ class AttributeAv extends BaseAction implements EventSubscriberInterface
|
||||
/**
|
||||
* Changes position, selecting absolute ou relative change.
|
||||
*
|
||||
* @param CategoryChangePositionEvent $event
|
||||
* @param UpdatePositionEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function updatePosition(UpdatePositionEvent $event)
|
||||
public function updatePosition(UpdatePositionEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$this->genericUpdatePosition(AttributeAvQuery::create(), $event);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
|
||||
@@ -12,12 +12,13 @@
|
||||
namespace Thelia\Action;
|
||||
|
||||
use Propel\Runtime\ActiveQuery\ModelCriteria;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Thelia\Core\Event\ToggleVisibilityEvent;
|
||||
use Thelia\Core\Event\UpdatePositionEvent;
|
||||
use Thelia\Core\Event\UpdateSeoEvent;
|
||||
|
||||
use Thelia\Exception\UrlRewritingException;
|
||||
use Thelia\Form\Exception\FormValidationException;
|
||||
use Thelia\Model\ProductCategory;
|
||||
|
||||
class BaseAction
|
||||
{
|
||||
@@ -26,23 +27,56 @@ class BaseAction
|
||||
*
|
||||
* @param ModelCriteria $query
|
||||
* @param UpdatePositionEvent $event
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
protected function genericUpdatePosition(ModelCriteria $query, UpdatePositionEvent $event)
|
||||
protected function genericUpdatePosition(ModelCriteria $query, UpdatePositionEvent $event, EventDispatcherInterface $dispatcher = null)
|
||||
{
|
||||
if (null !== $object = $query->findPk($event->getObjectId())) {
|
||||
if (!isset(class_uses($object)['Thelia\Model\Tools\PositionManagementTrait'])) {
|
||||
throw new \InvalidArgumentException("Your model does not implement the PositionManagementTrait trait");
|
||||
}
|
||||
|
||||
$object->setDispatcher($event->getDispatcher());
|
||||
$object->setDispatcher($dispatcher !== null ? $dispatcher : $event->getDispatcher());
|
||||
|
||||
$mode = $event->getMode();
|
||||
|
||||
if ($mode == UpdatePositionEvent::POSITION_ABSOLUTE)
|
||||
if ($mode == UpdatePositionEvent::POSITION_ABSOLUTE) {
|
||||
$object->changeAbsolutePosition($event->getPosition());
|
||||
else if ($mode == UpdatePositionEvent::POSITION_UP)
|
||||
} elseif ($mode == UpdatePositionEvent::POSITION_UP) {
|
||||
$object->movePositionUp();
|
||||
else if ($mode == UpdatePositionEvent::POSITION_DOWN)
|
||||
} elseif ($mode == UpdatePositionEvent::POSITION_DOWN) {
|
||||
$object->movePositionDown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ModelCriteria $query
|
||||
* @param UpdatePositionEvent $event
|
||||
* @param EventDispatcherInterface|null $dispatcher
|
||||
*
|
||||
* @since 2.3
|
||||
*/
|
||||
protected function genericUpdateDelegatePosition(ModelCriteria $query, UpdatePositionEvent $event, EventDispatcherInterface $dispatcher = null)
|
||||
{
|
||||
if (null !== $object = $query->findOne()) {
|
||||
if (!isset(class_uses($object)['Thelia\Model\Tools\PositionManagementTrait'])) {
|
||||
throw new \InvalidArgumentException("Your model does not implement the PositionManagementTrait trait");
|
||||
}
|
||||
|
||||
//$object->setDispatcher($dispatcher !== null ? $dispatcher : $event->getDispatcher());
|
||||
|
||||
$mode = $event->getMode();
|
||||
|
||||
if ($mode == UpdatePositionEvent::POSITION_ABSOLUTE) {
|
||||
$object->changeAbsolutePosition($event->getPosition());
|
||||
} elseif ($mode == UpdatePositionEvent::POSITION_UP) {
|
||||
$object->movePositionUp();
|
||||
} elseif ($mode == UpdatePositionEvent::POSITION_DOWN) {
|
||||
$object->movePositionDown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,16 +85,17 @@ class BaseAction
|
||||
*
|
||||
* @param ModelCriteria $query
|
||||
* @param UpdateSeoEvent $event
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*
|
||||
* @return mixed an SEOxxx object
|
||||
* @throws FormValidationException if a rewritten URL cannot be created
|
||||
*/
|
||||
protected function genericUpdateSeo(ModelCriteria $query, UpdateSeoEvent $event)
|
||||
protected function genericUpdateSeo(ModelCriteria $query, UpdateSeoEvent $event, EventDispatcherInterface $dispatcher = null)
|
||||
{
|
||||
if (null !== $object = $query->findPk($event->getObjectId())) {
|
||||
|
||||
$object
|
||||
->setDispatcher($event->getDispatcher())
|
||||
//for backward compatibility
|
||||
->setDispatcher($dispatcher !== null ? $dispatcher : $event->getDispatcher())
|
||||
|
||||
->setLocale($event->getLocale())
|
||||
->setMetaTitle($event->getMetaTitle())
|
||||
@@ -77,7 +112,33 @@ class BaseAction
|
||||
throw new FormValidationException($e->getMessage(), $e->getCode());
|
||||
}
|
||||
|
||||
$event->setObject($object);
|
||||
$event->setObject($object);
|
||||
}
|
||||
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle visibility for an object
|
||||
*
|
||||
* @param ModelCriteria $query
|
||||
* @param ToggleVisibilityEvent $event
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function genericToggleVisibility(ModelCriteria $query, ToggleVisibilityEvent $event, EventDispatcherInterface $dispatcher = null)
|
||||
{
|
||||
if (null !== $object = $query->findPk($event->getObjectId())) {
|
||||
$newVisibility = !$object->getVisible();
|
||||
$object
|
||||
//for backward compatibility
|
||||
->setDispatcher($dispatcher !== null ? $dispatcher : $event->getDispatcher())
|
||||
->setVisible($newVisibility)
|
||||
->save()
|
||||
;
|
||||
|
||||
$event->setObject($object);
|
||||
}
|
||||
|
||||
return $object;
|
||||
|
||||
@@ -11,12 +11,16 @@
|
||||
/*************************************************************************************/
|
||||
namespace Thelia\Action;
|
||||
|
||||
use Propel\Runtime\Propel;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Thelia\Core\Event\CachedFileEvent;
|
||||
use Thelia\Core\Event\File\FileCreateOrUpdateEvent;
|
||||
use Thelia\Core\Event\File\FileDeleteEvent;
|
||||
use Thelia\Core\Event\File\FileToggleVisibilityEvent;
|
||||
use Thelia\Core\Event\UpdateFilePositionEvent;
|
||||
use Thelia\Exception\FileException;
|
||||
use Thelia\Files\FileManager;
|
||||
use Thelia\Model\Map\ProductImageTableMap;
|
||||
use Thelia\Tools\URL;
|
||||
|
||||
/**
|
||||
@@ -77,8 +81,9 @@ abstract class BaseCachedFile extends BaseAction
|
||||
|
||||
/** @var \DirectoryIterator $fileinfo */
|
||||
foreach ($iterator as $fileinfo) {
|
||||
|
||||
if ($fileinfo->isDot()) continue;
|
||||
if ($fileinfo->isDot()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($fileinfo->isFile() || $fileinfo->isLink()) {
|
||||
@unlink($fileinfo->getPathname());
|
||||
@@ -91,7 +96,7 @@ abstract class BaseCachedFile extends BaseAction
|
||||
/**
|
||||
* Return the absolute URL to the cached file
|
||||
*
|
||||
* @param string $subdir the subdirectory related to cache base
|
||||
* @param string $subdir the subdirectory related to cache base
|
||||
* @param string $safe_filename the safe filename, as returned by getCacheFilePath()
|
||||
* @return string the absolute URL to the cached file
|
||||
*/
|
||||
@@ -105,10 +110,10 @@ abstract class BaseCachedFile extends BaseAction
|
||||
/**
|
||||
* Return the full path of the cached file
|
||||
*
|
||||
* @param string $subdir the subdirectory related to cache base
|
||||
* @param string $filename the filename
|
||||
* @param string $subdir the subdirectory related to cache base
|
||||
* @param string $filename the filename
|
||||
* @param boolean $forceOriginalFile if true, the original file path in the cache dir is returned.
|
||||
* @param string $hashed_options a hash of transformation options, or null if no transformations have been applied
|
||||
* @param string $hashed_options a hash of transformation options, or null if no transformations have been applied
|
||||
* @return string the cache directory path relative to Web Root
|
||||
*/
|
||||
protected function getCacheFilePath($subdir, $filename, $forceOriginalFile = false, $hashed_options = null)
|
||||
@@ -117,11 +122,12 @@ abstract class BaseCachedFile extends BaseAction
|
||||
|
||||
$safe_filename = preg_replace("[^:alnum:\-\._]", "-", strtolower(basename($filename)));
|
||||
|
||||
// Keep original safe name if no tranformations are applied
|
||||
if ($forceOriginalFile || $hashed_options == null)
|
||||
// Keep original safe name if no tranformations are applied
|
||||
if ($forceOriginalFile || $hashed_options == null) {
|
||||
return sprintf("%s/%s", $path, $safe_filename);
|
||||
else
|
||||
} else {
|
||||
return sprintf("%s/%s-%s", $path, $hashed_options, $safe_filename);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,8 +144,9 @@ abstract class BaseCachedFile extends BaseAction
|
||||
$safe_subdir = basename($subdir);
|
||||
|
||||
$path = sprintf("%s/%s", $cache_dir_from_web_root, $safe_subdir);
|
||||
} else
|
||||
} else {
|
||||
$path = $cache_dir_from_web_root;
|
||||
}
|
||||
|
||||
// Check if path is valid, e.g. in the cache dir
|
||||
return $path;
|
||||
@@ -148,8 +155,8 @@ abstract class BaseCachedFile extends BaseAction
|
||||
/**
|
||||
* Return the absolute cache directory path
|
||||
*
|
||||
* @param string $subdir the subdirectory related to cache base, or null to get the cache base directory.
|
||||
* @param bool $create_if_not_exists create the directory if it is not found
|
||||
* @param string $subdir the subdirectory related to cache base, or null to get the cache base directory.
|
||||
* @param bool $create_if_not_exists create the directory if it is not found
|
||||
*
|
||||
* @throws \RuntimeException if cache directory cannot be created
|
||||
* @throws \InvalidArgumentException ii path is invalid, e.g. not in the cache dir
|
||||
@@ -167,7 +174,7 @@ abstract class BaseCachedFile extends BaseAction
|
||||
// Create directory (recursively) if it does not exists.
|
||||
if ($create_if_not_exists && !is_dir($path)) {
|
||||
if (!@mkdir($path, 0777, true)) {
|
||||
throw new \RuntimeException(sprintf("Failed to create %s file in cache directory", $path));
|
||||
throw new \RuntimeException(sprintf("Failed to create %s file in cache directory", $path));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,30 +193,40 @@ abstract class BaseCachedFile extends BaseAction
|
||||
*
|
||||
* @param FileCreateOrUpdateEvent $event Image event
|
||||
*
|
||||
* @throws \Thelia\Exception\FileException
|
||||
* @throws \Thelia\Exception\FileException|\Exception
|
||||
*
|
||||
*/
|
||||
public function saveFile(FileCreateOrUpdateEvent $event)
|
||||
{
|
||||
$model = $event->getModel();
|
||||
$model->setFile(sprintf("tmp/%s", $event->getUploadedFile()->getFilename()));
|
||||
$con = Propel::getWriteConnection(ProductImageTableMap::DATABASE_NAME);
|
||||
$con->beginTransaction();
|
||||
|
||||
$nbModifiedLines = $model->save();
|
||||
$event->setModel($model);
|
||||
try {
|
||||
$nbModifiedLines = $model->save($con);
|
||||
$event->setModel($model);
|
||||
|
||||
if (!$nbModifiedLines) {
|
||||
throw new FileException(
|
||||
sprintf(
|
||||
'File "%s" (type %s) with parent id %s failed to be saved',
|
||||
$event->getParentName(),
|
||||
get_class($model),
|
||||
$event->getParentId()
|
||||
)
|
||||
);
|
||||
if (!$nbModifiedLines) {
|
||||
throw new FileException(
|
||||
sprintf(
|
||||
'File "%s" (type %s) with parent id %s failed to be saved',
|
||||
$event->getParentName(),
|
||||
get_class($model),
|
||||
$event->getParentId()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$newUploadedFile = $this->fileManager->copyUploadedFile($event->getModel(), $event->getUploadedFile());
|
||||
|
||||
$event->setUploadedFile($newUploadedFile);
|
||||
$con->commit();
|
||||
} catch (\Exception $e) {
|
||||
$con->rollBack();
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$newUploadedFile = $this->fileManager->copyUploadedFile($event->getModel(), $event->getUploadedFile());
|
||||
|
||||
$event->setUploadedFile($newUploadedFile);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -247,9 +264,13 @@ abstract class BaseCachedFile extends BaseAction
|
||||
$this->fileManager->deleteFile($event->getFileToDelete());
|
||||
}
|
||||
|
||||
public function updatePosition(UpdateFilePositionEvent $event)
|
||||
public function updatePosition(UpdateFilePositionEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$this->genericUpdatePosition($event->getQuery(), $event);
|
||||
$this->genericUpdatePosition($event->getQuery(), $event, $dispatcher);
|
||||
}
|
||||
|
||||
public function toggleVisibility(FileToggleVisibilityEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$this->genericToggleVisibility($event->getQuery(), $event, $dispatcher);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,9 @@
|
||||
|
||||
namespace Thelia\Action;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Thelia\Core\Event\Brand\BrandCreateEvent;
|
||||
use Thelia\Core\Event\Brand\BrandDeleteEvent;
|
||||
use Thelia\Core\Event\Brand\BrandToggleVisibilityEvent;
|
||||
@@ -20,6 +22,7 @@ use Thelia\Core\Event\Brand\BrandUpdateEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\Event\UpdatePositionEvent;
|
||||
use Thelia\Core\Event\UpdateSeoEvent;
|
||||
use Thelia\Core\Event\ViewCheckEvent;
|
||||
use Thelia\Model\Brand as BrandModel;
|
||||
use Thelia\Model\BrandQuery;
|
||||
|
||||
@@ -31,7 +34,6 @@ use Thelia\Model\BrandQuery;
|
||||
*/
|
||||
class Brand extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
|
||||
public function create(BrandCreateEvent $event)
|
||||
{
|
||||
$brand = new BrandModel();
|
||||
@@ -50,11 +52,13 @@ class Brand extends BaseAction implements EventSubscriberInterface
|
||||
* process update brand
|
||||
*
|
||||
* @param BrandUpdateEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function update(BrandUpdateEvent $event)
|
||||
public function update(BrandUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $brand = BrandQuery::create()->findPk($event->getBrandId())) {
|
||||
$brand->setDispatcher($event->getDispatcher());
|
||||
$brand->setDispatcher($dispatcher);
|
||||
|
||||
$brand
|
||||
->setVisible($event->getVisible())
|
||||
@@ -75,13 +79,17 @@ class Brand extends BaseAction implements EventSubscriberInterface
|
||||
* Toggle Brand visibility
|
||||
*
|
||||
* @param BrandToggleVisibilityEvent $event
|
||||
* @param string $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
* @throws \Exception
|
||||
* @throws \Propel\Runtime\Exception\PropelException
|
||||
*/
|
||||
public function toggleVisibility(BrandToggleVisibilityEvent $event)
|
||||
public function toggleVisibility(BrandToggleVisibilityEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$brand = $event->getBrand();
|
||||
|
||||
$brand
|
||||
->setDispatcher($event->getDispatcher())
|
||||
->setDispatcher($dispatcher)
|
||||
->setVisible(!$brand->getVisible())
|
||||
->save();
|
||||
|
||||
@@ -91,31 +99,62 @@ class Brand extends BaseAction implements EventSubscriberInterface
|
||||
/**
|
||||
* Change Brand SEO
|
||||
*
|
||||
* @param \Thelia\Core\Event\UpdateSeoEvent $event
|
||||
*
|
||||
* @return mixed
|
||||
* @param UpdateSeoEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
* @return Object
|
||||
*/
|
||||
public function updateSeo(UpdateSeoEvent $event)
|
||||
public function updateSeo(UpdateSeoEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
return $this->genericUpdateSeo(BrandQuery::create(), $event);
|
||||
return $this->genericUpdateSeo(BrandQuery::create(), $event, $dispatcher);
|
||||
}
|
||||
|
||||
public function delete(BrandDeleteEvent $event)
|
||||
public function delete(BrandDeleteEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $brand = BrandQuery::create()->findPk($event->getBrandId())) {
|
||||
|
||||
$brand->setDispatcher($event->getDispatcher())->delete();
|
||||
$brand->setDispatcher($dispatcher)->delete();
|
||||
|
||||
$event->setBrand($brand);
|
||||
}
|
||||
}
|
||||
|
||||
public function updatePosition(UpdatePositionEvent $event)
|
||||
public function updatePosition(UpdatePositionEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$this->genericUpdatePosition(BrandQuery::create(), $event);
|
||||
$this->genericUpdatePosition(BrandQuery::create(), $event, $dispatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
* Check if is a brand view and if brand_id is visible
|
||||
*
|
||||
* @param ViewCheckEvent $event
|
||||
* @param string $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function viewCheck(ViewCheckEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if ($event->getView() == 'brand') {
|
||||
$brand = BrandQuery::create()
|
||||
->filterById($event->getViewId())
|
||||
->filterByVisible(1)
|
||||
->count();
|
||||
|
||||
if ($brand == 0) {
|
||||
$dispatcher->dispatch(TheliaEvents::VIEW_BRAND_ID_NOT_VISIBLE, $event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ViewCheckEvent $event
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public function viewBrandIdNotVisible(ViewCheckEvent $event)
|
||||
{
|
||||
throw new NotFoundHttpException();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
@@ -128,6 +167,9 @@ class Brand extends BaseAction implements EventSubscriberInterface
|
||||
|
||||
TheliaEvents::BRAND_UPDATE_POSITION => array('updatePosition', 128),
|
||||
TheliaEvents::BRAND_TOGGLE_VISIBILITY => array('toggleVisibility', 128),
|
||||
|
||||
TheliaEvents::VIEW_CHECK => array('viewCheck', 128),
|
||||
TheliaEvents::VIEW_BRAND_ID_NOT_VISIBLE => array('viewBrandIdNotVisible', 128),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Thelia\Action;
|
||||
|
||||
use Symfony\Component\Cache\Adapter\AdapterInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
use Thelia\Core\Event\Cache\CacheEvent;
|
||||
@@ -19,39 +21,35 @@ use Thelia\Core\Event\TheliaEvents;
|
||||
/**
|
||||
* Class Cache
|
||||
* @package Thelia\Action
|
||||
* @author Manuel Raynaud <mraynaud@openstudio.fr>
|
||||
* @author Manuel Raynaud <manu@raynaud.io>
|
||||
*/
|
||||
class Cache extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
/** @var AdapterInterface */
|
||||
protected $adapter;
|
||||
|
||||
/**
|
||||
* CacheListener constructor.
|
||||
* @param AdapterInterface $adapter
|
||||
*/
|
||||
public function __construct(AdapterInterface $adapter)
|
||||
{
|
||||
$this->adapter = $adapter;
|
||||
}
|
||||
|
||||
public function cacheClear(CacheEvent $event)
|
||||
{
|
||||
// clear cache on thelia.cache service
|
||||
$this->adapter->clear();
|
||||
|
||||
$dir = $event->getDir();
|
||||
|
||||
$fs = new Filesystem();
|
||||
$fs->remove($dir);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of event names this subscriber wants to listen to.
|
||||
*
|
||||
* The array keys are event names and the value can be:
|
||||
*
|
||||
* * The method name to call (priority defaults to 0)
|
||||
* * An array composed of the method name to call and the priority
|
||||
* * An array of arrays composed of the method names to call and respective
|
||||
* priorities, or 0 if unset
|
||||
*
|
||||
* For instance:
|
||||
*
|
||||
* * array('eventName' => 'methodName')
|
||||
* * array('eventName' => array('methodName', $priority))
|
||||
* * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
|
||||
*
|
||||
* @return array The event names to listen to
|
||||
*
|
||||
* @api
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
|
||||
@@ -14,15 +14,27 @@ namespace Thelia\Action;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Thelia\Core\Event\Cart\CartCreateEvent;
|
||||
use Thelia\Core\Event\Cart\CartDuplicationEvent;
|
||||
use Thelia\Core\Event\Cart\CartPersistEvent;
|
||||
use Thelia\Core\Event\Cart\CartRestoreEvent;
|
||||
use Thelia\Core\Event\Cart\CartEvent;
|
||||
use Thelia\Core\Event\Currency\CurrencyChangeEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Exception\TheliaProcessException;
|
||||
use Thelia\Model\Base\CustomerQuery;
|
||||
use Thelia\Model\Base\ProductSaleElementsQuery;
|
||||
use Thelia\Model\Currency as CurrencyModel;
|
||||
use Thelia\Model\CartItem;
|
||||
use Thelia\Model\Cart as CartModel;
|
||||
use Thelia\Model\CartItemQuery;
|
||||
use Thelia\Model\CartQuery;
|
||||
use Thelia\Model\ConfigQuery;
|
||||
use Thelia\Model\Currency;
|
||||
use Thelia\Model\ProductSaleElementsQuery;
|
||||
use Thelia\Model\Customer as CustomerModel;
|
||||
use Thelia\Model\ProductSaleElements;
|
||||
use Thelia\Model\Tools\ProductPriceTools;
|
||||
use Thelia\Tools\TokenProvider;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -30,19 +42,44 @@ use Thelia\Model\Tools\ProductPriceTools;
|
||||
*
|
||||
* Class Cart
|
||||
* @package Thelia\Action
|
||||
* @author Manuel Raynaud <mraynaud@openstudio.fr>
|
||||
* @author Manuel Raynaud <manu@raynaud.io>
|
||||
*/
|
||||
class Cart extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
/** @var RequestStack */
|
||||
protected $requestStack;
|
||||
|
||||
/** @var TokenProvider */
|
||||
protected $tokenProvider;
|
||||
|
||||
public function __construct(RequestStack $requestStack, TokenProvider $tokenProvider)
|
||||
{
|
||||
$this->requestStack = $requestStack;
|
||||
|
||||
$this->tokenProvider = $tokenProvider;
|
||||
}
|
||||
|
||||
public function persistCart(CartPersistEvent $event)
|
||||
{
|
||||
$cart = $event->getCart();
|
||||
|
||||
if ($cart->isNew()) {
|
||||
$cart
|
||||
->setToken($this->generateCartCookieIdentifier())
|
||||
->save();
|
||||
$this->getSession()->setSessionCart($cart);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* add an article in the current cart
|
||||
*
|
||||
* @param \Thelia\Core\Event\Cart\CartEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function addItem(CartEvent $event)
|
||||
public function addItem(CartEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
|
||||
$cart = $event->getCart();
|
||||
$newness = $event->getNewness();
|
||||
$append = $event->getAppend();
|
||||
@@ -51,6 +88,11 @@ class Cart extends BaseAction implements EventSubscriberInterface
|
||||
$customer = $cart->getCustomer();
|
||||
$discount = 0;
|
||||
|
||||
if ($cart->isNew()) {
|
||||
$persistEvent = new CartPersistEvent($cart);
|
||||
$dispatcher->dispatch(TheliaEvents::CART_PERSIST, $persistEvent);
|
||||
}
|
||||
|
||||
if (null !== $customer && $customer->getDiscount() > 0) {
|
||||
$discount = $customer->getDiscount();
|
||||
}
|
||||
@@ -58,29 +100,29 @@ class Cart extends BaseAction implements EventSubscriberInterface
|
||||
$productSaleElementsId = $event->getProductSaleElementsId();
|
||||
$productId = $event->getProduct();
|
||||
|
||||
$cartItem = $this->findItem($cart->getId(), $productId, $productSaleElementsId);
|
||||
// Search for an identical item in the cart
|
||||
$findItemEvent = clone $event;
|
||||
|
||||
$dispatcher->dispatch(TheliaEvents::CART_FINDITEM, $findItemEvent);
|
||||
|
||||
$cartItem = $findItemEvent->getCartItem();
|
||||
|
||||
if ($cartItem === null || $newness) {
|
||||
|
||||
$productSaleElements = ProductSaleElementsQuery::create()
|
||||
->findPk($productSaleElementsId);
|
||||
$productSaleElements = ProductSaleElementsQuery::create()->findPk($productSaleElementsId);
|
||||
|
||||
if (null !== $productSaleElements) {
|
||||
$productPrices = $productSaleElements->getPricesByCurrency($currency, $discount);
|
||||
$event->setCartItem(
|
||||
$this->doAddItem($event->getDispatcher(), $cart, $productId, $productSaleElements, $quantity, $productPrices)
|
||||
);
|
||||
|
||||
$cartItem = $this->doAddItem($dispatcher, $cart, $productId, $productSaleElements, $quantity, $productPrices);
|
||||
} else {
|
||||
// We did no find any PSE... Something is wrong with the DB, just throw an exception.
|
||||
throw new TheliaProcessException("This item cannot be added to the cart: no matching product sale element was found.");
|
||||
}
|
||||
} elseif ($append && $cartItem !== null) {
|
||||
$cartItem->addQuantity($quantity)->save();
|
||||
}
|
||||
|
||||
if ($append && $cartItem !== null) {
|
||||
$cartItem->addQuantity($quantity)
|
||||
->save();
|
||||
|
||||
$event->setCartItem(
|
||||
$cartItem
|
||||
);
|
||||
}
|
||||
$event->setCartItem($cartItem);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -91,13 +133,16 @@ class Cart extends BaseAction implements EventSubscriberInterface
|
||||
*/
|
||||
public function deleteItem(CartEvent $event)
|
||||
{
|
||||
if (null !== $cartItemId = $event->getCartItem()) {
|
||||
if (null !== $cartItemId = $event->getCartItemId()) {
|
||||
$cart = $event->getCart();
|
||||
CartItemQuery::create()
|
||||
->filterByCartId($cart->getId())
|
||||
->filterById($cartItemId)
|
||||
->delete();
|
||||
|
||||
// Force an update of the Cart object to provide
|
||||
// to other listeners an updated CartItem collection.
|
||||
$cart->clearCartItems();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,10 +164,12 @@ class Cart extends BaseAction implements EventSubscriberInterface
|
||||
* don't use Form here just test the Request.
|
||||
*
|
||||
* @param \Thelia\Core\Event\Cart\CartEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function changeItem(CartEvent $event)
|
||||
public function changeItem(CartEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if ((null !== $cartItemId = $event->getCartItem()) && (null !== $quantity = $event->getQuantity())) {
|
||||
if ((null !== $cartItemId = $event->getCartItemId()) && (null !== $quantity = $event->getQuantity())) {
|
||||
$cart = $event->getCart();
|
||||
|
||||
$cartItem = CartItemQuery::create()
|
||||
@@ -132,16 +179,16 @@ class Cart extends BaseAction implements EventSubscriberInterface
|
||||
|
||||
if ($cartItem) {
|
||||
$event->setCartItem(
|
||||
$this->updateQuantity($event->getDispatcher(), $cartItem, $quantity)
|
||||
$this->updateQuantity($dispatcher, $cartItem, $quantity)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function updateCart(CurrencyChangeEvent $event)
|
||||
public function updateCart(CurrencyChangeEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$session = $event->getRequest()->getSession();
|
||||
$cart = $session->getCart();
|
||||
$cart = $event->getRequest()->getSession()->getSessionCart($dispatcher);
|
||||
|
||||
if (null !== $cart) {
|
||||
$this->updateCartPrices($cart, $event->getCurrency());
|
||||
}
|
||||
@@ -154,9 +201,8 @@ class Cart extends BaseAction implements EventSubscriberInterface
|
||||
* @param \Thelia\Model\Cart $cart
|
||||
* @param \Thelia\Model\Currency $currency
|
||||
*/
|
||||
public function updateCartPrices(\Thelia\Model\Cart $cart, Currency $currency)
|
||||
public function updateCartPrices(CartModel $cart, CurrencyModel $currency)
|
||||
{
|
||||
|
||||
$customer = $cart->getCustomer();
|
||||
$discount = 0;
|
||||
|
||||
@@ -180,47 +226,17 @@ class Cart extends BaseAction implements EventSubscriberInterface
|
||||
// update the currency cart
|
||||
$cart->setCurrencyId($currency->getId());
|
||||
$cart->save();
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns an array of event names this subscriber wants to listen to.
|
||||
*
|
||||
* The array keys are event names and the value can be:
|
||||
*
|
||||
* * The method name to call (priority defaults to 0)
|
||||
* * An array composed of the method name to call and the priority
|
||||
* * An array of arrays composed of the method names to call and respective
|
||||
* priorities, or 0 if unset
|
||||
*
|
||||
* For instance:
|
||||
*
|
||||
* * array('eventName' => 'methodName')
|
||||
* * array('eventName' => array('methodName', $priority))
|
||||
* * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
|
||||
*
|
||||
* @return array The event names to listen to
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::CART_ADDITEM => array("addItem", 128),
|
||||
TheliaEvents::CART_DELETEITEM => array("deleteItem", 128),
|
||||
TheliaEvents::CART_UPDATEITEM => array("changeItem", 128),
|
||||
TheliaEvents::CART_CLEAR => array("clear", 128),
|
||||
TheliaEvents::CHANGE_DEFAULT_CURRENCY => array("updateCart", 128),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* increase the quantity for an existing cartItem
|
||||
*
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
* @param CartItem $cartItem
|
||||
* @param float $quantity
|
||||
* @param float $quantity
|
||||
*
|
||||
* @throws \Exception
|
||||
* @throws \Propel\Runtime\Exception\PropelException
|
||||
* @return CartItem
|
||||
*/
|
||||
protected function updateQuantity(EventDispatcherInterface $dispatcher, CartItem $cartItem, $quantity)
|
||||
@@ -235,17 +251,23 @@ class Cart extends BaseAction implements EventSubscriberInterface
|
||||
/**
|
||||
* try to attach a new item to an existing cart
|
||||
*
|
||||
* @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $dispatcher
|
||||
* @param \Thelia\Model\Cart $cart
|
||||
* @param int $productId
|
||||
* @param \Thelia\Model\ProductSaleElements $productSaleElements
|
||||
* @param float $quantity
|
||||
* @param ProductPriceTools $productPrices
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
* @param \Thelia\Model\Cart $cart
|
||||
* @param int $productId
|
||||
* @param ProductSaleElements $productSaleElements
|
||||
* @param float $quantity
|
||||
* @param ProductPriceTools $productPrices
|
||||
*
|
||||
* @return CartItem
|
||||
*/
|
||||
protected function doAddItem(EventDispatcherInterface $dispatcher, \Thelia\Model\Cart $cart, $productId, \Thelia\Model\ProductSaleElements $productSaleElements, $quantity, ProductPriceTools $productPrices)
|
||||
{
|
||||
protected function doAddItem(
|
||||
EventDispatcherInterface $dispatcher,
|
||||
CartModel $cart,
|
||||
$productId,
|
||||
ProductSaleElements $productSaleElements,
|
||||
$quantity,
|
||||
ProductPriceTools $productPrices
|
||||
) {
|
||||
$cartItem = new CartItem();
|
||||
$cartItem->setDisptacher($dispatcher);
|
||||
$cartItem
|
||||
@@ -269,7 +291,9 @@ class Cart extends BaseAction implements EventSubscriberInterface
|
||||
* @param int $cartId
|
||||
* @param int $productId
|
||||
* @param int $productSaleElementsId
|
||||
* @return ChildCartItem
|
||||
* @return CartItem
|
||||
*
|
||||
* @deprecated this method is deprecated. Dispatch a TheliaEvents::CART_FINDITEM instead
|
||||
*/
|
||||
protected function findItem($cartId, $productId, $productSaleElementsId)
|
||||
{
|
||||
@@ -280,4 +304,247 @@ class Cart extends BaseAction implements EventSubscriberInterface
|
||||
->findOne();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a specific record in CartItem table using the current CartEvent
|
||||
*
|
||||
* @param CartEvent $event the cart event
|
||||
*/
|
||||
public function findCartItem(CartEvent $event)
|
||||
{
|
||||
// Do not try to find a cartItem if one exists in the event, as previous event handlers
|
||||
// mays have put it in th event.
|
||||
if (null === $event->getCartItem() && null !== $foundItem = CartItemQuery::create()
|
||||
->filterByCartId($event->getCart()->getId())
|
||||
->filterByProductId($event->getProduct())
|
||||
->filterByProductSaleElementsId($event->getProductSaleElementsId())
|
||||
->findOne()) {
|
||||
$event->setCartItem($foundItem);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Search if cart already exists in session. If not try to restore it from the cart cookie,
|
||||
* or duplicate an old one.
|
||||
*
|
||||
* @param CartRestoreEvent $cartRestoreEvent
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function restoreCurrentCart(CartRestoreEvent $cartRestoreEvent, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$cookieName = ConfigQuery::read("cart.cookie_name", 'thelia_cart');
|
||||
$persistentCookie = ConfigQuery::read("cart.use_persistent_cookie", 1);
|
||||
|
||||
$cart = null;
|
||||
|
||||
if ($this->requestStack->getCurrentRequest()->cookies->has($cookieName) && $persistentCookie) {
|
||||
$cart = $this->managePersistentCart($cartRestoreEvent, $cookieName, $dispatcher);
|
||||
} elseif (!$persistentCookie) {
|
||||
$cart = $this->manageNonPersistentCookie($cartRestoreEvent, $dispatcher);
|
||||
}
|
||||
|
||||
// Still no cart ? Create a new one.
|
||||
if (null === $cart) {
|
||||
$cart = $this->dispatchNewCart($dispatcher);
|
||||
}
|
||||
|
||||
$cartRestoreEvent->setCart($cart);
|
||||
}
|
||||
|
||||
/**
|
||||
* The cart token is not saved in a cookie, if the cart is present in session, we just change the customer id
|
||||
* if needed or create duplicate the current cart if the customer is not the same as customer already present in
|
||||
* the cart.
|
||||
*
|
||||
* @param CartRestoreEvent $cartRestoreEvent
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
* @return CartModel
|
||||
* @throws \Exception
|
||||
* @throws \Propel\Runtime\Exception\PropelException
|
||||
*/
|
||||
protected function manageNonPersistentCookie(CartRestoreEvent $cartRestoreEvent, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$cart = $cartRestoreEvent->getCart();
|
||||
|
||||
if (null === $cart) {
|
||||
$cart = $this->dispatchNewCart($dispatcher);
|
||||
} else {
|
||||
$cart = $this->manageCartDuplicationAtCustomerLogin($cart, $dispatcher);
|
||||
}
|
||||
|
||||
return $cart;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* The cart token is saved in a cookie so we try to retrieve it. Then the customer is checked.
|
||||
*
|
||||
* @param CartRestoreEvent $cartRestoreEvent
|
||||
* @param $cookieName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
* @return CartModel
|
||||
* @throws \Exception
|
||||
* @throws \Propel\Runtime\Exception\PropelException
|
||||
*/
|
||||
protected function managePersistentCart(CartRestoreEvent $cartRestoreEvent, $cookieName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
// The cart cookie exists -> get the cart token
|
||||
$token = $this->requestStack->getCurrentRequest()->cookies->get($cookieName);
|
||||
|
||||
// Check if a cart exists for this token
|
||||
if (null !== $cart = CartQuery::create()->findOneByToken($token)) {
|
||||
$cart = $this->manageCartDuplicationAtCustomerLogin($cart, $dispatcher);
|
||||
}
|
||||
|
||||
return $cart;
|
||||
}
|
||||
|
||||
protected function manageCartDuplicationAtCustomerLogin(CartModel $cart, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
/** @var CustomerModel $customer */
|
||||
if (null !== $customer = $this->getSession()->getCustomerUser()) {
|
||||
// Check if we have to duplicate the existing cart.
|
||||
|
||||
$duplicateCart = true;
|
||||
|
||||
// A customer is logged in.
|
||||
if (null === $cart->getCustomerId()) {
|
||||
// If the customer has a discount, whe have to duplicate the cart,
|
||||
// so that the discount will be applied to the products in cart.
|
||||
|
||||
if (0 === $customer->getDiscount() || 0 === $cart->countCartItems()) {
|
||||
// If no discount, or an empty cart, there's no need to duplicate.
|
||||
$duplicateCart = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($duplicateCart) {
|
||||
// Duplicate the cart
|
||||
$cart = $this->duplicateCart($dispatcher, $cart, $customer);
|
||||
} else {
|
||||
// No duplication required, just assign the cart to the customer
|
||||
$cart->setCustomerId($customer->getId())->save();
|
||||
}
|
||||
} elseif ($cart->getCustomerId() != null) {
|
||||
// The cart belongs to another user
|
||||
if (0 === $cart->countCartItems()) {
|
||||
// No items in cart, assign it to nobody.
|
||||
$cart->setCustomerId(null)->save();
|
||||
} else {
|
||||
// Some itemls in cart, duplicate it without assigning a customer ID.
|
||||
$cart = $this->duplicateCart($dispatcher, $cart);
|
||||
}
|
||||
}
|
||||
|
||||
return $cart;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
* @return CartModel
|
||||
*/
|
||||
protected function dispatchNewCart(EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$cartCreateEvent = new CartCreateEvent();
|
||||
|
||||
$dispatcher->dispatch(TheliaEvents::CART_CREATE_NEW, $cartCreateEvent);
|
||||
|
||||
return $cartCreateEvent->getCart();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new, empty cart object, and assign it to the current customer, if any.
|
||||
*
|
||||
* @param CartCreateEvent $cartCreateEvent
|
||||
*/
|
||||
public function createEmptyCart(CartCreateEvent $cartCreateEvent)
|
||||
{
|
||||
$cart = new CartModel();
|
||||
|
||||
$cart->setCurrency($this->getSession()->getCurrency(true));
|
||||
|
||||
/** @var CustomerModel $customer */
|
||||
if (null !== $customer = $this->getSession()->getCustomerUser()) {
|
||||
$cart->setCustomer(CustomerQuery::create()->findPk($customer->getId()));
|
||||
}
|
||||
|
||||
$this->getSession()->setSessionCart($cart);
|
||||
|
||||
if (ConfigQuery::read("cart.use_persistent_cookie", 1) == 1) {
|
||||
// set cart_use_cookie to "" to remove the cart cookie
|
||||
// see Thelia\Core\EventListener\ResponseListener
|
||||
$this->getSession()->set("cart_use_cookie", "");
|
||||
}
|
||||
|
||||
$cartCreateEvent->setCart($cart);
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicate an existing Cart. If a customer ID is provided the created cart will be attached to this customer.
|
||||
*
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
* @param CartModel $cart
|
||||
* @param CustomerModel $customer
|
||||
* @return CartModel
|
||||
*/
|
||||
protected function duplicateCart(EventDispatcherInterface $dispatcher, CartModel $cart, CustomerModel $customer = null)
|
||||
{
|
||||
$newCart = $cart->duplicate(
|
||||
$this->generateCartCookieIdentifier(),
|
||||
$customer,
|
||||
$this->getSession()->getCurrency(),
|
||||
$dispatcher
|
||||
);
|
||||
|
||||
$cartEvent = new CartDuplicationEvent($newCart, $cart);
|
||||
$dispatcher->dispatch(TheliaEvents::CART_DUPLICATE, $cartEvent);
|
||||
|
||||
return $cartEvent->getDuplicatedCart();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the cart cookie identifier, or return null if the cart is only managed in the session object,
|
||||
* not in a client cookie.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function generateCartCookieIdentifier()
|
||||
{
|
||||
$id = null;
|
||||
|
||||
if (ConfigQuery::read("cart.use_persistent_cookie", 1) == 1) {
|
||||
$id = $this->tokenProvider->getToken();
|
||||
$this->getSession()->set('cart_use_cookie', $id);
|
||||
}
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::CART_PERSIST => array("persistCart", 128),
|
||||
TheliaEvents::CART_RESTORE_CURRENT => array("restoreCurrentCart", 128),
|
||||
TheliaEvents::CART_CREATE_NEW => array("createEmptyCart", 128),
|
||||
TheliaEvents::CART_ADDITEM => array("addItem", 128),
|
||||
TheliaEvents::CART_FINDITEM => array("findCartItem", 128),
|
||||
TheliaEvents::CART_DELETEITEM => array("deleteItem", 128),
|
||||
TheliaEvents::CART_UPDATEITEM => array("changeItem", 128),
|
||||
TheliaEvents::CART_CLEAR => array("clear", 128),
|
||||
TheliaEvents::CHANGE_DEFAULT_CURRENCY => array("updateCart", 128),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the session from the current request
|
||||
*
|
||||
* @return \Thelia\Core\HttpFoundation\Session\Session
|
||||
*/
|
||||
protected function getSession()
|
||||
{
|
||||
return $this->requestStack->getCurrentRequest()->getSession();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,14 +12,17 @@
|
||||
|
||||
namespace Thelia\Action;
|
||||
|
||||
use Propel\Runtime\Propel;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Thelia\Core\Event\File\FileDeleteEvent;
|
||||
use Thelia\Core\Event\UpdateSeoEvent;
|
||||
use Thelia\Model\CategoryDocumentQuery;
|
||||
use Thelia\Model\CategoryImageQuery;
|
||||
use Thelia\Model\CategoryQuery;
|
||||
use Thelia\Model\Category as CategoryModel;
|
||||
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
|
||||
use Thelia\Core\Event\Category\CategoryUpdateEvent;
|
||||
use Thelia\Core\Event\Category\CategoryCreateEvent;
|
||||
use Thelia\Core\Event\Category\CategoryDeleteEvent;
|
||||
@@ -27,8 +30,10 @@ use Thelia\Core\Event\UpdatePositionEvent;
|
||||
use Thelia\Core\Event\Category\CategoryToggleVisibilityEvent;
|
||||
use Thelia\Core\Event\Category\CategoryAddContentEvent;
|
||||
use Thelia\Core\Event\Category\CategoryDeleteContentEvent;
|
||||
use Thelia\Core\Event\ViewCheckEvent;
|
||||
use Thelia\Model\CategoryAssociatedContent;
|
||||
use Thelia\Model\CategoryAssociatedContentQuery;
|
||||
use Thelia\Model\Map\CategoryTableMap;
|
||||
|
||||
class Category extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
@@ -36,13 +41,15 @@ class Category extends BaseAction implements EventSubscriberInterface
|
||||
* Create a new category entry
|
||||
*
|
||||
* @param \Thelia\Core\Event\Category\CategoryCreateEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function create(CategoryCreateEvent $event)
|
||||
public function create(CategoryCreateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$category = new CategoryModel();
|
||||
|
||||
$category
|
||||
->setDispatcher($event->getDispatcher())
|
||||
->setDispatcher($dispatcher)
|
||||
|
||||
->setLocale($event->getLocale())
|
||||
->setParent($event->getParent())
|
||||
@@ -59,14 +66,15 @@ class Category extends BaseAction implements EventSubscriberInterface
|
||||
* Change a category
|
||||
*
|
||||
* @param \Thelia\Core\Event\Category\CategoryUpdateEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function update(CategoryUpdateEvent $event)
|
||||
public function update(CategoryUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $category = CategoryQuery::create()->findPk($event->getCategoryId())) {
|
||||
|
||||
$category
|
||||
->setDispatcher($event->getDispatcher())
|
||||
|
||||
->setDispatcher($dispatcher)
|
||||
->setDefaultTemplateId($event->getDefaultTemplateId() == 0 ? null : $event->getDefaultTemplateId())
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
->setDescription($event->getDescription())
|
||||
@@ -85,44 +93,78 @@ class Category extends BaseAction implements EventSubscriberInterface
|
||||
/**
|
||||
* Change a Category SEO
|
||||
*
|
||||
* @param \Thelia\Core\Event\UpdateSeoEvent $event
|
||||
*
|
||||
* @return mixed
|
||||
* @param UpdateSeoEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
* @return Object
|
||||
*/
|
||||
public function updateSeo(UpdateSeoEvent $event)
|
||||
public function updateSeo(UpdateSeoEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
return $this->genericUpdateSeo(CategoryQuery::create(), $event);
|
||||
return $this->genericUpdateSeo(CategoryQuery::create(), $event, $dispatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a category entry
|
||||
*
|
||||
* @param \Thelia\Core\Event\Category\CategoryDeleteEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function delete(CategoryDeleteEvent $event)
|
||||
public function delete(CategoryDeleteEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $category = CategoryQuery::create()->findPk($event->getCategoryId())) {
|
||||
$con = Propel::getWriteConnection(CategoryTableMap::DATABASE_NAME);
|
||||
$con->beginTransaction();
|
||||
|
||||
$category
|
||||
->setDispatcher($event->getDispatcher())
|
||||
->delete()
|
||||
;
|
||||
try {
|
||||
$fileList = ['images' => [], 'documentList' => []];
|
||||
|
||||
$event->setCategory($category);
|
||||
// Get category's files to delete after category deletion
|
||||
$fileList['images']['list'] = CategoryImageQuery::create()
|
||||
->findByCategoryId($event->getCategoryId());
|
||||
$fileList['images']['type'] = TheliaEvents::IMAGE_DELETE;
|
||||
|
||||
$fileList['documentList']['list'] = CategoryDocumentQuery::create()
|
||||
->findByCategoryId($event->getCategoryId());
|
||||
$fileList['documentList']['type'] = TheliaEvents::DOCUMENT_DELETE;
|
||||
|
||||
// Delete category
|
||||
$category
|
||||
->setDispatcher($dispatcher)
|
||||
->delete($con);
|
||||
|
||||
$event->setCategory($category);
|
||||
|
||||
// Dispatch delete category's files event
|
||||
foreach ($fileList as $fileTypeList) {
|
||||
foreach ($fileTypeList['list'] as $fileToDelete) {
|
||||
$fileDeleteEvent = new FileDeleteEvent($fileToDelete);
|
||||
$dispatcher->dispatch($fileTypeList['type'], $fileDeleteEvent);
|
||||
}
|
||||
}
|
||||
|
||||
$con->commit();
|
||||
} catch (\Exception $e) {
|
||||
$con->rollback();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle category visibility. No form used here
|
||||
*
|
||||
* @param ActionEvent $event
|
||||
* @param CategoryToggleVisibilityEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function toggleVisibility(CategoryToggleVisibilityEvent $event)
|
||||
public function toggleVisibility(CategoryToggleVisibilityEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$category = $event->getCategory();
|
||||
$category = $event->getCategory();
|
||||
|
||||
$category
|
||||
->setDispatcher($event->getDispatcher())
|
||||
$category
|
||||
->setDispatcher($dispatcher)
|
||||
->setVisible($category->getVisible() ? false : true)
|
||||
->save()
|
||||
;
|
||||
@@ -133,31 +175,32 @@ class Category extends BaseAction implements EventSubscriberInterface
|
||||
/**
|
||||
* Changes position, selecting absolute ou relative change.
|
||||
*
|
||||
* @param CategoryChangePositionEvent $event
|
||||
* @param UpdatePositionEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function updatePosition(UpdatePositionEvent $event)
|
||||
public function updatePosition(UpdatePositionEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$this->genericUpdatePosition(CategoryQuery::create(), $event);
|
||||
$this->genericUpdatePosition(CategoryQuery::create(), $event, $dispatcher);
|
||||
}
|
||||
|
||||
public function addContent(CategoryAddContentEvent $event)
|
||||
public function addContent(CategoryAddContentEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (CategoryAssociatedContentQuery::create()
|
||||
->filterByContentId($event->getContentId())
|
||||
->filterByCategory($event->getCategory())->count() <= 0) {
|
||||
|
||||
$content = new CategoryAssociatedContent();
|
||||
|
||||
$content
|
||||
->setDispatcher($event->getDispatcher())
|
||||
->setDispatcher($dispatcher)
|
||||
->setCategory($event->getCategory())
|
||||
->setContentId($event->getContentId())
|
||||
->save()
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function removeContent(CategoryDeleteContentEvent $event)
|
||||
public function removeContent(CategoryDeleteContentEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$content = CategoryAssociatedContentQuery::create()
|
||||
->filterByContentId($event->getContentId())
|
||||
@@ -166,11 +209,41 @@ class Category extends BaseAction implements EventSubscriberInterface
|
||||
|
||||
if ($content !== null) {
|
||||
$content
|
||||
->setDispatcher($event->getDispatcher())
|
||||
->setDispatcher($dispatcher)
|
||||
->delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if is a category view and if category_id is visible
|
||||
*
|
||||
* @param ViewCheckEvent $event
|
||||
* @param string $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function viewCheck(ViewCheckEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if ($event->getView() == 'category') {
|
||||
$category = CategoryQuery::create()
|
||||
->filterById($event->getViewId())
|
||||
->filterByVisible(1)
|
||||
->count();
|
||||
|
||||
if ($category == 0) {
|
||||
$dispatcher->dispatch(TheliaEvents::VIEW_CATEGORY_ID_NOT_VISIBLE, $event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ViewCheckEvent $event
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public function viewcategoryIdNotVisible(ViewCheckEvent $event)
|
||||
{
|
||||
throw new NotFoundHttpException();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@@ -188,6 +261,8 @@ class Category extends BaseAction implements EventSubscriberInterface
|
||||
TheliaEvents::CATEGORY_ADD_CONTENT => array("addContent", 128),
|
||||
TheliaEvents::CATEGORY_REMOVE_CONTENT => array("removeContent", 128),
|
||||
|
||||
TheliaEvents::VIEW_CHECK => array('viewCheck', 128),
|
||||
TheliaEvents::VIEW_CATEGORY_ID_NOT_VISIBLE => array('viewcategoryIdNotVisible', 128),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Thelia\Action;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Core\Event\Config\ConfigCreateEvent;
|
||||
use Thelia\Core\Event\Config\ConfigDeleteEvent;
|
||||
@@ -25,12 +27,14 @@ class Config extends BaseAction implements EventSubscriberInterface
|
||||
* Create a new configuration entry
|
||||
*
|
||||
* @param \Thelia\Core\Event\Config\ConfigCreateEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function create(ConfigCreateEvent $event)
|
||||
public function create(ConfigCreateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$config = new ConfigModel();
|
||||
|
||||
$config->setDispatcher($event->getDispatcher())
|
||||
$config->setDispatcher($dispatcher)
|
||||
->setName($event->getEventName())
|
||||
->setValue($event->getValue())
|
||||
->setLocale($event->getLocale())
|
||||
@@ -46,15 +50,14 @@ class Config extends BaseAction implements EventSubscriberInterface
|
||||
* Change a configuration entry value
|
||||
*
|
||||
* @param \Thelia\Core\Event\Config\ConfigUpdateEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function setValue(ConfigUpdateEvent $event)
|
||||
public function setValue(ConfigUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
|
||||
if (null !== $config = ConfigQuery::create()->findPk($event->getConfigId())) {
|
||||
|
||||
if ($event->getValue() !== $config->getValue()) {
|
||||
|
||||
$config->setDispatcher($event->getDispatcher())->setValue($event->getValue())->save();
|
||||
$config->setDispatcher($dispatcher)->setValue($event->getValue())->save();
|
||||
|
||||
$event->setConfig($config);
|
||||
}
|
||||
@@ -65,13 +68,13 @@ class Config extends BaseAction implements EventSubscriberInterface
|
||||
* Change a configuration entry
|
||||
*
|
||||
* @param \Thelia\Core\Event\Config\ConfigUpdateEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function modify(ConfigUpdateEvent $event)
|
||||
public function modify(ConfigUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
|
||||
if (null !== $config = ConfigQuery::create()->findPk($event->getConfigId())) {
|
||||
|
||||
$config->setDispatcher($event->getDispatcher())
|
||||
$config->setDispatcher($dispatcher)
|
||||
->setName($event->getEventName())
|
||||
->setValue($event->getValue())
|
||||
->setHidden($event->getHidden())
|
||||
@@ -91,15 +94,14 @@ class Config extends BaseAction implements EventSubscriberInterface
|
||||
* Delete a configuration entry
|
||||
*
|
||||
* @param \Thelia\Core\Event\Config\ConfigDeleteEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function delete(ConfigDeleteEvent $event)
|
||||
public function delete(ConfigDeleteEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
|
||||
if (null !== ($config = ConfigQuery::create()->findPk($event->getConfigId()))) {
|
||||
|
||||
if (!$config->getSecured()) {
|
||||
|
||||
$config->setDispatcher($event->getDispatcher())->delete();
|
||||
$config->setDispatcher($dispatcher)->delete();
|
||||
|
||||
$event->setConfig($config);
|
||||
}
|
||||
|
||||
@@ -12,34 +12,41 @@
|
||||
|
||||
namespace Thelia\Action;
|
||||
|
||||
use Propel\Runtime\Exception\PropelException;
|
||||
use Propel\Runtime\Propel;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Thelia\Core\Event\Content\ContentAddFolderEvent;
|
||||
use Thelia\Core\Event\Content\ContentCreateEvent;
|
||||
use Thelia\Core\Event\Content\ContentDeleteEvent;
|
||||
use Thelia\Core\Event\Content\ContentRemoveFolderEvent;
|
||||
use Thelia\Core\Event\Content\ContentToggleVisibilityEvent;
|
||||
use Thelia\Core\Event\Content\ContentUpdateEvent;
|
||||
use Thelia\Core\Event\File\FileDeleteEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\Event\UpdatePositionEvent;
|
||||
use Thelia\Core\Event\UpdateSeoEvent;
|
||||
use Thelia\Core\Event\ViewCheckEvent;
|
||||
use Thelia\Model\ContentDocumentQuery;
|
||||
use Thelia\Model\ContentFolder;
|
||||
use Thelia\Model\ContentFolderQuery;
|
||||
use Thelia\Model\ContentImageQuery;
|
||||
use Thelia\Model\ContentQuery;
|
||||
use Thelia\Model\Content as ContentModel;
|
||||
use Thelia\Model\Map\ContentTableMap;
|
||||
|
||||
/**
|
||||
* Class Content
|
||||
* @package Thelia\Action
|
||||
* @author manuel raynaud <mraynaud@openstudio.fr>
|
||||
* @author manuel raynaud <manu@raynaud.io>
|
||||
*/
|
||||
class Content extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
|
||||
public function create(ContentCreateEvent $event)
|
||||
public function create(ContentCreateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$content = new ContentModel();
|
||||
|
||||
$content
|
||||
$content = (new ContentModel)
|
||||
->setDispatcher($dispatcher)
|
||||
->setVisible($event->getVisible())
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
@@ -53,68 +60,116 @@ class Content extends BaseAction implements EventSubscriberInterface
|
||||
* process update content
|
||||
*
|
||||
* @param ContentUpdateEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
* @throws PropelException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function update(ContentUpdateEvent $event)
|
||||
public function update(ContentUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $content = ContentQuery::create()->findPk($event->getContentId())) {
|
||||
$content->setDispatcher($event->getDispatcher());
|
||||
$con = Propel::getWriteConnection(ContentTableMap::DATABASE_NAME);
|
||||
$con->beginTransaction();
|
||||
|
||||
$content
|
||||
->setVisible($event->getVisible())
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
->setDescription($event->getDescription())
|
||||
->setChapo($event->getChapo())
|
||||
->setPostscriptum($event->getPostscriptum())
|
||||
->save()
|
||||
;
|
||||
$content->setDispatcher($dispatcher);
|
||||
try {
|
||||
$content
|
||||
->setVisible($event->getVisible())
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
->setDescription($event->getDescription())
|
||||
->setChapo($event->getChapo())
|
||||
->setPostscriptum($event->getPostscriptum())
|
||||
->save($con)
|
||||
;
|
||||
|
||||
$content->updateDefaultFolder($event->getDefaultFolder());
|
||||
$content->setDefaultFolder($event->getDefaultFolder());
|
||||
|
||||
$event->setContent($content);
|
||||
$event->setContent($content);
|
||||
$con->commit();
|
||||
} catch (PropelException $e) {
|
||||
$con->rollBack();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Change Content SEO
|
||||
*
|
||||
* @param \Thelia\Core\Event\UpdateSeoEvent $event
|
||||
*
|
||||
* @return mixed
|
||||
* @param UpdateSeoEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
* @return Object
|
||||
*/
|
||||
public function updateSeo(UpdateSeoEvent $event)
|
||||
public function updateSeo(UpdateSeoEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
return $this->genericUpdateSeo(ContentQuery::create(), $event);
|
||||
return $this->genericUpdateSeo(ContentQuery::create(), $event, $dispatcher);
|
||||
}
|
||||
|
||||
public function updatePosition(UpdatePositionEvent $event)
|
||||
public function updatePosition(UpdatePositionEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$this->genericUpdatePosition(ContentQuery::create(), $event);
|
||||
$this->genericUpdateDelegatePosition(
|
||||
ContentFolderQuery::create()
|
||||
->filterByContentId($event->getObjectId())
|
||||
->filterByFolderId($event->getReferrerId()),
|
||||
$event,
|
||||
$dispatcher
|
||||
);
|
||||
}
|
||||
|
||||
public function toggleVisibility(ContentToggleVisibilityEvent $event)
|
||||
public function toggleVisibility(ContentToggleVisibilityEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$content = $event->getContent();
|
||||
|
||||
$content
|
||||
->setDispatcher($event->getDispatcher())
|
||||
->setDispatcher($dispatcher)
|
||||
->setVisible(!$content->getVisible())
|
||||
->save();
|
||||
|
||||
$event->setContent($content);
|
||||
|
||||
}
|
||||
|
||||
public function delete(ContentDeleteEvent $event)
|
||||
public function delete(ContentDeleteEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $content = ContentQuery::create()->findPk($event->getContentId())) {
|
||||
$defaultFolderId = $content->getDefaultFolderId();
|
||||
$con = Propel::getWriteConnection(ContentTableMap::DATABASE_NAME);
|
||||
$con->beginTransaction();
|
||||
|
||||
$content->setDispatcher($event->getDispatcher())
|
||||
->delete();
|
||||
try {
|
||||
$fileList = ['images' => [], 'documentList' => []];
|
||||
|
||||
$event->setDefaultFolderId($defaultFolderId);
|
||||
$event->setContent($content);
|
||||
$defaultFolderId = $content->getDefaultFolderId();
|
||||
|
||||
// Get content's files to delete after content deletion
|
||||
$fileList['images']['list'] = ContentImageQuery::create()
|
||||
->findByContentId($event->getContentId());
|
||||
$fileList['images']['type'] = TheliaEvents::IMAGE_DELETE;
|
||||
|
||||
$fileList['documentList']['list'] = ContentDocumentQuery::create()
|
||||
->findByContentId($event->getContentId());
|
||||
$fileList['documentList']['type'] = TheliaEvents::DOCUMENT_DELETE;
|
||||
|
||||
// Delete content
|
||||
$content->setDispatcher($dispatcher)
|
||||
->delete($con);
|
||||
|
||||
$event->setDefaultFolderId($defaultFolderId);
|
||||
$event->setContent($content);
|
||||
|
||||
// Dispatch delete content's files event
|
||||
foreach ($fileList as $fileTypeList) {
|
||||
foreach ($fileTypeList['list'] as $fileToDelete) {
|
||||
$fileDeleteEvent = new FileDeleteEvent($fileToDelete);
|
||||
$dispatcher->dispatch($fileTypeList['type'], $fileDeleteEvent);
|
||||
}
|
||||
}
|
||||
|
||||
$con->commit();
|
||||
} catch (\Exception $e) {
|
||||
$con->rollback();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,17 +181,18 @@ class Content extends BaseAction implements EventSubscriberInterface
|
||||
*/
|
||||
public function addFolder(ContentAddFolderEvent $event)
|
||||
{
|
||||
if(ContentFolderQuery::create()
|
||||
if (ContentFolderQuery::create()
|
||||
->filterByContent($event->getContent())
|
||||
->filterByFolderId($event->getFolderId())
|
||||
->count() <= 0
|
||||
) {
|
||||
$contentFolder = new ContentFolder();
|
||||
|
||||
$contentFolder
|
||||
$contentFolder = (new ContentFolder())
|
||||
->setFolderId($event->getFolderId())
|
||||
->setContent($event->getContent())
|
||||
->setDefaultFolder(false)
|
||||
->setDefaultFolder(false);
|
||||
|
||||
$contentFolder
|
||||
->setPosition($contentFolder->getNextPosition())
|
||||
->save();
|
||||
}
|
||||
}
|
||||
@@ -154,29 +210,42 @@ class Content extends BaseAction implements EventSubscriberInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of event names this subscriber wants to listen to.
|
||||
* Check if is a content view and if content_id is visible
|
||||
*
|
||||
* The array keys are event names and the value can be:
|
||||
*
|
||||
* * The method name to call (priority defaults to 0)
|
||||
* * An array composed of the method name to call and the priority
|
||||
* * An array of arrays composed of the method names to call and respective
|
||||
* priorities, or 0 if unset
|
||||
*
|
||||
* For instance:
|
||||
*
|
||||
* * array('eventName' => 'methodName')
|
||||
* * array('eventName' => array('methodName', $priority))
|
||||
* * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
|
||||
*
|
||||
* @return array The event names to listen to
|
||||
*
|
||||
* @api
|
||||
* @param ViewCheckEvent $event
|
||||
* @param string $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function viewCheck(ViewCheckEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if ($event->getView() == 'content') {
|
||||
$content = ContentQuery::create()
|
||||
->filterById($event->getViewId())
|
||||
->filterByVisible(1)
|
||||
->count();
|
||||
|
||||
if ($content == 0) {
|
||||
$dispatcher->dispatch(TheliaEvents::VIEW_CONTENT_ID_NOT_VISIBLE, $event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ViewCheckEvent $event
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public function viewContentIdNotVisible(ViewCheckEvent $event)
|
||||
{
|
||||
throw new NotFoundHttpException();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::CONTENT_CREATE => array('create', 128),
|
||||
TheliaEvents::CONTENT_CREATE => array('create', 128),
|
||||
TheliaEvents::CONTENT_UPDATE => array('update', 128),
|
||||
TheliaEvents::CONTENT_DELETE => array('delete', 128),
|
||||
TheliaEvents::CONTENT_TOGGLE_VISIBILITY => array('toggleVisibility', 128),
|
||||
@@ -186,7 +255,9 @@ class Content extends BaseAction implements EventSubscriberInterface
|
||||
|
||||
TheliaEvents::CONTENT_ADD_FOLDER => array('addFolder', 128),
|
||||
TheliaEvents::CONTENT_REMOVE_FOLDER => array('removeFolder', 128),
|
||||
|
||||
TheliaEvents::VIEW_CHECK => array('viewCheck', 128),
|
||||
TheliaEvents::VIEW_CONTENT_ID_NOT_VISIBLE => array('viewContentIdNotVisible', 128),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,10 +12,12 @@
|
||||
|
||||
namespace Thelia\Action;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Core\Event\Country\CountryCreateEvent;
|
||||
use Thelia\Core\Event\Country\CountryDeleteEvent;
|
||||
use Thelia\Core\Event\Country\CountryToggleDefaultEvent;
|
||||
use Thelia\Core\Event\Country\CountryToggleVisibilityEvent;
|
||||
use Thelia\Core\Event\Country\CountryUpdateEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Model\Country as CountryModel;
|
||||
@@ -24,34 +26,38 @@ use Thelia\Model\CountryQuery;
|
||||
/**
|
||||
* Class Country
|
||||
* @package Thelia\Action
|
||||
* @author Manuel Raynaud <mraynaud@openstudio.fr>
|
||||
* @author Manuel Raynaud <manu@raynaud.io>
|
||||
*/
|
||||
class Country extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
|
||||
public function create(CountryCreateEvent $event)
|
||||
{
|
||||
$country = new CountryModel();
|
||||
|
||||
$country
|
||||
->setVisible($event->isVisible())
|
||||
->setIsocode($event->getIsocode())
|
||||
->setIsoalpha2($event->getIsoAlpha2())
|
||||
->setIsoalpha3($event->getIsoAlpha3())
|
||||
->setHasStates($event->isHasStates())
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
->save();
|
||||
|
||||
$event->setCountry($country);
|
||||
|
||||
}
|
||||
|
||||
public function update(CountryUpdateEvent $event)
|
||||
{
|
||||
if (null !== $country = CountryQuery::create()->findPk($event->getCountryId())) {
|
||||
$country
|
||||
->setVisible($event->isVisible())
|
||||
->setIsocode($event->getIsocode())
|
||||
->setIsoalpha2($event->getIsoAlpha2())
|
||||
->setIsoalpha3($event->getIsoAlpha3())
|
||||
->setHasStates($event->isHasStates())
|
||||
->setNeedZipCode($event->isNeedZipCode())
|
||||
->setZipCodeFormat($event->getZipCodeFormat())
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
->setChapo($event->getChapo())
|
||||
@@ -73,7 +79,7 @@ class Country extends BaseAction implements EventSubscriberInterface
|
||||
|
||||
public function toggleDefault(CountryToggleDefaultEvent $event)
|
||||
{
|
||||
if ( null !== $country = CountryQuery::create()->findPk($event->getCountryId())) {
|
||||
if (null !== $country = CountryQuery::create()->findPk($event->getCountryId())) {
|
||||
$country->toggleDefault();
|
||||
|
||||
$event->setCountry($country);
|
||||
@@ -81,24 +87,26 @@ class Country extends BaseAction implements EventSubscriberInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of event names this subscriber wants to listen to.
|
||||
* Toggle Country visibility
|
||||
*
|
||||
* The array keys are event names and the value can be:
|
||||
*
|
||||
* * The method name to call (priority defaults to 0)
|
||||
* * An array composed of the method name to call and the priority
|
||||
* * An array of arrays composed of the method names to call and respective
|
||||
* priorities, or 0 if unset
|
||||
*
|
||||
* For instance:
|
||||
*
|
||||
* * array('eventName' => 'methodName')
|
||||
* * array('eventName' => array('methodName', $priority))
|
||||
* * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
|
||||
*
|
||||
* @return array The event names to listen to
|
||||
*
|
||||
* @api
|
||||
* @param CountryToggleVisibilityEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function toggleVisibility(CountryToggleVisibilityEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$country = $event->getCountry();
|
||||
|
||||
$country
|
||||
->setDispatcher($dispatcher)
|
||||
->setVisible(!$country->getVisible())
|
||||
->save();
|
||||
|
||||
$event->setCountry($country);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
@@ -106,7 +114,8 @@ class Country extends BaseAction implements EventSubscriberInterface
|
||||
TheliaEvents::COUNTRY_CREATE => array('create', 128),
|
||||
TheliaEvents::COUNTRY_UPDATE => array('update', 128),
|
||||
TheliaEvents::COUNTRY_DELETE => array('delete', 128),
|
||||
TheliaEvents::COUNTRY_TOGGLE_DEFAULT => array('toggleDefault', 128)
|
||||
TheliaEvents::COUNTRY_TOGGLE_DEFAULT => array('toggleDefault', 128),
|
||||
TheliaEvents::COUNTRY_TOGGLE_VISIBILITY => array('toggleVisibility', 128)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,15 +13,18 @@
|
||||
namespace Thelia\Action;
|
||||
|
||||
use Propel\Runtime\Propel;
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Thelia\Condition\ConditionCollection;
|
||||
use Thelia\Condition\ConditionFactory;
|
||||
use Thelia\Condition\Implementation\ConditionInterface;
|
||||
use Thelia\Core\Event\Coupon\CouponConsumeEvent;
|
||||
use Thelia\Core\Event\Coupon\CouponCreateOrUpdateEvent;
|
||||
use Thelia\Core\Event\Coupon\CouponDeleteEvent;
|
||||
use Thelia\Core\Event\Order\OrderEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\HttpFoundation\Request;
|
||||
use Thelia\Coupon\CouponFactory;
|
||||
use Thelia\Coupon\CouponManager;
|
||||
use Thelia\Coupon\Type\CouponInterface;
|
||||
@@ -35,6 +38,8 @@ use Thelia\Model\Map\OrderCouponTableMap;
|
||||
use Thelia\Model\OrderCoupon;
|
||||
use Thelia\Model\OrderCouponCountry;
|
||||
use Thelia\Model\OrderCouponModule;
|
||||
use Thelia\Model\OrderCouponQuery;
|
||||
use Thelia\Model\OrderStatusQuery;
|
||||
|
||||
/**
|
||||
* Process Coupon Events
|
||||
@@ -45,10 +50,8 @@ use Thelia\Model\OrderCouponModule;
|
||||
*/
|
||||
class Coupon extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
/**
|
||||
* @var \Thelia\Core\HttpFoundation\Request
|
||||
*/
|
||||
protected $request;
|
||||
/** @var RequestStack */
|
||||
protected $requestStack;
|
||||
|
||||
/** @var CouponFactory $couponFactory */
|
||||
protected $couponFactory;
|
||||
@@ -62,11 +65,14 @@ class Coupon extends BaseAction implements EventSubscriberInterface
|
||||
/** @var ConditionFactory $conditionFactory */
|
||||
protected $conditionFactory;
|
||||
|
||||
public function __construct(Request $request,
|
||||
CouponFactory $couponFactory, CouponManager $couponManager,
|
||||
ConditionInterface $noConditionRule, ConditionFactory $conditionFactory)
|
||||
{
|
||||
$this->request = $request;
|
||||
public function __construct(
|
||||
RequestStack $requestStack,
|
||||
CouponFactory $couponFactory,
|
||||
CouponManager $couponManager,
|
||||
ConditionInterface $noConditionRule,
|
||||
ConditionFactory $conditionFactory
|
||||
) {
|
||||
$this->requestStack = $requestStack;
|
||||
$this->couponFactory = $couponFactory;
|
||||
$this->couponManager = $couponManager;
|
||||
$this->noConditionRule = $noConditionRule;
|
||||
@@ -77,57 +83,87 @@ class Coupon extends BaseAction implements EventSubscriberInterface
|
||||
* Occurring when a Coupon is about to be created
|
||||
*
|
||||
* @param CouponCreateOrUpdateEvent $event Event creation or update Coupon
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function create(CouponCreateOrUpdateEvent $event)
|
||||
public function create(CouponCreateOrUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$coupon = new CouponModel();
|
||||
|
||||
$this->createOrUpdate($coupon, $event);
|
||||
$this->createOrUpdate($coupon, $event, $dispatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Occurring when a Coupon is about to be updated
|
||||
*
|
||||
* @param CouponCreateOrUpdateEvent $event Event creation or update Coupon
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function update(CouponCreateOrUpdateEvent $event)
|
||||
public function update(CouponCreateOrUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$coupon = $event->getCouponModel();
|
||||
|
||||
$this->createOrUpdate($coupon, $event);
|
||||
$this->createOrUpdate($coupon, $event, $dispatcher);
|
||||
}
|
||||
|
||||
public function delete(CouponDeleteEvent $event)
|
||||
{
|
||||
$coupon = $event->getCoupon();
|
||||
|
||||
if (null === $coupon) {
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf(
|
||||
"The coupon id '%d' doesn't exist",
|
||||
$event->getCouponId()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$coupon->delete();
|
||||
|
||||
$event->setCoupon(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Occurring when a Coupon condition is about to be updated
|
||||
*
|
||||
* @param CouponCreateOrUpdateEvent $event Event creation or update Coupon condition
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function updateCondition(CouponCreateOrUpdateEvent $event)
|
||||
public function updateCondition(CouponCreateOrUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$modelCoupon = $event->getCouponModel();
|
||||
|
||||
$this->createOrUpdateCondition($modelCoupon, $event);
|
||||
$this->createOrUpdateCondition($modelCoupon, $event, $dispatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all coupons in session.
|
||||
*
|
||||
* @param Event $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function clearAllCoupons()
|
||||
public function clearAllCoupons(Event $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
// Tell coupons to clear any data they may have stored
|
||||
$this->couponManager->clear();
|
||||
|
||||
$this->request->getSession()->setConsumedCoupons(array());
|
||||
$this->getSession()->setConsumedCoupons(array());
|
||||
|
||||
$this->updateOrderDiscount(null);
|
||||
$this->updateOrderDiscount($event, $eventName, $dispatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Occurring when a Coupon condition is about to be consumed
|
||||
*
|
||||
* @param CouponConsumeEvent $event Event consuming Coupon
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function consume(CouponConsumeEvent $event)
|
||||
public function consume(CouponConsumeEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$totalDiscount = 0;
|
||||
$isValid = false;
|
||||
@@ -136,56 +172,38 @@ class Coupon extends BaseAction implements EventSubscriberInterface
|
||||
$coupon = $this->couponFactory->buildCouponFromCode($event->getCode());
|
||||
|
||||
if ($coupon) {
|
||||
|
||||
$isValid = $coupon->isMatching();
|
||||
|
||||
if ($isValid) {
|
||||
$consumedCoupons = $this->request->getSession()->getConsumedCoupons();
|
||||
|
||||
if (!isset($consumedCoupons) || !$consumedCoupons) {
|
||||
$consumedCoupons = array();
|
||||
}
|
||||
|
||||
if (!isset($consumedCoupons[$event->getCode()])) {
|
||||
|
||||
// Prevent accumulation of the same Coupon on a Checkout
|
||||
$consumedCoupons[$event->getCode()] = $event->getCode();
|
||||
|
||||
$this->request->getSession()->setConsumedCoupons($consumedCoupons);
|
||||
}
|
||||
|
||||
$this->couponManager->pushCouponInSession($event->getCode());
|
||||
$totalDiscount = $this->couponManager->getDiscount();
|
||||
|
||||
$this->request
|
||||
->getSession()
|
||||
->getCart()
|
||||
$this->getSession()
|
||||
->getSessionCart($dispatcher)
|
||||
->setDiscount($totalDiscount)
|
||||
->save();
|
||||
|
||||
$this->request
|
||||
->getSession()
|
||||
$this->getSession()
|
||||
->getOrder()
|
||||
->setDiscount($totalDiscount)
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$event->setIsValid($isValid);
|
||||
$event->setDiscount($totalDiscount);
|
||||
}
|
||||
|
||||
public function updateOrderDiscount(/** @noinspection PhpUnusedParameterInspection */ $event)
|
||||
public function updateOrderDiscount(Event $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$discount = $this->couponManager->getDiscount();
|
||||
|
||||
$this->request
|
||||
->getSession()
|
||||
->getCart()
|
||||
$this->getSession()
|
||||
->getSessionCart($dispatcher)
|
||||
->setDiscount($discount)
|
||||
->save();
|
||||
|
||||
$this->request
|
||||
->getSession()
|
||||
$this->getSession()
|
||||
->getOrder()
|
||||
->setDiscount($discount);
|
||||
}
|
||||
@@ -196,10 +214,11 @@ class Coupon extends BaseAction implements EventSubscriberInterface
|
||||
*
|
||||
* @param CouponModel $coupon Model to save
|
||||
* @param CouponCreateOrUpdateEvent $event Event containing data
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
protected function createOrUpdate(CouponModel $coupon, CouponCreateOrUpdateEvent $event)
|
||||
protected function createOrUpdate(CouponModel $coupon, CouponCreateOrUpdateEvent $event, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$coupon->setDispatcher($event->getDispatcher());
|
||||
$coupon->setDispatcher($dispatcher);
|
||||
|
||||
// Set default condition if none found
|
||||
/** @var ConditionInterface $noConditionRule */
|
||||
@@ -229,7 +248,8 @@ class Coupon extends BaseAction implements EventSubscriberInterface
|
||||
$event->getLocale(),
|
||||
$event->getFreeShippingForCountries(),
|
||||
$event->getFreeShippingForMethods(),
|
||||
$event->getPerCustomerUsageCount()
|
||||
$event->getPerCustomerUsageCount(),
|
||||
$event->getStartDate()
|
||||
);
|
||||
|
||||
$event->setCouponModel($coupon);
|
||||
@@ -241,10 +261,11 @@ class Coupon extends BaseAction implements EventSubscriberInterface
|
||||
*
|
||||
* @param CouponModel $coupon Model to save
|
||||
* @param CouponCreateOrUpdateEvent $event Event containing data
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
protected function createOrUpdateCondition(CouponModel $coupon, CouponCreateOrUpdateEvent $event)
|
||||
protected function createOrUpdateCondition(CouponModel $coupon, CouponCreateOrUpdateEvent $event, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$coupon->setDispatcher($event->getDispatcher());
|
||||
$coupon->setDispatcher($dispatcher);
|
||||
|
||||
/** @var ConditionFactory $conditionFactory */
|
||||
$conditionFactory = $this->conditionFactory;
|
||||
@@ -265,7 +286,6 @@ class Coupon extends BaseAction implements EventSubscriberInterface
|
||||
$order = $event->getOrder();
|
||||
|
||||
if ($this->couponManager->isCouponRemovingPostage($order)) {
|
||||
|
||||
$order->setPostage(0);
|
||||
|
||||
$event->setOrder($order);
|
||||
@@ -278,21 +298,23 @@ class Coupon extends BaseAction implements EventSubscriberInterface
|
||||
* @param \Thelia\Core\Event\Order\OrderEvent $event
|
||||
*
|
||||
* @throws \Exception if something goes wrong.
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function afterOrder(OrderEvent $event)
|
||||
public function afterOrder(OrderEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$consumedCoupons = $this->request->getSession()->getConsumedCoupons();
|
||||
|
||||
if (is_array($consumedCoupons)) {
|
||||
/** @var CouponInterface[] $consumedCoupons */
|
||||
$consumedCoupons = $this->couponManager->getCouponsKept();
|
||||
|
||||
if (is_array($consumedCoupons) && count($consumedCoupons) > 0) {
|
||||
$con = Propel::getWriteConnection(OrderCouponTableMap::DATABASE_NAME);
|
||||
$con->beginTransaction();
|
||||
|
||||
try {
|
||||
foreach ($consumedCoupons as $couponCode) {
|
||||
$couponQuery = CouponQuery::create();
|
||||
$couponModel = $couponQuery->findOneByCode($couponCode);
|
||||
$couponModel->setLocale($this->request->getSession()->getLang()->getLocale());
|
||||
$couponModel = $couponQuery->findOneByCode($couponCode->getCode());
|
||||
$couponModel->setLocale($this->getSession()->getLang()->getLocale());
|
||||
|
||||
/* decrease coupon quantity */
|
||||
$this->couponManager->decrementQuantity($couponModel, $event->getOrder()->getCustomerId());
|
||||
@@ -302,12 +324,13 @@ class Coupon extends BaseAction implements EventSubscriberInterface
|
||||
$orderCoupon->setOrder($event->getOrder())
|
||||
->setCode($couponModel->getCode())
|
||||
->setType($couponModel->getType())
|
||||
->setAmount($couponModel->getAmount())
|
||||
->setAmount($couponCode->exec())
|
||||
|
||||
->setTitle($couponModel->getTitle())
|
||||
->setShortDescription($couponModel->getShortDescription())
|
||||
->setDescription($couponModel->getDescription())
|
||||
|
||||
->setStartDate($couponModel->getStartDate())
|
||||
->setExpirationDate($couponModel->getExpirationDate())
|
||||
->setIsCumulative($couponModel->getIsCumulative())
|
||||
->setIsRemovingPostage($couponModel->getIsRemovingPostage())
|
||||
@@ -354,42 +377,90 @@ class Coupon extends BaseAction implements EventSubscriberInterface
|
||||
}
|
||||
|
||||
// Clear all coupons.
|
||||
$event->getDispatcher()->dispatch(TheliaEvents::COUPON_CLEAR_ALL);
|
||||
$dispatcher->dispatch(TheliaEvents::COUPON_CLEAR_ALL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of event names this subscriber listens to.
|
||||
* Cancels order coupons usage when order is canceled or refunded,
|
||||
* or use canceled coupons again if the order is no longer canceled or refunded
|
||||
*
|
||||
* The array keys are event names and the value can be:
|
||||
*
|
||||
* * The method name to call (priority defaults to 0)
|
||||
* * An array composed of the method name to call and the priority
|
||||
* * An array of arrays composed of the method names to call and respective
|
||||
* priorities, or 0 if unset
|
||||
*
|
||||
* For instance:
|
||||
*
|
||||
* * array('eventName' => 'methodName')
|
||||
* * array('eventName' => array('methodName', $priority))
|
||||
* * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
|
||||
*
|
||||
* @return array The event names to listen to
|
||||
*
|
||||
* @api
|
||||
* @param OrderEvent $event
|
||||
* @param string $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
* @throws \Exception
|
||||
* @throws \Propel\Runtime\Exception\PropelException
|
||||
*/
|
||||
public function orderStatusChange(OrderEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
// The order has been canceled or refunded ?
|
||||
if ($event->getOrder()->isCancelled() || $event->getOrder()->isRefunded()) {
|
||||
// Cancel usage of all coupons for this order
|
||||
$usedCoupons = OrderCouponQuery::create()
|
||||
->filterByUsageCanceled(false)
|
||||
->findByOrderId($event->getOrder()->getId());
|
||||
|
||||
$customerId = $event->getOrder()->getCustomerId();
|
||||
|
||||
/** @var OrderCoupon $usedCoupon */
|
||||
foreach ($usedCoupons as $usedCoupon) {
|
||||
if (null !== $couponModel = CouponQuery::create()->findOneByCode($usedCoupon->getCode())) {
|
||||
// If the coupon still exists, restore one usage to the usage count.
|
||||
$this->couponManager->incrementQuantity($couponModel, $customerId);
|
||||
}
|
||||
|
||||
// Mark coupon usage as canceled in the OrderCoupon table
|
||||
$usedCoupon->setUsageCanceled(true)->save();
|
||||
}
|
||||
} else {
|
||||
// Mark canceled coupons for this order as used again
|
||||
$usedCoupons = OrderCouponQuery::create()
|
||||
->filterByUsageCanceled(true)
|
||||
->findByOrderId($event->getOrder()->getId());
|
||||
|
||||
$customerId = $event->getOrder()->getCustomerId();
|
||||
|
||||
/** @var OrderCoupon $usedCoupon */
|
||||
foreach ($usedCoupons as $usedCoupon) {
|
||||
if (null !== $couponModel = CouponQuery::create()->findOneByCode($usedCoupon->getCode())) {
|
||||
// If the coupon still exists, mark the coupon as used
|
||||
$this->couponManager->decrementQuantity($couponModel, $customerId);
|
||||
}
|
||||
|
||||
// The coupon is no longer canceled
|
||||
$usedCoupon->setUsageCanceled(false)->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::COUPON_CREATE => array("create", 128),
|
||||
TheliaEvents::COUPON_UPDATE => array("update", 128),
|
||||
TheliaEvents::COUPON_DELETE => array("delete", 128),
|
||||
TheliaEvents::COUPON_CONSUME => array("consume", 128),
|
||||
TheliaEvents::COUPON_CLEAR_ALL => array("clearAllCoupons", 128),
|
||||
TheliaEvents::COUPON_CONDITION_UPDATE => array("updateCondition", 128),
|
||||
TheliaEvents::ORDER_SET_POSTAGE => array("testFreePostage", 132),
|
||||
TheliaEvents::ORDER_BEFORE_PAYMENT => array("afterOrder", 128),
|
||||
TheliaEvents::ORDER_UPDATE_STATUS => array("orderStatusChange", 10),
|
||||
TheliaEvents::CART_ADDITEM => array("updateOrderDiscount", 10),
|
||||
TheliaEvents::CART_UPDATEITEM => array("updateOrderDiscount", 10),
|
||||
TheliaEvents::CART_DELETEITEM => array("updateOrderDiscount", 10),
|
||||
TheliaEvents::CUSTOMER_LOGIN => array("updateOrderDiscount", 10)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the session from the current request
|
||||
*
|
||||
* @return \Thelia\Core\HttpFoundation\Session\Session
|
||||
*/
|
||||
protected function getSession()
|
||||
{
|
||||
return $this->requestStack->getCurrentRequest()->getSession();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,40 +12,54 @@
|
||||
|
||||
namespace Thelia\Action;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
|
||||
use Thelia\Core\Event\ActionEvent;
|
||||
use Thelia\Model\CurrencyQuery;
|
||||
use Thelia\Model\Currency as CurrencyModel;
|
||||
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
|
||||
use Thelia\Core\Event\Currency\CurrencyUpdateEvent;
|
||||
use Thelia\Core\Event\Currency\CurrencyCreateEvent;
|
||||
use Thelia\Core\Event\Currency\CurrencyDeleteEvent;
|
||||
use Thelia\Model\ConfigQuery;
|
||||
use Thelia\Core\Event\Currency\CurrencyUpdateEvent;
|
||||
use Thelia\Core\Event\Currency\CurrencyUpdateRateEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\Event\UpdatePositionEvent;
|
||||
use Thelia\Core\Translation\Translator;
|
||||
use Thelia\CurrencyConverter\CurrencyConverter;
|
||||
use Thelia\CurrencyConverter\Exception\CurrencyNotFoundException;
|
||||
use Thelia\Log\Tlog;
|
||||
use Thelia\Math\Number;
|
||||
use Thelia\Model\Currency as CurrencyModel;
|
||||
use Thelia\Model\CurrencyQuery;
|
||||
|
||||
class Currency extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
/** @var CurrencyConverter */
|
||||
protected $currencyConverter;
|
||||
|
||||
public function __construct(CurrencyConverter $currencyConverter)
|
||||
{
|
||||
$this->currencyConverter = $currencyConverter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new currencyuration entry
|
||||
*
|
||||
* @param \Thelia\Core\Event\Currency\CurrencyCreateEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function create(CurrencyCreateEvent $event)
|
||||
public function create(CurrencyCreateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$currency = new CurrencyModel();
|
||||
|
||||
$currency
|
||||
->setDispatcher($event->getDispatcher())
|
||||
$isDefault = CurrencyQuery::create()->count() === 0;
|
||||
|
||||
$currency
|
||||
->setDispatcher($dispatcher)
|
||||
->setLocale($event->getLocale())
|
||||
->setName($event->getCurrencyName())
|
||||
->setSymbol($event->getSymbol())
|
||||
->setFormat($event->getFormat())
|
||||
->setRate($event->getRate())
|
||||
->setCode(strtoupper($event->getCode()))
|
||||
|
||||
->setByDefault($isDefault)
|
||||
->save()
|
||||
;
|
||||
|
||||
@@ -56,17 +70,19 @@ class Currency extends BaseAction implements EventSubscriberInterface
|
||||
* Change a currency
|
||||
*
|
||||
* @param \Thelia\Core\Event\Currency\CurrencyUpdateEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function update(CurrencyUpdateEvent $event)
|
||||
public function update(CurrencyUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $currency = CurrencyQuery::create()->findPk($event->getCurrencyId())) {
|
||||
|
||||
$currency
|
||||
->setDispatcher($event->getDispatcher())
|
||||
->setDispatcher($dispatcher)
|
||||
|
||||
->setLocale($event->getLocale())
|
||||
->setName($event->getCurrencyName())
|
||||
->setSymbol($event->getSymbol())
|
||||
->setFormat($event->getFormat())
|
||||
->setRate($event->getRate())
|
||||
->setCode(strtoupper($event->getCode()))
|
||||
|
||||
@@ -80,36 +96,63 @@ class Currency extends BaseAction implements EventSubscriberInterface
|
||||
* Set the default currency
|
||||
*
|
||||
* @param CurrencyUpdateEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function setDefault(CurrencyUpdateEvent $event)
|
||||
public function setDefault(CurrencyUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
|
||||
if (null !== $currency = CurrencyQuery::create()->findPk($event->getCurrencyId())) {
|
||||
// Reset default status
|
||||
CurrencyQuery::create()->filterByByDefault(true)->update(array('ByDefault' => false));
|
||||
|
||||
$currency
|
||||
->setDispatcher($event->getDispatcher())
|
||||
->setDispatcher($dispatcher)
|
||||
->setVisible($event->getVisible())
|
||||
->setByDefault($event->getIsDefault())
|
||||
->save()
|
||||
;
|
||||
|
||||
// Update rates when setting a new default currency
|
||||
if ($event->getIsDefault()) {
|
||||
$updateRateEvent = new CurrencyUpdateRateEvent();
|
||||
|
||||
$dispatcher->dispatch(TheliaEvents::CURRENCY_UPDATE_RATES, $updateRateEvent);
|
||||
}
|
||||
|
||||
$event->setCurrency($currency);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CurrencyUpdateEvent $event
|
||||
*/
|
||||
public function setVisible(CurrencyUpdateEvent $event)
|
||||
{
|
||||
if (null !== $currency = CurrencyQuery::create()->findPk($event->getCurrencyId())) {
|
||||
if (!$currency->getByDefault()) {
|
||||
$currency->setVisible($event->getVisible())->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a currencyuration entry
|
||||
*
|
||||
* @param \Thelia\Core\Event\Currency\CurrencyDeleteEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function delete(CurrencyDeleteEvent $event)
|
||||
public function delete(CurrencyDeleteEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
|
||||
if (null !== ($currency = CurrencyQuery::create()->findPk($event->getCurrencyId()))) {
|
||||
if ($currency->getByDefault()) {
|
||||
throw new \RuntimeException(
|
||||
Translator::getInstance()->trans('It is not allowed to delete the default currency')
|
||||
);
|
||||
}
|
||||
|
||||
$currency
|
||||
->setDispatcher($event->getDispatcher())
|
||||
->setDispatcher($dispatcher)
|
||||
->delete()
|
||||
;
|
||||
|
||||
@@ -117,39 +160,45 @@ class Currency extends BaseAction implements EventSubscriberInterface
|
||||
}
|
||||
}
|
||||
|
||||
public function updateRates(ActionEvent $event)
|
||||
public function updateRates(CurrencyUpdateRateEvent $event)
|
||||
{
|
||||
$rates_url = ConfigQuery::read('currency_rate_update_url', 'http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml');
|
||||
if (null === $defaultCurrency = CurrencyQuery::create()->findOneByByDefault(true)) {
|
||||
throw new \RuntimeException('Unable to find a default currency, please define a default currency.');
|
||||
}
|
||||
|
||||
$rate_data = @file_get_contents($rates_url);
|
||||
$defaultCurrency->setRate(1)->save();
|
||||
|
||||
if ($rate_data && $sxe = new \SimpleXMLElement($rate_data)) {
|
||||
$currencies = CurrencyQuery::create()->filterByByDefault(false);
|
||||
$baseValue = new Number('1');
|
||||
|
||||
foreach ($sxe->Cube[0]->Cube[0]->Cube as $last) {
|
||||
$code = strtoupper($last["currency"]);
|
||||
$rate = floatval($last['rate']);
|
||||
/** @var \Thelia\Model\Currency $currency */
|
||||
foreach ($currencies as $currency) {
|
||||
try {
|
||||
$rate = $this->currencyConverter
|
||||
->from($defaultCurrency->getCode())
|
||||
->to($currency->getCode())
|
||||
->convert($baseValue);
|
||||
|
||||
if (null !== $currency = CurrencyQuery::create()->findOneByCode($code)) {
|
||||
$currency
|
||||
->setDispatcher($event->getDispatcher())
|
||||
->setRate($rate)
|
||||
->save()
|
||||
;
|
||||
}
|
||||
$currency->setRate($rate->getNumber(-1))->save();
|
||||
} catch (CurrencyNotFoundException $ex) {
|
||||
Tlog::getInstance()->addError(
|
||||
sprintf("Unable to find exchange rate for currency %s, ID %d", $currency->getCode(), $currency->getId())
|
||||
);
|
||||
$event->addUndefinedRate($currency->getId());
|
||||
}
|
||||
} else {
|
||||
throw new \RuntimeException(sprintf("Failed to get currency rates data from URL %s", $rates_url));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes position, selecting absolute ou relative change.
|
||||
*
|
||||
* @param CategoryChangePositionEvent $event
|
||||
* @param UpdatePositionEvent $event
|
||||
* @param string $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function updatePosition(UpdatePositionEvent $event)
|
||||
public function updatePosition(UpdatePositionEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$this->genericUpdatePosition(CurrencyQuery::create(), $event);
|
||||
$this->genericUpdatePosition(CurrencyQuery::create(), $event, $dispatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -162,6 +211,7 @@ class Currency extends BaseAction implements EventSubscriberInterface
|
||||
TheliaEvents::CURRENCY_UPDATE => array("update", 128),
|
||||
TheliaEvents::CURRENCY_DELETE => array("delete", 128),
|
||||
TheliaEvents::CURRENCY_SET_DEFAULT => array("setDefault", 128),
|
||||
TheliaEvents::CURRENCY_SET_VISIBLE => array("setVisible", 128),
|
||||
TheliaEvents::CURRENCY_UPDATE_RATES => array("updateRates", 128),
|
||||
TheliaEvents::CURRENCY_UPDATE_POSITION => array("updatePosition", 128)
|
||||
);
|
||||
|
||||
@@ -12,23 +12,21 @@
|
||||
|
||||
namespace Thelia\Action;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Core\Event\ActionEvent;
|
||||
use Thelia\Core\Event\Customer\CustomerCreateOrUpdateEvent;
|
||||
use Thelia\Core\Event\Customer\CustomerEvent;
|
||||
use Thelia\Core\Event\Customer\CustomerLoginEvent;
|
||||
use Thelia\Core\Event\LostPasswordEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\Security\SecurityContext;
|
||||
use Thelia\Core\Template\ParserInterface;
|
||||
use Thelia\Core\Translation\Translator;
|
||||
use Thelia\Exception\CustomerException;
|
||||
use Thelia\Mailer\MailerFactory;
|
||||
use Thelia\Model\ConfigQuery;
|
||||
use Thelia\Model\Customer as CustomerModel;
|
||||
use Thelia\Core\Event\Customer\CustomerLoginEvent;
|
||||
use Thelia\Model\CustomerQuery;
|
||||
use Thelia\Model\LangQuery;
|
||||
use Thelia\Model\MessageQuery;
|
||||
use Thelia\Tools\Password;
|
||||
|
||||
/**
|
||||
@@ -37,46 +35,77 @@ use Thelia\Tools\Password;
|
||||
*
|
||||
* Class Customer
|
||||
* @package Thelia\Action
|
||||
* @author Manuel Raynaud <mraynaud@openstudio.fr>
|
||||
* @author Manuel Raynaud <manu@raynaud.io>
|
||||
*/
|
||||
class Customer extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
/** @var SecurityContext */
|
||||
protected $securityContext;
|
||||
|
||||
protected $parser;
|
||||
|
||||
/** @var MailerFactory */
|
||||
protected $mailer;
|
||||
|
||||
public function __construct(SecurityContext $securityContext, ParserInterface $parser, MailerFactory $mailer)
|
||||
public function __construct(SecurityContext $securityContext, MailerFactory $mailer)
|
||||
{
|
||||
$this->securityContext = $securityContext;
|
||||
$this->mailer = $mailer;
|
||||
$this->parser = $parser;
|
||||
}
|
||||
|
||||
public function create(CustomerCreateOrUpdateEvent $event)
|
||||
public function create(CustomerCreateOrUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
|
||||
$customer = new CustomerModel();
|
||||
|
||||
$this->createOrUpdateCustomer($customer, $event);
|
||||
$plainPassword = $event->getPassword();
|
||||
|
||||
$this->createOrUpdateCustomer($customer, $event, $dispatcher);
|
||||
|
||||
if ($event->getNotifyCustomerOfAccountCreation()) {
|
||||
$this->mailer->sendEmailToCustomer(
|
||||
'customer_account_created',
|
||||
$customer,
|
||||
[ 'password' => $plainPassword ]
|
||||
);
|
||||
}
|
||||
|
||||
$dispatcher->dispatch(
|
||||
TheliaEvents::SEND_ACCOUNT_CONFIRMATION_EMAIL,
|
||||
new CustomerEvent($customer)
|
||||
);
|
||||
}
|
||||
|
||||
public function modify(CustomerCreateOrUpdateEvent $event)
|
||||
{
|
||||
|
||||
$customer = $event->getCustomer();
|
||||
|
||||
$this->createOrUpdateCustomer($customer, $event);
|
||||
|
||||
}
|
||||
|
||||
public function updateProfile(CustomerCreateOrUpdateEvent $event)
|
||||
public function customerConfirmationEmail(CustomerEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$customer = $event->getCustomer();
|
||||
|
||||
$customer->setDispatcher($event->getDispatcher());
|
||||
if (ConfigQuery::isCustomerEmailConfirmationEnable() && $customer->getConfirmationToken() !== null && $customer !== null) {
|
||||
$this->mailer->sendEmailToCustomer(
|
||||
'customer_confirmation',
|
||||
$customer,
|
||||
['customer_id' => $customer->getId()]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function modify(CustomerCreateOrUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$plainPassword = $event->getPassword();
|
||||
|
||||
$customer = $event->getCustomer();
|
||||
|
||||
$emailChanged = $customer->getEmail() !== $event->getEmail();
|
||||
|
||||
$this->createOrUpdateCustomer($customer, $event, $dispatcher);
|
||||
|
||||
if (! empty($plainPassword) || $emailChanged) {
|
||||
$this->mailer->sendEmailToCustomer('customer_account_changed', $customer, ['password' => $plainPassword]);
|
||||
}
|
||||
}
|
||||
|
||||
public function updateProfile(CustomerCreateOrUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$customer = $event->getCustomer();
|
||||
|
||||
$customer->setDispatcher($dispatcher);
|
||||
|
||||
if ($event->getTitle() !== null) {
|
||||
$customer->setTitleId($event->getTitle());
|
||||
@@ -91,7 +120,7 @@ class Customer extends BaseAction implements EventSubscriberInterface
|
||||
}
|
||||
|
||||
if ($event->getEmail() !== null) {
|
||||
$customer->setEmail($event->getEmail());
|
||||
$customer->setEmail($event->getEmail(), $event->getEmailUpdateAllowed());
|
||||
}
|
||||
|
||||
if ($event->getPassword() !== null) {
|
||||
@@ -118,7 +147,6 @@ class Customer extends BaseAction implements EventSubscriberInterface
|
||||
public function delete(CustomerEvent $event)
|
||||
{
|
||||
if (null !== $customer = $event->getCustomer()) {
|
||||
|
||||
if (true === $customer->hasOrder()) {
|
||||
throw new CustomerException(Translator::getInstance()->trans("Impossible to delete a customer who already have orders"));
|
||||
}
|
||||
@@ -127,9 +155,9 @@ class Customer extends BaseAction implements EventSubscriberInterface
|
||||
}
|
||||
}
|
||||
|
||||
private function createOrUpdateCustomer(CustomerModel $customer, CustomerCreateOrUpdateEvent $event)
|
||||
private function createOrUpdateCustomer(CustomerModel $customer, CustomerCreateOrUpdateEvent $event, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$customer->setDispatcher($event->getDispatcher());
|
||||
$customer->setDispatcher($dispatcher);
|
||||
|
||||
$customer->createOrUpdate(
|
||||
$event->getTitle(),
|
||||
@@ -145,12 +173,14 @@ class Customer extends BaseAction implements EventSubscriberInterface
|
||||
$event->getCountry(),
|
||||
$event->getEmail(),
|
||||
$event->getPassword(),
|
||||
$event->getLang(),
|
||||
$event->getLangId(),
|
||||
$event->getReseller(),
|
||||
$event->getSponsor(),
|
||||
$event->getDiscount(),
|
||||
$event->getCompany(),
|
||||
$event->getRef()
|
||||
$event->getRef(),
|
||||
$event->getEmailUpdateAllowed(),
|
||||
$event->getState()
|
||||
);
|
||||
|
||||
$event->setCustomer($customer);
|
||||
@@ -171,84 +201,27 @@ class Customer extends BaseAction implements EventSubscriberInterface
|
||||
*
|
||||
* @param ActionEvent $event
|
||||
*/
|
||||
public function logout(ActionEvent $event)
|
||||
public function logout(/** @noinspection PhpUnusedParameterInspection */ ActionEvent $event)
|
||||
{
|
||||
$this->securityContext->clearCustomerUser();
|
||||
}
|
||||
|
||||
public function lostPassword(LostPasswordEvent $event)
|
||||
{
|
||||
$contact_email = ConfigQuery::read('store_email');
|
||||
if (null !== $customer = CustomerQuery::create()->filterByEmail($event->getEmail())->findOne()) {
|
||||
$password = Password::generateRandom(8);
|
||||
|
||||
if ($contact_email) {
|
||||
if (null !== $customer = CustomerQuery::create()->filterByEmail($event->getEmail())->findOne()) {
|
||||
$customer
|
||||
->setPassword($password)
|
||||
->save()
|
||||
;
|
||||
|
||||
$password = Password::generateRandom(8);
|
||||
|
||||
$customer
|
||||
->setPassword($password)
|
||||
->save()
|
||||
;
|
||||
|
||||
if ($customer->getLang() !== null) {
|
||||
$lang = LangQuery::create()
|
||||
->findPk($customer->getLang());
|
||||
|
||||
$locale = $lang->getLocale();
|
||||
} else {
|
||||
$lang = LangQuery::create()
|
||||
->filterByByDefault(1)
|
||||
->findOne();
|
||||
|
||||
$locale = $lang->getLocale();
|
||||
}
|
||||
|
||||
$message = MessageQuery::create()
|
||||
->filterByName('lost_password')
|
||||
->findOne();
|
||||
|
||||
$message->setLocale($locale);
|
||||
|
||||
if (false === $message) {
|
||||
throw new \Exception("Failed to load message 'order_confirmation'.");
|
||||
}
|
||||
|
||||
$this->parser->assign('password', $password);
|
||||
|
||||
$instance = \Swift_Message::newInstance()
|
||||
->addTo($customer->getEmail(), $customer->getFirstname()." ".$customer->getLastname())
|
||||
->addFrom($contact_email, ConfigQuery::read('store_name'))
|
||||
;
|
||||
|
||||
// Build subject and body
|
||||
|
||||
$message->buildMessage($this->parser, $instance);
|
||||
|
||||
$this->mailer->send($instance);
|
||||
|
||||
}
|
||||
$this->mailer->sendEmailToCustomer('lost_password', $customer, ['password' => $password]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of event names this subscriber wants to listen to.
|
||||
*
|
||||
* The array keys are event names and the value can be:
|
||||
*
|
||||
* * The method name to call (priority defaults to 0)
|
||||
* * An array composed of the method name to call and the priority
|
||||
* * An array of arrays composed of the method names to call and respective
|
||||
* priorities, or 0 if unset
|
||||
*
|
||||
* For instance:
|
||||
*
|
||||
* * array('eventName' => 'methodName')
|
||||
* * array('eventName' => array('methodName', $priority))
|
||||
* * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
|
||||
*
|
||||
* @return array The event names to listen to
|
||||
*
|
||||
* @api
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
@@ -259,7 +232,8 @@ class Customer extends BaseAction implements EventSubscriberInterface
|
||||
TheliaEvents::CUSTOMER_LOGOUT => array('logout', 128),
|
||||
TheliaEvents::CUSTOMER_LOGIN => array('login', 128),
|
||||
TheliaEvents::CUSTOMER_DELETEACCOUNT => array('delete', 128),
|
||||
TheliaEvents::LOST_PASSWORD => array('lostPassword', 128)
|
||||
TheliaEvents::LOST_PASSWORD => array('lostPassword', 128),
|
||||
TheliaEvents::SEND_ACCOUNT_CONFIRMATION_EMAIL => array('customerConfirmationEmail', 128)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
111
core/lib/Thelia/Action/CustomerTitle.php
Normal file
111
core/lib/Thelia/Action/CustomerTitle.php
Normal file
@@ -0,0 +1,111 @@
|
||||
<?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 Thelia\Action;
|
||||
|
||||
use Propel\Runtime\Propel;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Core\Event\CustomerTitle\CustomerTitleEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Model\CustomerTitle as CustomerTitleModel;
|
||||
use Thelia\Model\Map\CustomerTitleTableMap;
|
||||
|
||||
/**
|
||||
* Class CustomerTitle
|
||||
* @package Thelia\Action
|
||||
* @author Benjamin Perche <bperche@openstudio.fr>
|
||||
*/
|
||||
class CustomerTitle extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
public function create(CustomerTitleEvent $event)
|
||||
{
|
||||
$this->createOrUpdate($event, new CustomerTitleModel());
|
||||
}
|
||||
|
||||
public function update(CustomerTitleEvent $event)
|
||||
{
|
||||
$this->checkCustomerTitle($event);
|
||||
|
||||
$this->createOrUpdate($event, $event->getCustomerTitle());
|
||||
}
|
||||
|
||||
public function delete(CustomerTitleEvent $event)
|
||||
{
|
||||
$this->checkCustomerTitle($event);
|
||||
|
||||
$con = Propel::getConnection(CustomerTitleTableMap::DATABASE_NAME);
|
||||
$con->beginTransaction();
|
||||
|
||||
try {
|
||||
$event->getCustomerTitle()->delete();
|
||||
|
||||
$con->commit();
|
||||
} catch (\Exception $e) {
|
||||
$con->rollBack();
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$event->setCustomerTitle(null);
|
||||
}
|
||||
|
||||
protected function checkCustomerTitle(CustomerTitleEvent $event)
|
||||
{
|
||||
if (null === $event->getCustomerTitle()) {
|
||||
throw new \LogicException(
|
||||
"You must set the customer title before its update"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected function createOrUpdate(CustomerTitleEvent $event, CustomerTitleModel $customerTitle)
|
||||
{
|
||||
$con = Propel::getConnection(CustomerTitleTableMap::DATABASE_NAME);
|
||||
$con->beginTransaction();
|
||||
|
||||
$i18n = $customerTitle->getTranslation($event->getLocale(), $con);
|
||||
|
||||
try {
|
||||
$i18n
|
||||
->setShort($event->getShort())
|
||||
->setLong($event->getLong())
|
||||
;
|
||||
|
||||
$customerTitle->save($con);
|
||||
|
||||
if ($event->isDefault()) {
|
||||
$customerTitle->toggleDefault($con);
|
||||
$event->setDefault(false);
|
||||
}
|
||||
|
||||
$con->commit();
|
||||
} catch (\Exception $e) {
|
||||
$con->rollBack();
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$event->setCustomerTitle($customerTitle);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::CUSTOMER_TITLE_CREATE => array("create"),
|
||||
TheliaEvents::CUSTOMER_TITLE_UPDATE => array("update"),
|
||||
TheliaEvents::CUSTOMER_TITLE_DELETE => array("delete"),
|
||||
);
|
||||
}
|
||||
}
|
||||
66
core/lib/Thelia/Action/Delivery.php
Normal file
66
core/lib/Thelia/Action/Delivery.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?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 Thelia\Action;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Core\Event\Delivery\DeliveryPostageEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
|
||||
/**
|
||||
* Class Delivery
|
||||
* @package Thelia\Action
|
||||
* @author Julien Chanséaume <julien@thelia.net>
|
||||
*/
|
||||
class Delivery implements EventSubscriberInterface
|
||||
{
|
||||
/**
|
||||
* Get postage from module using the classical module functions
|
||||
*
|
||||
* @param DeliveryPostageEvent $event
|
||||
*/
|
||||
public function getPostage(DeliveryPostageEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$module = $event->getModule();
|
||||
|
||||
// dispatch event to target specific module
|
||||
$dispatcher->dispatch(
|
||||
TheliaEvents::getModuleEvent(
|
||||
TheliaEvents::MODULE_DELIVERY_GET_POSTAGE,
|
||||
$module->getCode()
|
||||
),
|
||||
$event
|
||||
);
|
||||
|
||||
if ($event->isPropagationStopped()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// call legacy module method
|
||||
$event->setValidModule($module->isValidDelivery($event->getCountry()));
|
||||
if ($event->isValidModule()) {
|
||||
$event->setPostage($module->getPostage($event->getCountry()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return [
|
||||
TheliaEvents::MODULE_DELIVERY_GET_POSTAGE => ['getPostage', 128]
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -41,12 +41,17 @@ use Thelia\Tools\URL;
|
||||
*/
|
||||
class Document extends BaseCachedFile implements EventSubscriberInterface
|
||||
{
|
||||
/**
|
||||
* @var string Config key for document delivery mode
|
||||
*/
|
||||
const CONFIG_DELIVERY_MODE = 'original_document_delivery_mode';
|
||||
|
||||
/**
|
||||
* @return string root of the document cache directory in web space
|
||||
*/
|
||||
protected function getCacheDirFromWebRoot()
|
||||
{
|
||||
return ConfigQuery::read('document_cache_dir_from_web_root', 'cache');
|
||||
return ConfigQuery::read('document_cache_dir_from_web_root', 'cache' . DS . 'documents');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,20 +79,19 @@ class Document extends BaseCachedFile implements EventSubscriberInterface
|
||||
$originalDocumentPathInCache = $this->getCacheFilePath($subdir, $sourceFile, true);
|
||||
|
||||
if (! file_exists($originalDocumentPathInCache)) {
|
||||
|
||||
if (! file_exists($sourceFile)) {
|
||||
throw new DocumentException(sprintf("Source document file %s does not exists.", $sourceFile));
|
||||
}
|
||||
|
||||
$mode = ConfigQuery::read('original_document_delivery_mode', 'symlink');
|
||||
$mode = ConfigQuery::read(self::CONFIG_DELIVERY_MODE, 'symlink');
|
||||
|
||||
if ($mode == 'symlink') {
|
||||
if (false == symlink($sourceFile, $originalDocumentPathInCache)) {
|
||||
throw new DocumentException(sprintf("Failed to create symbolic link for %s in %s document cache directory", basename($sourceFile), $subdir));
|
||||
if (false === symlink($sourceFile, $originalDocumentPathInCache)) {
|
||||
throw new DocumentException(sprintf("Failed to create symbolic link for %s in %s document cache directory", basename($sourceFile), $subdir));
|
||||
}
|
||||
} else {
|
||||
// mode = 'copy'
|
||||
if (false == @copy($sourceFile, $originalDocumentPathInCache)) {
|
||||
if (false === @copy($sourceFile, $originalDocumentPathInCache)) {
|
||||
throw new DocumentException(sprintf("Failed to copy %s in %s document cache directory", basename($sourceFile), $subdir));
|
||||
}
|
||||
}
|
||||
@@ -101,6 +105,9 @@ class Document extends BaseCachedFile implements EventSubscriberInterface
|
||||
$event->setDocumentUrl(URL::getInstance()->absoluteUrl($documentUrl, null, URL::PATH_TO_FILE));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
@@ -112,6 +119,7 @@ class Document extends BaseCachedFile implements EventSubscriberInterface
|
||||
TheliaEvents::DOCUMENT_SAVE => array("saveFile", 128),
|
||||
TheliaEvents::DOCUMENT_UPDATE => array("updateFile", 128),
|
||||
TheliaEvents::DOCUMENT_UPDATE_POSITION => array("updatePosition", 128),
|
||||
TheliaEvents::DOCUMENT_TOGGLE_VISIBILITY => array("toggleVisibility", 128),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,77 +11,69 @@
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Thelia\Action;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Core\Event\Cache\CacheEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\Event\UpdatePositionEvent;
|
||||
use Thelia\Handler\ExportHandler;
|
||||
use Thelia\Model\ExportCategoryQuery;
|
||||
use Thelia\Model\ExportQuery;
|
||||
|
||||
/**
|
||||
* Class Export
|
||||
* @package Thelia\Action
|
||||
* @author Benjamin Perche <bperche@openstudio.fr>
|
||||
* @author Jérôme Billiras <jbilliras@openstudio.fr>
|
||||
*/
|
||||
class Export extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
protected $environment;
|
||||
/**
|
||||
* @var \Thelia\Handler\ExportHandler The export handler
|
||||
*/
|
||||
protected $handler;
|
||||
|
||||
public function __construct($environment)
|
||||
/**
|
||||
* @param \Thelia\Handler\ExportHandler $exportHandler The export handler
|
||||
*/
|
||||
public function __construct(ExportHandler $exportHandler)
|
||||
{
|
||||
$this->environment = $environment;
|
||||
$this->handler = $exportHandler;
|
||||
}
|
||||
|
||||
public function changeCategoryPosition(UpdatePositionEvent $event)
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
$this->genericUpdatePosition(new ExportCategoryQuery(), $event);
|
||||
|
||||
$this->cacheClear($event->getDispatcher());
|
||||
}
|
||||
|
||||
public function changeExportPosition(UpdatePositionEvent $event)
|
||||
{
|
||||
$this->genericUpdatePosition(new ExportQuery(), $event);
|
||||
|
||||
$this->cacheClear($event->getDispatcher());
|
||||
}
|
||||
|
||||
protected function cacheClear(EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$cacheEvent = new CacheEvent(
|
||||
$this->environment
|
||||
);
|
||||
|
||||
$dispatcher->dispatch(TheliaEvents::CACHE_CLEAR, $cacheEvent);
|
||||
return [
|
||||
TheliaEvents::EXPORT_CHANGE_POSITION => [
|
||||
['exportChangePosition', 128]
|
||||
],
|
||||
TheliaEvents::EXPORT_CATEGORY_CHANGE_POSITION => [
|
||||
['exportCategoryChangePosition', 128]
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of event names this subscriber wants to listen to.
|
||||
* Handle export change position event
|
||||
*
|
||||
* The array keys are event names and the value can be:
|
||||
*
|
||||
* * The method name to call (priority defaults to 0)
|
||||
* * An array composed of the method name to call and the priority
|
||||
* * An array of arrays composed of the method names to call and respective
|
||||
* priorities, or 0 if unset
|
||||
*
|
||||
* For instance:
|
||||
*
|
||||
* * array('eventName' => 'methodName')
|
||||
* * array('eventName' => array('methodName', $priority))
|
||||
* * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
|
||||
*
|
||||
* @return array The event names to listen to
|
||||
*
|
||||
* @api
|
||||
* @param UpdatePositionEvent $updatePositionEvent
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
public function exportChangePosition(UpdatePositionEvent $updatePositionEvent, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::EXPORT_CATEGORY_CHANGE_POSITION => array("changeCategoryPosition", 128),
|
||||
TheliaEvents::EXPORT_CHANGE_POSITION => array("changeExportPosition", 128),
|
||||
);
|
||||
$this->handler->getExport($updatePositionEvent->getObjectId(), true);
|
||||
$this->genericUpdatePosition(new ExportQuery, $updatePositionEvent, $dispatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle export category change position event
|
||||
*
|
||||
* @param UpdatePositionEvent $updatePositionEvent
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function exportCategoryChangePosition(UpdatePositionEvent $updatePositionEvent, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$this->handler->getCategory($updatePositionEvent->getObjectId(), true);
|
||||
$this->genericUpdatePosition(new ExportCategoryQuery, $updatePositionEvent, $dispatcher);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,13 +12,11 @@
|
||||
|
||||
namespace Thelia\Action;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
|
||||
use Thelia\Model\FeatureQuery;
|
||||
use Thelia\Model\Feature as FeatureModel;
|
||||
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
|
||||
use Thelia\Core\Event\Feature\FeatureUpdateEvent;
|
||||
use Thelia\Core\Event\Feature\FeatureCreateEvent;
|
||||
use Thelia\Core\Event\Feature\FeatureDeleteEvent;
|
||||
@@ -34,13 +32,15 @@ class Feature extends BaseAction implements EventSubscriberInterface
|
||||
* Create a new feature entry
|
||||
*
|
||||
* @param \Thelia\Core\Event\Feature\FeatureCreateEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function create(FeatureCreateEvent $event)
|
||||
public function create(FeatureCreateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$feature = new FeatureModel();
|
||||
|
||||
$feature
|
||||
->setDispatcher($event->getDispatcher())
|
||||
->setDispatcher($dispatcher)
|
||||
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
@@ -60,14 +60,14 @@ class Feature extends BaseAction implements EventSubscriberInterface
|
||||
* Change a product feature
|
||||
*
|
||||
* @param \Thelia\Core\Event\Feature\FeatureUpdateEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function update(FeatureUpdateEvent $event)
|
||||
public function update(FeatureUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
|
||||
if (null !== $feature = FeatureQuery::create()->findPk($event->getFeatureId())) {
|
||||
|
||||
$feature
|
||||
->setDispatcher($event->getDispatcher())
|
||||
->setDispatcher($dispatcher)
|
||||
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
@@ -85,14 +85,14 @@ class Feature extends BaseAction implements EventSubscriberInterface
|
||||
* Delete a product feature entry
|
||||
*
|
||||
* @param FeatureDeleteEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function delete(FeatureDeleteEvent $event)
|
||||
public function delete(FeatureDeleteEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
|
||||
if (null !== ($feature = FeatureQuery::create()->findPk($event->getFeatureId()))) {
|
||||
|
||||
$feature
|
||||
->setDispatcher($event->getDispatcher())
|
||||
->setDispatcher($dispatcher)
|
||||
->delete()
|
||||
;
|
||||
|
||||
@@ -104,10 +104,12 @@ class Feature extends BaseAction implements EventSubscriberInterface
|
||||
* Changes position, selecting absolute ou relative change.
|
||||
*
|
||||
* @param UpdatePositionEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function updatePosition(UpdatePositionEvent $event)
|
||||
public function updatePosition(UpdatePositionEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$this->genericUpdatePosition(FeatureQuery::create(), $event);
|
||||
$this->genericUpdatePosition(FeatureQuery::create(), $event, $dispatcher);
|
||||
}
|
||||
|
||||
protected function doAddToAllTemplates(FeatureModel $feature)
|
||||
@@ -115,7 +117,6 @@ class Feature extends BaseAction implements EventSubscriberInterface
|
||||
$templates = TemplateQuery::create()->find();
|
||||
|
||||
foreach ($templates as $template) {
|
||||
|
||||
$feature_template = new FeatureTemplate();
|
||||
|
||||
if (null === FeatureTemplateQuery::create()->filterByFeature($feature)->filterByTemplate($template)->findOne()) {
|
||||
|
||||
@@ -12,13 +12,11 @@
|
||||
|
||||
namespace Thelia\Action;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
|
||||
use Thelia\Model\FeatureAvQuery;
|
||||
use Thelia\Model\FeatureAv as FeatureAvModel;
|
||||
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
|
||||
use Thelia\Core\Event\Feature\FeatureAvUpdateEvent;
|
||||
use Thelia\Core\Event\Feature\FeatureAvCreateEvent;
|
||||
use Thelia\Core\Event\Feature\FeatureAvDeleteEvent;
|
||||
@@ -30,13 +28,15 @@ class FeatureAv extends BaseAction implements EventSubscriberInterface
|
||||
* Create a new feature entry
|
||||
*
|
||||
* @param FeatureAvCreateEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function create(FeatureAvCreateEvent $event)
|
||||
public function create(FeatureAvCreateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$feature = new FeatureAvModel();
|
||||
|
||||
$feature
|
||||
->setDispatcher($event->getDispatcher())
|
||||
->setDispatcher($dispatcher)
|
||||
|
||||
->setFeatureId($event->getFeatureId())
|
||||
->setLocale($event->getLocale())
|
||||
@@ -52,14 +52,14 @@ class FeatureAv extends BaseAction implements EventSubscriberInterface
|
||||
* Change a product feature
|
||||
*
|
||||
* @param FeatureAvUpdateEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function update(FeatureAvUpdateEvent $event)
|
||||
public function update(FeatureAvUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
|
||||
if (null !== $feature = FeatureAvQuery::create()->findPk($event->getFeatureAvId())) {
|
||||
|
||||
$feature
|
||||
->setDispatcher($event->getDispatcher())
|
||||
->setDispatcher($dispatcher)
|
||||
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
@@ -77,14 +77,14 @@ class FeatureAv extends BaseAction implements EventSubscriberInterface
|
||||
* Delete a product feature entry
|
||||
*
|
||||
* @param FeatureAvDeleteEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function delete(FeatureAvDeleteEvent $event)
|
||||
public function delete(FeatureAvDeleteEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
|
||||
if (null !== ($feature = FeatureAvQuery::create()->findPk($event->getFeatureAvId()))) {
|
||||
|
||||
$feature
|
||||
->setDispatcher($event->getDispatcher())
|
||||
->setDispatcher($dispatcher)
|
||||
->delete()
|
||||
;
|
||||
|
||||
@@ -96,10 +96,12 @@ class FeatureAv extends BaseAction implements EventSubscriberInterface
|
||||
* Changes position, selecting absolute ou relative change.
|
||||
*
|
||||
* @param UpdatePositionEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function updatePosition(UpdatePositionEvent $event)
|
||||
public function updatePosition(UpdatePositionEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$this->genericUpdatePosition(FeatureAvQuery::create(), $event);
|
||||
$this->genericUpdatePosition(FeatureAvQuery::create(), $event, $dispatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
175
core/lib/Thelia/Action/File.php
Normal file
175
core/lib/Thelia/Action/File.php
Normal file
@@ -0,0 +1,175 @@
|
||||
<?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 Thelia\Action;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||
use Thelia\Core\Event\File\FileCreateOrUpdateEvent;
|
||||
use Thelia\Core\Event\Product\ProductCloneEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Log\Tlog;
|
||||
use Thelia\Model\ProductDocument;
|
||||
use Thelia\Model\ProductDocumentI18n;
|
||||
use Thelia\Model\ProductDocumentI18nQuery;
|
||||
use Thelia\Model\ProductDocumentQuery;
|
||||
use Thelia\Model\ProductImage;
|
||||
use Thelia\Model\ProductImageI18nQuery;
|
||||
use Thelia\Model\ProductImageQuery;
|
||||
|
||||
/**
|
||||
* Class File
|
||||
*
|
||||
* @package Thelia\Action
|
||||
* @author Etienne Perriere <eperriere@openstudio.fr>
|
||||
*/
|
||||
class File extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
public function cloneFile(ProductCloneEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$originalProductId = $event->getOriginalProduct()->getId();
|
||||
$clonedProduct = $event->getClonedProduct();
|
||||
|
||||
foreach ($event->getTypes() as $type) {
|
||||
$originalProductFiles = [];
|
||||
|
||||
switch ($type) {
|
||||
case 'images':
|
||||
$originalProductFiles = ProductImageQuery::create()
|
||||
->findByProductId($originalProductId);
|
||||
break;
|
||||
|
||||
case 'documents':
|
||||
$originalProductFiles = ProductDocumentQuery::create()
|
||||
->findByProductId($originalProductId);
|
||||
break;
|
||||
}
|
||||
|
||||
// Set clone's files
|
||||
/** @var ProductDocument|ProductImage $originalProductFile */
|
||||
foreach ($originalProductFiles as $originalProductFile) {
|
||||
$srcPath = $originalProductFile->getUploadDir() . DS . $originalProductFile->getFile();
|
||||
|
||||
if (file_exists($srcPath)) {
|
||||
$ext = pathinfo($srcPath, PATHINFO_EXTENSION);
|
||||
|
||||
$clonedProductFile = [];
|
||||
|
||||
switch ($type) {
|
||||
case 'images':
|
||||
$fileName = $clonedProduct->getRef().'.'.$ext;
|
||||
$clonedProductFile = new ProductImage();
|
||||
break;
|
||||
|
||||
case 'documents':
|
||||
$fileName = pathinfo($originalProductFile->getFile(), PATHINFO_FILENAME).'-'.$clonedProduct->getRef().'.'.$ext;
|
||||
$clonedProductFile = new ProductDocument();
|
||||
break;
|
||||
}
|
||||
|
||||
// Copy a temporary file of the source file as it will be deleted by IMAGE_SAVE or DOCUMENT_SAVE event
|
||||
$srcTmp = $srcPath.'.tmp';
|
||||
copy($srcPath, $srcTmp);
|
||||
|
||||
// Get file mimeType
|
||||
$finfo = new \finfo();
|
||||
$fileMimeType = $finfo->file($srcPath, FILEINFO_MIME_TYPE);
|
||||
|
||||
// Get file event's parameters
|
||||
$clonedProductFile
|
||||
->setProductId($clonedProduct->getId())
|
||||
->setVisible($originalProductFile->getVisible())
|
||||
->setPosition($originalProductFile->getPosition())
|
||||
->setLocale($clonedProduct->getLocale())
|
||||
->setTitle($clonedProduct->getTitle());
|
||||
|
||||
$clonedProductCopiedFile = new UploadedFile($srcPath, $fileName, $fileMimeType, filesize($srcPath), null, true);
|
||||
|
||||
// Create and dispatch event
|
||||
$clonedProductCreateFileEvent = new FileCreateOrUpdateEvent($clonedProduct->getId());
|
||||
$clonedProductCreateFileEvent
|
||||
->setModel($clonedProductFile)
|
||||
->setUploadedFile($clonedProductCopiedFile)
|
||||
->setParentName($clonedProduct->getTitle());
|
||||
|
||||
$originalProductFileI18ns = [];
|
||||
|
||||
switch ($type) {
|
||||
case 'images':
|
||||
$dispatcher->dispatch(TheliaEvents::IMAGE_SAVE, $clonedProductCreateFileEvent);
|
||||
|
||||
// Get original product image I18n
|
||||
$originalProductFileI18ns = ProductImageI18nQuery::create()
|
||||
->findById($originalProductFile->getId());
|
||||
break;
|
||||
|
||||
case 'documents':
|
||||
$dispatcher->dispatch(TheliaEvents::DOCUMENT_SAVE, $clonedProductCreateFileEvent);
|
||||
|
||||
// Get original product document I18n
|
||||
$originalProductFileI18ns = ProductDocumentI18nQuery::create()
|
||||
->findById($originalProductFile->getId());
|
||||
break;
|
||||
}
|
||||
|
||||
// Set temporary source file as original one
|
||||
rename($srcTmp, $srcPath);
|
||||
|
||||
// Clone file's I18n
|
||||
$this->cloneFileI18n($originalProductFileI18ns, $clonedProductFile, $type, $event, $dispatcher);
|
||||
} else {
|
||||
Tlog::getInstance()->addWarning("Failed to find media file $srcPath");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function cloneFileI18n($originalProductFileI18ns, $clonedProductFile, $type, ProductCloneEvent $event, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
// Set clone files I18n
|
||||
/** @var ProductDocumentI18n $originalProductFileI18n */
|
||||
foreach ($originalProductFileI18ns as $originalProductFileI18n) {
|
||||
// Update file with current I18n info. Update or create I18n according to existing or absent Locale in DB
|
||||
$clonedProductFile
|
||||
->setLocale($originalProductFileI18n->getLocale())
|
||||
->setTitle($originalProductFileI18n->getTitle())
|
||||
->setDescription($originalProductFileI18n->getDescription())
|
||||
->setChapo($originalProductFileI18n->getChapo())
|
||||
->setPostscriptum($originalProductFileI18n->getPostscriptum());
|
||||
|
||||
// Create and dispatch event
|
||||
$clonedProductUpdateFileEvent = new FileCreateOrUpdateEvent($event->getClonedProduct()->getId());
|
||||
$clonedProductUpdateFileEvent->setModel($clonedProductFile);
|
||||
|
||||
switch ($type) {
|
||||
case 'images':
|
||||
$dispatcher->dispatch(TheliaEvents::IMAGE_UPDATE, $clonedProductUpdateFileEvent);
|
||||
break;
|
||||
|
||||
case 'documents':
|
||||
$dispatcher->dispatch(TheliaEvents::DOCUMENT_UPDATE, $clonedProductUpdateFileEvent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::FILE_CLONE => array("cloneFile", 128)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,12 @@
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Thelia\Action;
|
||||
|
||||
use Propel\Runtime\Propel;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Thelia\Core\Event\File\FileDeleteEvent;
|
||||
use Thelia\Core\Event\Folder\FolderCreateEvent;
|
||||
use Thelia\Core\Event\Folder\FolderDeleteEvent;
|
||||
use Thelia\Core\Event\Folder\FolderToggleVisibilityEvent;
|
||||
@@ -19,21 +24,24 @@ use Thelia\Core\Event\Folder\FolderUpdateEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\Event\UpdatePositionEvent;
|
||||
use Thelia\Core\Event\UpdateSeoEvent;
|
||||
use Thelia\Core\Event\ViewCheckEvent;
|
||||
use Thelia\Model\FolderDocumentQuery;
|
||||
use Thelia\Model\FolderImageQuery;
|
||||
use Thelia\Model\FolderQuery;
|
||||
use Thelia\Model\Folder as FolderModel;
|
||||
use Thelia\Model\Map\FolderTableMap;
|
||||
|
||||
/**
|
||||
* Class Folder
|
||||
* @package Thelia\Action
|
||||
* @author Manuel Raynaud <mraynaud@openstudio.fr>
|
||||
* @author Manuel Raynaud <manu@raynaud.io>
|
||||
*/
|
||||
class Folder extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
public function update(FolderUpdateEvent $event)
|
||||
public function update(FolderUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
|
||||
if (null !== $folder = FolderQuery::create()->findPk($event->getFolderId())) {
|
||||
$folder->setDispatcher($event->getDispatcher());
|
||||
$folder->setDispatcher($dispatcher);
|
||||
|
||||
$folder
|
||||
->setParent($event->getParent())
|
||||
@@ -53,32 +61,60 @@ class Folder extends BaseAction implements EventSubscriberInterface
|
||||
/**
|
||||
* Change Folder SEO
|
||||
*
|
||||
* @param \Thelia\Core\Event\UpdateSeoEvent $event
|
||||
*
|
||||
* @return mixed
|
||||
* @param UpdateSeoEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
* @return Object
|
||||
*/
|
||||
public function updateSeo(UpdateSeoEvent $event)
|
||||
public function updateSeo(UpdateSeoEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
return $this->genericUpdateSeo(FolderQuery::create(), $event);
|
||||
return $this->genericUpdateSeo(FolderQuery::create(), $event, $dispatcher);
|
||||
}
|
||||
|
||||
public function delete(FolderDeleteEvent $event)
|
||||
public function delete(FolderDeleteEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $folder = FolderQuery::create()->findPk($event->getFolderId())) {
|
||||
$folder->setDispatcher($event->getDispatcher())
|
||||
->delete();
|
||||
$con = Propel::getWriteConnection(FolderTableMap::DATABASE_NAME);
|
||||
$con->beginTransaction();
|
||||
|
||||
$event->setFolder($folder);
|
||||
try {
|
||||
$fileList = ['images' => [], 'documentList' => []];
|
||||
|
||||
// Get folder's files to delete after folder deletion
|
||||
$fileList['images']['list'] = FolderImageQuery::create()
|
||||
->findByFolderId($event->getFolderId());
|
||||
$fileList['images']['type'] = TheliaEvents::IMAGE_DELETE;
|
||||
|
||||
$fileList['documentList']['list'] = FolderDocumentQuery::create()
|
||||
->findByFolderId($event->getFolderId());
|
||||
$fileList['documentList']['type'] = TheliaEvents::DOCUMENT_DELETE;
|
||||
|
||||
// Delete folder
|
||||
$folder->setDispatcher($dispatcher)
|
||||
->delete($con);
|
||||
|
||||
$event->setFolder($folder);
|
||||
|
||||
// Dispatch delete folder's files event
|
||||
foreach ($fileList as $fileTypeList) {
|
||||
foreach ($fileTypeList['list'] as $fileToDelete) {
|
||||
$fileDeleteEvent = new FileDeleteEvent($fileToDelete);
|
||||
$dispatcher->dispatch($fileTypeList['type'], $fileDeleteEvent);
|
||||
}
|
||||
}
|
||||
|
||||
$con->commit();
|
||||
} catch (\Exception $e) {
|
||||
$con->rollback();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param FolderCreateEvent $event
|
||||
*/
|
||||
public function create(FolderCreateEvent $event)
|
||||
public function create(FolderCreateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$folder = new FolderModel();
|
||||
$folder->setDispatcher($event->getDispatcher());
|
||||
$folder->setDispatcher($dispatcher);
|
||||
|
||||
$folder
|
||||
->setParent($event->getParent())
|
||||
@@ -90,23 +126,22 @@ class Folder extends BaseAction implements EventSubscriberInterface
|
||||
$event->setFolder($folder);
|
||||
}
|
||||
|
||||
public function toggleVisibility(FolderToggleVisibilityEvent $event)
|
||||
public function toggleVisibility(FolderToggleVisibilityEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$folder = $event->getFolder();
|
||||
|
||||
$folder
|
||||
->setDispatcher($event->getDispatcher())
|
||||
->setDispatcher($dispatcher)
|
||||
->setVisible(!$folder->getVisible())
|
||||
->save();
|
||||
|
||||
$event->setFolder($folder);
|
||||
|
||||
}
|
||||
|
||||
public function updatePosition(UpdatePositionEvent $event)
|
||||
public function updatePosition(UpdatePositionEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $folder = FolderQuery::create()->findPk($event->getObjectId())) {
|
||||
$folder->setDispatcher($event->getDispatcher());
|
||||
$folder->setDispatcher($dispatcher);
|
||||
|
||||
switch ($event->getMode()) {
|
||||
case UpdatePositionEvent::POSITION_ABSOLUTE:
|
||||
@@ -123,24 +158,37 @@ class Folder extends BaseAction implements EventSubscriberInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of event names this subscriber wants to listen to.
|
||||
* Check if is a folder view and if folder_id is visible
|
||||
*
|
||||
* The array keys are event names and the value can be:
|
||||
*
|
||||
* * The method name to call (priority defaults to 0)
|
||||
* * An array composed of the method name to call and the priority
|
||||
* * An array of arrays composed of the method names to call and respective
|
||||
* priorities, or 0 if unset
|
||||
*
|
||||
* For instance:
|
||||
*
|
||||
* * array('eventName' => 'methodName')
|
||||
* * array('eventName' => array('methodName', $priority))
|
||||
* * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
|
||||
*
|
||||
* @return array The event names to listen to
|
||||
*
|
||||
* @api
|
||||
* @param ViewCheckEvent $event
|
||||
* @param string $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function viewCheck(ViewCheckEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if ($event->getView() == 'folder') {
|
||||
$folder = FolderQuery::create()
|
||||
->filterById($event->getViewId())
|
||||
->filterByVisible(1)
|
||||
->count();
|
||||
|
||||
if ($folder == 0) {
|
||||
$dispatcher->dispatch(TheliaEvents::VIEW_FOLDER_ID_NOT_VISIBLE, $event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ViewCheckEvent $event
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public function viewFolderIdNotVisible(ViewCheckEvent $event)
|
||||
{
|
||||
throw new NotFoundHttpException();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
@@ -151,7 +199,10 @@ class Folder extends BaseAction implements EventSubscriberInterface
|
||||
TheliaEvents::FOLDER_TOGGLE_VISIBILITY => array("toggleVisibility", 128),
|
||||
|
||||
TheliaEvents::FOLDER_UPDATE_POSITION => array("updatePosition", 128),
|
||||
TheliaEvents::FOLDER_UPDATE_SEO => array('updateSeo', 128)
|
||||
TheliaEvents::FOLDER_UPDATE_SEO => array('updateSeo', 128),
|
||||
|
||||
TheliaEvents::VIEW_CHECK => array('viewCheck', 128),
|
||||
TheliaEvents::VIEW_FOLDER_ID_NOT_VISIBLE => array('viewFolderIdNotVisible', 128),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
168
core/lib/Thelia/Action/Hook.php
Normal file
168
core/lib/Thelia/Action/Hook.php
Normal file
@@ -0,0 +1,168 @@
|
||||
<?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 Thelia\Action;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Core\Event\Cache\CacheEvent;
|
||||
use Thelia\Core\Event\Hook\HookCreateAllEvent;
|
||||
use Thelia\Core\Event\Hook\HookCreateEvent;
|
||||
use Thelia\Core\Event\Hook\HookDeactivationEvent;
|
||||
use Thelia\Core\Event\Hook\HookDeleteEvent;
|
||||
use Thelia\Core\Event\Hook\HookToggleActivationEvent;
|
||||
use Thelia\Core\Event\Hook\HookToggleNativeEvent;
|
||||
use Thelia\Core\Event\Hook\HookUpdateEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Model\Hook as HookModel;
|
||||
use Thelia\Model\HookQuery;
|
||||
|
||||
/**
|
||||
* Class HookAction
|
||||
* @package Thelia\Action
|
||||
* @author Julien Chanséaume <jchanseaume@openstudio.fr>
|
||||
*/
|
||||
class Hook extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
/** @var string */
|
||||
protected $cacheDir;
|
||||
|
||||
public function __construct($cacheDir)
|
||||
{
|
||||
$this->cacheDir = $cacheDir;
|
||||
}
|
||||
|
||||
public function create(HookCreateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$hook = new HookModel();
|
||||
|
||||
$hook
|
||||
->setLocale($event->getLocale())
|
||||
->setCode($event->getCode())
|
||||
->setType($event->getType())
|
||||
->setNative($event->getNative())
|
||||
->setActivate($event->getActive())
|
||||
->setTitle($event->getTitle())
|
||||
->save();
|
||||
|
||||
$event->setHook($hook);
|
||||
|
||||
$this->cacheClear($dispatcher);
|
||||
}
|
||||
|
||||
public function update(HookUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $hook = HookQuery::create()->findPk($event->getHookId())) {
|
||||
$hook
|
||||
->setLocale($event->getLocale())
|
||||
->setCode($event->getCode())
|
||||
->setType($event->getType())
|
||||
->setNative($event->getNative())
|
||||
->setActivate($event->getActive())
|
||||
->setBlock($event->getBlock())
|
||||
->setByModule($event->getByModule())
|
||||
->setTitle($event->getTitle())
|
||||
->setChapo($event->getChapo())
|
||||
->setDescription($event->getDescription())
|
||||
->save();
|
||||
|
||||
$event->setHook($hook);
|
||||
$this->cacheClear($dispatcher);
|
||||
}
|
||||
}
|
||||
|
||||
public function delete(HookDeleteEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $hook = HookQuery::create()->findPk($event->getHookId())) {
|
||||
$hook->delete();
|
||||
$event->setHook($hook);
|
||||
|
||||
$this->cacheClear($dispatcher);
|
||||
}
|
||||
}
|
||||
|
||||
public function createAll(HookCreateAllEvent $event)
|
||||
{
|
||||
$hook = new HookModel();
|
||||
|
||||
$hook
|
||||
->setLocale($event->getLocale())
|
||||
->setCode($event->getCode())
|
||||
->setType($event->getType())
|
||||
->setNative($event->getNative())
|
||||
->setActivate($event->getActive())
|
||||
->setBlock($event->getBlock())
|
||||
->setByModule($event->getByModule())
|
||||
->setTitle($event->getTitle())
|
||||
->setChapo($event->getChapo())
|
||||
->setDescription($event->getDescription())
|
||||
->save();
|
||||
|
||||
$event->setHook($hook);
|
||||
}
|
||||
|
||||
public function deactivation(HookDeactivationEvent $event)
|
||||
{
|
||||
if (null !== $hook = HookQuery::create()->findPk($event->getHookId())) {
|
||||
$hook
|
||||
->setActivate(false)
|
||||
->save();
|
||||
$event->setHook($hook);
|
||||
}
|
||||
}
|
||||
|
||||
public function toggleNative(HookToggleNativeEvent $event)
|
||||
{
|
||||
if (null !== $hook = HookQuery::create()->findPk($event->getHookId())) {
|
||||
$hook
|
||||
->setNative(!$hook->getNative())
|
||||
->save();
|
||||
$event->setHook($hook);
|
||||
}
|
||||
}
|
||||
|
||||
public function toggleActivation(HookToggleActivationEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $hook = HookQuery::create()->findPk($event->getHookId())) {
|
||||
$hook
|
||||
->setActivate(!$hook->getActivate())
|
||||
->save();
|
||||
$event->setHook($hook);
|
||||
|
||||
$this->cacheClear($dispatcher);
|
||||
}
|
||||
}
|
||||
|
||||
protected function cacheClear(EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$cacheEvent = new CacheEvent($this->cacheDir);
|
||||
|
||||
$dispatcher->dispatch(TheliaEvents::CACHE_CLEAR, $cacheEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::HOOK_CREATE => array('create', 128),
|
||||
TheliaEvents::HOOK_UPDATE => array('update', 128),
|
||||
TheliaEvents::HOOK_DELETE => array('delete', 128),
|
||||
TheliaEvents::HOOK_TOGGLE_ACTIVATION => array('toggleActivation', 128),
|
||||
TheliaEvents::HOOK_TOGGLE_NATIVE => array('toggleNative', 128),
|
||||
TheliaEvents::HOOK_CREATE_ALL => array('createAll', 128),
|
||||
TheliaEvents::HOOK_DEACTIVATION => array('deactivation', 128),
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -13,32 +13,30 @@
|
||||
namespace Thelia\Action;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Core\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
|
||||
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException as BaseHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Symfony\Component\HttpKernel\KernelEvents;
|
||||
use Thelia\Core\HttpFoundation\Response;
|
||||
use Thelia\Core\Template\ParserInterface;
|
||||
use Thelia\Exception\AdminAccessDenied;
|
||||
use Thelia\Model\ConfigQuery;
|
||||
use Thelia\Core\Template\TemplateHelper;
|
||||
|
||||
/**
|
||||
*
|
||||
* Class HttpException
|
||||
* @package Thelia\Action
|
||||
* @author Etienne Roudeix <eroudeix@openstudio.fr>
|
||||
* @author Manuel Raynaud <manu@raynaud.io>
|
||||
*/
|
||||
class HttpException extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
/**
|
||||
* @var ParserInterface
|
||||
*/
|
||||
/** @var ParserInterface */
|
||||
protected $parser;
|
||||
|
||||
public function __construct(ParserInterface $parser)
|
||||
{
|
||||
$this->parser = $parser;
|
||||
$this->parser = $parser;
|
||||
}
|
||||
|
||||
public function checkHttpException(GetResponseForExceptionEvent $event)
|
||||
@@ -48,29 +46,33 @@ class HttpException extends BaseAction implements EventSubscriberInterface
|
||||
$this->display404($event);
|
||||
}
|
||||
|
||||
if ($exception instanceof AccessDeniedHttpException) {
|
||||
$this->display403($event);
|
||||
}
|
||||
|
||||
if ($exception instanceof AdminAccessDenied) {
|
||||
$this->displayAdminGeneralError($event);
|
||||
}
|
||||
|
||||
if ($exception instanceof BaseHttpException && null === $event->getResponse()) {
|
||||
$this->displayException($event);
|
||||
}
|
||||
}
|
||||
|
||||
protected function displayAdminGeneralError(GetResponseForExceptionEvent $event)
|
||||
{
|
||||
// Define the template thant shoud be used
|
||||
$this->parser->setTemplateDefinition(TemplateHelper::getInstance()->getActiveAdminTemplate());
|
||||
$this->parser->setTemplateDefinition(
|
||||
$this->parser->getTemplateHelper()->getActiveAdminTemplate()
|
||||
);
|
||||
|
||||
$message = $event->getException()->getMessage();
|
||||
|
||||
$response = Response::create(
|
||||
$this->parser->render('general_error.html',
|
||||
$this->parser->render(
|
||||
'general_error.html',
|
||||
array(
|
||||
"error_message" => $message
|
||||
)),
|
||||
)
|
||||
),
|
||||
403
|
||||
) ;
|
||||
);
|
||||
|
||||
$event->setResponse($response);
|
||||
}
|
||||
@@ -78,42 +80,35 @@ class HttpException extends BaseAction implements EventSubscriberInterface
|
||||
protected function display404(GetResponseForExceptionEvent $event)
|
||||
{
|
||||
// Define the template thant shoud be used
|
||||
$this->parser->setTemplateDefinition(TemplateHelper::getInstance()->getActiveFrontTemplate());
|
||||
$this->parser->setTemplateDefinition(
|
||||
$this->parser->getTemplateHelper()->getActiveFrontTemplate()
|
||||
);
|
||||
|
||||
$response = new Response($this->parser->render(ConfigQuery::getPageNotFoundView()), 404);
|
||||
|
||||
$event->setResponse($response);
|
||||
}
|
||||
|
||||
protected function display403(GetResponseForExceptionEvent $event)
|
||||
protected function displayException(GetResponseForExceptionEvent $event)
|
||||
{
|
||||
$event->setResponse(new Response("You don't have access to this resources", 403));
|
||||
/** @var \Symfony\Component\HttpKernel\Exception\HttpException $exception */
|
||||
$exception = $event->getException();
|
||||
$event->setResponse(
|
||||
new Response(
|
||||
$exception->getMessage(),
|
||||
$exception->getStatusCode(),
|
||||
$exception->getHeaders()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of event names this subscriber wants to listen to.
|
||||
*
|
||||
* The array keys are event names and the value can be:
|
||||
*
|
||||
* * The method name to call (priority defaults to 0)
|
||||
* * An array composed of the method name to call and the priority
|
||||
* * An array of arrays composed of the method names to call and respective
|
||||
* priorities, or 0 if unset
|
||||
*
|
||||
* For instance:
|
||||
*
|
||||
* * array('eventName' => 'methodName')
|
||||
* * array('eventName' => array('methodName', $priority))
|
||||
* * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
|
||||
*
|
||||
* @return array The event names to listen to
|
||||
*
|
||||
* @api
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
KernelEvents::EXCEPTION => array("checkHttpException", 128),
|
||||
KernelEvents::EXCEPTION => ["checkHttpException", 128],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,16 +13,21 @@
|
||||
namespace Thelia\Action;
|
||||
|
||||
use Imagine\Image\Box;
|
||||
use Imagine\Image\Color;
|
||||
use Imagine\Image\ImageInterface;
|
||||
use Imagine\Image\ImagineInterface;
|
||||
use Imagine\Image\Palette\RGB;
|
||||
use Imagine\Image\Point;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Core\Event\Image\ImageEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Exception\ImageException;
|
||||
use Thelia\Files\FileManager;
|
||||
use Thelia\Model\ConfigQuery;
|
||||
use Thelia\Tools\URL;
|
||||
use Imagine\Imagick\Imagine as ImagickImagine;
|
||||
use Imagine\Gmagick\Imagine as GmagickImagine;
|
||||
use Imagine\Gd\Imagine;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -70,7 +75,7 @@ class Image extends BaseCachedFile implements EventSubscriberInterface
|
||||
*/
|
||||
protected function getCacheDirFromWebRoot()
|
||||
{
|
||||
return ConfigQuery::read('image_cache_dir_from_web_root', 'cache');
|
||||
return ConfigQuery::read('image_cache_dir_from_web_root', 'cache' . DS . 'images');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,13 +88,14 @@ class Image extends BaseCachedFile implements EventSubscriberInterface
|
||||
* This method updates the cache_file_path and file_url attributes of the event
|
||||
*
|
||||
* @param ImageEvent $event
|
||||
* @param string $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*
|
||||
* @throws \Thelia\Exception\ImageException
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function processImage(ImageEvent $event)
|
||||
public function processImage(ImageEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
|
||||
$subdir = $event->getCacheSubdirectory();
|
||||
$source_file = $event->getSourceFilepath();
|
||||
|
||||
@@ -103,23 +109,22 @@ class Image extends BaseCachedFile implements EventSubscriberInterface
|
||||
$originalImagePathInCache = $this->getCacheFilePath($subdir, $source_file, true);
|
||||
|
||||
if (! file_exists($cacheFilePath)) {
|
||||
|
||||
if (! file_exists($source_file)) {
|
||||
throw new ImageException(sprintf("Source image file %s does not exists.", $source_file));
|
||||
}
|
||||
|
||||
// Create a chached version of the original image in the web space, if not exists
|
||||
// Create a cached version of the original image in the web space, if not exists
|
||||
|
||||
if (! file_exists($originalImagePathInCache)) {
|
||||
|
||||
$mode = ConfigQuery::read('original_image_delivery_mode', 'symlink');
|
||||
|
||||
if ($mode == 'symlink') {
|
||||
if (false == symlink($source_file, $originalImagePathInCache)) {
|
||||
throw new ImageException(sprintf("Failed to create symbolic link for %s in %s image cache directory", basename($source_file), $subdir));
|
||||
if (false === symlink($source_file, $originalImagePathInCache)) {
|
||||
throw new ImageException(sprintf("Failed to create symbolic link for %s in %s image cache directory", basename($source_file), $subdir));
|
||||
}
|
||||
} else {// mode = 'copy'
|
||||
if (false == @copy($source_file, $originalImagePathInCache)) {
|
||||
} else {
|
||||
// mode = 'copy'
|
||||
if (false === @copy($source_file, $originalImagePathInCache)) {
|
||||
throw new ImageException(sprintf("Failed to copy %s in %s image cache directory", basename($source_file), $subdir));
|
||||
}
|
||||
}
|
||||
@@ -127,97 +132,109 @@ class Image extends BaseCachedFile implements EventSubscriberInterface
|
||||
|
||||
// Process image only if we have some transformations to do.
|
||||
if (! $event->isOriginalImage()) {
|
||||
|
||||
// We have to process the image.
|
||||
$imagine = $this->createImagineInstance();
|
||||
|
||||
$image = $imagine->open($source_file);
|
||||
|
||||
if ($image) {
|
||||
|
||||
// Allow image pre-processing (watermarging, or other stuff...)
|
||||
$event->setImageObject($image);
|
||||
$event->getDispatcher()->dispatch(TheliaEvents::IMAGE_PREPROCESSING, $event);
|
||||
$dispatcher->dispatch(TheliaEvents::IMAGE_PREPROCESSING, $event);
|
||||
$image = $event->getImageObject();
|
||||
|
||||
$background_color = $event->getBackgroundColor();
|
||||
|
||||
$palette = new RGB();
|
||||
|
||||
if ($background_color != null) {
|
||||
$bg_color = new Color($background_color);
|
||||
} else
|
||||
$bg_color = null;
|
||||
$bg_color = $palette->color($background_color);
|
||||
} else {
|
||||
// Define a fully transparent white background color
|
||||
$bg_color = $palette->color('fff', 0);
|
||||
}
|
||||
|
||||
// Apply resize
|
||||
$image = $this->applyResize($imagine, $image, $event->getWidth(), $event->getHeight(), $event->getResizeMode(), $bg_color);
|
||||
$image = $this->applyResize(
|
||||
$imagine,
|
||||
$image,
|
||||
$event->getWidth(),
|
||||
$event->getHeight(),
|
||||
$event->getResizeMode(),
|
||||
$bg_color,
|
||||
$event->getAllowZoom()
|
||||
);
|
||||
|
||||
// Rotate if required
|
||||
$rotation = intval($event->getRotation());
|
||||
|
||||
if ($rotation != 0)
|
||||
if ($rotation != 0) {
|
||||
$image->rotate($rotation, $bg_color);
|
||||
}
|
||||
|
||||
// Flip
|
||||
// Process each effects
|
||||
foreach ($event->getEffects() as $effect) {
|
||||
|
||||
$effect = trim(strtolower($effect));
|
||||
|
||||
$params = explode(':', $effect);
|
||||
|
||||
switch ($params[0]) {
|
||||
|
||||
case 'greyscale':
|
||||
case 'grayscale':
|
||||
$image->effects()->grayscale();
|
||||
break;
|
||||
case 'greyscale':
|
||||
case 'grayscale':
|
||||
$image->effects()->grayscale();
|
||||
break;
|
||||
|
||||
case 'negative':
|
||||
$image->effects()->negative();
|
||||
break;
|
||||
case 'negative':
|
||||
$image->effects()->negative();
|
||||
break;
|
||||
|
||||
case 'horizontal_flip':
|
||||
case 'hflip':
|
||||
$image->flipHorizontally();
|
||||
break;
|
||||
case 'horizontal_flip':
|
||||
case 'hflip':
|
||||
$image->flipHorizontally();
|
||||
break;
|
||||
|
||||
case 'vertical_flip':
|
||||
case 'vflip':
|
||||
$image-> flipVertically();
|
||||
break;
|
||||
case 'vertical_flip':
|
||||
case 'vflip':
|
||||
$image->flipVertically();
|
||||
break;
|
||||
|
||||
case 'gamma':
|
||||
// Syntax: gamma:value. Exemple: gamma:0.7
|
||||
if (isset($params[1])) {
|
||||
$gamma = floatval($params[1]);
|
||||
case 'gamma':
|
||||
// Syntax: gamma:value. Exemple: gamma:0.7
|
||||
if (isset($params[1])) {
|
||||
$gamma = floatval($params[1]);
|
||||
|
||||
$image->effects()->gamma($gamma);
|
||||
}
|
||||
break;
|
||||
$image->effects()->gamma($gamma);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'colorize':
|
||||
// Syntax: colorize:couleur. Exemple: colorize:#ff00cc
|
||||
if (isset($params[1])) {
|
||||
$the_color = new Color($params[1]);
|
||||
case 'colorize':
|
||||
// Syntax: colorize:couleur. Exemple: colorize:#ff00cc
|
||||
if (isset($params[1])) {
|
||||
$the_color = $palette->color($params[1]);
|
||||
|
||||
$image->effects()->colorize($the_color);
|
||||
}
|
||||
break;
|
||||
$image->effects()->colorize($the_color);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$quality = $event->getQuality();
|
||||
|
||||
if (is_null($quality)) $quality = ConfigQuery::read('default_image_quality_percent', 75);
|
||||
if (is_null($quality)) {
|
||||
$quality = ConfigQuery::read('default_images_quality_percent', 75);
|
||||
}
|
||||
|
||||
// Allow image post-processing (watermarging, or other stuff...)
|
||||
$event->setImageObject($image);
|
||||
$event->getDispatcher()->dispatch(TheliaEvents::IMAGE_POSTPROCESSING, $event);
|
||||
$dispatcher->dispatch(TheliaEvents::IMAGE_POSTPROCESSING, $event);
|
||||
$image = $event->getImageObject();
|
||||
|
||||
$image->save(
|
||||
$cacheFilePath,
|
||||
array('quality' => $quality)
|
||||
);
|
||||
$cacheFilePath,
|
||||
array('quality' => $quality)
|
||||
);
|
||||
} else {
|
||||
throw new ImageException(sprintf("Source file %s cannot be opened.", basename($source_file)));
|
||||
}
|
||||
@@ -248,23 +265,35 @@ class Image extends BaseCachedFile implements EventSubscriberInterface
|
||||
* @param int $dest_height the required height
|
||||
* @param int $resize_mode the resize mode (crop / bands / keep image ratio)p
|
||||
* @param string $bg_color the bg_color used for bands
|
||||
* @param bool $allow_zoom if true, image may be zoomed to matchrequired size. If false, image is not zoomed.
|
||||
* @return ImageInterface the resized image.
|
||||
*/
|
||||
protected function applyResize(ImagineInterface $imagine, ImageInterface $image, $dest_width, $dest_height, $resize_mode, $bg_color)
|
||||
{
|
||||
protected function applyResize(
|
||||
ImagineInterface $imagine,
|
||||
ImageInterface $image,
|
||||
$dest_width,
|
||||
$dest_height,
|
||||
$resize_mode,
|
||||
$bg_color,
|
||||
$allow_zoom = false
|
||||
) {
|
||||
if (! (is_null($dest_width) && is_null($dest_height))) {
|
||||
|
||||
$width_orig = $image->getSize()->getWidth();
|
||||
$height_orig = $image->getSize()->getHeight();
|
||||
|
||||
if (is_null($dest_width))
|
||||
$dest_width = $width_orig;
|
||||
$ratio = $width_orig / $height_orig;
|
||||
|
||||
if (is_null($dest_height))
|
||||
$dest_height = $height_orig;
|
||||
if (is_null($dest_width)) {
|
||||
$dest_width = $dest_height * $ratio;
|
||||
}
|
||||
|
||||
if (is_null($resize_mode))
|
||||
if (is_null($dest_height)) {
|
||||
$dest_height = $dest_width / $ratio;
|
||||
}
|
||||
|
||||
if (is_null($resize_mode)) {
|
||||
$resize_mode = self::KEEP_IMAGE_RATIO;
|
||||
}
|
||||
|
||||
$width_diff = $dest_width / $width_orig;
|
||||
$height_diff = $dest_height / $height_orig;
|
||||
@@ -272,45 +301,66 @@ class Image extends BaseCachedFile implements EventSubscriberInterface
|
||||
$delta_x = $delta_y = $border_width = $border_height = 0;
|
||||
|
||||
if ($width_diff > 1 && $height_diff > 1) {
|
||||
// Set the default final size. If zoom is allowed, we will get the required
|
||||
// image dimension. Otherwise, the final image may be smaller than required.
|
||||
if ($allow_zoom) {
|
||||
$resize_width = $dest_width;
|
||||
$resize_height = $dest_height;
|
||||
} else {
|
||||
$resize_width = $width_orig;
|
||||
$resize_height = $height_orig;
|
||||
}
|
||||
|
||||
$next_width = $width_orig;
|
||||
$next_height = $height_orig;
|
||||
|
||||
$dest_width = ($resize_mode == self::EXACT_RATIO_WITH_BORDERS ? $dest_width : $next_width);
|
||||
$dest_height = ($resize_mode == self::EXACT_RATIO_WITH_BORDERS ? $dest_height : $next_height);
|
||||
// When cropping, be sure to always generate an image which is
|
||||
// not smaller than the required size, zooming it if required.
|
||||
if ($resize_mode == self::EXACT_RATIO_WITH_CROP) {
|
||||
if ($allow_zoom) {
|
||||
if ($width_diff > $height_diff) {
|
||||
$resize_width = $dest_width;
|
||||
$resize_height = intval($height_orig * $dest_width / $width_orig);
|
||||
$delta_y = ($resize_height - $dest_height) / 2;
|
||||
} else {
|
||||
$resize_height = $dest_height;
|
||||
$resize_width = intval(($width_orig * $resize_height) / $height_orig);
|
||||
$delta_x = ($resize_width - $dest_width) / 2;
|
||||
}
|
||||
} else {
|
||||
// No zoom : final image may be smaller than the required size.
|
||||
$dest_width = $resize_width;
|
||||
$dest_height = $resize_height;
|
||||
}
|
||||
}
|
||||
} elseif ($width_diff > $height_diff) {
|
||||
// Image height > image width
|
||||
|
||||
$next_height = $dest_height;
|
||||
$next_width = intval(($width_orig * $next_height) / $height_orig);
|
||||
$resize_height = $dest_height;
|
||||
$resize_width = intval(($width_orig * $resize_height) / $height_orig);
|
||||
|
||||
if ($resize_mode == self::EXACT_RATIO_WITH_CROP) {
|
||||
$next_width = $dest_width;
|
||||
$next_height = intval($height_orig * $dest_width / $width_orig);
|
||||
$delta_y = ($next_height - $dest_height) / 2;
|
||||
$resize_width = $dest_width;
|
||||
$resize_height = intval($height_orig * $dest_width / $width_orig);
|
||||
$delta_y = ($resize_height - $dest_height) / 2;
|
||||
} elseif ($resize_mode != self::EXACT_RATIO_WITH_BORDERS) {
|
||||
$dest_width = $next_width;
|
||||
$dest_width = $resize_width;
|
||||
}
|
||||
} else {
|
||||
// Image width > image height
|
||||
$next_width = $dest_width;
|
||||
$next_height = intval($height_orig * $dest_width / $width_orig);
|
||||
$resize_width = $dest_width;
|
||||
$resize_height = intval($height_orig * $dest_width / $width_orig);
|
||||
|
||||
if ($resize_mode == self::EXACT_RATIO_WITH_CROP) {
|
||||
$next_height = $dest_height;
|
||||
$next_width = intval(($width_orig * $next_height) / $height_orig);
|
||||
$delta_x = ($next_width - $dest_width) / 2;
|
||||
$resize_height = $dest_height;
|
||||
$resize_width = intval(($width_orig * $resize_height) / $height_orig);
|
||||
$delta_x = ($resize_width - $dest_width) / 2;
|
||||
} elseif ($resize_mode != self::EXACT_RATIO_WITH_BORDERS) {
|
||||
$dest_height = $next_height;
|
||||
$dest_height = $resize_height;
|
||||
}
|
||||
}
|
||||
|
||||
$image->resize(new Box($next_width, $next_height));
|
||||
$image->resize(new Box($resize_width, $resize_height));
|
||||
|
||||
if ($resize_mode == self::EXACT_RATIO_WITH_BORDERS) {
|
||||
|
||||
$border_width = intval(($dest_width - $next_width) / 2);
|
||||
$border_height = intval(($dest_height - $next_height) / 2);
|
||||
$border_width = intval(($dest_width - $resize_width) / 2);
|
||||
$border_height = intval(($dest_height - $resize_height) / 2);
|
||||
|
||||
$canvas = new Box($dest_width, $dest_height);
|
||||
|
||||
@@ -337,22 +387,25 @@ class Image extends BaseCachedFile implements EventSubscriberInterface
|
||||
$driver = ConfigQuery::read("imagine_graphic_driver", "gd");
|
||||
|
||||
switch ($driver) {
|
||||
case 'imagik':
|
||||
$image = new \Imagine\Imagick\Imagine();
|
||||
break;
|
||||
case 'imagick':
|
||||
$image = new ImagickImagine();
|
||||
break;
|
||||
|
||||
case 'gmagick':
|
||||
$image = new \Imagine\Gmagick\Imagine();
|
||||
break;
|
||||
case 'gmagick':
|
||||
$image = new GmagickImagine();
|
||||
break;
|
||||
|
||||
case 'gd':
|
||||
default:
|
||||
$image = new \Imagine\Gd\Imagine();
|
||||
case 'gd':
|
||||
default:
|
||||
$image = new Imagine();
|
||||
}
|
||||
|
||||
return $image;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
@@ -364,6 +417,7 @@ class Image extends BaseCachedFile implements EventSubscriberInterface
|
||||
TheliaEvents::IMAGE_SAVE => array("saveFile", 128),
|
||||
TheliaEvents::IMAGE_UPDATE => array("updateFile", 128),
|
||||
TheliaEvents::IMAGE_UPDATE_POSITION => array("updatePosition", 128),
|
||||
TheliaEvents::IMAGE_TOGGLE_VISIBILITY => array("toggleVisibility", 128),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,77 +11,69 @@
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Thelia\Action;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Core\Event\Cache\CacheEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\Event\UpdatePositionEvent;
|
||||
use Thelia\Handler\ImportHandler;
|
||||
use Thelia\Model\ImportCategoryQuery;
|
||||
use Thelia\Model\ImportQuery;
|
||||
|
||||
/**
|
||||
* Class Import
|
||||
* @package Thelia\Action
|
||||
* @author Benjamin Perche <bperche@openstudio.fr>
|
||||
* @author Jérôme Billiras <jbilliras@openstudio.fr>
|
||||
*/
|
||||
class Import extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
protected $environment;
|
||||
/**
|
||||
* @var \Thelia\Handler\ImportHandler The import handler
|
||||
*/
|
||||
protected $handler;
|
||||
|
||||
public function __construct($environment)
|
||||
/**
|
||||
* @param \Thelia\Handler\ImportHandler $importHandler The import handler
|
||||
*/
|
||||
public function __construct(ImportHandler $importHandler)
|
||||
{
|
||||
$this->environment = $environment;
|
||||
$this->handler = $importHandler;
|
||||
}
|
||||
|
||||
public function changeCategoryPosition(UpdatePositionEvent $event)
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
$this->genericUpdatePosition(new ImportCategoryQuery(), $event);
|
||||
|
||||
$this->cacheClear($event->getDispatcher());
|
||||
}
|
||||
|
||||
public function changeImportPosition(UpdatePositionEvent $event)
|
||||
{
|
||||
$this->genericUpdatePosition(new ImportQuery(), $event);
|
||||
|
||||
$this->cacheClear($event->getDispatcher());
|
||||
}
|
||||
|
||||
protected function cacheClear(EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$cacheEvent = new CacheEvent(
|
||||
$this->environment
|
||||
);
|
||||
|
||||
$dispatcher->dispatch(TheliaEvents::CACHE_CLEAR, $cacheEvent);
|
||||
return [
|
||||
TheliaEvents::IMPORT_CHANGE_POSITION => [
|
||||
['importChangePosition', 128]
|
||||
],
|
||||
TheliaEvents::IMPORT_CATEGORY_CHANGE_POSITION => [
|
||||
['importCategoryChangePosition', 128]
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of event names this subscriber wants to listen to.
|
||||
* Handle import change position event
|
||||
*
|
||||
* The array keys are event names and the value can be:
|
||||
*
|
||||
* * The method name to call (priority defaults to 0)
|
||||
* * An array composed of the method name to call and the priority
|
||||
* * An array of arrays composed of the method names to call and respective
|
||||
* priorities, or 0 if unset
|
||||
*
|
||||
* For instance:
|
||||
*
|
||||
* * array('eventName' => 'methodName')
|
||||
* * array('eventName' => array('methodName', $priority))
|
||||
* * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
|
||||
*
|
||||
* @return array The event names to listen to
|
||||
*
|
||||
* @api
|
||||
* @param UpdatePositionEvent $updatePositionEvent
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
public function importChangePosition(UpdatePositionEvent $updatePositionEvent, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::IMPORT_CATEGORY_CHANGE_POSITION => array("changeCategoryPosition", 128),
|
||||
TheliaEvents::IMPORT_CHANGE_POSITION => array("changeImportPosition", 128),
|
||||
);
|
||||
$this->handler->getImport($updatePositionEvent->getObjectId(), true);
|
||||
$this->genericUpdatePosition(new ImportQuery, $updatePositionEvent, $dispatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle import category change position event
|
||||
*
|
||||
* @param UpdatePositionEvent $updatePositionEvent
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function importCategoryChangePosition(UpdatePositionEvent $updatePositionEvent, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$this->handler->getCategory($updatePositionEvent->getObjectId(), true);
|
||||
$this->genericUpdatePosition(new ImportCategoryQuery, $updatePositionEvent, $dispatcher);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,13 +11,23 @@
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Thelia\Action;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Thelia\Core\Event\Lang\LangCreateEvent;
|
||||
use Thelia\Core\Event\Lang\LangDefaultBehaviorEvent;
|
||||
use Thelia\Core\Event\Lang\LangDeleteEvent;
|
||||
use Thelia\Core\Event\Lang\LangEvent;
|
||||
use Thelia\Core\Event\Lang\LangToggleActiveEvent;
|
||||
use Thelia\Core\Event\Lang\LangToggleDefaultEvent;
|
||||
use Thelia\Core\Event\Lang\LangToggleVisibleEvent;
|
||||
use Thelia\Core\Event\Lang\LangUpdateEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\HttpFoundation\Session\Session;
|
||||
use Thelia\Core\Template\TemplateHelperInterface;
|
||||
use Thelia\Core\Translation\Translator;
|
||||
use Thelia\Form\Lang\LangUrlEvent;
|
||||
use Thelia\Model\ConfigQuery;
|
||||
use Thelia\Model\LangQuery;
|
||||
@@ -26,19 +36,31 @@ use Thelia\Model\Lang as LangModel;
|
||||
/**
|
||||
* Class Lang
|
||||
* @package Thelia\Action
|
||||
* @author Manuel Raynaud <mraynaud@openstudio.fr>
|
||||
* @author Manuel Raynaud <manu@raynaud.io>
|
||||
*/
|
||||
class Lang extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
/** @var TemplateHelperInterface */
|
||||
protected $templateHelper;
|
||||
|
||||
public function update(LangUpdateEvent $event)
|
||||
/** @var RequestStack */
|
||||
protected $requestStack;
|
||||
|
||||
public function __construct(TemplateHelperInterface $templateHelper, RequestStack $requestStack)
|
||||
{
|
||||
$this->templateHelper = $templateHelper;
|
||||
$this->requestStack = $requestStack;
|
||||
}
|
||||
|
||||
public function update(LangUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $lang = LangQuery::create()->findPk($event->getId())) {
|
||||
$lang->setDispatcher($event->getDispatcher());
|
||||
$lang->setDispatcher($dispatcher);
|
||||
|
||||
$lang->setTitle($event->getTitle())
|
||||
->setLocale($event->getLocale())
|
||||
->setCode($event->getCode())
|
||||
->setDateTimeFormat($event->getDateTimeFormat())
|
||||
->setDateFormat($event->getDateFormat())
|
||||
->setTimeFormat($event->getTimeFormat())
|
||||
->setDecimalSeparator($event->getDecimalSeparator())
|
||||
@@ -50,10 +72,10 @@ class Lang extends BaseAction implements EventSubscriberInterface
|
||||
}
|
||||
}
|
||||
|
||||
public function toggleDefault(LangToggleDefaultEvent $event)
|
||||
public function toggleDefault(LangToggleDefaultEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $lang = LangQuery::create()->findPk($event->getLangId())) {
|
||||
$lang->setDispatcher($event->getDispatcher());
|
||||
$lang->setDispatcher($dispatcher);
|
||||
|
||||
$lang->toggleDefault();
|
||||
|
||||
@@ -61,15 +83,58 @@ class Lang extends BaseAction implements EventSubscriberInterface
|
||||
}
|
||||
}
|
||||
|
||||
public function create(LangCreateEvent $event)
|
||||
public function toggleActive(LangToggleActiveEvent $event)
|
||||
{
|
||||
if (null !== $lang = LangQuery::create()->findPk($event->getLangId())) {
|
||||
if ($lang->getByDefault()) {
|
||||
throw new \RuntimeException(
|
||||
Translator::getInstance()->trans('Cannot disable the default language')
|
||||
);
|
||||
}
|
||||
|
||||
$lang->setActive($lang->getActive() ? 0 : 1);
|
||||
|
||||
if (!$lang->getActive()) {
|
||||
$lang->setVisible(0);
|
||||
}
|
||||
|
||||
$lang->save();
|
||||
|
||||
$event->setLang($lang);
|
||||
}
|
||||
}
|
||||
|
||||
public function toggleVisible(LangToggleVisibleEvent $event)
|
||||
{
|
||||
if (null !== $lang = LangQuery::create()->findPk($event->getLangId())) {
|
||||
if ($lang->getByDefault()) {
|
||||
throw new \RuntimeException(
|
||||
Translator::getInstance()->trans('Cannot hide the default language')
|
||||
);
|
||||
}
|
||||
|
||||
$lang->setVisible($lang->getVisible() ? 0 : 1);
|
||||
|
||||
if (!$lang->getActive() && $lang->getVisible()) {
|
||||
$lang->setActive(1);
|
||||
}
|
||||
|
||||
$lang->save();
|
||||
|
||||
$event->setLang($lang);
|
||||
}
|
||||
}
|
||||
|
||||
public function create(LangCreateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$lang = new LangModel();
|
||||
|
||||
$lang
|
||||
->setDispatcher($event->getDispatcher())
|
||||
->setDispatcher($dispatcher)
|
||||
->setTitle($event->getTitle())
|
||||
->setCode($event->getCode())
|
||||
->setLocale($event->getLocale())
|
||||
->setDateTimeFormat($event->getDateTimeFormat())
|
||||
->setDateFormat($event->getDateFormat())
|
||||
->setTimeFormat($event->getTimeFormat())
|
||||
->setDecimalSeparator($event->getDecimalSeparator())
|
||||
@@ -80,12 +145,31 @@ class Lang extends BaseAction implements EventSubscriberInterface
|
||||
$event->setLang($lang);
|
||||
}
|
||||
|
||||
public function delete(LangDeleteEvent $event)
|
||||
public function delete(LangDeleteEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $lang = LangQuery::create()->findPk($event->getLangId())) {
|
||||
$lang->setDispatcher($event->getDispatcher())
|
||||
if ($lang->getByDefault()) {
|
||||
throw new \RuntimeException(
|
||||
Translator::getInstance()->trans('It is not allowed to delete the default language')
|
||||
);
|
||||
}
|
||||
|
||||
$lang->setDispatcher($dispatcher)
|
||||
->delete();
|
||||
|
||||
/** @var Session $session */
|
||||
$session = $this->requestStack->getCurrentRequest()->getSession();
|
||||
|
||||
// If we've just deleted the current admin edition language, set it to the default one.
|
||||
if ($lang->getId() == $session->getAdminEditionLang()->getId()) {
|
||||
$session->setAdminEditionLang(LangModel::getDefaultLanguage());
|
||||
}
|
||||
|
||||
// If we've just deleted the current admin language, set it to the default one.
|
||||
if ($lang->getId() == $session->getLang()->getId()) {
|
||||
$session->setLang(LangModel::getDefaultLanguage());
|
||||
}
|
||||
|
||||
$event->setLang($lang);
|
||||
}
|
||||
}
|
||||
@@ -106,35 +190,49 @@ class Lang extends BaseAction implements EventSubscriberInterface
|
||||
}
|
||||
}
|
||||
|
||||
public function fixMissingFlag(LangEvent $event)
|
||||
{
|
||||
// Be sure that a lang have a flag, otherwise copy the
|
||||
// "unknown" flag
|
||||
$adminTemplate = $this->templateHelper->getActiveAdminTemplate();
|
||||
$unknownFlag = ConfigQuery::getUnknownFlagPath();
|
||||
|
||||
$unknownFlagPath = $adminTemplate->getAbsolutePath().DS.$unknownFlag;
|
||||
|
||||
if (! file_exists($unknownFlagPath)) {
|
||||
throw new \RuntimeException(
|
||||
Translator::getInstance()->trans(
|
||||
"The image which replaces an undefined country flag (%file) was not found. Please check unknown-flag-path configuration variable, and check that the image exists.",
|
||||
array("%file" => $unknownFlag)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Check if the country flag exists
|
||||
$countryFlag = rtrim(dirname($unknownFlagPath), DS).DS.$event->getLang()->getCode().'.png';
|
||||
|
||||
if (! file_exists($countryFlag)) {
|
||||
$fs = new Filesystem();
|
||||
|
||||
$fs->copy($unknownFlagPath, $countryFlag);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of event names this subscriber wants to listen to.
|
||||
*
|
||||
* The array keys are event names and the value can be:
|
||||
*
|
||||
* * The method name to call (priority defaults to 0)
|
||||
* * An array composed of the method name to call and the priority
|
||||
* * An array of arrays composed of the method names to call and respective
|
||||
* priorities, or 0 if unset
|
||||
*
|
||||
* For instance:
|
||||
*
|
||||
* * array('eventName' => 'methodName')
|
||||
* * array('eventName' => array('methodName', $priority))
|
||||
* * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
|
||||
*
|
||||
* @return array The event names to listen to
|
||||
*
|
||||
* @api
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::LANG_UPDATE => array('update', 128),
|
||||
TheliaEvents::LANG_TOGGLEDEFAULT => array('toggleDefault', 128),
|
||||
TheliaEvents::LANG_TOGGLEACTIVE => array('toggleActive', 128),
|
||||
TheliaEvents::LANG_TOGGLEVISIBLE => array('toggleVisible', 128),
|
||||
TheliaEvents::LANG_CREATE => array('create', 128),
|
||||
TheliaEvents::LANG_DELETE => array('delete', 128),
|
||||
TheliaEvents::LANG_DEFAULTBEHAVIOR => array('defaultBehavior', 128),
|
||||
TheliaEvents::LANG_URL => array('langUrl', 128)
|
||||
TheliaEvents::LANG_URL => array('langUrl', 128),
|
||||
TheliaEvents::LANG_FIX_MISSING_FLAG => array('fixMissingFlag', 128)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ class MailingSystem extends BaseAction implements EventSubscriberInterface
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::MAILING_SYSTEM_UPDATE => array("update", 128),
|
||||
TheliaEvents::MAILING_SYSTEM_UPDATE => array("update", 128),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,13 +12,11 @@
|
||||
|
||||
namespace Thelia\Action;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
|
||||
use Thelia\Model\MessageQuery;
|
||||
use Thelia\Model\Message as MessageModel;
|
||||
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
|
||||
use Thelia\Core\Event\Message\MessageUpdateEvent;
|
||||
use Thelia\Core\Event\Message\MessageCreateEvent;
|
||||
use Thelia\Core\Event\Message\MessageDeleteEvent;
|
||||
@@ -29,19 +27,19 @@ class Message extends BaseAction implements EventSubscriberInterface
|
||||
* Create a new messageuration entry
|
||||
*
|
||||
* @param \Thelia\Core\Event\Message\MessageCreateEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function create(MessageCreateEvent $event)
|
||||
public function create(MessageCreateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$message = new MessageModel();
|
||||
|
||||
$message
|
||||
->setDispatcher($event->getDispatcher())
|
||||
->setDispatcher($dispatcher)
|
||||
|
||||
->setName($event->getMessageName())
|
||||
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
|
||||
->setSecured($event->getSecured())
|
||||
|
||||
->save()
|
||||
@@ -54,14 +52,14 @@ class Message extends BaseAction implements EventSubscriberInterface
|
||||
* Change a message
|
||||
*
|
||||
* @param \Thelia\Core\Event\Message\MessageUpdateEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function modify(MessageUpdateEvent $event)
|
||||
public function modify(MessageUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
|
||||
if (null !== $message = MessageQuery::create()->findPk($event->getMessageId())) {
|
||||
|
||||
$message
|
||||
->setDispatcher($event->getDispatcher())
|
||||
->setDispatcher($dispatcher)
|
||||
|
||||
->setName($event->getMessageName())
|
||||
->setSecured($event->getSecured())
|
||||
@@ -89,14 +87,14 @@ class Message extends BaseAction implements EventSubscriberInterface
|
||||
* Delete a messageuration entry
|
||||
*
|
||||
* @param \Thelia\Core\Event\Message\MessageDeleteEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function delete(MessageDeleteEvent $event)
|
||||
public function delete(MessageDeleteEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
|
||||
if (null !== ($message = MessageQuery::create()->findPk($event->getMessageId()))) {
|
||||
|
||||
$message
|
||||
->setDispatcher($event->getDispatcher())
|
||||
->setDispatcher($dispatcher)
|
||||
->delete()
|
||||
;
|
||||
|
||||
|
||||
75
core/lib/Thelia/Action/MetaData.php
Normal file
75
core/lib/Thelia/Action/MetaData.php
Normal file
@@ -0,0 +1,75 @@
|
||||
<?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 Thelia\Action;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Core\Event\MetaData\MetaDataCreateOrUpdateEvent;
|
||||
use Thelia\Core\Event\MetaData\MetaDataDeleteEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Model\MetaData as MetaDataModel;
|
||||
use Thelia\Model\MetaDataQuery;
|
||||
|
||||
/**
|
||||
* Class MetaData
|
||||
* @package Thelia\Action
|
||||
* @author Julien Chanséaume <jchanseaume@openstudio.fr>
|
||||
*/
|
||||
class MetaData extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
public function createOrUpdate(MetaDataCreateOrUpdateEvent $event)
|
||||
{
|
||||
$metaData = MetaDataQuery::create()
|
||||
->filterByMetaKey($event->getMetaKey())
|
||||
->filterByElementKey($event->getElementKey())
|
||||
->filterByElementId($event->getElementId())
|
||||
->findOne();
|
||||
|
||||
if (null === $metaData) {
|
||||
$metaData = new MetaDataModel();
|
||||
$metaData
|
||||
->setMetaKey($event->getMetaKey())
|
||||
->setElementKey($event->getElementkey())
|
||||
->setElementId($event->getElementId());
|
||||
}
|
||||
$metaData->
|
||||
setValue($event->getValue());
|
||||
$metaData->save();
|
||||
|
||||
$event->setMetaData($metaData);
|
||||
}
|
||||
|
||||
public function delete(MetaDataDeleteEvent $event)
|
||||
{
|
||||
$metaData = MetaDataQuery::create()
|
||||
->filterByMetaKey($event->getMetaKey())
|
||||
->filterByElementKey($event->getElementKey())
|
||||
->filterByElementId($event->getElementId())
|
||||
->findOne();
|
||||
$event->setMetaData($metaData);
|
||||
if (null !== $metaData) {
|
||||
$metaData->delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::META_DATA_CREATE => array('createOrUpdate', 128),
|
||||
TheliaEvents::META_DATA_UPDATE => array('createOrUpdate', 128),
|
||||
TheliaEvents::META_DATA_DELETE => array('delete', 128),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -11,35 +11,43 @@
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Thelia\Action;
|
||||
|
||||
use Exception;
|
||||
use Propel\Runtime\Propel;
|
||||
use SplFileInfo;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\Filesystem\Exception\IOException;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Thelia\Core\Event\Cache\CacheEvent;
|
||||
use Thelia\Core\Event\Module\ModuleDeleteEvent;
|
||||
use Thelia\Core\Event\Module\ModuleEvent;
|
||||
use Thelia\Core\Event\Module\ModuleInstallEvent;
|
||||
use Thelia\Core\Event\Module\ModuleToggleActivationEvent;
|
||||
use Thelia\Core\Event\Order\OrderPaymentEvent;
|
||||
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\Event\UpdatePositionEvent;
|
||||
use Thelia\Core\Translation\Translator;
|
||||
use Thelia\Exception\FileNotFoundException;
|
||||
use Thelia\Exception\ModuleException;
|
||||
use Thelia\Log\Tlog;
|
||||
use Thelia\Model\Base\OrderQuery;
|
||||
use Thelia\Model\Map\ModuleTableMap;
|
||||
use Thelia\Model\ModuleQuery;
|
||||
use Thelia\Module\BaseModule;
|
||||
use Thelia\Module\ModuleManagement;
|
||||
use Thelia\Module\Validator\ModuleValidator;
|
||||
|
||||
/**
|
||||
* Class Module
|
||||
* @package Thelia\Action
|
||||
* @author Manuel Raynaud <mraynaud@openstudio.fr>
|
||||
* @author Manuel Raynaud <manu@raynaud.io>
|
||||
*/
|
||||
class Module extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
/**
|
||||
* @var ContainerInterface
|
||||
*/
|
||||
/** @var ContainerInterface */
|
||||
protected $container;
|
||||
|
||||
public function __construct(ContainerInterface $container)
|
||||
@@ -47,13 +55,12 @@ class Module extends BaseAction implements EventSubscriberInterface
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
public function toggleActivation(ModuleToggleActivationEvent $event)
|
||||
public function toggleActivation(ModuleToggleActivationEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $module = ModuleQuery::create()->findPk($event->getModuleId())) {
|
||||
|
||||
$moduleInstance = $module->createInstance();
|
||||
|
||||
if ( method_exists($moduleInstance, 'setContainer')) {
|
||||
if (method_exists($moduleInstance, 'setContainer')) {
|
||||
$moduleInstance->setContainer($this->container);
|
||||
if ($module->getActivate() == BaseModule::IS_ACTIVATED) {
|
||||
$moduleInstance->deActivate($module);
|
||||
@@ -64,28 +71,188 @@ class Module extends BaseAction implements EventSubscriberInterface
|
||||
|
||||
$event->setModule($module);
|
||||
|
||||
$this->cacheClear($event->getDispatcher());
|
||||
$this->cacheClear($dispatcher);
|
||||
}
|
||||
}
|
||||
|
||||
public function delete(ModuleDeleteEvent $event)
|
||||
public function checkToggleActivation(ModuleToggleActivationEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (true === $event->isNoCheck()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (null !== $module = ModuleQuery::create()->findPk($event->getModuleId())) {
|
||||
try {
|
||||
if ($module->getActivate() == BaseModule::IS_ACTIVATED) {
|
||||
if ($module->getMandatory() == BaseModule::IS_MANDATORY && $event->getAssumeDeactivate() === false) {
|
||||
throw new \Exception(
|
||||
Translator::getInstance()->trans('Can\'t deactivate a secure module')
|
||||
);
|
||||
}
|
||||
|
||||
if ($event->isRecursive()) {
|
||||
$this->recursiveDeactivation($event, $eventName, $dispatcher);
|
||||
}
|
||||
$this->checkDeactivation($module);
|
||||
} else {
|
||||
if ($event->isRecursive()) {
|
||||
$this->recursiveActivation($event, $eventName, $dispatcher);
|
||||
}
|
||||
$this->checkActivation($module);
|
||||
}
|
||||
} catch (\Exception $ex) {
|
||||
$event->stopPropagation();
|
||||
throw $ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if module can be activated : supported version of Thelia, module dependencies.
|
||||
*
|
||||
* @param \Thelia\Model\Module $module
|
||||
* @throws Exception if activation fails.
|
||||
* @return bool true if the module can be activated, otherwise false
|
||||
*/
|
||||
private function checkActivation($module)
|
||||
{
|
||||
try {
|
||||
$moduleValidator = new ModuleValidator($module->getAbsoluteBaseDir());
|
||||
$moduleValidator->validate(false);
|
||||
} catch (\Exception $ex) {
|
||||
throw $ex;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if module can be deactivated safely because other modules
|
||||
* could have dependencies to this module
|
||||
*
|
||||
* @param \Thelia\Model\Module $module
|
||||
* @return bool true if the module can be deactivated, otherwise false
|
||||
*/
|
||||
private function checkDeactivation($module)
|
||||
{
|
||||
$moduleValidator = new ModuleValidator($module->getAbsoluteBaseDir());
|
||||
|
||||
$modules = $moduleValidator->getModulesDependOf();
|
||||
|
||||
if (count($modules) > 0) {
|
||||
$moduleList = implode(', ', array_column($modules, 'code'));
|
||||
|
||||
$message = (count($modules) == 1)
|
||||
? Translator::getInstance()->trans(
|
||||
'%s has dependency to module %s. You have to deactivate this module before.'
|
||||
)
|
||||
: Translator::getInstance()->trans(
|
||||
'%s have dependencies to module %s. You have to deactivate these modules before.'
|
||||
);
|
||||
|
||||
throw new ModuleException(
|
||||
sprintf($message, $moduleList, $moduleValidator->getModuleDefinition()->getCode())
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get dependencies of the current module and activate it if needed
|
||||
*
|
||||
* @param ModuleToggleActivationEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function recursiveActivation(ModuleToggleActivationEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $module = ModuleQuery::create()->findPk($event->getModuleId())) {
|
||||
$con = Propel::getWriteConnection(ModuleTableMap::DATABASE_NAME);
|
||||
$con->beginTransaction();
|
||||
$moduleValidator = new ModuleValidator($module->getAbsoluteBaseDir());
|
||||
$dependencies = $moduleValidator->getCurrentModuleDependencies();
|
||||
foreach ($dependencies as $defMod) {
|
||||
$submodule = ModuleQuery::create()
|
||||
->findOneByCode($defMod["code"]);
|
||||
if ($submodule && $submodule->getActivate() != BaseModule::IS_ACTIVATED) {
|
||||
$subevent = new ModuleToggleActivationEvent($submodule->getId());
|
||||
$subevent->setRecursive(true);
|
||||
$dispatcher->dispatch(TheliaEvents::MODULE_TOGGLE_ACTIVATION, $subevent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get modules having current module in dependence and deactivate it if needed
|
||||
*
|
||||
* @param ModuleToggleActivationEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function recursiveDeactivation(ModuleToggleActivationEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $module = ModuleQuery::create()->findPk($event->getModuleId())) {
|
||||
$moduleValidator = new ModuleValidator($module->getAbsoluteBaseDir());
|
||||
$dependencies = $moduleValidator->getModulesDependOf(true);
|
||||
foreach ($dependencies as $defMod) {
|
||||
$submodule = ModuleQuery::create()
|
||||
->findOneByCode($defMod["code"]);
|
||||
if ($submodule && $submodule->getActivate() == BaseModule::IS_ACTIVATED) {
|
||||
$subevent = new ModuleToggleActivationEvent($submodule->getId());
|
||||
$subevent->setRecursive(true);
|
||||
$dispatcher->dispatch(TheliaEvents::MODULE_TOGGLE_ACTIVATION, $subevent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function delete(ModuleDeleteEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$con = Propel::getWriteConnection(ModuleTableMap::DATABASE_NAME);
|
||||
$con->beginTransaction();
|
||||
|
||||
if (null !== $module = ModuleQuery::create()->findPk($event->getModuleId(), $con)) {
|
||||
try {
|
||||
if (null === $module->getFullNamespace()) {
|
||||
throw new \LogicException(
|
||||
Translator::getInstance()->trans(
|
||||
'Cannot instanciante module "%name%": the namespace is null. Maybe the model is not loaded ?',
|
||||
array('%name%' => $module->getCode())
|
||||
));
|
||||
'Cannot instantiate module "%name%": the namespace is null. Maybe the model is not loaded ?',
|
||||
['%name%' => $module->getCode()]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// If the module is referenced by an order, display a meaningful error
|
||||
// instead of 'delete cannot delete' caused by a constraint violation.
|
||||
// FIXME: we hav to find a way to delete modules used by order.
|
||||
if (OrderQuery::create()->filterByDeliveryModuleId($module->getId())->count() > 0
|
||||
||
|
||||
OrderQuery::create()->filterByPaymentModuleId($module->getId())->count() > 0
|
||||
) {
|
||||
throw new \LogicException(
|
||||
Translator::getInstance()->trans(
|
||||
'The module "%name%" is currently in use by at least one order, and can\'t be deleted.',
|
||||
['%name%' => $module->getCode()]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
if ($module->getMandatory() == BaseModule::IS_MANDATORY && $event->getAssumeDelete() === false) {
|
||||
throw new \Exception(
|
||||
Translator::getInstance()->trans('Can\'t remove a core module')
|
||||
);
|
||||
}
|
||||
// First, try to create an instance
|
||||
$instance = $module->createInstance();
|
||||
|
||||
// Then, if module is activated, check if we can deactivate it
|
||||
if ($module->getActivate()) {
|
||||
// check for modules that depend of this one
|
||||
$this->checkDeactivation($module);
|
||||
}
|
||||
|
||||
$instance->setContainer($this->container);
|
||||
|
||||
$path = $module->getAbsoluteBaseDir();
|
||||
@@ -99,8 +266,19 @@ class Module extends BaseAction implements EventSubscriberInterface
|
||||
// Log a warning, and delete the database entry.
|
||||
Tlog::getInstance()->addWarning(
|
||||
Translator::getInstance()->trans(
|
||||
'Failed to create instance of module "%name%" when trying to delete module. Module directory has probably been deleted', array('%name%' => $module->getCode())
|
||||
));
|
||||
'Failed to create instance of module "%name%" when trying to delete module. Module directory has probably been deleted',
|
||||
['%name%' => $module->getCode()]
|
||||
)
|
||||
);
|
||||
} catch (FileNotFoundException $fnfe) {
|
||||
// The module directory has been deleted.
|
||||
// Log a warning, and delete the database entry.
|
||||
Tlog::getInstance()->addWarning(
|
||||
Translator::getInstance()->trans(
|
||||
'Module "%name%" directory was not found',
|
||||
['%name%' => $module->getCode()]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$module->delete($con);
|
||||
@@ -108,8 +286,7 @@ class Module extends BaseAction implements EventSubscriberInterface
|
||||
$con->commit();
|
||||
|
||||
$event->setModule($module);
|
||||
$this->cacheClear($event->getDispatcher());
|
||||
|
||||
$this->cacheClear($dispatcher);
|
||||
} catch (\Exception $e) {
|
||||
$con->rollBack();
|
||||
throw $e;
|
||||
@@ -119,19 +296,19 @@ class Module extends BaseAction implements EventSubscriberInterface
|
||||
|
||||
/**
|
||||
* @param ModuleEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function update(ModuleEvent $event)
|
||||
public function update(ModuleEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $module = ModuleQuery::create()->findPk($event->getId())) {
|
||||
|
||||
$module
|
||||
->setDispatcher($event->getDispatcher())
|
||||
->setDispatcher($dispatcher)
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
->setChapo($event->getChapo())
|
||||
->setDescription($event->getDescription())
|
||||
->setPostscriptum($event->getPostscriptum())
|
||||
;
|
||||
->setPostscriptum($event->getPostscriptum());
|
||||
|
||||
$module->save();
|
||||
|
||||
@@ -139,10 +316,86 @@ class Module extends BaseAction implements EventSubscriberInterface
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Thelia\Core\Event\Module\ModuleInstallEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*
|
||||
* @throws \Exception
|
||||
* @throws \Symfony\Component\Filesystem\Exception\IOException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function install(ModuleInstallEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$moduleDefinition = $event->getModuleDefinition();
|
||||
|
||||
$oldModule = ModuleQuery::create()->findOneByFullNamespace($moduleDefinition->getNamespace());
|
||||
|
||||
$fs = new Filesystem();
|
||||
|
||||
$activated = false;
|
||||
|
||||
// check existing module
|
||||
if (null !== $oldModule) {
|
||||
$activated = $oldModule->getActivate();
|
||||
|
||||
if ($activated) {
|
||||
// deactivate
|
||||
$toggleEvent = new ModuleToggleActivationEvent($oldModule->getId());
|
||||
// disable the check of the module because it's already done
|
||||
$toggleEvent->setNoCheck(true);
|
||||
|
||||
$dispatcher->dispatch(TheliaEvents::MODULE_TOGGLE_ACTIVATION, $toggleEvent);
|
||||
}
|
||||
|
||||
// delete
|
||||
$modulePath = $oldModule->getAbsoluteBaseDir();
|
||||
|
||||
$deleteEvent = new ModuleDeleteEvent($oldModule);
|
||||
|
||||
try {
|
||||
$dispatcher->dispatch(TheliaEvents::MODULE_DELETE, $deleteEvent);
|
||||
} catch (Exception $ex) {
|
||||
// if module has not been deleted
|
||||
if ($fs->exists($modulePath)) {
|
||||
throw $ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// move new module
|
||||
$modulePath = sprintf('%s%s', THELIA_MODULE_DIR, $event->getModuleDefinition()->getCode());
|
||||
|
||||
try {
|
||||
$fs->mirror($event->getModulePath(), $modulePath);
|
||||
} catch (IOException $ex) {
|
||||
if (!$fs->exists($modulePath)) {
|
||||
throw $ex;
|
||||
}
|
||||
}
|
||||
|
||||
// Update the module
|
||||
$moduleDescriptorFile = sprintf('%s%s%s%s%s', $modulePath, DS, 'Config', DS, 'module.xml');
|
||||
$moduleManagement = new ModuleManagement();
|
||||
$file = new SplFileInfo($moduleDescriptorFile);
|
||||
$module = $moduleManagement->updateModule($file, $this->container);
|
||||
|
||||
// activate if old was activated
|
||||
if ($activated) {
|
||||
$toggleEvent = new ModuleToggleActivationEvent($module->getId());
|
||||
$toggleEvent->setNoCheck(true);
|
||||
|
||||
$dispatcher->dispatch(TheliaEvents::MODULE_TOGGLE_ACTIVATION, $toggleEvent);
|
||||
}
|
||||
|
||||
$event->setModule($module);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the payment method of the payment module of the given order
|
||||
*
|
||||
* @param OrderPaymentEvent $event
|
||||
* @param OrderPaymentEvent $event
|
||||
*
|
||||
* @throws \RuntimeException if no payment module can be found.
|
||||
*/
|
||||
public function pay(OrderPaymentEvent $event)
|
||||
@@ -154,18 +407,19 @@ class Module extends BaseAction implements EventSubscriberInterface
|
||||
throw new \RuntimeException(
|
||||
Translator::getInstance()->trans(
|
||||
"Failed to find a payment Module with ID=%mid for order ID=%oid",
|
||||
array(
|
||||
[
|
||||
"%mid" => $order->getPaymentModuleId(),
|
||||
"%oid" => $order->getId()
|
||||
))
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$paymentModuleInstance = $paymentModule->getModuleInstance($this->container);
|
||||
$paymentModuleInstance = $paymentModule->getPaymentModuleInstance($this->container);
|
||||
|
||||
$response = $paymentModuleInstance->pay($order);
|
||||
|
||||
if (null !== $response && $response instanceof \Thelia\Core\HttpFoundation\Response) {
|
||||
if (null !== $response && $response instanceof Response) {
|
||||
$event->setResponse($response);
|
||||
}
|
||||
}
|
||||
@@ -174,12 +428,14 @@ class Module extends BaseAction implements EventSubscriberInterface
|
||||
* Changes position, selecting absolute ou relative change.
|
||||
*
|
||||
* @param UpdatePositionEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function updatePosition(UpdatePositionEvent $event)
|
||||
public function updatePosition(UpdatePositionEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$this->genericUpdatePosition(ModuleQuery::create(), $event);
|
||||
$this->genericUpdatePosition(ModuleQuery::create(), $event, $dispatcher);
|
||||
|
||||
$this->cacheClear($event->getDispatcher());
|
||||
$this->cacheClear($dispatcher);
|
||||
}
|
||||
|
||||
protected function cacheClear(EventDispatcherInterface $dispatcher)
|
||||
@@ -192,33 +448,20 @@ class Module extends BaseAction implements EventSubscriberInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of event names this subscriber wants to listen to.
|
||||
*
|
||||
* The array keys are event names and the value can be:
|
||||
*
|
||||
* * The method name to call (priority defaults to 0)
|
||||
* * An array composed of the method name to call and the priority
|
||||
* * An array of arrays composed of the method names to call and respective
|
||||
* priorities, or 0 if unset
|
||||
*
|
||||
* For instance:
|
||||
*
|
||||
* * array('eventName' => 'methodName')
|
||||
* * array('eventName' => array('methodName', $priority))
|
||||
* * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
|
||||
*
|
||||
* @return array The event names to listen to
|
||||
*
|
||||
* @api
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::MODULE_TOGGLE_ACTIVATION => array('toggleActivation', 128),
|
||||
TheliaEvents::MODULE_UPDATE_POSITION => array('updatePosition', 128),
|
||||
TheliaEvents::MODULE_DELETE => array('delete', 128),
|
||||
TheliaEvents::MODULE_UPDATE => array('update', 128),
|
||||
TheliaEvents::MODULE_PAY => array('pay', 128),
|
||||
);
|
||||
return [
|
||||
TheliaEvents::MODULE_TOGGLE_ACTIVATION => [
|
||||
['checkToggleActivation', 255],
|
||||
['toggleActivation', 128],
|
||||
],
|
||||
TheliaEvents::MODULE_UPDATE_POSITION => ['updatePosition', 128],
|
||||
TheliaEvents::MODULE_DELETE => ['delete', 128],
|
||||
TheliaEvents::MODULE_UPDATE => ['update', 128],
|
||||
TheliaEvents::MODULE_INSTALL => ['install', 128],
|
||||
TheliaEvents::MODULE_PAY => ['pay', 128],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
252
core/lib/Thelia/Action/ModuleHook.php
Normal file
252
core/lib/Thelia/Action/ModuleHook.php
Normal file
@@ -0,0 +1,252 @@
|
||||
<?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 Thelia\Action;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Core\Event\Cache\CacheEvent;
|
||||
use Thelia\Core\Event\Hook\HookToggleActivationEvent;
|
||||
use Thelia\Core\Event\Hook\HookUpdateEvent;
|
||||
use Thelia\Core\Event\Hook\ModuleHookCreateEvent;
|
||||
use Thelia\Core\Event\Hook\ModuleHookDeleteEvent;
|
||||
use Thelia\Core\Event\Hook\ModuleHookToggleActivationEvent;
|
||||
use Thelia\Core\Event\Hook\ModuleHookUpdateEvent;
|
||||
use Thelia\Core\Event\Module\ModuleDeleteEvent;
|
||||
use Thelia\Core\Event\Module\ModuleToggleActivationEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\Event\UpdatePositionEvent;
|
||||
use Thelia\Core\Translation\Translator;
|
||||
use Thelia\Model\Base\IgnoredModuleHookQuery;
|
||||
use Thelia\Model\HookQuery;
|
||||
use Thelia\Model\IgnoredModuleHook;
|
||||
use Thelia\Model\ModuleHook as ModuleHookModel;
|
||||
use Thelia\Model\ModuleHookQuery;
|
||||
use Thelia\Model\ModuleQuery;
|
||||
use Thelia\Module\BaseModule;
|
||||
|
||||
/**
|
||||
* Class ModuleHook
|
||||
* @package Thelia\Action
|
||||
* @author Julien Chanséaume <jchanseaume@openstudio.fr>
|
||||
*/
|
||||
class ModuleHook extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
/** @var string */
|
||||
protected $cacheDir;
|
||||
|
||||
public function __construct($cacheDir)
|
||||
{
|
||||
$this->cacheDir = $cacheDir;
|
||||
}
|
||||
|
||||
public function toggleModuleActivation(ModuleToggleActivationEvent $event)
|
||||
{
|
||||
if (null !== $module = ModuleQuery::create()->findPk($event->getModuleId())) {
|
||||
ModuleHookQuery::create()
|
||||
->filterByModuleId($module->getId())
|
||||
->update(array('ModuleActive' => ($module->getActivate() == BaseModule::IS_ACTIVATED)));
|
||||
}
|
||||
|
||||
return $event;
|
||||
}
|
||||
|
||||
public function deleteModule(ModuleDeleteEvent $event)
|
||||
{
|
||||
if ($event->getModuleId()) {
|
||||
ModuleHookQuery::create()
|
||||
->filterByModuleId($event->getModuleId())
|
||||
->delete();
|
||||
}
|
||||
|
||||
return $event;
|
||||
}
|
||||
|
||||
protected function isModuleActive($module_id)
|
||||
{
|
||||
if (null !== $module = ModuleQuery::create()->findPk($module_id)) {
|
||||
return $module->getActivate();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function isHookActive($hook_id)
|
||||
{
|
||||
if (null !== $hook = HookQuery::create()->findPk($hook_id)) {
|
||||
return $hook->getActivate();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function getLastPositionInHook($hook_id)
|
||||
{
|
||||
$result = ModuleHookQuery::create()
|
||||
->filterByHookId($hook_id)
|
||||
->withColumn('MAX(ModuleHook.position)', 'maxPos')
|
||||
->groupBy('ModuleHook.hook_id')
|
||||
->select(array('maxPos'))
|
||||
->findOne();
|
||||
|
||||
return intval($result) + 1;
|
||||
}
|
||||
|
||||
public function createModuleHook(ModuleHookCreateEvent $event)
|
||||
{
|
||||
$moduleHook = new ModuleHookModel();
|
||||
|
||||
// todo: test if classname and method exists
|
||||
$moduleHook
|
||||
->setModuleId($event->getModuleId())
|
||||
->setHookId($event->getHookId())
|
||||
->setActive(false)
|
||||
->setClassname($event->getClassname())
|
||||
->setMethod($event->getMethod())
|
||||
->setModuleActive($this->isModuleActive($event->getModuleId()))
|
||||
->setHookActive($this->isHookActive($event->getHookId()))
|
||||
->setPosition($this->getLastPositionInHook($event->getHookId()))
|
||||
->setTemplates($event->getTemplates())
|
||||
->save();
|
||||
|
||||
// Be sure to delete this module hook from the ignored module hook table
|
||||
IgnoredModuleHookQuery::create()
|
||||
->filterByHookId($event->getHookId())
|
||||
->filterByModuleId($event->getModuleId())
|
||||
->delete();
|
||||
|
||||
$event->setModuleHook($moduleHook);
|
||||
}
|
||||
|
||||
public function updateModuleHook(ModuleHookUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $moduleHook = ModuleHookQuery::create()->findPk($event->getModuleHookId())) {
|
||||
// todo: test if classname and method exists
|
||||
$moduleHook
|
||||
->setHookId($event->getHookId())
|
||||
->setModuleId($event->getModuleId())
|
||||
->setClassname($event->getClassname())
|
||||
->setMethod($event->getMethod())
|
||||
->setActive($event->getActive())
|
||||
->setHookActive($this->isHookActive($event->getHookId()))
|
||||
->setTemplates($event->getTemplates())
|
||||
->save();
|
||||
|
||||
$event->setModuleHook($moduleHook);
|
||||
|
||||
$this->cacheClear($dispatcher);
|
||||
}
|
||||
}
|
||||
|
||||
public function deleteModuleHook(ModuleHookDeleteEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $moduleHook = ModuleHookQuery::create()->findPk($event->getModuleHookId())) {
|
||||
$moduleHook->delete();
|
||||
$event->setModuleHook($moduleHook);
|
||||
|
||||
// Prevent hook recreation by RegisterListenersPass::registerHook()
|
||||
// We store the method here to be able to retreive it when
|
||||
// we need to get all hook declared by a module
|
||||
$imh = new IgnoredModuleHook();
|
||||
$imh
|
||||
->setModuleId($moduleHook->getModuleId())
|
||||
->setHookId($moduleHook->getHookId())
|
||||
->setMethod($moduleHook->getMethod())
|
||||
->setClassname($moduleHook->getClassname())
|
||||
->save();
|
||||
|
||||
$this->cacheClear($dispatcher);
|
||||
}
|
||||
}
|
||||
|
||||
public function toggleModuleHookActivation(ModuleHookToggleActivationEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $moduleHook = $event->getModuleHook()) {
|
||||
if ($moduleHook->getModuleActive()) {
|
||||
$moduleHook->setActive(!$moduleHook->getActive());
|
||||
$moduleHook->save();
|
||||
} else {
|
||||
throw new \LogicException(Translator::getInstance()->trans("The module has to be activated."));
|
||||
}
|
||||
}
|
||||
$this->cacheClear($dispatcher);
|
||||
|
||||
return $event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes position, selecting absolute ou relative change.
|
||||
*
|
||||
* @param UpdatePositionEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*
|
||||
* @return UpdatePositionEvent $event
|
||||
*/
|
||||
public function updateModuleHookPosition(UpdatePositionEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$this->genericUpdatePosition(ModuleHookQuery::create(), $event, $dispatcher);
|
||||
$this->cacheClear($dispatcher);
|
||||
|
||||
return $event;
|
||||
}
|
||||
|
||||
public function updateHook(HookUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if ($event->hasHook()) {
|
||||
$hook = $event->getHook();
|
||||
ModuleHookQuery::create()
|
||||
->filterByHookId($hook->getId())
|
||||
->update(array('HookActive' => $hook->getActivate()));
|
||||
$this->cacheClear($dispatcher);
|
||||
}
|
||||
}
|
||||
|
||||
public function toggleHookActivation(HookToggleActivationEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if ($event->hasHook()) {
|
||||
$hook = $event->getHook();
|
||||
ModuleHookQuery::create()
|
||||
->filterByHookId($hook->getId())
|
||||
->update(array('HookActive' => $hook->getActivate()));
|
||||
$this->cacheClear($dispatcher);
|
||||
}
|
||||
}
|
||||
|
||||
protected function cacheClear(EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$cacheEvent = new CacheEvent($this->cacheDir);
|
||||
|
||||
$dispatcher->dispatch(TheliaEvents::CACHE_CLEAR, $cacheEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::MODULE_HOOK_CREATE => array('createModuleHook', 128),
|
||||
TheliaEvents::MODULE_HOOK_UPDATE => array('updateModuleHook', 128),
|
||||
TheliaEvents::MODULE_HOOK_DELETE => array('deleteModuleHook', 128),
|
||||
TheliaEvents::MODULE_HOOK_UPDATE_POSITION => array('updateModuleHookPosition', 128),
|
||||
TheliaEvents::MODULE_HOOK_TOGGLE_ACTIVATION => array('toggleModuleHookActivation', 128),
|
||||
|
||||
TheliaEvents::MODULE_TOGGLE_ACTIVATION => array('toggleModuleActivation', 64),
|
||||
TheliaEvents::MODULE_DELETE => array('deleteModule', 64),
|
||||
|
||||
TheliaEvents::HOOK_TOGGLE_ACTIVATION => array('toggleHookActivation', 64),
|
||||
TheliaEvents::HOOK_UPDATE => array('updateHook', 64),
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -11,39 +11,63 @@
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Thelia\Action;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Core\Event\Newsletter\NewsletterEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
|
||||
use Thelia\Mailer\MailerFactory;
|
||||
use Thelia\Model\ConfigQuery;
|
||||
use Thelia\Model\NewsletterQuery;
|
||||
use Thelia\Model\Newsletter as NewsletterModel;
|
||||
|
||||
/**
|
||||
* Class Newsletter
|
||||
* @package Thelia\Action
|
||||
* @author Manuel Raynaud <mraynaud@openstudio.fr>
|
||||
* @author Manuel Raynaud <manu@raynaud.io>
|
||||
*/
|
||||
class Newsletter extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
/** @var MailerFactory */
|
||||
protected $mailer;
|
||||
|
||||
/** @var EventDispatcherInterface */
|
||||
protected $dispatcher;
|
||||
|
||||
public function __construct(MailerFactory $mailer, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$this->mailer = $mailer;
|
||||
$this->dispatcher = $dispatcher;
|
||||
}
|
||||
|
||||
public function subscribe(NewsletterEvent $event)
|
||||
{
|
||||
$newsletter = new NewsletterModel();
|
||||
// test if the email is already registered and unsubscribed
|
||||
if (null === $newsletter = NewsletterQuery::create()->findOneByEmail($event->getEmail())) {
|
||||
$newsletter = new NewsletterModel();
|
||||
}
|
||||
|
||||
$newsletter
|
||||
->setEmail($event->getEmail())
|
||||
->setFirstname($event->getFirstname())
|
||||
->setLastname($event->getLastname())
|
||||
->setLocale($event->getLocale())
|
||||
->setUnsubscribed(false)
|
||||
->save();
|
||||
|
||||
$event->setNewsletter($newsletter);
|
||||
|
||||
if (ConfigQuery::getNotifyNewsletterSubscription()) {
|
||||
$this->dispatcher->dispatch(TheliaEvents::NEWSLETTER_CONFIRM_SUBSCRIPTION, $event);
|
||||
}
|
||||
}
|
||||
|
||||
public function unsubscribe(NewsletterEvent $event)
|
||||
{
|
||||
if (null !== $nl = NewsletterQuery::create()->findPk($event->getId())) {
|
||||
$nl->delete();
|
||||
$nl
|
||||
->setUnsubscribed(true)
|
||||
->save();
|
||||
|
||||
$event->setNewsletter($nl);
|
||||
}
|
||||
@@ -63,31 +87,33 @@ class Newsletter extends BaseAction implements EventSubscriberInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of event names this subscriber wants to listen to.
|
||||
*
|
||||
* The array keys are event names and the value can be:
|
||||
*
|
||||
* * The method name to call (priority defaults to 0)
|
||||
* * An array composed of the method name to call and the priority
|
||||
* * An array of arrays composed of the method names to call and respective
|
||||
* priorities, or 0 if unset
|
||||
*
|
||||
* For instance:
|
||||
*
|
||||
* * array('eventName' => 'methodName')
|
||||
* * array('eventName' => array('methodName', $priority))
|
||||
* * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
|
||||
*
|
||||
* @return array The event names to listen to
|
||||
*
|
||||
* @api
|
||||
* @since 2.3.0-alpha2
|
||||
*/
|
||||
public function confirmSubscription(NewsletterEvent $event)
|
||||
{
|
||||
$this->mailer->sendEmailMessage(
|
||||
'newsletter_subscription_confirmation',
|
||||
[ ConfigQuery::getStoreEmail() => ConfigQuery::getStoreName() ],
|
||||
[ $event->getEmail() => $event->getFirstname()." ".$event->getLastname() ],
|
||||
[
|
||||
'email' => $event->getEmail(),
|
||||
'firstname' => $event->getFirstname(),
|
||||
'lastname' => $event->getLastname()
|
||||
],
|
||||
$event->getLocale()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::NEWSLETTER_SUBSCRIBE => array('subscribe', 128),
|
||||
TheliaEvents::NEWSLETTER_UPDATE => array('update', 128),
|
||||
TheliaEvents::NEWSLETTER_UNSUBSCRIBE => array('unsubscribe', 128)
|
||||
TheliaEvents::NEWSLETTER_UNSUBSCRIBE => array('unsubscribe', 128),
|
||||
TheliaEvents::NEWSLETTER_CONFIRM_SUBSCRIPTION => array('confirmSubscription', 128)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,32 +12,42 @@
|
||||
|
||||
namespace Thelia\Action;
|
||||
|
||||
use Propel\Runtime\Propel;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcher;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Cart\CartTrait;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Thelia\Core\Event\Order\OrderAddressEvent;
|
||||
use Thelia\Core\Event\Order\OrderEvent;
|
||||
use Thelia\Core\Event\Order\OrderManualEvent;
|
||||
use Thelia\Core\Event\Order\OrderPaymentEvent;
|
||||
use Thelia\Core\Event\Payment\ManageStockOnCreationEvent;
|
||||
use Thelia\Core\Event\Product\VirtualProductOrderHandleEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\HttpFoundation\Request;
|
||||
use Thelia\Core\Security\SecurityContext;
|
||||
use Thelia\Core\Template\ParserInterface;
|
||||
use Thelia\Core\Security\User\UserInterface;
|
||||
use Thelia\Exception\TheliaProcessException;
|
||||
use Thelia\Mailer\MailerFactory;
|
||||
use Thelia\Model\AddressQuery;
|
||||
use Thelia\Model\Cart as CartModel;
|
||||
use Thelia\Model\ConfigQuery;
|
||||
use Thelia\Model\Currency as CurrencyModel;
|
||||
use Thelia\Model\Customer as CustomerModel;
|
||||
use Thelia\Model\Lang as LangModel;
|
||||
use Thelia\Model\Map\OrderTableMap;
|
||||
use Thelia\Model\MessageQuery;
|
||||
use Thelia\Model\ModuleQuery;
|
||||
use Thelia\Model\Order as ModelOrder;
|
||||
use Thelia\Model\Order as OrderModel;
|
||||
use Thelia\Model\OrderAddress;
|
||||
use Thelia\Model\OrderAddressQuery;
|
||||
use Thelia\Model\OrderProduct;
|
||||
use Thelia\Model\OrderProductAttributeCombination;
|
||||
use Thelia\Model\OrderProductTax;
|
||||
use Thelia\Model\OrderStatusQuery;
|
||||
use Thelia\Model\ProductI18n;
|
||||
use Thelia\Model\ProductSaleElements;
|
||||
use Thelia\Model\ProductSaleElementsQuery;
|
||||
use Thelia\Model\TaxRuleI18n;
|
||||
use Thelia\Module\PaymentModuleInterface;
|
||||
use Thelia\Tools\I18n;
|
||||
|
||||
/**
|
||||
@@ -48,29 +58,18 @@ use Thelia\Tools\I18n;
|
||||
*/
|
||||
class Order extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
use CartTrait;
|
||||
/** @var RequestStack */
|
||||
protected $requestStack;
|
||||
|
||||
/**
|
||||
* @var \Thelia\Core\HttpFoundation\Request
|
||||
*/
|
||||
protected $request;
|
||||
/**
|
||||
* @var MailerFactory
|
||||
*/
|
||||
/** @var MailerFactory */
|
||||
protected $mailer;
|
||||
/**
|
||||
* @var ParserInterface
|
||||
*/
|
||||
protected $parser;
|
||||
/**
|
||||
* @var SecurityContext
|
||||
*/
|
||||
|
||||
/** @var SecurityContext */
|
||||
protected $securityContext;
|
||||
|
||||
public function __construct(Request $request, ParserInterface $parser, MailerFactory $mailer, SecurityContext $securityContext)
|
||||
public function __construct(RequestStack $requestStack, MailerFactory $mailer, SecurityContext $securityContext)
|
||||
{
|
||||
$this->request = $request;
|
||||
$this->parser = $parser;
|
||||
$this->requestStack = $requestStack;
|
||||
$this->mailer = $mailer;
|
||||
$this->securityContext = $securityContext;
|
||||
}
|
||||
@@ -101,6 +100,8 @@ class Order extends BaseAction implements EventSubscriberInterface
|
||||
// Reset postage cost if the delivery module had been removed
|
||||
if ($deliveryModuleId <= 0) {
|
||||
$order->setPostage(0);
|
||||
$order->setPostageTax(0);
|
||||
$order->setPostageTaxRuleTitle(null);
|
||||
}
|
||||
|
||||
$event->setOrder($order);
|
||||
@@ -114,6 +115,8 @@ class Order extends BaseAction implements EventSubscriberInterface
|
||||
$order = $event->getOrder();
|
||||
|
||||
$order->setPostage($event->getPostage());
|
||||
$order->setPostageTax($event->getPostageTax());
|
||||
$order->setPostageTaxRuleTitle($event->getPostageTaxRuleTitle());
|
||||
|
||||
$event->setOrder($order);
|
||||
}
|
||||
@@ -142,20 +145,48 @@ class Order extends BaseAction implements EventSubscriberInterface
|
||||
$event->setOrder($order);
|
||||
}
|
||||
|
||||
protected function createOrder(EventDispatcherInterface $dispatcher, ModelOrder $sessionOrder, CurrencyModel $currency, LangModel $lang, CartModel $cart, CustomerModel $customer)
|
||||
{
|
||||
$con = \Propel\Runtime\Propel::getConnection(
|
||||
OrderTableMap::DATABASE_NAME
|
||||
/**
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
* @param ModelOrder $sessionOrder
|
||||
* @param CurrencyModel $currency
|
||||
* @param LangModel $lang
|
||||
* @param CartModel $cart
|
||||
* @param UserInterface $customer
|
||||
* @param bool $manageStock decrement stock when order is created if true
|
||||
* @param bool $useOrderDefinedAddresses if true, the delivery and invoice OrderAddresses will be used instead of creating new OrderAdresses using Order::getChoosenXXXAddress()
|
||||
* @return ModelOrder
|
||||
* @throws \Exception
|
||||
* @throws \Propel\Runtime\Exception\PropelException
|
||||
*/
|
||||
protected function createOrder(
|
||||
EventDispatcherInterface $dispatcher,
|
||||
ModelOrder $sessionOrder,
|
||||
CurrencyModel $currency,
|
||||
LangModel $lang,
|
||||
CartModel $cart,
|
||||
UserInterface $customer,
|
||||
$manageStock,
|
||||
$useOrderDefinedAddresses = false
|
||||
) {
|
||||
$con = Propel::getConnection(
|
||||
OrderTableMap::DATABASE_NAME
|
||||
);
|
||||
|
||||
$con->beginTransaction();
|
||||
|
||||
$placedOrder = $sessionOrder->copy();
|
||||
|
||||
// Be sure to create a brand new order, as copy raises the modified flag for all fields
|
||||
// and will also copy order reference and id.
|
||||
$placedOrder->setId(null)->setRef(null)->setNew(true);
|
||||
|
||||
// Dates should be marked as not updated so that Propel will update them.
|
||||
$placedOrder->resetModified(OrderTableMap::CREATED_AT);
|
||||
$placedOrder->resetModified(OrderTableMap::UPDATED_AT);
|
||||
$placedOrder->resetModified(OrderTableMap::VERSION_CREATED_AT);
|
||||
|
||||
$placedOrder->setDispatcher($dispatcher);
|
||||
|
||||
$deliveryAddress = AddressQuery::create()->findPk($sessionOrder->getChoosenDeliveryAddress());
|
||||
$taxCountry = $deliveryAddress->getCountry();
|
||||
$invoiceAddress = AddressQuery::create()->findPk($sessionOrder->getChoosenInvoiceAddress());
|
||||
$cartItems = $cart->getCartItems();
|
||||
|
||||
/* fulfill order */
|
||||
@@ -163,50 +194,67 @@ class Order extends BaseAction implements EventSubscriberInterface
|
||||
$placedOrder->setCurrencyId($currency->getId());
|
||||
$placedOrder->setCurrencyRate($currency->getRate());
|
||||
$placedOrder->setLangId($lang->getId());
|
||||
|
||||
if ($useOrderDefinedAddresses) {
|
||||
$taxCountry =
|
||||
OrderAddressQuery::create()
|
||||
->findPk($placedOrder->getDeliveryOrderAddressId())
|
||||
->getCountry()
|
||||
;
|
||||
} else {
|
||||
$deliveryAddress = AddressQuery::create()->findPk($sessionOrder->getChoosenDeliveryAddress());
|
||||
$invoiceAddress = AddressQuery::create()->findPk($sessionOrder->getChoosenInvoiceAddress());
|
||||
|
||||
/* hard save the delivery and invoice addresses */
|
||||
$deliveryOrderAddress = new OrderAddress();
|
||||
$deliveryOrderAddress
|
||||
->setCustomerTitleId($deliveryAddress->getTitleId())
|
||||
->setCompany($deliveryAddress->getCompany())
|
||||
->setFirstname($deliveryAddress->getFirstname())
|
||||
->setLastname($deliveryAddress->getLastname())
|
||||
->setAddress1($deliveryAddress->getAddress1())
|
||||
->setAddress2($deliveryAddress->getAddress2())
|
||||
->setAddress3($deliveryAddress->getAddress3())
|
||||
->setZipcode($deliveryAddress->getZipcode())
|
||||
->setCity($deliveryAddress->getCity())
|
||||
->setPhone($deliveryAddress->getPhone())
|
||||
->setCountryId($deliveryAddress->getCountryId())
|
||||
->save($con)
|
||||
;
|
||||
/* hard save the delivery and invoice addresses */
|
||||
$deliveryOrderAddress = new OrderAddress();
|
||||
$deliveryOrderAddress
|
||||
->setCustomerTitleId($deliveryAddress->getTitleId())
|
||||
->setCompany($deliveryAddress->getCompany())
|
||||
->setFirstname($deliveryAddress->getFirstname())
|
||||
->setLastname($deliveryAddress->getLastname())
|
||||
->setAddress1($deliveryAddress->getAddress1())
|
||||
->setAddress2($deliveryAddress->getAddress2())
|
||||
->setAddress3($deliveryAddress->getAddress3())
|
||||
->setZipcode($deliveryAddress->getZipcode())
|
||||
->setCity($deliveryAddress->getCity())
|
||||
->setPhone($deliveryAddress->getPhone())
|
||||
->setCellphone($deliveryAddress->getCellphone())
|
||||
->setCountryId($deliveryAddress->getCountryId())
|
||||
->setStateId($deliveryAddress->getStateId())
|
||||
->save($con);
|
||||
|
||||
$invoiceOrderAddress = new OrderAddress();
|
||||
$invoiceOrderAddress
|
||||
->setCustomerTitleId($invoiceAddress->getTitleId())
|
||||
->setCompany($invoiceAddress->getCompany())
|
||||
->setFirstname($invoiceAddress->getFirstname())
|
||||
->setLastname($invoiceAddress->getLastname())
|
||||
->setAddress1($invoiceAddress->getAddress1())
|
||||
->setAddress2($invoiceAddress->getAddress2())
|
||||
->setAddress3($invoiceAddress->getAddress3())
|
||||
->setZipcode($invoiceAddress->getZipcode())
|
||||
->setCity($invoiceAddress->getCity())
|
||||
->setPhone($invoiceAddress->getPhone())
|
||||
->setCountryId($invoiceAddress->getCountryId())
|
||||
->save($con)
|
||||
;
|
||||
$invoiceOrderAddress = new OrderAddress();
|
||||
$invoiceOrderAddress
|
||||
->setCustomerTitleId($invoiceAddress->getTitleId())
|
||||
->setCompany($invoiceAddress->getCompany())
|
||||
->setFirstname($invoiceAddress->getFirstname())
|
||||
->setLastname($invoiceAddress->getLastname())
|
||||
->setAddress1($invoiceAddress->getAddress1())
|
||||
->setAddress2($invoiceAddress->getAddress2())
|
||||
->setAddress3($invoiceAddress->getAddress3())
|
||||
->setZipcode($invoiceAddress->getZipcode())
|
||||
->setCity($invoiceAddress->getCity())
|
||||
->setPhone($invoiceAddress->getPhone())
|
||||
->setCellphone($invoiceAddress->getCellphone())
|
||||
->setCountryId($invoiceAddress->getCountryId())
|
||||
->setStateId($deliveryAddress->getStateId())
|
||||
->save($con);
|
||||
|
||||
$placedOrder->setDeliveryOrderAddressId($deliveryOrderAddress->getId());
|
||||
$placedOrder->setInvoiceOrderAddressId($invoiceOrderAddress->getId());
|
||||
$placedOrder->setDeliveryOrderAddressId($deliveryOrderAddress->getId());
|
||||
$placedOrder->setInvoiceOrderAddressId($invoiceOrderAddress->getId());
|
||||
|
||||
$taxCountry = $deliveryAddress->getCountry();
|
||||
}
|
||||
|
||||
$placedOrder->setStatusId(
|
||||
OrderStatusQuery::getNotPaidStatus()->getId()
|
||||
OrderStatusQuery::getNotPaidStatus()->getId()
|
||||
);
|
||||
|
||||
$placedOrder->setCartId($cart->getId());
|
||||
|
||||
/* memorize discount */
|
||||
$placedOrder->setDiscount(
|
||||
$cart->getDiscount()
|
||||
$cart->getDiscount()
|
||||
);
|
||||
|
||||
$placedOrder->save($con);
|
||||
@@ -217,30 +265,57 @@ class Order extends BaseAction implements EventSubscriberInterface
|
||||
$product = $cartItem->getProduct();
|
||||
|
||||
/* get translation */
|
||||
/** @var ProductI18n $productI18n */
|
||||
$productI18n = I18n::forceI18nRetrieving($lang->getLocale(), 'Product', $product->getId());
|
||||
|
||||
$pse = $cartItem->getProductSaleElements();
|
||||
|
||||
// get the virtual document path
|
||||
$virtualDocumentEvent = new VirtualProductOrderHandleEvent($placedOrder, $pse->getId());
|
||||
// essentially used for virtual product. modules that handles virtual product can
|
||||
// allow the use of stock even for virtual products
|
||||
$useStock = true;
|
||||
$virtual = 0;
|
||||
|
||||
// if the product is virtual, dispatch an event to collect information
|
||||
if ($product->getVirtual() === 1) {
|
||||
$dispatcher->dispatch(TheliaEvents::VIRTUAL_PRODUCT_ORDER_HANDLE, $virtualDocumentEvent);
|
||||
$useStock = $virtualDocumentEvent->isUseStock();
|
||||
$virtual = $virtualDocumentEvent->isVirtual() ? 1 : 0;
|
||||
}
|
||||
|
||||
/* check still in stock */
|
||||
if ($cartItem->getQuantity() > $pse->getQuantity()) {
|
||||
if ($cartItem->getQuantity() > $pse->getQuantity()
|
||||
&& true === ConfigQuery::checkAvailableStock()
|
||||
&& $useStock) {
|
||||
throw new TheliaProcessException("Not enough stock", TheliaProcessException::CART_ITEM_NOT_ENOUGH_STOCK, $cartItem);
|
||||
}
|
||||
|
||||
/* decrease stock */
|
||||
$pse->setQuantity(
|
||||
$pse->getQuantity() - $cartItem->getQuantity()
|
||||
);
|
||||
$pse->save($con);
|
||||
if ($useStock && $manageStock) {
|
||||
/* decrease stock for non virtual product */
|
||||
$allowNegativeStock = intval(ConfigQuery::read('allow_negative_stock', 0));
|
||||
$newStock = $pse->getQuantity() - $cartItem->getQuantity();
|
||||
//Forbid negative stock
|
||||
if ($newStock < 0 && 0 === $allowNegativeStock) {
|
||||
$newStock = 0;
|
||||
}
|
||||
$pse->setQuantity(
|
||||
$newStock
|
||||
);
|
||||
|
||||
$pse->save($con);
|
||||
}
|
||||
|
||||
/* get tax */
|
||||
/** @var TaxRuleI18n $taxRuleI18n */
|
||||
$taxRuleI18n = I18n::forceI18nRetrieving($lang->getLocale(), 'TaxRule', $product->getTaxRuleId());
|
||||
|
||||
$taxDetail = $product->getTaxRule()->getTaxDetail(
|
||||
$product,
|
||||
$taxCountry,
|
||||
$cartItem->getPrice(),
|
||||
$cartItem->getPromoPrice(),
|
||||
$lang->getLocale()
|
||||
$product,
|
||||
$taxCountry,
|
||||
$cartItem->getPrice(),
|
||||
$cartItem->getPromoPrice(),
|
||||
$lang->getLocale()
|
||||
);
|
||||
|
||||
$orderProduct = new OrderProduct();
|
||||
@@ -248,10 +323,13 @@ class Order extends BaseAction implements EventSubscriberInterface
|
||||
->setOrderId($placedOrder->getId())
|
||||
->setProductRef($product->getRef())
|
||||
->setProductSaleElementsRef($pse->getRef())
|
||||
->setProductSaleElementsId($pse->getId())
|
||||
->setTitle($productI18n->getTitle())
|
||||
->setChapo($productI18n->getChapo())
|
||||
->setDescription($productI18n->getDescription())
|
||||
->setPostscriptum($productI18n->getPostscriptum())
|
||||
->setVirtual($virtual)
|
||||
->setVirtualDocument($virtualDocumentEvent->getPath())
|
||||
->setQuantity($cartItem->getQuantity())
|
||||
->setPrice($cartItem->getPrice())
|
||||
->setPromoPrice($cartItem->getPromoPrice())
|
||||
@@ -261,12 +339,13 @@ class Order extends BaseAction implements EventSubscriberInterface
|
||||
->setTaxRuleTitle($taxRuleI18n->getTitle())
|
||||
->setTaxRuleDescription($taxRuleI18n->getDescription())
|
||||
->setEanCode($pse->getEanCode())
|
||||
->setCartIemId($cartItem->getId())
|
||||
->setCartItemId($cartItem->getId())
|
||||
->setDispatcher($dispatcher)
|
||||
->save($con)
|
||||
->save($con)
|
||||
;
|
||||
|
||||
/* fulfill order_product_tax */
|
||||
/** @var OrderProductTax $tax */
|
||||
foreach ($taxDetail as $tax) {
|
||||
$tax->setOrderProductId($orderProduct->getId());
|
||||
$tax->save($con);
|
||||
@@ -274,7 +353,10 @@ class Order extends BaseAction implements EventSubscriberInterface
|
||||
|
||||
/* fulfill order_attribute_combination and decrease stock */
|
||||
foreach ($pse->getAttributeCombinations() as $attributeCombination) {
|
||||
/** @var \Thelia\Model\Attribute $attribute */
|
||||
$attribute = I18n::forceI18nRetrieving($lang->getLocale(), 'Attribute', $attributeCombination->getAttributeId());
|
||||
|
||||
/** @var \Thelia\Model\AttributeAv $attributeAv */
|
||||
$attributeAv = I18n::forceI18nRetrieving($lang->getLocale(), 'AttributeAv', $attributeCombination->getAttributeAvId());
|
||||
|
||||
$orderAttributeCombination = new OrderProductAttributeCombination();
|
||||
@@ -288,7 +370,7 @@ class Order extends BaseAction implements EventSubscriberInterface
|
||||
->setAttributeAvChapo($attributeAv->getChapo())
|
||||
->setAttributeAvDescription($attributeAv->getDescription())
|
||||
->setAttributeAvPostscriptum($attributeAv->getPostscriptum())
|
||||
->save($con);
|
||||
->save($con);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -299,50 +381,72 @@ class Order extends BaseAction implements EventSubscriberInterface
|
||||
|
||||
/**
|
||||
* Create an order outside of the front-office context, e.g. manually from the back-office.
|
||||
* @param OrderManualEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function createManual(OrderManualEvent $event)
|
||||
public function createManual(OrderManualEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$paymentModule = ModuleQuery::create()->findPk($event->getOrder()->getPaymentModuleId());
|
||||
|
||||
/** @var \Thelia\Module\PaymentModuleInterface $paymentModuleInstance */
|
||||
$paymentModuleInstance = $paymentModule->createInstance();
|
||||
|
||||
$event->setPlacedOrder(
|
||||
$this->createOrder(
|
||||
$event->getDispatcher(),
|
||||
$dispatcher,
|
||||
$event->getOrder(),
|
||||
$event->getCurrency(),
|
||||
$event->getLang(),
|
||||
$event->getCart(),
|
||||
$event->getCustomer()
|
||||
$event->getCustomer(),
|
||||
$this->isModuleManageStockOnCreation(
|
||||
$dispatcher,
|
||||
$paymentModuleInstance
|
||||
),
|
||||
$event->getUseOrderDefinedAddresses()
|
||||
)
|
||||
);
|
||||
|
||||
$event->setOrder(new \Thelia\Model\Order());
|
||||
$event->setOrder(new OrderModel());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OrderEvent $event
|
||||
*
|
||||
* @throws \Thelia\Exception\TheliaProcessException
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function create(OrderEvent $event)
|
||||
public function create(OrderEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$session = $this->getSession();
|
||||
|
||||
$order = $event->getOrder();
|
||||
$paymentModule = ModuleQuery::create()->findPk($order->getPaymentModuleId());
|
||||
|
||||
/** @var \Thelia\Module\PaymentModuleInterface $paymentModuleInstance */
|
||||
$paymentModuleInstance = $paymentModule->createInstance();
|
||||
|
||||
$placedOrder = $this->createOrder(
|
||||
$event->getDispatcher(),
|
||||
$dispatcher,
|
||||
$event->getOrder(),
|
||||
$session->getCurrency(),
|
||||
$session->getLang(),
|
||||
$session->getCart(),
|
||||
$this->securityContext->getCustomerUser()
|
||||
$session->getSessionCart($dispatcher),
|
||||
$this->securityContext->getCustomerUser(),
|
||||
$this->isModuleManageStockOnCreation(
|
||||
$dispatcher,
|
||||
$paymentModuleInstance
|
||||
)
|
||||
);
|
||||
|
||||
$event->getDispatcher()->dispatch(TheliaEvents::ORDER_BEFORE_PAYMENT, new OrderEvent($placedOrder));
|
||||
$dispatcher->dispatch(TheliaEvents::ORDER_BEFORE_PAYMENT, new OrderEvent($placedOrder));
|
||||
|
||||
/* but memorize placed order */
|
||||
$event->setOrder(new \Thelia\Model\Order());
|
||||
$event->setOrder(new OrderModel());
|
||||
$event->setPlacedOrder($placedOrder);
|
||||
|
||||
/* empty cart */
|
||||
$dispatcher = $event->getDispatcher();
|
||||
|
||||
/* call pay method */
|
||||
$payEvent = new OrderPaymentEvent($placedOrder);
|
||||
|
||||
@@ -354,68 +458,177 @@ class Order extends BaseAction implements EventSubscriberInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Thelia\Core\Event\Order\OrderEvent $event
|
||||
* @param OrderEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function sendOrderEmail(OrderEvent $event)
|
||||
public function orderBeforePayment(OrderEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$contact_email = ConfigQuery::read('store_email');
|
||||
$dispatcher ->dispatch(TheliaEvents::ORDER_SEND_CONFIRMATION_EMAIL, clone $event);
|
||||
|
||||
if ($contact_email) {
|
||||
|
||||
$message = MessageQuery::create()
|
||||
->filterByName('order_confirmation')
|
||||
->findOne();
|
||||
|
||||
if (false === $message) {
|
||||
throw new \Exception("Failed to load message 'order_confirmation'.");
|
||||
}
|
||||
|
||||
$order = $event->getOrder();
|
||||
$customer = $order->getCustomer();
|
||||
|
||||
$this->parser->assign('order_id', $order->getId());
|
||||
$this->parser->assign('order_ref', $order->getRef());
|
||||
|
||||
$message
|
||||
->setLocale($order->getLang()->getLocale());
|
||||
|
||||
$instance = \Swift_Message::newInstance()
|
||||
->addTo($customer->getEmail(), $customer->getFirstname()." ".$customer->getLastname())
|
||||
->addFrom($contact_email, ConfigQuery::read('store_name'))
|
||||
;
|
||||
|
||||
// Build subject and body
|
||||
|
||||
$message->buildMessage($this->parser, $instance);
|
||||
|
||||
$this->getMailer()->send($instance);
|
||||
}
|
||||
$dispatcher->dispatch(TheliaEvents::ORDER_SEND_NOTIFICATION_EMAIL, clone $event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the cart and the order in the customer session once the order is placed,
|
||||
* and the payment performed.
|
||||
*
|
||||
* return an instance of \Swift_Mailer with good Transporter configured.
|
||||
*
|
||||
* @return \Swift_Mailer
|
||||
* @param OrderEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function getMailer()
|
||||
public function orderCartClear(/** @noinspection PhpUnusedParameterInspection */ OrderEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
return $this->mailer->getSwiftMailer();
|
||||
// Empty cart and clear current order
|
||||
$session = $this->getSession();
|
||||
|
||||
$session->clearSessionCart($dispatcher);
|
||||
|
||||
$session->setOrder(new OrderModel());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OrderEvent $event
|
||||
*
|
||||
* @throws \Exception if the message cannot be loaded.
|
||||
*/
|
||||
public function sendConfirmationEmail(OrderEvent $event)
|
||||
{
|
||||
$this->mailer->sendEmailToCustomer(
|
||||
'order_confirmation',
|
||||
$event->getOrder()->getCustomer(),
|
||||
[
|
||||
'order_id' => $event->getOrder()->getId(),
|
||||
'order_ref' => $event->getOrder()->getRef()
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OrderEvent $event
|
||||
*
|
||||
* @throws \Exception if the message cannot be loaded.
|
||||
*/
|
||||
public function sendNotificationEmail(OrderEvent $event)
|
||||
{
|
||||
$this->mailer->sendEmailToShopManagers(
|
||||
'order_notification',
|
||||
[
|
||||
'order_id' => $event->getOrder()->getId(),
|
||||
'order_ref' => $event->getOrder()->getRef()
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OrderEvent $event
|
||||
*/
|
||||
public function updateStatus(OrderEvent $event)
|
||||
public function updateStatus(OrderEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$order = $event->getOrder();
|
||||
$newStatus = $event->getStatus();
|
||||
$paymentModule = ModuleQuery::create()->findPk($order->getPaymentModuleId());
|
||||
/** @var PaymentModuleInterface $paymentModuleInstance */
|
||||
$paymentModuleInstance = $paymentModule->createInstance();
|
||||
|
||||
$order->setStatusId($event->getStatus());
|
||||
$manageStockOnCreation = $this->isModuleManageStockOnCreation(
|
||||
$dispatcher,
|
||||
$paymentModuleInstance
|
||||
);
|
||||
|
||||
$this->updateQuantity($order, $newStatus, $manageStockOnCreation);
|
||||
|
||||
$order->setStatusId($newStatus);
|
||||
$order->save();
|
||||
|
||||
$event->setOrder($order);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ModelOrder $order
|
||||
* @param $newStatus $newStatus the new status ID
|
||||
* @throws \Thelia\Exception\TheliaProcessException
|
||||
*/
|
||||
public function updateQuantity(ModelOrder $order, $newStatus, $manageStockOnCreation = true)
|
||||
{
|
||||
$canceledStatus = OrderStatusQuery::getCancelledStatus()->getId();
|
||||
$paidStatus = OrderStatusQuery::getPaidStatus()->getId();
|
||||
if ($newStatus == $canceledStatus || $order->isCancelled()) {
|
||||
$this->updateQuantityForCanceledOrder($order, $newStatus, $canceledStatus);
|
||||
} elseif ($paidStatus == $newStatus && $order->isNotPaid() && $order->getVersion() == 1) {
|
||||
$this->updateQuantityForPaidOrder($order, $manageStockOnCreation);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ModelOrder $order
|
||||
* @throws \Exception
|
||||
* @throws \Propel\Runtime\Exception\PropelException
|
||||
*/
|
||||
protected function updateQuantityForPaidOrder(ModelOrder $order, $manageStockOnCreation)
|
||||
{
|
||||
$paymentModule = ModuleQuery::create()->findPk($order->getPaymentModuleId());
|
||||
|
||||
/** @var \Thelia\Module\PaymentModuleInterface $paymentModuleInstance */
|
||||
$paymentModuleInstance = $paymentModule->createInstance();
|
||||
|
||||
if (false === $manageStockOnCreation) {
|
||||
$orderProductList = $order->getOrderProducts();
|
||||
|
||||
/** @var OrderProduct $orderProduct */
|
||||
foreach ($orderProductList as $orderProduct) {
|
||||
$productSaleElementsId = $orderProduct->getProductSaleElementsId();
|
||||
|
||||
/** @var ProductSaleElements $productSaleElements */
|
||||
if (null !== $productSaleElements = ProductSaleElementsQuery::create()->findPk($productSaleElementsId)) {
|
||||
/* check still in stock */
|
||||
if ($orderProduct->getQuantity() > $productSaleElements->getQuantity() && true === ConfigQuery::checkAvailableStock()) {
|
||||
throw new TheliaProcessException($productSaleElements->getRef() . " : Not enough stock");
|
||||
}
|
||||
|
||||
$productSaleElements->setQuantity($productSaleElements->getQuantity() - $orderProduct->getQuantity());
|
||||
|
||||
$productSaleElements->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update product quantity if new status is canceled or if old status is canceled.
|
||||
*
|
||||
* @param ModelOrder $order
|
||||
* @param $newStatus
|
||||
* @param $canceledStatus
|
||||
* @throws \Exception
|
||||
* @throws \Propel\Runtime\Exception\PropelException
|
||||
*/
|
||||
protected function updateQuantityForCanceledOrder(ModelOrder $order, $newStatus, $canceledStatus)
|
||||
{
|
||||
$orderProductList = $order->getOrderProducts();
|
||||
|
||||
/** @var OrderProduct $orderProduct */
|
||||
foreach ($orderProductList as $orderProduct) {
|
||||
$productSaleElementsId = $orderProduct->getProductSaleElementsId();
|
||||
|
||||
/** @var ProductSaleElements $productSaleElements */
|
||||
if (null !== $productSaleElements = ProductSaleElementsQuery::create()->findPk($productSaleElementsId)) {
|
||||
if ($newStatus == $canceledStatus) {
|
||||
$productSaleElements->setQuantity($productSaleElements->getQuantity() + $orderProduct->getQuantity());
|
||||
} else {
|
||||
/* check still in stock */
|
||||
if ($orderProduct->getQuantity() > $productSaleElements->getQuantity() && true === ConfigQuery::checkAvailableStock()) {
|
||||
throw new TheliaProcessException($productSaleElements->getRef() . " : Not enough stock");
|
||||
}
|
||||
|
||||
$productSaleElements->setQuantity($productSaleElements->getQuantity() - $orderProduct->getQuantity());
|
||||
}
|
||||
|
||||
$productSaleElements->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OrderEvent $event
|
||||
*/
|
||||
@@ -429,6 +642,19 @@ class Order extends BaseAction implements EventSubscriberInterface
|
||||
$event->setOrder($order);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OrderEvent $event
|
||||
*/
|
||||
public function updateTransactionRef(OrderEvent $event)
|
||||
{
|
||||
$order = $event->getOrder();
|
||||
|
||||
$order->setTransactionRef($event->getTransactionRef());
|
||||
$order->save();
|
||||
|
||||
$event->setOrder($order);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OrderAddressEvent $event
|
||||
*/
|
||||
@@ -447,7 +673,9 @@ class Order extends BaseAction implements EventSubscriberInterface
|
||||
->setZipcode($event->getZipcode())
|
||||
->setCity($event->getCity())
|
||||
->setCountryId($event->getCountry())
|
||||
->setStateId($event->getState())
|
||||
->setPhone($event->getPhone())
|
||||
->setCellphone($event->getCellphone())
|
||||
;
|
||||
$orderAddress->save();
|
||||
|
||||
@@ -455,24 +683,30 @@ class Order extends BaseAction implements EventSubscriberInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of event names this subscriber wants to listen to.
|
||||
* Check if a payment module manage stock on creation
|
||||
*
|
||||
* The array keys are event names and the value can be:
|
||||
*
|
||||
* * The method name to call (priority defaults to 0)
|
||||
* * An array composed of the method name to call and the priority
|
||||
* * An array of arrays composed of the method names to call and respective
|
||||
* priorities, or 0 if unset
|
||||
*
|
||||
* For instance:
|
||||
*
|
||||
* * array('eventName' => 'methodName')
|
||||
* * array('eventName' => array('methodName', $priority))
|
||||
* * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
|
||||
*
|
||||
* @return array The event names to listen to
|
||||
*
|
||||
* @api
|
||||
* @param EventDispatcher $dispatcher
|
||||
* @param PaymentModuleInterface $module
|
||||
* @return bool if the module manage stock on creation, false otherwise
|
||||
*/
|
||||
protected function isModuleManageStockOnCreation(EventDispatcherInterface $dispatcher, PaymentModuleInterface $module)
|
||||
{
|
||||
$event = new ManageStockOnCreationEvent($module);
|
||||
|
||||
$dispatcher->dispatch(
|
||||
TheliaEvents::getModuleEvent(
|
||||
TheliaEvents::MODULE_PAYMENT_MANAGE_STOCK,
|
||||
$module->getCode()
|
||||
)
|
||||
);
|
||||
|
||||
return (null !== $event->getManageStock())
|
||||
? $event->getManageStock()
|
||||
: $module->manageStockOnCreation();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
@@ -483,9 +717,13 @@ class Order extends BaseAction implements EventSubscriberInterface
|
||||
TheliaEvents::ORDER_SET_INVOICE_ADDRESS => array("setInvoiceAddress", 128),
|
||||
TheliaEvents::ORDER_SET_PAYMENT_MODULE => array("setPaymentModule", 128),
|
||||
TheliaEvents::ORDER_PAY => array("create", 128),
|
||||
TheliaEvents::ORDER_BEFORE_PAYMENT => array("sendOrderEmail", 128),
|
||||
TheliaEvents::ORDER_CART_CLEAR => array("orderCartClear", 128),
|
||||
TheliaEvents::ORDER_BEFORE_PAYMENT => array("orderBeforePayment", 128),
|
||||
TheliaEvents::ORDER_SEND_CONFIRMATION_EMAIL => array("sendConfirmationEmail", 128),
|
||||
TheliaEvents::ORDER_SEND_NOTIFICATION_EMAIL => array("sendNotificationEmail", 128),
|
||||
TheliaEvents::ORDER_UPDATE_STATUS => array("updateStatus", 128),
|
||||
TheliaEvents::ORDER_UPDATE_DELIVERY_REF => array("updateDeliveryRef", 128),
|
||||
TheliaEvents::ORDER_UPDATE_TRANSACTION_REF => array("updateTransactionRef", 128),
|
||||
TheliaEvents::ORDER_UPDATE_ADDRESS => array("updateAddress", 128),
|
||||
TheliaEvents::ORDER_CREATE_MANUAL => array("createManual", 128),
|
||||
);
|
||||
@@ -498,6 +736,6 @@ class Order extends BaseAction implements EventSubscriberInterface
|
||||
*/
|
||||
protected function getSession()
|
||||
{
|
||||
return $this->request->getSession();
|
||||
return $this->requestStack->getCurrentRequest()->getSession();
|
||||
}
|
||||
}
|
||||
|
||||
147
core/lib/Thelia/Action/OrderStatus.php
Normal file
147
core/lib/Thelia/Action/OrderStatus.php
Normal file
@@ -0,0 +1,147 @@
|
||||
<?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 Thelia\Action;
|
||||
|
||||
use Propel\Runtime\ActiveQuery\Criteria;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Core\Event\OrderStatus\OrderStatusCreateEvent;
|
||||
use Thelia\Core\Event\OrderStatus\OrderStatusDeleteEvent;
|
||||
use Thelia\Core\Event\OrderStatus\OrderStatusEvent;
|
||||
use Thelia\Core\Event\OrderStatus\OrderStatusUpdateEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\Event\UpdatePositionEvent;
|
||||
use Thelia\Core\Translation\Translator;
|
||||
use Thelia\Model\OrderQuery;
|
||||
use Thelia\Model\OrderStatus as OrderStatusModel;
|
||||
use Thelia\Model\OrderStatusQuery;
|
||||
|
||||
/**
|
||||
* Class OrderStatus
|
||||
* @package Thelia\Action
|
||||
* @author Gilles Bourgeat <gbourgeat@openstudio.fr>
|
||||
* @since 2.4
|
||||
*/
|
||||
class OrderStatus extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
/**
|
||||
* @param OrderStatusCreateEvent $event
|
||||
*/
|
||||
public function create(OrderStatusCreateEvent $event)
|
||||
{
|
||||
$this->createOrUpdate($event, new OrderStatusModel());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OrderStatusUpdateEvent $event
|
||||
*/
|
||||
public function update(OrderStatusUpdateEvent $event)
|
||||
{
|
||||
$orderStatus = $this->getOrderStatus($event);
|
||||
$this->createOrUpdate($event, $orderStatus);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OrderStatusDeleteEvent $event
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function delete(OrderStatusDeleteEvent $event)
|
||||
{
|
||||
$orderStatus = $this->getOrderStatus($event);
|
||||
|
||||
if ($orderStatus->getProtectedStatus()) {
|
||||
throw new \Exception(
|
||||
Translator::getInstance()->trans('This status is protected.')
|
||||
. ' ' . Translator::getInstance()->trans('You can not delete it.')
|
||||
);
|
||||
}
|
||||
|
||||
if (null !== OrderQuery::create()->findOneByStatusId($orderStatus->getId())) {
|
||||
throw new \Exception(
|
||||
Translator::getInstance()->trans('Some commands use this status.')
|
||||
. ' ' . Translator::getInstance()->trans('You can not delete it.')
|
||||
);
|
||||
}
|
||||
|
||||
$orderStatus->delete();
|
||||
|
||||
$event->setOrderStatus($orderStatus);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::ORDER_STATUS_CREATE => ["create", 128],
|
||||
TheliaEvents::ORDER_STATUS_UPDATE => ["update", 128],
|
||||
TheliaEvents::ORDER_STATUS_DELETE => ["delete", 128],
|
||||
TheliaEvents::ORDER_STATUS_UPDATE_POSITION => ["updatePosition", 128]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OrderStatusEvent $event
|
||||
* @param OrderStatusModel $orderStatus
|
||||
*/
|
||||
protected function createOrUpdate(OrderStatusEvent $event, OrderStatusModel $orderStatus)
|
||||
{
|
||||
$orderStatus
|
||||
->setCode(!$orderStatus->getProtectedStatus() ? $event->getCode() : $orderStatus->getCode())
|
||||
->setColor($event->getColor())
|
||||
// i18n
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
->setDescription($event->getDescription())
|
||||
->setPostscriptum($event->getPostscriptum())
|
||||
->setChapo($event->getChapo());
|
||||
|
||||
if ($orderStatus->getId() === null) {
|
||||
$orderStatus->setPosition(
|
||||
OrderStatusQuery::create()->orderByPosition(Criteria::DESC)->findOne()->getPosition() + 1
|
||||
);
|
||||
}
|
||||
|
||||
$orderStatus->save();
|
||||
|
||||
$event->setOrderStatus($orderStatus);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes position, selecting absolute ou relative change.
|
||||
*
|
||||
* @param UpdatePositionEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function updatePosition(UpdatePositionEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$this->genericUpdatePosition(OrderStatusQuery::create(), $event, $dispatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OrderStatusUpdateEvent $event
|
||||
* @return OrderStatusModel
|
||||
*/
|
||||
protected function getOrderStatus(OrderStatusUpdateEvent $event)
|
||||
{
|
||||
if (null === $orderStatus = OrderStatusQuery::create()->findOneById($event->getId())) {
|
||||
throw new \LogicException(
|
||||
"Order status not found"
|
||||
);
|
||||
}
|
||||
|
||||
return $orderStatus;
|
||||
}
|
||||
}
|
||||
63
core/lib/Thelia/Action/Payment.php
Normal file
63
core/lib/Thelia/Action/Payment.php
Normal file
@@ -0,0 +1,63 @@
|
||||
<?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 Thelia\Action;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Core\Event\Payment\IsValidPaymentEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
|
||||
/**
|
||||
* Class Payment
|
||||
* @package Thelia\Action
|
||||
* @author Julien Chanséaume <julien@thelia.net>
|
||||
*/
|
||||
class Payment implements EventSubscriberInterface
|
||||
{
|
||||
/**
|
||||
* Check if a module is valid
|
||||
*
|
||||
* @param IsValidPaymentEvent $event
|
||||
*/
|
||||
public function isValid(IsValidPaymentEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$module = $event->getModule();
|
||||
|
||||
// dispatch event to target specific module
|
||||
$dispatcher->dispatch(
|
||||
TheliaEvents::getModuleEvent(
|
||||
TheliaEvents::MODULE_PAYMENT_IS_VALID,
|
||||
$module->getCode()
|
||||
),
|
||||
$event
|
||||
);
|
||||
|
||||
if ($event->isPropagationStopped()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// call legacy module method
|
||||
$event->setValidModule($module->isValidPayment());
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return [
|
||||
TheliaEvents::MODULE_PAYMENT_IS_VALID => ['isValid', 128],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Thelia\Action;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Core\Event\PdfEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
@@ -18,15 +19,22 @@ use Thelia\Core\Event\TheliaEvents;
|
||||
/**
|
||||
* Class Pdf
|
||||
* @package Thelia\Action
|
||||
* @author Manuel Raynaud <mraynaud@openstudio.fr>
|
||||
* @author Manuel Raynaud <manu@raynaud.io>
|
||||
*/
|
||||
class Pdf extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
|
||||
public function generatePdf(PdfEvent $event)
|
||||
{
|
||||
$html2pdf = new \HTML2PDF(
|
||||
$event->getOrientation(),
|
||||
$event->getFormat(),
|
||||
$event->getLang(),
|
||||
$event->getUnicode(),
|
||||
$event->getEncoding(),
|
||||
$event->getMarges()
|
||||
);
|
||||
|
||||
$html2pdf = new \HTML2PDF($event->getOrientation(), $event->getFormat(), $event->getLang(), $event->getUnicode(), $event->getEncoding(), $event->getMarges());
|
||||
$html2pdf->setDefaultFont($event->getFontName());
|
||||
|
||||
$html2pdf->pdf->SetDisplayMode('real');
|
||||
|
||||
@@ -35,24 +43,7 @@ class Pdf extends BaseAction implements EventSubscriberInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of event names this subscriber wants to listen to.
|
||||
*
|
||||
* The array keys are event names and the value can be:
|
||||
*
|
||||
* * The method name to call (priority defaults to 0)
|
||||
* * An array composed of the method name to call and the priority
|
||||
* * An array of arrays composed of the method names to call and respective
|
||||
* priorities, or 0 if unset
|
||||
*
|
||||
* For instance:
|
||||
*
|
||||
* * array('eventName' => 'methodName')
|
||||
* * array('eventName' => array('methodName', $priority))
|
||||
* * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
|
||||
*
|
||||
* @return array The event names to listen to
|
||||
*
|
||||
* @api
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -12,21 +12,30 @@
|
||||
|
||||
namespace Thelia\Action;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
|
||||
use Thelia\Core\Event\Product\ProductCloneEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\Event\ProductSaleElement\ProductSaleElementCreateEvent;
|
||||
use Thelia\Core\Template\Loop\ProductSaleElementsDocument;
|
||||
use Thelia\Core\Template\Loop\ProductSaleElementsImage;
|
||||
use Thelia\Model\AttributeCombinationQuery;
|
||||
use Thelia\Model\Map\ProductSaleElementsTableMap;
|
||||
use Thelia\Model\ProductDocumentQuery;
|
||||
use Thelia\Model\ProductImageQuery;
|
||||
use Thelia\Model\ProductSaleElements;
|
||||
use Thelia\Model\ProductPrice;
|
||||
use Thelia\Model\AttributeCombination;
|
||||
use Thelia\Core\Event\ProductSaleElement\ProductSaleElementDeleteEvent;
|
||||
use Thelia\Model\ProductSaleElementsProductDocument;
|
||||
use Thelia\Model\ProductSaleElementsProductDocumentQuery;
|
||||
use Thelia\Model\ProductSaleElementsProductImage;
|
||||
use Thelia\Model\ProductSaleElementsProductImageQuery;
|
||||
use Thelia\Model\ProductSaleElementsQuery;
|
||||
use Thelia\Core\Event\ProductSaleElement\ProductSaleElementUpdateEvent;
|
||||
use Thelia\Model\ProductPriceQuery;
|
||||
use Propel\Runtime\Propel;
|
||||
use Thelia\Model\AttributeAvQuery;
|
||||
|
||||
use Thelia\Model\Map\AttributeCombinationTableMap;
|
||||
use Propel\Runtime\ActiveQuery\Criteria;
|
||||
use Thelia\Core\Event\Product\ProductCombinationGenerationEvent;
|
||||
@@ -34,11 +43,19 @@ use Propel\Runtime\Connection\ConnectionInterface;
|
||||
|
||||
class ProductSaleElement extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
/** @var EventDispatcherInterface */
|
||||
protected $eventDispatcher;
|
||||
|
||||
public function __construct(EventDispatcherInterface $eventDispatcher)
|
||||
{
|
||||
$this->eventDispatcher = $eventDispatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new product sale element, with or without combination
|
||||
*
|
||||
* @param ProductSaleElementCreateEvent $event
|
||||
* @throws Exception
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function create(ProductSaleElementCreateEvent $event)
|
||||
{
|
||||
@@ -56,7 +73,7 @@ class ProductSaleElement extends BaseAction implements EventSubscriberInterface
|
||||
|
||||
if ($salesElement == null) {
|
||||
// Create a new default product sale element
|
||||
$salesElement = $event->getProduct()->createProductSaleElement($con, 0, 0, 0, $event->getCurrencyId(), true);
|
||||
$salesElement = $event->getProduct()->createProductSaleElement($con, 0, 0, 0, $event->getCurrencyId(), false);
|
||||
} else {
|
||||
// This (new) one is the default
|
||||
$salesElement->setIsDefault(true)->save($con);
|
||||
@@ -66,9 +83,7 @@ class ProductSaleElement extends BaseAction implements EventSubscriberInterface
|
||||
$combinationAttributes = $event->getAttributeAvList();
|
||||
|
||||
if (count($combinationAttributes) > 0) {
|
||||
|
||||
foreach ($combinationAttributes as $attributeAvId) {
|
||||
|
||||
$attributeAv = AttributeAvQuery::create()->findPk($attributeAvId);
|
||||
|
||||
if ($attributeAv !== null) {
|
||||
@@ -88,7 +103,6 @@ class ProductSaleElement extends BaseAction implements EventSubscriberInterface
|
||||
// Store all the stuff !
|
||||
$con->commit();
|
||||
} catch (\Exception $ex) {
|
||||
|
||||
$con->rollback();
|
||||
|
||||
throw $ex;
|
||||
@@ -98,7 +112,8 @@ class ProductSaleElement extends BaseAction implements EventSubscriberInterface
|
||||
/**
|
||||
* Update an existing product sale element
|
||||
*
|
||||
* @param ProductSaleElementUpdateEvent $event
|
||||
* @param ProductSaleElementUpdateEvent $event
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function update(ProductSaleElementUpdateEvent $event)
|
||||
{
|
||||
@@ -109,7 +124,6 @@ class ProductSaleElement extends BaseAction implements EventSubscriberInterface
|
||||
$con->beginTransaction();
|
||||
|
||||
try {
|
||||
|
||||
// Update the product's tax rule
|
||||
$event->getProduct()->setTaxRuleId($event->getTaxRuleId())->save($con);
|
||||
|
||||
@@ -120,6 +134,16 @@ class ProductSaleElement extends BaseAction implements EventSubscriberInterface
|
||||
$salesElement->setProduct($event->getProduct());
|
||||
}
|
||||
|
||||
// If this PSE is the default one, be sure to have *only one* default for this product
|
||||
if ($event->getIsDefault()) {
|
||||
ProductSaleElementsQuery::create()
|
||||
->filterByProduct($event->getProduct())
|
||||
->filterByIsDefault(true)
|
||||
->filterById($event->getProductSaleElementId(), Criteria::NOT_EQUAL)
|
||||
->update(['IsDefault' => false], $con)
|
||||
;
|
||||
}
|
||||
|
||||
// Update sale element
|
||||
$salesElement
|
||||
->setRef($event->getReference())
|
||||
@@ -140,7 +164,6 @@ class ProductSaleElement extends BaseAction implements EventSubscriberInterface
|
||||
|
||||
// If price is not defined, create it.
|
||||
if ($productPrice == null) {
|
||||
|
||||
$productPrice = new ProductPrice();
|
||||
|
||||
$productPrice
|
||||
@@ -171,7 +194,6 @@ class ProductSaleElement extends BaseAction implements EventSubscriberInterface
|
||||
// Store all the stuff !
|
||||
$con->commit();
|
||||
} catch (\Exception $ex) {
|
||||
|
||||
$con->rollback();
|
||||
|
||||
throw $ex;
|
||||
@@ -181,12 +203,12 @@ class ProductSaleElement extends BaseAction implements EventSubscriberInterface
|
||||
/**
|
||||
* Delete a product sale element
|
||||
*
|
||||
* @param ProductSaleElementDeleteEvent $event
|
||||
* @param ProductSaleElementDeleteEvent $event
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function delete(ProductSaleElementDeleteEvent $event)
|
||||
{
|
||||
if (null !== $pse = ProductSaleElementsQuery::create()->findPk($event->getProductSaleElementId())) {
|
||||
|
||||
$product = $pse->getProduct();
|
||||
|
||||
$con = Propel::getWriteConnection(ProductSaleElementsTableMap::DATABASE_NAME);
|
||||
@@ -194,28 +216,28 @@ class ProductSaleElement extends BaseAction implements EventSubscriberInterface
|
||||
$con->beginTransaction();
|
||||
|
||||
try {
|
||||
|
||||
$pse->delete($con);
|
||||
|
||||
if ($product->countSaleElements() <= 0) {
|
||||
if ($product->countSaleElements($con) <= 0) {
|
||||
// If we just deleted the last PSE, create a default one
|
||||
$product->createProductSaleElement($con, 0, 0, 0, $event->getCurrencyId(), true);
|
||||
} elseif ($pse->getIsDefault()) {
|
||||
|
||||
// If we deleted the default PSE, make the last created one the default
|
||||
$pse = ProductSaleElementsQuery::create()
|
||||
$newDefaultPse = ProductSaleElementsQuery::create()
|
||||
->filterByProductId($product->getId())
|
||||
->filterById($pse->getId(), Criteria::NOT_EQUAL)
|
||||
->orderByCreatedAt(Criteria::DESC)
|
||||
->findOne($con)
|
||||
;
|
||||
|
||||
$pse->setIsDefault(true)->save($con);
|
||||
if (null !== $newDefaultPse) {
|
||||
$newDefaultPse->setIsDefault(true)->save($con);
|
||||
}
|
||||
}
|
||||
|
||||
// Store all the stuff !
|
||||
$con->commit();
|
||||
} catch (\Exception $ex) {
|
||||
|
||||
$con->rollback();
|
||||
|
||||
throw $ex;
|
||||
@@ -226,7 +248,8 @@ class ProductSaleElement extends BaseAction implements EventSubscriberInterface
|
||||
/**
|
||||
* Generate combinations. All existing combinations for the product are deleted.
|
||||
*
|
||||
* @param ProductCombinationGenerationEvent $event
|
||||
* @param ProductCombinationGenerationEvent $event
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function generateCombinations(ProductCombinationGenerationEvent $event)
|
||||
{
|
||||
@@ -235,7 +258,6 @@ class ProductSaleElement extends BaseAction implements EventSubscriberInterface
|
||||
$con->beginTransaction();
|
||||
|
||||
try {
|
||||
|
||||
// Delete all product's productSaleElement
|
||||
ProductSaleElementsQuery::create()->filterByProductId($event->product->getId())->delete();
|
||||
|
||||
@@ -243,20 +265,19 @@ class ProductSaleElement extends BaseAction implements EventSubscriberInterface
|
||||
|
||||
// Create all combinations
|
||||
foreach ($event->getCombinations() as $combinationAttributesAvIds) {
|
||||
|
||||
// Create the PSE
|
||||
$saleElement = $event->getProduct()->createProductSaleElement(
|
||||
$con,
|
||||
$event->getWeight(),
|
||||
$event->getPrice(),
|
||||
$event->getSalePrice(),
|
||||
$event->getCurrencyId(),
|
||||
$isDefault,
|
||||
$event->getOnsale(),
|
||||
$event->getIsnew(),
|
||||
$event->getQuantity(),
|
||||
$event->getEanCode(),
|
||||
$event->getReference()
|
||||
$con,
|
||||
$event->getWeight(),
|
||||
$event->getPrice(),
|
||||
$event->getSalePrice(),
|
||||
$event->getCurrencyId(),
|
||||
$isDefault,
|
||||
$event->getOnsale(),
|
||||
$event->getIsnew(),
|
||||
$event->getQuantity(),
|
||||
$event->getEanCode(),
|
||||
$event->getReference()
|
||||
);
|
||||
|
||||
$isDefault = false;
|
||||
@@ -267,7 +288,6 @@ class ProductSaleElement extends BaseAction implements EventSubscriberInterface
|
||||
// Store all the stuff !
|
||||
$con->commit();
|
||||
} catch (\Exception $ex) {
|
||||
|
||||
$con->rollback();
|
||||
|
||||
throw $ex;
|
||||
@@ -278,13 +298,12 @@ class ProductSaleElement extends BaseAction implements EventSubscriberInterface
|
||||
* Create a combination for a given product sale element
|
||||
*
|
||||
* @param ConnectionInterface $con the Propel connection
|
||||
* @param ProductSaleElement $salesElement the product sale element
|
||||
* @param unknown $combinationAttributes an array oif attributes av IDs
|
||||
* @param ProductSaleElements $salesElement the product sale element
|
||||
* @param array $combinationAttributes an array oif attributes av IDs
|
||||
*/
|
||||
protected function createCombination(ConnectionInterface $con, ProductSaleElements $salesElement, $combinationAttributes)
|
||||
{
|
||||
foreach ($combinationAttributes as $attributeAvId) {
|
||||
|
||||
$attributeAv = AttributeAvQuery::create()->findPk($attributeAvId);
|
||||
|
||||
if ($attributeAv !== null) {
|
||||
@@ -299,6 +318,156 @@ class ProductSaleElement extends BaseAction implements EventSubscriberInterface
|
||||
}
|
||||
}
|
||||
|
||||
/*******************
|
||||
* CLONING PROCESS *
|
||||
*******************/
|
||||
|
||||
/**
|
||||
* Clone product's PSEs and associated datas
|
||||
*
|
||||
* @param ProductCloneEvent $event
|
||||
*/
|
||||
public function clonePSE(ProductCloneEvent $event)
|
||||
{
|
||||
$clonedProduct = $event->getClonedProduct();
|
||||
|
||||
// Get original product's PSEs
|
||||
$originalProductPSEs = ProductSaleElementsQuery::create()
|
||||
->orderByIsDefault(Criteria::DESC)
|
||||
->findByProductId($event->getOriginalProduct()->getId());
|
||||
|
||||
/**
|
||||
* Handle PSEs
|
||||
*
|
||||
* @var int $key
|
||||
* @var ProductSaleElements $originalProductPSE
|
||||
*/
|
||||
foreach ($originalProductPSEs as $key => $originalProductPSE) {
|
||||
$currencyId = ProductPriceQuery::create()
|
||||
->filterByProductSaleElementsId($originalProductPSE->getId())
|
||||
->select('CURRENCY_ID')
|
||||
->findOne();
|
||||
|
||||
// The default PSE, created at the same time as the clone product, is overwritten
|
||||
$clonedProductPSEId = $this->createClonePSE($event, $originalProductPSE, $currencyId);
|
||||
|
||||
$this->updateClonePSE($event, $clonedProductPSEId, $originalProductPSE, $key);
|
||||
|
||||
// PSE associated images
|
||||
$originalProductPSEImages = ProductSaleElementsProductImageQuery::create()
|
||||
->findByProductSaleElementsId($originalProductPSE->getId());
|
||||
|
||||
if (null !== $originalProductPSEImages) {
|
||||
$this->clonePSEAssociatedFiles($clonedProduct->getId(), $clonedProductPSEId, $originalProductPSEImages, $type = 'image');
|
||||
}
|
||||
|
||||
// PSE associated documents
|
||||
$originalProductPSEDocuments = ProductSaleElementsProductDocumentQuery::create()
|
||||
->findByProductSaleElementsId($originalProductPSE->getId());
|
||||
|
||||
if (null !== $originalProductPSEDocuments) {
|
||||
$this->clonePSEAssociatedFiles($clonedProduct->getId(), $clonedProductPSEId, $originalProductPSEDocuments, $type = 'document');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function createClonePSE(ProductCloneEvent $event, ProductSaleElements $originalProductPSE, $currencyId)
|
||||
{
|
||||
$attributeCombinationList = AttributeCombinationQuery::create()
|
||||
->filterByProductSaleElementsId($originalProductPSE->getId())
|
||||
->select(['ATTRIBUTE_AV_ID'])
|
||||
->find();
|
||||
|
||||
$clonedProductCreatePSEEvent = new ProductSaleElementCreateEvent($event->getClonedProduct(), $attributeCombinationList, $currencyId);
|
||||
$this->eventDispatcher->dispatch(TheliaEvents::PRODUCT_ADD_PRODUCT_SALE_ELEMENT, $clonedProductCreatePSEEvent);
|
||||
|
||||
return $clonedProductCreatePSEEvent->getProductSaleElement()->getId();
|
||||
}
|
||||
|
||||
public function updateClonePSE(ProductCloneEvent $event, $clonedProductPSEId, ProductSaleElements $originalProductPSE, $key)
|
||||
{
|
||||
$originalProductPSEPrice = ProductPriceQuery::create()
|
||||
->findOneByProductSaleElementsId($originalProductPSE->getId());
|
||||
|
||||
$clonedProductUpdatePSEEvent = new ProductSaleElementUpdateEvent($event->getClonedProduct(), $clonedProductPSEId);
|
||||
$clonedProductUpdatePSEEvent
|
||||
->setReference($event->getClonedProduct()->getRef().'-'.($key + 1))
|
||||
->setIsdefault($originalProductPSE->getIsDefault())
|
||||
->setFromDefaultCurrency(0)
|
||||
|
||||
->setWeight($originalProductPSE->getWeight())
|
||||
->setQuantity($originalProductPSE->getQuantity())
|
||||
->setOnsale($originalProductPSE->getPromo())
|
||||
->setIsnew($originalProductPSE->getNewness())
|
||||
->setEanCode($originalProductPSE->getEanCode())
|
||||
->setTaxRuleId($event->getOriginalProduct()->getTaxRuleId())
|
||||
|
||||
->setPrice($originalProductPSEPrice->getPrice())
|
||||
->setSalePrice($originalProductPSEPrice->getPromoPrice())
|
||||
->setCurrencyId($originalProductPSEPrice->getCurrencyId());
|
||||
|
||||
$this->eventDispatcher->dispatch(TheliaEvents::PRODUCT_UPDATE_PRODUCT_SALE_ELEMENT, $clonedProductUpdatePSEEvent);
|
||||
}
|
||||
|
||||
public function clonePSEAssociatedFiles($clonedProductId, $clonedProductPSEId, $originalProductPSEFiles, $type)
|
||||
{
|
||||
/** @var ProductSaleElementsDocument|ProductSaleElementsImage $originalProductPSEFile */
|
||||
foreach ($originalProductPSEFiles as $originalProductPSEFile) {
|
||||
$originalProductFilePositionQuery = [];
|
||||
$originalProductPSEFileId = null;
|
||||
|
||||
// Get file's original position
|
||||
switch ($type) {
|
||||
case 'image':
|
||||
$originalProductFilePositionQuery = ProductImageQuery::create();
|
||||
$originalProductPSEFileId = $originalProductPSEFile->getProductImageId();
|
||||
break;
|
||||
case 'document':
|
||||
$originalProductFilePositionQuery = ProductDocumentQuery::create();
|
||||
$originalProductPSEFileId = $originalProductPSEFile->getProductDocumentId();
|
||||
break;
|
||||
}
|
||||
$originalProductFilePosition = $originalProductFilePositionQuery
|
||||
->select(['POSITION'])
|
||||
->findPk($originalProductPSEFileId);
|
||||
|
||||
// Get cloned file ID to link to the cloned PSE
|
||||
switch ($type) {
|
||||
case 'image':
|
||||
$clonedProductFileIdToLinkToPSEQuery = ProductImageQuery::create();
|
||||
break;
|
||||
case 'document':
|
||||
$clonedProductFileIdToLinkToPSEQuery = ProductDocumentQuery::create();
|
||||
break;
|
||||
}
|
||||
|
||||
$clonedProductFileIdToLinkToPSE = $clonedProductFileIdToLinkToPSEQuery
|
||||
->filterByProductId($clonedProductId)
|
||||
->filterByPosition($originalProductFilePosition)
|
||||
->select(['ID'])
|
||||
->findOne();
|
||||
|
||||
// Save association
|
||||
switch ($type) {
|
||||
case 'image':
|
||||
$assoc = new ProductSaleElementsProductImage();
|
||||
$assoc->setProductImageId($clonedProductFileIdToLinkToPSE);
|
||||
break;
|
||||
case 'document':
|
||||
$assoc = new ProductSaleElementsProductDocument();
|
||||
$assoc->setProductDocumentId($clonedProductFileIdToLinkToPSE);
|
||||
break;
|
||||
}
|
||||
$assoc
|
||||
->setProductSaleElementsId($clonedProductPSEId)
|
||||
->save();
|
||||
}
|
||||
}
|
||||
|
||||
/***************
|
||||
* END CLONING *
|
||||
***************/
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@@ -309,7 +478,7 @@ class ProductSaleElement extends BaseAction implements EventSubscriberInterface
|
||||
TheliaEvents::PRODUCT_UPDATE_PRODUCT_SALE_ELEMENT => array("update", 128),
|
||||
TheliaEvents::PRODUCT_DELETE_PRODUCT_SALE_ELEMENT => array("delete", 128),
|
||||
TheliaEvents::PRODUCT_COMBINATION_GENERATION => array("generateCombinations", 128),
|
||||
|
||||
TheliaEvents::PSE_CLONE => array("clonePSE", 128)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
namespace Thelia\Action;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Core\Event\Profile\ProfileEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
@@ -29,13 +30,15 @@ class Profile extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
/**
|
||||
* @param ProfileEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function create(ProfileEvent $event)
|
||||
public function create(ProfileEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$profile = new ProfileModel();
|
||||
|
||||
$profile
|
||||
->setDispatcher($event->getDispatcher())
|
||||
->setDispatcher($dispatcher)
|
||||
->setCode($event->getCode())
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
@@ -51,13 +54,14 @@ class Profile extends BaseAction implements EventSubscriberInterface
|
||||
|
||||
/**
|
||||
* @param ProfileEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function update(ProfileEvent $event)
|
||||
public function update(ProfileEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $profile = ProfileQuery::create()->findPk($event->getId())) {
|
||||
|
||||
$profile
|
||||
->setDispatcher($event->getDispatcher())
|
||||
->setDispatcher($dispatcher)
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
->setChapo($event->getChapo())
|
||||
@@ -85,10 +89,9 @@ class Profile extends BaseAction implements EventSubscriberInterface
|
||||
$profileResource = new ProfileResource();
|
||||
$profileResource->setProfileId($event->getId())
|
||||
->setResource(ResourceQuery::create()->findOneByCode($resourceCode))
|
||||
->setAccess( $manager->getAccessValue() );
|
||||
->setAccess($manager->getAccessValue());
|
||||
|
||||
$profileResource->save();
|
||||
|
||||
}
|
||||
|
||||
$event->setProfile($profile);
|
||||
@@ -109,10 +112,9 @@ class Profile extends BaseAction implements EventSubscriberInterface
|
||||
$profileModule = new ProfileModule();
|
||||
$profileModule->setProfileId($event->getId())
|
||||
->setModule(ModuleQuery::create()->findOneByCode($moduleCode))
|
||||
->setAccess( $manager->getAccessValue() );
|
||||
->setAccess($manager->getAccessValue());
|
||||
|
||||
$profileModule->save();
|
||||
|
||||
}
|
||||
|
||||
$event->setProfile($profile);
|
||||
@@ -125,7 +127,6 @@ class Profile extends BaseAction implements EventSubscriberInterface
|
||||
public function delete(ProfileEvent $event)
|
||||
{
|
||||
if (null !== $profile = ProfileQuery::create()->findPk($event->getId())) {
|
||||
|
||||
$profile
|
||||
->delete()
|
||||
;
|
||||
|
||||
60
core/lib/Thelia/Action/RedirectException.php
Normal file
60
core/lib/Thelia/Action/RedirectException.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?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 Thelia\Action;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
|
||||
use Symfony\Component\HttpKernel\KernelEvents;
|
||||
use Thelia\Tools\URL;
|
||||
use Thelia\Core\Security\Exception\AuthenticationException;
|
||||
use Thelia\Core\HttpKernel\Exception\RedirectException as ExceptionRedirectException;
|
||||
|
||||
/**
|
||||
* Class RedirectException
|
||||
* @package Thelia\Action
|
||||
* @author manuel raynaud <manu@raynaud.io>
|
||||
*/
|
||||
class RedirectException extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
/** @var URL */
|
||||
protected $urlManager;
|
||||
|
||||
public function __construct(URL $urlManager)
|
||||
{
|
||||
$this->urlManager = $urlManager;
|
||||
}
|
||||
|
||||
public function checkRedirectException(GetResponseForExceptionEvent $event)
|
||||
{
|
||||
$exception = $event->getException();
|
||||
if ($exception instanceof ExceptionRedirectException) {
|
||||
$response = RedirectResponse::create($exception->getUrl(), $exception->getStatusCode());
|
||||
$event->setResponse($response);
|
||||
} elseif ($exception instanceof AuthenticationException) {
|
||||
// Redirect to the login template
|
||||
$response = RedirectResponse::create($this->urlManager->viewUrl($exception->getLoginTemplate()));
|
||||
$event->setResponse($response);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return [
|
||||
KernelEvents::EXCEPTION => array("checkRedirectException", 128),
|
||||
];
|
||||
}
|
||||
}
|
||||
505
core/lib/Thelia/Action/Sale.php
Normal file
505
core/lib/Thelia/Action/Sale.php
Normal file
@@ -0,0 +1,505 @@
|
||||
<?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 Thelia\Action;
|
||||
|
||||
use Propel\Runtime\ActiveQuery\Criteria;
|
||||
use Propel\Runtime\Connection\ConnectionInterface;
|
||||
use Propel\Runtime\Exception\PropelException;
|
||||
use Propel\Runtime\Propel;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Core\Event\Sale\ProductSaleStatusUpdateEvent;
|
||||
use Thelia\Core\Event\Sale\SaleActiveStatusCheckEvent;
|
||||
use Thelia\Core\Event\Sale\SaleClearStatusEvent;
|
||||
use Thelia\Core\Event\Sale\SaleCreateEvent;
|
||||
use Thelia\Core\Event\Sale\SaleDeleteEvent;
|
||||
use Thelia\Core\Event\Sale\SaleToggleActivityEvent;
|
||||
use Thelia\Core\Event\Sale\SaleUpdateEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Model\Base\ProductPriceQuery;
|
||||
use Thelia\Model\Country as CountryModel;
|
||||
use Thelia\Model\Map\SaleTableMap;
|
||||
use Thelia\Model\ProductSaleElements;
|
||||
use Thelia\Model\ProductSaleElementsQuery;
|
||||
use Thelia\Model\Sale as SaleModel;
|
||||
use Thelia\Model\SaleOffsetCurrency;
|
||||
use Thelia\Model\SaleOffsetCurrencyQuery;
|
||||
use Thelia\Model\SaleProduct;
|
||||
use Thelia\Model\SaleProductQuery;
|
||||
use Thelia\Model\SaleQuery;
|
||||
use Thelia\TaxEngine\Calculator;
|
||||
|
||||
/**
|
||||
* Class Sale
|
||||
*
|
||||
* @package Thelia\Action
|
||||
* @author Franck Allimant <franck@cqfdev.fr>
|
||||
*/
|
||||
class Sale extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
/**
|
||||
* Update PSE for a given product
|
||||
*
|
||||
* @param array $pseList an array of priduct sale elements
|
||||
* @param bool $promoStatus true if the PSEs are on sale, false otherwise
|
||||
* @param int $offsetType the offset type, see SaleModel::OFFSET_* constants
|
||||
* @param Calculator $taxCalculator the tax calculator
|
||||
* @param array $saleOffsetByCurrency an array of price offset for each currency (currency ID => offset_amount)
|
||||
* @param ConnectionInterface $con
|
||||
*/
|
||||
protected function updateProductSaleElementsPrices($pseList, $promoStatus, $offsetType, Calculator $taxCalculator, $saleOffsetByCurrency, ConnectionInterface $con)
|
||||
{
|
||||
/** @var ProductSaleElements $pse */
|
||||
foreach ($pseList as $pse) {
|
||||
if ($pse->getPromo()!= $promoStatus) {
|
||||
$pse
|
||||
->setPromo($promoStatus)
|
||||
->save($con)
|
||||
;
|
||||
}
|
||||
|
||||
/** @var SaleOffsetCurrency $offsetByCurrency */
|
||||
foreach ($saleOffsetByCurrency as $currencyId => $offset) {
|
||||
$productPrice = ProductPriceQuery::create()
|
||||
->filterByProductSaleElementsId($pse->getId())
|
||||
->filterByCurrencyId($currencyId)
|
||||
->findOne($con);
|
||||
|
||||
if (null !== $productPrice) {
|
||||
// Get the taxed price
|
||||
$priceWithTax = $taxCalculator->getTaxedPrice($productPrice->getPrice());
|
||||
|
||||
// Remove the price offset to get the taxed promo price
|
||||
switch ($offsetType) {
|
||||
case SaleModel::OFFSET_TYPE_AMOUNT:
|
||||
$promoPrice = max(0, $priceWithTax - $offset);
|
||||
break;
|
||||
|
||||
case SaleModel::OFFSET_TYPE_PERCENTAGE:
|
||||
$promoPrice = $priceWithTax * (1 - $offset / 100);
|
||||
break;
|
||||
|
||||
default:
|
||||
$promoPrice = $priceWithTax;
|
||||
}
|
||||
|
||||
// and then get the untaxed promo price.
|
||||
$promoPrice = $taxCalculator->getUntaxedPrice($promoPrice);
|
||||
|
||||
$productPrice
|
||||
->setPromoPrice($promoPrice)
|
||||
->save($con)
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Update the promo status of the sale's selected products and combinations
|
||||
*
|
||||
* @param ProductSaleStatusUpdateEvent $event
|
||||
* @throws \RuntimeException
|
||||
* @throws \Exception
|
||||
* @throws \Propel\Runtime\Exception\PropelException
|
||||
*/
|
||||
public function updateProductsSaleStatus(ProductSaleStatusUpdateEvent $event)
|
||||
{
|
||||
$taxCalculator = new Calculator();
|
||||
|
||||
$sale = $event->getSale();
|
||||
|
||||
// Get all selected product sale elements for this sale
|
||||
if (null !== $saleProducts = SaleProductQuery::create()->filterBySale($sale)->orderByProductId()) {
|
||||
$saleOffsetByCurrency = $sale->getPriceOffsets();
|
||||
|
||||
$offsetType = $sale->getPriceOffsetType();
|
||||
|
||||
$con = Propel::getWriteConnection(SaleTableMap::DATABASE_NAME);
|
||||
|
||||
$con->beginTransaction();
|
||||
|
||||
try {
|
||||
/** @var SaleProduct $saleProduct */
|
||||
foreach ($saleProducts as $saleProduct) {
|
||||
// Reset all sale status on product's PSE
|
||||
ProductSaleElementsQuery::create()
|
||||
->filterByProductId($saleProduct->getProductId())
|
||||
->update([ 'Promo' => false], $con)
|
||||
;
|
||||
|
||||
$taxCalculator->load(
|
||||
$saleProduct->getProduct($con),
|
||||
CountryModel::getShopLocation()
|
||||
);
|
||||
|
||||
$attributeAvId = $saleProduct->getAttributeAvId();
|
||||
|
||||
$pseRequest = ProductSaleElementsQuery::create()
|
||||
->filterByProductId($saleProduct->getProductId())
|
||||
;
|
||||
|
||||
// If no attribute AV id is defined, consider ALL product combinations
|
||||
if (! is_null($attributeAvId)) {
|
||||
// Find PSE attached to combination containing this attribute av :
|
||||
// SELECT * from product_sale_elements pse
|
||||
// left join attribute_combination ac on ac.product_sale_elements_id = pse.id
|
||||
// where pse.product_id=363
|
||||
// and ac.attribute_av_id = 7
|
||||
// group by pse.id
|
||||
|
||||
$pseRequest
|
||||
->useAttributeCombinationQuery(null, Criteria::LEFT_JOIN)
|
||||
->filterByAttributeAvId($attributeAvId)
|
||||
->endUse()
|
||||
;
|
||||
}
|
||||
|
||||
$pseList = $pseRequest->find();
|
||||
|
||||
if (null !== $pseList) {
|
||||
$this->updateProductSaleElementsPrices(
|
||||
$pseList,
|
||||
$sale->getActive(),
|
||||
$offsetType,
|
||||
$taxCalculator,
|
||||
$saleOffsetByCurrency,
|
||||
$con
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$con->commit();
|
||||
} catch (PropelException $e) {
|
||||
$con->rollback();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Sale
|
||||
*
|
||||
* @param SaleCreateEvent $event
|
||||
*/
|
||||
public function create(SaleCreateEvent $event)
|
||||
{
|
||||
$sale = new SaleModel();
|
||||
|
||||
$sale
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
->setSaleLabel($event->getSaleLabel())
|
||||
->save()
|
||||
;
|
||||
|
||||
$event->setSale($sale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process update sale
|
||||
*
|
||||
* @param SaleUpdateEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
* @throws PropelException
|
||||
*/
|
||||
public function update(SaleUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $sale = SaleQuery::create()->findPk($event->getSaleId())) {
|
||||
$sale->setDispatcher($dispatcher);
|
||||
|
||||
$con = Propel::getWriteConnection(SaleTableMap::DATABASE_NAME);
|
||||
|
||||
$con->beginTransaction();
|
||||
|
||||
try {
|
||||
// Disable all promo flag on sale's currently selected products,
|
||||
// to reset promo status of the products that have been removed from the selection.
|
||||
$sale->setActive(false);
|
||||
|
||||
$now = new \DateTime();
|
||||
$startDate = $event->getStartDate();
|
||||
$endDate = $event->getEndDate();
|
||||
|
||||
$update = ($startDate <= $now && $now <= $endDate);
|
||||
|
||||
if ($update) {
|
||||
$dispatcher->dispatch(
|
||||
TheliaEvents::UPDATE_PRODUCT_SALE_STATUS,
|
||||
new ProductSaleStatusUpdateEvent($sale)
|
||||
);
|
||||
}
|
||||
|
||||
$sale
|
||||
->setActive($event->getActive())
|
||||
->setStartDate($startDate)
|
||||
->setEndDate($endDate)
|
||||
->setPriceOffsetType($event->getPriceOffsetType())
|
||||
->setDisplayInitialPrice($event->getDisplayInitialPrice())
|
||||
->setLocale($event->getLocale())
|
||||
->setSaleLabel($event->getSaleLabel())
|
||||
->setTitle($event->getTitle())
|
||||
->setDescription($event->getDescription())
|
||||
->setChapo($event->getChapo())
|
||||
->setPostscriptum($event->getPostscriptum())
|
||||
->save($con)
|
||||
;
|
||||
|
||||
$event->setSale($sale);
|
||||
|
||||
// Update price offsets
|
||||
SaleOffsetCurrencyQuery::create()->filterBySaleId($sale->getId())->delete($con);
|
||||
|
||||
foreach ($event->getPriceOffsets() as $currencyId => $priceOffset) {
|
||||
$saleOffset = new SaleOffsetCurrency();
|
||||
|
||||
$saleOffset
|
||||
->setCurrencyId($currencyId)
|
||||
->setSaleId($sale->getId())
|
||||
->setPriceOffsetValue($priceOffset)
|
||||
->save($con)
|
||||
;
|
||||
}
|
||||
|
||||
// Update products
|
||||
SaleProductQuery::create()->filterBySaleId($sale->getId())->delete($con);
|
||||
|
||||
$productAttributesArray = $event->getProductAttributes();
|
||||
|
||||
foreach ($event->getProducts() as $productId) {
|
||||
if (isset($productAttributesArray[$productId])) {
|
||||
foreach ($productAttributesArray[$productId] as $attributeId) {
|
||||
$saleProduct = new SaleProduct();
|
||||
|
||||
$saleProduct
|
||||
->setSaleId($sale->getId())
|
||||
->setProductId($productId)
|
||||
->setAttributeAvId($attributeId)
|
||||
->save($con)
|
||||
;
|
||||
}
|
||||
} else {
|
||||
$saleProduct = new SaleProduct();
|
||||
|
||||
$saleProduct
|
||||
->setSaleId($sale->getId())
|
||||
->setProductId($productId)
|
||||
->setAttributeAvId(null)
|
||||
->save($con)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ($update) {
|
||||
// Update related products sale status
|
||||
$dispatcher->dispatch(
|
||||
TheliaEvents::UPDATE_PRODUCT_SALE_STATUS,
|
||||
new ProductSaleStatusUpdateEvent($sale)
|
||||
);
|
||||
}
|
||||
|
||||
$con->commit();
|
||||
} catch (PropelException $e) {
|
||||
$con->rollback();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle Sale activity
|
||||
*
|
||||
* @param SaleToggleActivityEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
* @throws \Propel\Runtime\Exception\PropelException
|
||||
*/
|
||||
public function toggleActivity(SaleToggleActivityEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$sale = $event->getSale();
|
||||
|
||||
$con = Propel::getWriteConnection(SaleTableMap::DATABASE_NAME);
|
||||
|
||||
$con->beginTransaction();
|
||||
|
||||
try {
|
||||
$sale
|
||||
->setDispatcher($dispatcher)
|
||||
->setActive(!$sale->getActive())
|
||||
->save($con);
|
||||
|
||||
// Update related products sale status
|
||||
$dispatcher->dispatch(
|
||||
TheliaEvents::UPDATE_PRODUCT_SALE_STATUS,
|
||||
new ProductSaleStatusUpdateEvent($sale)
|
||||
);
|
||||
|
||||
$event->setSale($sale);
|
||||
|
||||
$con->commit();
|
||||
} catch (PropelException $e) {
|
||||
$con->rollback();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a sale
|
||||
*
|
||||
* @param SaleDeleteEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
* @throws \Propel\Runtime\Exception\PropelException
|
||||
*/
|
||||
public function delete(SaleDeleteEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $sale = SaleQuery::create()->findPk($event->getSaleId())) {
|
||||
$con = Propel::getWriteConnection(SaleTableMap::DATABASE_NAME);
|
||||
|
||||
$con->beginTransaction();
|
||||
|
||||
try {
|
||||
// Update related products sale status, if required
|
||||
if ($sale->getActive()) {
|
||||
$sale->setActive(false);
|
||||
|
||||
// Update related products sale status
|
||||
$dispatcher->dispatch(
|
||||
TheliaEvents::UPDATE_PRODUCT_SALE_STATUS,
|
||||
new ProductSaleStatusUpdateEvent($sale)
|
||||
);
|
||||
}
|
||||
|
||||
$sale->setDispatcher($dispatcher)->delete($con);
|
||||
|
||||
$event->setSale($sale);
|
||||
|
||||
$con->commit();
|
||||
} catch (PropelException $e) {
|
||||
$con->rollback();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all sales
|
||||
*
|
||||
* @param SaleClearStatusEvent $event
|
||||
* @throws \Propel\Runtime\Exception\PropelException
|
||||
*/
|
||||
public function clearStatus(/** @noinspection PhpUnusedParameterInspection */ SaleClearStatusEvent $event)
|
||||
{
|
||||
$con = Propel::getWriteConnection(SaleTableMap::DATABASE_NAME);
|
||||
$con->beginTransaction();
|
||||
|
||||
try {
|
||||
// Set the active status of all Sales to false
|
||||
SaleQuery::create()
|
||||
->filterByActive(true)
|
||||
->update([ 'Active' => false ], $con)
|
||||
;
|
||||
|
||||
// Reset all sale status on PSE
|
||||
ProductSaleElementsQuery::create()
|
||||
->filterByPromo(true)
|
||||
->update([ 'Promo' => false], $con)
|
||||
;
|
||||
|
||||
$con->commit();
|
||||
} catch (PropelException $e) {
|
||||
$con->rollback();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method check the activation and deactivation dates of sales, and perform
|
||||
* the required action depending on the current date.
|
||||
*
|
||||
* @param SaleActiveStatusCheckEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
* @throws \Propel\Runtime\Exception\PropelException
|
||||
*/
|
||||
public function checkSaleActivation(SaleActiveStatusCheckEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$con = Propel::getWriteConnection(SaleTableMap::DATABASE_NAME);
|
||||
$con->beginTransaction();
|
||||
|
||||
try {
|
||||
$now = time();
|
||||
|
||||
// Disable expired sales
|
||||
if (null !== $salesToDisable = SaleQuery::create()
|
||||
->filterByActive(true)
|
||||
->filterByEndDate($now, Criteria::LESS_THAN)
|
||||
->find()) {
|
||||
/** @var SaleModel $sale */
|
||||
foreach ($salesToDisable as $sale) {
|
||||
$sale->setActive(false)->save();
|
||||
|
||||
// Update related products sale status
|
||||
$dispatcher->dispatch(
|
||||
TheliaEvents::UPDATE_PRODUCT_SALE_STATUS,
|
||||
new ProductSaleStatusUpdateEvent($sale)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Enable sales that should be enabled.
|
||||
if (null !== $salesToEnable = SaleQuery::create()
|
||||
->filterByActive(false)
|
||||
->filterByStartDate($now, Criteria::LESS_EQUAL)
|
||||
->filterByEndDate($now, Criteria::GREATER_EQUAL)
|
||||
->find()) {
|
||||
/** @var SaleModel $sale */
|
||||
foreach ($salesToEnable as $sale) {
|
||||
$sale->setActive(true)->save();
|
||||
|
||||
// Update related products sale status
|
||||
$dispatcher->dispatch(
|
||||
TheliaEvents::UPDATE_PRODUCT_SALE_STATUS,
|
||||
new ProductSaleStatusUpdateEvent($sale)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$con->commit();
|
||||
} catch (PropelException $e) {
|
||||
$con->rollback();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::SALE_CREATE => array('create', 128),
|
||||
TheliaEvents::SALE_UPDATE => array('update', 128),
|
||||
TheliaEvents::SALE_DELETE => array('delete', 128),
|
||||
|
||||
TheliaEvents::SALE_TOGGLE_ACTIVITY => array('toggleActivity', 128),
|
||||
|
||||
TheliaEvents::SALE_CLEAR_SALE_STATUS => array('clearStatus', 128),
|
||||
|
||||
TheliaEvents::UPDATE_PRODUCT_SALE_STATUS => array('updateProductsSaleStatus', 128),
|
||||
|
||||
TheliaEvents::CHECK_SALE_ACTIVATION_EVENT => array('checkSaleActivation', 128),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Thelia\Action;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Core\Event\ShippingZone\ShippingZoneAddAreaEvent;
|
||||
use Thelia\Core\Event\ShippingZone\ShippingZoneRemoveAreaEvent;
|
||||
@@ -21,11 +22,10 @@ use Thelia\Model\AreaDeliveryModuleQuery;
|
||||
/**
|
||||
* Class ShippingZone
|
||||
* @package Thelia\Action
|
||||
* @author Manuel Raynaud <mraynaud@openstudio.fr>
|
||||
* @author Manuel Raynaud <manu@raynaud.io>
|
||||
*/
|
||||
class ShippingZone extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
|
||||
public function addArea(ShippingZoneAddAreaEvent $event)
|
||||
{
|
||||
$areaDelivery = new AreaDeliveryModule();
|
||||
@@ -51,24 +51,7 @@ class ShippingZone extends BaseAction implements EventSubscriberInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of event names this subscriber wants to listen to.
|
||||
*
|
||||
* The array keys are event names and the value can be:
|
||||
*
|
||||
* * The method name to call (priority defaults to 0)
|
||||
* * An array composed of the method name to call and the priority
|
||||
* * An array of arrays composed of the method names to call and respective
|
||||
* priorities, or 0 if unset
|
||||
*
|
||||
* For instance:
|
||||
*
|
||||
* * array('eventName' => 'methodName')
|
||||
* * array('eventName' => array('methodName', $priority))
|
||||
* * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
|
||||
*
|
||||
* @return array The event names to listen to
|
||||
*
|
||||
* @api
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
|
||||
103
core/lib/Thelia/Action/State.php
Normal file
103
core/lib/Thelia/Action/State.php
Normal file
@@ -0,0 +1,103 @@
|
||||
<?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 Thelia\Action;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Core\Event\State\StateCreateEvent;
|
||||
use Thelia\Core\Event\State\StateDeleteEvent;
|
||||
use Thelia\Core\Event\State\StateToggleVisibilityEvent;
|
||||
use Thelia\Core\Event\State\StateUpdateEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Model\State as StateModel;
|
||||
use Thelia\Model\StateQuery;
|
||||
|
||||
/**
|
||||
* Class State
|
||||
* @package Thelia\Action
|
||||
* @author Julien Chanséaume <julien@thelia.net>
|
||||
*/
|
||||
class State extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
public function create(StateCreateEvent $event)
|
||||
{
|
||||
$state = new StateModel();
|
||||
|
||||
$state
|
||||
->setVisible($event->isVisible())
|
||||
->setCountryId($event->getCountry())
|
||||
->setIsocode($event->getIsocode())
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
->save()
|
||||
;
|
||||
|
||||
$event->setState($state);
|
||||
}
|
||||
|
||||
public function update(StateUpdateEvent $event)
|
||||
{
|
||||
if (null !== $state = StateQuery::create()->findPk($event->getStateId())) {
|
||||
$state
|
||||
->setVisible($event->isVisible())
|
||||
->setCountryId($event->getCountry())
|
||||
->setIsocode($event->getIsocode())
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
->save()
|
||||
;
|
||||
|
||||
$event->setState($state);
|
||||
}
|
||||
}
|
||||
|
||||
public function delete(StateDeleteEvent $event)
|
||||
{
|
||||
if (null !== $state = StateQuery::create()->findPk($event->getStateId())) {
|
||||
$state->delete();
|
||||
|
||||
$event->setState($state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle State visibility
|
||||
*
|
||||
* @param StateToggleVisibilityEvent $event
|
||||
*/
|
||||
public function toggleVisibility(StateToggleVisibilityEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$state = $event->getState();
|
||||
|
||||
$state
|
||||
->setDispatcher($dispatcher)
|
||||
->setVisible(!$state->getVisible())
|
||||
->save()
|
||||
;
|
||||
|
||||
$event->setState($state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::STATE_CREATE => array('create', 128),
|
||||
TheliaEvents::STATE_UPDATE => array('update', 128),
|
||||
TheliaEvents::STATE_DELETE => array('delete', 128),
|
||||
TheliaEvents::STATE_TOGGLE_VISIBILITY => array('toggleVisibility', 128)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
namespace Thelia\Action;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Core\Event\Tax\TaxEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
@@ -22,13 +23,15 @@ class Tax extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
/**
|
||||
* @param TaxEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function create(TaxEvent $event)
|
||||
public function create(TaxEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$tax = new TaxModel();
|
||||
|
||||
$tax
|
||||
->setDispatcher($event->getDispatcher())
|
||||
->setDispatcher($dispatcher)
|
||||
->setRequirements($event->getRequirements())
|
||||
->setType($event->getType())
|
||||
->setLocale($event->getLocale())
|
||||
@@ -43,13 +46,14 @@ class Tax extends BaseAction implements EventSubscriberInterface
|
||||
|
||||
/**
|
||||
* @param TaxEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function update(TaxEvent $event)
|
||||
public function update(TaxEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $tax = TaxQuery::create()->findPk($event->getId())) {
|
||||
|
||||
$tax
|
||||
->setDispatcher($event->getDispatcher())
|
||||
->setDispatcher($dispatcher)
|
||||
->setRequirements($event->getRequirements())
|
||||
->setType($event->getType())
|
||||
->setLocale($event->getLocale())
|
||||
@@ -69,7 +73,6 @@ class Tax extends BaseAction implements EventSubscriberInterface
|
||||
public function delete(TaxEvent $event)
|
||||
{
|
||||
if (null !== $tax = TaxQuery::create()->findPk($event->getId())) {
|
||||
|
||||
$tax
|
||||
->delete()
|
||||
;
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
namespace Thelia\Action;
|
||||
|
||||
use Propel\Runtime\ActiveQuery\Criteria;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Core\Event\Tax\TaxRuleEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
@@ -26,31 +27,30 @@ class TaxRule extends BaseAction implements EventSubscriberInterface
|
||||
/**
|
||||
* @param TaxRuleEvent $event
|
||||
*/
|
||||
public function create(TaxRuleEvent $event)
|
||||
public function create(TaxRuleEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$taxRule = new TaxRuleModel();
|
||||
|
||||
$taxRule
|
||||
->setDispatcher($event->getDispatcher())
|
||||
->setDispatcher($dispatcher)
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
->setDescription($event->getDescription())
|
||||
;
|
||||
;
|
||||
|
||||
$taxRule->save();
|
||||
|
||||
$event->setTaxRule($taxRule);
|
||||
$event->setTaxRule($taxRule)->setId($taxRule->getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TaxRuleEvent $event
|
||||
*/
|
||||
public function update(TaxRuleEvent $event)
|
||||
public function update(TaxRuleEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $taxRule = TaxRuleQuery::create()->findPk($event->getId())) {
|
||||
|
||||
$taxRule
|
||||
->setDispatcher($event->getDispatcher())
|
||||
->setDispatcher($dispatcher)
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
->setDescription($event->getDescription())
|
||||
@@ -67,25 +67,34 @@ class TaxRule extends BaseAction implements EventSubscriberInterface
|
||||
public function updateTaxes(TaxRuleEvent $event)
|
||||
{
|
||||
if (null !== $taxRule = TaxRuleQuery::create()->findPk($event->getId())) {
|
||||
$taxList = $this->getArrayFromJson($event->getTaxList());
|
||||
$countryList = $this->getArrayFromJson22Compat($event->getCountryList());
|
||||
$countryDeletedList = $this->getArrayFromJson22Compat($event->getCountryDeletedList());
|
||||
|
||||
$taxList = json_decode($event->getTaxList(), true);
|
||||
|
||||
/* clean the current tax rule for the countries */
|
||||
TaxRuleCountryQuery::create()
|
||||
->filterByTaxRule($taxRule)
|
||||
->filterByCountryId($event->getCountryList(), Criteria::IN)
|
||||
->delete();
|
||||
/* clean the current tax rule for the countries/states */
|
||||
$deletes = array_merge($countryList, $countryDeletedList);
|
||||
foreach ($deletes as $item) {
|
||||
TaxRuleCountryQuery::create()
|
||||
->filterByTaxRule($taxRule)
|
||||
->filterByCountryId(intval($item[0]), Criteria::EQUAL)
|
||||
->filterByStateId(intval($item[1]) !== 0 ? $item[1] : null, Criteria::EQUAL)
|
||||
->delete();
|
||||
}
|
||||
|
||||
/* for each country */
|
||||
foreach ($event->getCountryList() as $country) {
|
||||
foreach ($countryList as $item) {
|
||||
$position = 1;
|
||||
$countryId = intval($item[0]);
|
||||
$stateId = intval($item[1]);
|
||||
|
||||
/* on applique les nouvelles regles */
|
||||
foreach ($taxList as $tax) {
|
||||
if (is_array($tax)) {
|
||||
foreach ($tax as $samePositionTax) {
|
||||
$taxModel = new TaxRuleCountry();
|
||||
$taxModel->setTaxRule($taxRule)
|
||||
->setCountryId($country)
|
||||
->setCountryId($countryId)
|
||||
->setStateId($stateId ?: null)
|
||||
->setTaxId($samePositionTax)
|
||||
->setPosition($position);
|
||||
$taxModel->save();
|
||||
@@ -93,7 +102,8 @@ class TaxRule extends BaseAction implements EventSubscriberInterface
|
||||
} else {
|
||||
$taxModel = new TaxRuleCountry();
|
||||
$taxModel->setTaxRule($taxRule)
|
||||
->setCountryId($country)
|
||||
->setCountryId($countryId)
|
||||
->setStateId($stateId ?: null)
|
||||
->setTaxId($tax)
|
||||
->setPosition($position);
|
||||
$taxModel->save();
|
||||
@@ -106,13 +116,55 @@ class TaxRule extends BaseAction implements EventSubscriberInterface
|
||||
}
|
||||
}
|
||||
|
||||
protected function getArrayFromJson($obj)
|
||||
{
|
||||
if (is_null($obj)) {
|
||||
$obj = [];
|
||||
} else {
|
||||
$obj = is_array($obj)
|
||||
? $obj
|
||||
: json_decode($obj, true);
|
||||
}
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method ensures compatibility with the 2.2.x country arrays passed throught the TaxRuleEvent
|
||||
*
|
||||
* In 2.2.x, the TaxRuleEvent::getXXXCountryList() methods returned an array of country IDs. [ country ID, country ID ...].
|
||||
* From 2.3.0-alpha1, these functions are expected to return an array of arrays, each one containing a country ID and
|
||||
* a state ID. [ [ country ID, state ID], [ country ID, state ID], ...].
|
||||
*
|
||||
* This method checks the $obj parameter, and create a 2.3.0-alpha1 compatible return value if $obj is expressed using
|
||||
* the 2.2.x form.
|
||||
*
|
||||
* @param array $obj
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getArrayFromJson22Compat($obj)
|
||||
{
|
||||
$obj = $this->getArrayFromJson($obj);
|
||||
|
||||
if (isset($obj[0]) && ! is_array($obj[0])) {
|
||||
$objEx = [];
|
||||
foreach ($obj as $item) {
|
||||
$objEx[] = [$item, 0];
|
||||
}
|
||||
|
||||
return $objEx;
|
||||
}
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TaxRuleEvent $event
|
||||
*/
|
||||
public function delete(TaxRuleEvent $event)
|
||||
{
|
||||
if (null !== $taxRule = TaxRuleQuery::create()->findPk($event->getId())) {
|
||||
|
||||
$taxRule
|
||||
->delete()
|
||||
;
|
||||
@@ -127,7 +179,6 @@ class TaxRule extends BaseAction implements EventSubscriberInterface
|
||||
public function setDefault(TaxRuleEvent $event)
|
||||
{
|
||||
if (null !== $taxRule = TaxRuleQuery::create()->findPk($event->getId())) {
|
||||
|
||||
TaxRuleQuery::create()->update(array(
|
||||
"IsDefault" => 0
|
||||
));
|
||||
|
||||
@@ -12,26 +12,29 @@
|
||||
|
||||
namespace Thelia\Action;
|
||||
|
||||
use Propel\Runtime\Propel;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
|
||||
use Thelia\Model\TemplateQuery;
|
||||
use Thelia\Model\Template as TemplateModel;
|
||||
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
|
||||
use Thelia\Core\Event\Template\TemplateUpdateEvent;
|
||||
use Thelia\Core\Event\Template\TemplateCreateEvent;
|
||||
use Thelia\Core\Event\Template\TemplateDeleteEvent;
|
||||
use Thelia\Core\Event\UpdatePositionEvent;
|
||||
use Thelia\Model\ProductQuery;
|
||||
use Thelia\Core\Event\Template\TemplateAddAttributeEvent;
|
||||
use Thelia\Core\Event\Template\TemplateDeleteAttributeEvent;
|
||||
use Thelia\Model\AttributeTemplateQuery;
|
||||
use Thelia\Model\AttributeTemplate;
|
||||
use Thelia\Core\Event\Template\TemplateDeleteFeatureEvent;
|
||||
use Thelia\Core\Event\Template\TemplateAddFeatureEvent;
|
||||
use Thelia\Model\FeatureTemplateQuery;
|
||||
use Thelia\Core\Event\Template\TemplateCreateEvent;
|
||||
use Thelia\Core\Event\Template\TemplateDeleteAttributeEvent;
|
||||
use Thelia\Core\Event\Template\TemplateDeleteEvent;
|
||||
use Thelia\Core\Event\Template\TemplateDeleteFeatureEvent;
|
||||
use Thelia\Core\Event\Template\TemplateDuplicateEvent;
|
||||
use Thelia\Core\Event\Template\TemplateUpdateEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\Event\UpdatePositionEvent;
|
||||
use Thelia\Core\Translation\Translator;
|
||||
use Thelia\Model\AttributeTemplate;
|
||||
use Thelia\Model\AttributeTemplateQuery;
|
||||
use Thelia\Model\CategoryQuery;
|
||||
use Thelia\Model\FeatureTemplate;
|
||||
use Thelia\Model\FeatureTemplateQuery;
|
||||
use Thelia\Model\Map\TemplateTableMap;
|
||||
use Thelia\Model\ProductQuery;
|
||||
use Thelia\Model\Template as TemplateModel;
|
||||
use Thelia\Model\TemplateQuery;
|
||||
|
||||
class Template extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
@@ -39,137 +42,228 @@ class Template extends BaseAction implements EventSubscriberInterface
|
||||
* Create a new template entry
|
||||
*
|
||||
* @param \Thelia\Core\Event\Template\TemplateCreateEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function create(TemplateCreateEvent $event)
|
||||
public function create(TemplateCreateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$template = new TemplateModel();
|
||||
|
||||
|
||||
$template
|
||||
->setDispatcher($event->getDispatcher())
|
||||
|
||||
->setDispatcher($dispatcher)
|
||||
|
||||
->setLocale($event->getLocale())
|
||||
->setName($event->getTemplateName())
|
||||
|
||||
|
||||
->save()
|
||||
;
|
||||
|
||||
|
||||
$event->setTemplate($template);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Dupliucate an existing template entry
|
||||
*
|
||||
* @param \Thelia\Core\Event\Template\TemplateCreateEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function duplicate(TemplateDuplicateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $source = TemplateQuery::create()->findPk($event->getSourceTemplateId())) {
|
||||
$source->setLocale($event->getLocale());
|
||||
|
||||
$createEvent = new TemplateCreateEvent();
|
||||
$createEvent
|
||||
->setLocale($event->getLocale())
|
||||
->setTemplateName(
|
||||
Translator::getInstance()->trans("Copy of %tpl", ["%tpl" => $source->getName() ])
|
||||
);
|
||||
|
||||
$dispatcher->dispatch(TheliaEvents::TEMPLATE_CREATE, $createEvent);
|
||||
|
||||
$clone = $createEvent->getTemplate();
|
||||
|
||||
$attrList = AttributeTemplateQuery::create()->findByTemplateId($source->getId());
|
||||
|
||||
/** @var $feat AttributeTemplate */
|
||||
foreach ($attrList as $feat) {
|
||||
$dispatcher->dispatch(
|
||||
TheliaEvents::TEMPLATE_ADD_ATTRIBUTE,
|
||||
new TemplateAddAttributeEvent($clone, $feat->getAttributeId())
|
||||
);
|
||||
}
|
||||
|
||||
$featList = FeatureTemplateQuery::create()->findByTemplateId($source->getId());
|
||||
|
||||
/** @var $feat FeatureTemplate */
|
||||
foreach ($featList as $feat) {
|
||||
$dispatcher->dispatch(
|
||||
TheliaEvents::TEMPLATE_ADD_FEATURE,
|
||||
new TemplateAddFeatureEvent($clone, $feat->getFeatureId())
|
||||
);
|
||||
}
|
||||
|
||||
$event->setTemplate($clone);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Change a product template
|
||||
*
|
||||
* @param \Thelia\Core\Event\Template\TemplateUpdateEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function update(TemplateUpdateEvent $event)
|
||||
public function update(TemplateUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
|
||||
if (null !== $template = TemplateQuery::create()->findPk($event->getTemplateId())) {
|
||||
|
||||
$template
|
||||
->setDispatcher($event->getDispatcher())
|
||||
|
||||
->setLocale($event->getLocale())
|
||||
->setName($event->getTemplateName())
|
||||
->save();
|
||||
|
||||
->setDispatcher($dispatcher)
|
||||
|
||||
->setLocale($event->getLocale())
|
||||
->setName($event->getTemplateName())
|
||||
->save();
|
||||
|
||||
$event->setTemplate($template);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Delete a product template entry
|
||||
*
|
||||
* @param \Thelia\Core\Event\Template\TemplateDeleteEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function delete(TemplateDeleteEvent $event)
|
||||
public function delete(TemplateDeleteEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== ($template = TemplateQuery::create()->findPk($event->getTemplateId()))) {
|
||||
|
||||
// Check if template is used by a product
|
||||
$product_count = ProductQuery::create()->findByTemplateId($template->getId())->count();
|
||||
|
||||
if ($product_count <= 0) {
|
||||
$template
|
||||
->setDispatcher($event->getDispatcher())
|
||||
->delete()
|
||||
;
|
||||
$productCount = ProductQuery::create()->findByTemplateId($template->getId())->count();
|
||||
|
||||
if ($productCount <= 0) {
|
||||
$con = Propel::getWriteConnection(TemplateTableMap::DATABASE_NAME);
|
||||
$con->beginTransaction();
|
||||
|
||||
try {
|
||||
$template
|
||||
->setDispatcher($dispatcher)
|
||||
->delete($con);
|
||||
|
||||
// We have to also delete any reference of this template in category tables
|
||||
// We can't use a FK here, as the DefaultTemplateId column may be NULL
|
||||
// so let's take care of this.
|
||||
CategoryQuery::create()
|
||||
->filterByDefaultTemplateId($event->getTemplateId())
|
||||
->update([ 'DefaultTemplateId' => null], $con);
|
||||
|
||||
$con->commit();
|
||||
} catch (\Exception $ex) {
|
||||
$con->rollback();
|
||||
|
||||
throw $ex;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$event->setTemplate($template);
|
||||
|
||||
$event->setProductCount($product_count);
|
||||
|
||||
$event->setProductCount($productCount);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function addAttribute(TemplateAddAttributeEvent $event)
|
||||
{
|
||||
if (null === AttributeTemplateQuery::create()->filterByAttributeId($event->getAttributeId())->filterByTemplate($event->getTemplate())->findOne()) {
|
||||
|
||||
$attribute_template = new AttributeTemplate();
|
||||
|
||||
$attribute_template
|
||||
if (null === AttributeTemplateQuery::create()
|
||||
->filterByAttributeId($event->getAttributeId())
|
||||
->filterByTemplate($event->getTemplate())
|
||||
->findOne()) {
|
||||
$attributeTemplate = new AttributeTemplate();
|
||||
|
||||
$attributeTemplate
|
||||
->setAttributeId($event->getAttributeId())
|
||||
->setTemplate($event->getTemplate())
|
||||
->save()
|
||||
->save()
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Changes position, selecting absolute ou relative change.
|
||||
*
|
||||
* @param CategoryChangePositionEvent $event
|
||||
* @param UpdatePositionEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function updateAttributePosition(UpdatePositionEvent $event)
|
||||
public function updateAttributePosition(UpdatePositionEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
return $this->genericUpdatePosition(AttributeTemplateQuery::create(), $event);
|
||||
$this->genericUpdatePosition(AttributeTemplateQuery::create(), $event, $dispatcher);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Changes position, selecting absolute ou relative change.
|
||||
*
|
||||
* @param CategoryChangePositionEvent $event
|
||||
* @param UpdatePositionEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function updateFeaturePosition(UpdatePositionEvent $event)
|
||||
public function updateFeaturePosition(UpdatePositionEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
return $this->genericUpdatePosition(FeatureTemplateQuery::create(), $event);
|
||||
$this->genericUpdatePosition(FeatureTemplateQuery::create(), $event, $dispatcher);
|
||||
}
|
||||
|
||||
public function deleteAttribute(TemplateDeleteAttributeEvent $event)
|
||||
|
||||
public function deleteAttribute(TemplateDeleteAttributeEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$attribute_template = AttributeTemplateQuery::create()
|
||||
$attributeTemplate = AttributeTemplateQuery::create()
|
||||
->filterByAttributeId($event->getAttributeId())
|
||||
->filterByTemplate($event->getTemplate())->findOne()
|
||||
;
|
||||
|
||||
if ($attribute_template !== null) $attribute_template->delete();
|
||||
|
||||
if ($attributeTemplate !== null) {
|
||||
$attributeTemplate
|
||||
->setDispatcher($dispatcher)
|
||||
->delete();
|
||||
} else {
|
||||
// Prevent event propagation
|
||||
$event->stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function addFeature(TemplateAddFeatureEvent $event)
|
||||
{
|
||||
if (null === FeatureTemplateQuery::create()->filterByFeatureId($event->getFeatureId())->filterByTemplate($event->getTemplate())->findOne()) {
|
||||
|
||||
$feature_template = new FeatureTemplate();
|
||||
|
||||
$feature_template
|
||||
->setFeatureId($event->getFeatureId())
|
||||
->setTemplate($event->getTemplate())
|
||||
->save()
|
||||
if (null === FeatureTemplateQuery::create()
|
||||
->filterByFeatureId($event->getFeatureId())
|
||||
->filterByTemplate($event->getTemplate())
|
||||
->findOne()
|
||||
) {
|
||||
$featureTemplate = new FeatureTemplate();
|
||||
|
||||
$featureTemplate
|
||||
->setFeatureId($event->getFeatureId())
|
||||
->setTemplate($event->getTemplate())
|
||||
->save()
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
public function deleteFeature(TemplateDeleteFeatureEvent $event)
|
||||
|
||||
public function deleteFeature(TemplateDeleteFeatureEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$feature_template = FeatureTemplateQuery::create()
|
||||
$featureTemplate = FeatureTemplateQuery::create()
|
||||
->filterByFeatureId($event->getFeatureId())
|
||||
->filterByTemplate($event->getTemplate())->findOne()
|
||||
;
|
||||
|
||||
if ($feature_template !== null) $feature_template->delete();
|
||||
|
||||
if ($featureTemplate !== null) {
|
||||
$featureTemplate
|
||||
->setDispatcher($dispatcher)
|
||||
->delete();
|
||||
} else {
|
||||
// Prevent event propagation
|
||||
$event->stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@@ -179,16 +273,16 @@ class Template extends BaseAction implements EventSubscriberInterface
|
||||
TheliaEvents::TEMPLATE_CREATE => array("create", 128),
|
||||
TheliaEvents::TEMPLATE_UPDATE => array("update", 128),
|
||||
TheliaEvents::TEMPLATE_DELETE => array("delete", 128),
|
||||
|
||||
TheliaEvents::TEMPLATE_DUPLICATE => array("duplicate", 128),
|
||||
|
||||
TheliaEvents::TEMPLATE_ADD_ATTRIBUTE => array("addAttribute", 128),
|
||||
TheliaEvents::TEMPLATE_DELETE_ATTRIBUTE => array("deleteAttribute", 128),
|
||||
|
||||
|
||||
TheliaEvents::TEMPLATE_ADD_FEATURE => array("addFeature", 128),
|
||||
TheliaEvents::TEMPLATE_DELETE_FEATURE => array("deleteFeature", 128),
|
||||
|
||||
|
||||
TheliaEvents::TEMPLATE_CHANGE_ATTRIBUTE_POSITION => array('updateAttributePosition', 128),
|
||||
TheliaEvents::TEMPLATE_CHANGE_FEATURE_POSITION => array('updateFeaturePosition', 128),
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
372
core/lib/Thelia/Action/Translation.php
Normal file
372
core/lib/Thelia/Action/Translation.php
Normal file
@@ -0,0 +1,372 @@
|
||||
<?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 Thelia\Action;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
use Thelia\Core\Event\Cache\CacheEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\Event\Translation\TranslationEvent;
|
||||
use Thelia\Core\Translation\Translator;
|
||||
use Thelia\Log\Tlog;
|
||||
|
||||
/**
|
||||
* Class Translation
|
||||
* @package Thelia\Action
|
||||
* @author Manuel Raynaud <manu@raynaud.io>
|
||||
*/
|
||||
class Translation extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
/** @var ContainerInterface */
|
||||
protected $container;
|
||||
|
||||
public function __construct(ContainerInterface $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
public function getTranslatableStrings(TranslationEvent $event)
|
||||
{
|
||||
$stringCount = $this->walkDir(
|
||||
$event->getDirectory(),
|
||||
$event->getMode(),
|
||||
$event->getLocale(),
|
||||
$event->getDomain(),
|
||||
$strings
|
||||
);
|
||||
|
||||
$event
|
||||
->setTranslatableStrings($strings)
|
||||
->setTranslatableStringCount($stringCount)
|
||||
;
|
||||
}
|
||||
/**
|
||||
* Recursively examine files in a directory tree, and extract translatable strings.
|
||||
*
|
||||
* Returns an array of translatable strings, each item having with the following structure:
|
||||
* 'files' an array of file names in which the string appears,
|
||||
* 'text' the translatable text
|
||||
* 'translation' => the text translation, or an empty string if none available.
|
||||
* 'dollar' => true if the translatable text contains a $
|
||||
*
|
||||
* @param string $directory the path to the directory to examine
|
||||
* @param string $walkMode type of file scanning: WALK_MODE_PHP or WALK_MODE_TEMPLATE
|
||||
* @param string $currentLocale the current locale
|
||||
* @param string $domain the translation domain (fontoffice, backoffice, module, etc...)
|
||||
* @param array $strings the list of strings
|
||||
* @throws \InvalidArgumentException if $walkMode contains an invalid value
|
||||
* @return number the total number of translatable texts
|
||||
*/
|
||||
protected function walkDir($directory, $walkMode, $currentLocale, $domain, &$strings)
|
||||
{
|
||||
$numTexts = 0;
|
||||
|
||||
if ($walkMode == TranslationEvent::WALK_MODE_PHP) {
|
||||
$prefix = '\-\>[\s]*trans[\s]*\([\s]*';
|
||||
|
||||
$allowedExts = array('php');
|
||||
} elseif ($walkMode == TranslationEvent::WALK_MODE_TEMPLATE) {
|
||||
$prefix = '\{intl(?:.*?)[\s]l=[\s]*';
|
||||
|
||||
$allowedExts = array('html', 'tpl', 'xml', 'txt');
|
||||
} else {
|
||||
throw new \InvalidArgumentException(
|
||||
Translator::getInstance()->trans(
|
||||
'Invalid value for walkMode parameter: %value',
|
||||
array('%value' => $walkMode)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
Tlog::getInstance()->debug("Walking in $directory, in mode $walkMode");
|
||||
|
||||
/** @var \DirectoryIterator $fileInfo */
|
||||
foreach (new \DirectoryIterator($directory) as $fileInfo) {
|
||||
if ($fileInfo->isDot()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($fileInfo->isDir()) {
|
||||
$numTexts += $this->walkDir(
|
||||
$fileInfo->getPathName(),
|
||||
$walkMode,
|
||||
$currentLocale,
|
||||
$domain,
|
||||
$strings
|
||||
);
|
||||
}
|
||||
|
||||
if ($fileInfo->isFile()) {
|
||||
$ext = $fileInfo->getExtension();
|
||||
|
||||
if (in_array($ext, $allowedExts)) {
|
||||
if ($content = file_get_contents($fileInfo->getPathName())) {
|
||||
$short_path = $this->normalizePath($fileInfo->getPathName());
|
||||
|
||||
Tlog::getInstance()->debug("Examining file $short_path\n");
|
||||
|
||||
$matches = array();
|
||||
|
||||
if (preg_match_all(
|
||||
'/'.$prefix.'((?<![\\\\])[\'"])((?:.(?!(?<![\\\\])\1))*.?)*?\1/ms',
|
||||
$content,
|
||||
$matches
|
||||
)) {
|
||||
Tlog::getInstance()->debug("Strings found: ", $matches[2]);
|
||||
|
||||
$idx = 0;
|
||||
|
||||
foreach ($matches[2] as $match) {
|
||||
$hash = md5($match);
|
||||
|
||||
if (isset($strings[$hash])) {
|
||||
if (! in_array($short_path, $strings[$hash]['files'])) {
|
||||
$strings[$hash]['files'][] = $short_path;
|
||||
}
|
||||
} else {
|
||||
$numTexts++;
|
||||
|
||||
// remove \' (or \"), that will prevent the translator to work properly, as
|
||||
// "abc \def\" ghi" will be passed as abc "def" ghi to the translator.
|
||||
|
||||
$quote = $matches[1][$idx];
|
||||
|
||||
$match = str_replace("\\$quote", $quote, $match);
|
||||
|
||||
// Ignore empty strings
|
||||
if (strlen($match) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$strings[$hash] = array(
|
||||
'files' => array($short_path),
|
||||
'text' => $match,
|
||||
'translation' => Translator::getInstance()->trans(
|
||||
$match,
|
||||
[],
|
||||
$domain,
|
||||
$currentLocale,
|
||||
false,
|
||||
false
|
||||
),
|
||||
'custom_fallback' => Translator::getInstance()->trans(
|
||||
sprintf(
|
||||
Translator::GLOBAL_FALLBACK_KEY,
|
||||
$domain,
|
||||
$match
|
||||
),
|
||||
[],
|
||||
Translator::GLOBAL_FALLBACK_DOMAIN,
|
||||
$currentLocale,
|
||||
false,
|
||||
false
|
||||
),
|
||||
'global_fallback' => Translator::getInstance()->trans(
|
||||
$match,
|
||||
[],
|
||||
Translator::GLOBAL_FALLBACK_DOMAIN,
|
||||
$currentLocale,
|
||||
false,
|
||||
false
|
||||
),
|
||||
'dollar' => strstr($match, '$') !== false
|
||||
);
|
||||
}
|
||||
|
||||
$idx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (\UnexpectedValueException $ex) {
|
||||
// Directory does not exists => ignore it.
|
||||
}
|
||||
|
||||
return $numTexts;
|
||||
}
|
||||
|
||||
public function writeTranslationFile(TranslationEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$file = $event->getTranslationFilePath();
|
||||
|
||||
$fs = new Filesystem();
|
||||
|
||||
if (! $fs->exists($file) && true === $event->isCreateFileIfNotExists()) {
|
||||
$dir = dirname($file);
|
||||
|
||||
if (! $fs->exists($file)) {
|
||||
$fs->mkdir($dir);
|
||||
|
||||
$this->cacheClear($dispatcher);
|
||||
}
|
||||
}
|
||||
|
||||
if ($fp = @fopen($file, 'w')) {
|
||||
fwrite($fp, '<' . "?php\n\n");
|
||||
fwrite($fp, "return array(\n");
|
||||
|
||||
$texts = $event->getTranslatableStrings();
|
||||
$translations = $event->getTranslatedStrings();
|
||||
|
||||
// Sort keys alphabetically while keeping index
|
||||
asort($texts);
|
||||
|
||||
foreach ($texts as $key => $text) {
|
||||
// Write only defined (not empty) translations
|
||||
if (! empty($translations[$key])) {
|
||||
$text = str_replace("'", "\'", $text);
|
||||
|
||||
$translation = str_replace("'", "\'", $translations[$key]);
|
||||
|
||||
fwrite($fp, sprintf(" '%s' => '%s',\n", $text, $translation));
|
||||
}
|
||||
}
|
||||
|
||||
fwrite($fp, ");\n");
|
||||
|
||||
@fclose($fp);
|
||||
} else {
|
||||
throw new \RuntimeException(
|
||||
Translator::getInstance()->trans(
|
||||
'Failed to open translation file %file. Please be sure that this file is writable by your Web server',
|
||||
array('%file' => $file)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function writeFallbackFile(TranslationEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$file = THELIA_LOCAL_DIR . 'I18n' . DS . $event->getLocale() . '.php';
|
||||
|
||||
$fs = new Filesystem();
|
||||
$translations = [];
|
||||
|
||||
if (! $fs->exists($file)) {
|
||||
if (true === $event->isCreateFileIfNotExists()) {
|
||||
$dir = dirname($file);
|
||||
$fs->mkdir($dir);
|
||||
|
||||
$this->cacheClear($dispatcher);
|
||||
} else {
|
||||
throw new \RuntimeException(
|
||||
Translator::getInstance()->trans(
|
||||
'Failed to open translation file %file. Please be sure that this file is writable by your Web server',
|
||||
array('%file' => $file)
|
||||
)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
/*$loader = new PhpFileLoader();
|
||||
$catalogue = $loade r->load($file);
|
||||
$translations = $catalogue->all();
|
||||
*/
|
||||
$translations = require $file;
|
||||
|
||||
if (! is_array($translations)) {
|
||||
$translations = [];
|
||||
}
|
||||
}
|
||||
|
||||
if ($fp = @fopen($file, 'w')) {
|
||||
$texts = $event->getTranslatableStrings();
|
||||
$customs = $event->getCustomFallbackStrings();
|
||||
$globals = $event->getGlobalFallbackStrings();
|
||||
|
||||
// just reset current translations for this domain to remove strings that do not exist anymore
|
||||
$translations[$event->getDomain()] = [];
|
||||
|
||||
foreach ($texts as $key => $text) {
|
||||
if (!empty($customs[$key])) {
|
||||
$translations[$event->getDomain()][$text] = $customs[$key];
|
||||
}
|
||||
|
||||
if (!empty($globals[$key])) {
|
||||
$translations[$text] = $globals[$key];
|
||||
} else {
|
||||
unset($translations[$text]);
|
||||
}
|
||||
}
|
||||
|
||||
fwrite($fp, '<' . "?php\n\n");
|
||||
fwrite($fp, "return [\n");
|
||||
|
||||
// Sort keys alphabetically while keeping index
|
||||
ksort($translations);
|
||||
|
||||
foreach ($translations as $key => $text) {
|
||||
// Write only defined (not empty) translations
|
||||
if (!empty($translations[$key])) {
|
||||
if (is_array($translations[$key])) {
|
||||
$key = str_replace("'", "\'", $key);
|
||||
fwrite($fp, sprintf(" '%s' => [\n", $key));
|
||||
ksort($translations[$key]);
|
||||
foreach ($translations[$key] as $subKey => $subText) {
|
||||
$subKey = str_replace("'", "\'", $subKey);
|
||||
$translation = str_replace("'", "\'", $subText);
|
||||
fwrite($fp, sprintf(" '%s' => '%s',\n", $subKey, $translation));
|
||||
}
|
||||
fwrite($fp, " ],\n");
|
||||
} else {
|
||||
$key = str_replace("'", "\'", $key);
|
||||
$translation = str_replace("'", "\'", $text);
|
||||
fwrite($fp, sprintf(" '%s' => '%s',\n", $key, $translation));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fwrite($fp, "];\n");
|
||||
|
||||
@fclose($fp);
|
||||
}
|
||||
}
|
||||
|
||||
protected function normalizePath($path)
|
||||
{
|
||||
$path = str_replace(
|
||||
str_replace('\\', '/', THELIA_ROOT),
|
||||
'',
|
||||
str_replace('\\', '/', realpath($path))
|
||||
);
|
||||
|
||||
return ltrim($path, '/');
|
||||
}
|
||||
|
||||
protected function cacheClear(EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$cacheEvent = new CacheEvent(
|
||||
$this->container->getParameter('kernel.cache_dir')
|
||||
);
|
||||
|
||||
$dispatcher->dispatch(TheliaEvents::CACHE_CLEAR, $cacheEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::TRANSLATION_GET_STRINGS => array('getTranslatableStrings', 128),
|
||||
TheliaEvents::TRANSLATION_WRITE_FILE => [
|
||||
['writeTranslationFile', 128],
|
||||
['writeFallbackFile', 128]
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -13,11 +13,11 @@
|
||||
namespace Thelia\Cart;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Thelia\Core\HttpFoundation\Request;
|
||||
use Thelia\Model\CartQuery;
|
||||
use Thelia\Model\Cart as CartModel;
|
||||
use Thelia\Model\ConfigQuery;
|
||||
use Thelia\Model\Customer;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Thelia\Core\HttpFoundation\Session\Session;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\Event\Cart\CartEvent;
|
||||
@@ -27,7 +27,9 @@ use Thelia\Core\Event\Cart\CartEvent;
|
||||
*
|
||||
* Trait CartTrait
|
||||
* @package Thelia\Cart
|
||||
* @author Manuel Raynaud <mraynaud@openstudio.fr>
|
||||
* @author Manuel Raynaud <manu@raynaud.io>
|
||||
*
|
||||
* @deprecated CartTrait is deprecated, please use Session::getSessionCart method instead
|
||||
*/
|
||||
trait CartTrait
|
||||
{
|
||||
@@ -37,101 +39,16 @@ trait CartTrait
|
||||
*
|
||||
* @param EventDispatcherInterface $dispatcher the event dispatcher
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* @deprecated use Session::getSessionCart method instead
|
||||
* @return \Thelia\Model\Cart
|
||||
*/
|
||||
public function getCart(EventDispatcherInterface $dispatcher, Request $request)
|
||||
{
|
||||
$session = $request->getSession();
|
||||
|
||||
if (null !== $cart = $session->getCart()) {
|
||||
return $cart;
|
||||
}
|
||||
|
||||
if ($request->cookies->has("thelia_cart")) {
|
||||
//le cookie de panier existe, on le récupère
|
||||
$token = $request->cookies->get("thelia_cart");
|
||||
|
||||
$cart = CartQuery::create()->findOneByToken($token);
|
||||
|
||||
if ($cart) {
|
||||
//le panier existe en base
|
||||
$customer = $session->getCustomerUser();
|
||||
|
||||
if ($customer) {
|
||||
if ($cart->getCustomerId() != $customer->getId()) {
|
||||
//le customer du panier n'est pas le mm que celui connecté, il faut cloner le panier sans le customer_id
|
||||
$cart = $this->duplicateCart($dispatcher, $cart, $session, $customer);
|
||||
}
|
||||
} else {
|
||||
if ($cart->getCustomerId() != null) {
|
||||
//il faut dupliquer le panier sans le customer_id
|
||||
$cart = $this->duplicateCart($dispatcher, $cart, $session);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
$cart = $this->createCart($session);
|
||||
}
|
||||
} else {
|
||||
//le cookie de panier n'existe pas, il va falloir le créer et faire un enregistrement en base.
|
||||
$cart = $this->createCart($session);
|
||||
}
|
||||
$session->setCart($cart->getId());
|
||||
|
||||
return $cart;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Thelia\Core\HttpFoundation\Session\Session $session
|
||||
* @return \Thelia\Model\Cart
|
||||
*/
|
||||
protected function createCart(Session $session)
|
||||
{
|
||||
$cart = new CartModel();
|
||||
$cart->setToken($this->generateCookie($session));
|
||||
$cart->setCurrency($session->getCurrency(true));
|
||||
|
||||
if (null !== $customer = $session->getCustomerUser()) {
|
||||
$cart->setCustomer($customer);
|
||||
}
|
||||
|
||||
$cart->save();
|
||||
|
||||
$session->setCart($cart->getId());
|
||||
|
||||
return $cart;
|
||||
}
|
||||
|
||||
/**
|
||||
* try to duplicate existing Cart. Customer is here to determine if this cart belong to him.
|
||||
*
|
||||
* @param \Thelia\Model\Cart $cart
|
||||
* @param \Thelia\Core\HttpFoundation\Session\Session $session
|
||||
* @param \Thelia\Model\Customer $customer
|
||||
* @return \Thelia\Model\Cart
|
||||
*/
|
||||
protected function duplicateCart(EventDispatcherInterface $dispatcher, CartModel $cart, Session $session, Customer $customer = null)
|
||||
{
|
||||
$currency = $session->getCurrency();
|
||||
$newCart = $cart->duplicate($this->generateCookie($session), $customer, $currency, $dispatcher);
|
||||
$session->setCart($newCart->getId());
|
||||
|
||||
$cartEvent = new CartEvent($newCart);
|
||||
|
||||
$dispatcher->dispatch(TheliaEvents::CART_DUPLICATE, $cartEvent);
|
||||
|
||||
return $cartEvent->getCart();
|
||||
}
|
||||
|
||||
protected function generateCookie(Session $session)
|
||||
{
|
||||
$id = null;
|
||||
if (ConfigQuery::read("cart.session_only", 0) == 0) {
|
||||
$id = uniqid('', true);
|
||||
$session->set('cart_use_cookie', $id);
|
||||
}
|
||||
|
||||
return $id;
|
||||
trigger_error(
|
||||
'CartTrait is deprecated, please use Session::getSessionCart method instead',
|
||||
E_USER_DEPRECATED
|
||||
);
|
||||
|
||||
return $request->getSession()->getSessionCart($dispatcher);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,12 @@ use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
|
||||
use Thelia\Core\Event\Administrator\AdministratorUpdatePasswordEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\HttpFoundation\Request;
|
||||
use Thelia\Core\HttpFoundation\Session\Session;
|
||||
use Thelia\Model\AdminQuery;
|
||||
use Thelia\Tools\Password;
|
||||
|
||||
@@ -28,10 +32,21 @@ use Thelia\Tools\Password;
|
||||
*
|
||||
* Class AdminUpdatePasswordCommand
|
||||
* @package Thelia\Command
|
||||
* @author Manuel Raynaud <mraynaud@openstudio.fr>
|
||||
* @author Manuel Raynaud <manu@raynaud.io>
|
||||
*/
|
||||
class AdminUpdatePasswordCommand extends ContainerAwareCommand
|
||||
{
|
||||
protected function init()
|
||||
{
|
||||
$container = $this->getContainer();
|
||||
|
||||
$request = new Request();
|
||||
$request->setSession(new Session(new MockArraySessionStorage()));
|
||||
|
||||
/** @var RequestStack $requestStack */
|
||||
$requestStack = $container->get('request_stack');
|
||||
$requestStack->push($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the current command.
|
||||
@@ -58,6 +73,8 @@ class AdminUpdatePasswordCommand extends ContainerAwareCommand
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->init();
|
||||
|
||||
$login = $input->getArgument('login');
|
||||
|
||||
if (null === $admin = AdminQuery::create()->filterByLogin($login)->findOne()) {
|
||||
@@ -69,10 +86,7 @@ class AdminUpdatePasswordCommand extends ContainerAwareCommand
|
||||
$event = new AdministratorUpdatePasswordEvent($admin);
|
||||
$event->setPassword($password);
|
||||
|
||||
$this->
|
||||
getContainer()
|
||||
->get('event_dispatcher')
|
||||
->dispatch(TheliaEvents::ADMINISTRATOR_UPDATEPASSWORD, $event);
|
||||
$this->getDispatcher()->dispatch(TheliaEvents::ADMINISTRATOR_UPDATEPASSWORD, $event);
|
||||
|
||||
$output->writeln(array(
|
||||
'',
|
||||
@@ -80,7 +94,5 @@ class AdminUpdatePasswordCommand extends ContainerAwareCommand
|
||||
sprintf('<info>new password is : %s</info>', $password),
|
||||
''
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,25 +12,23 @@
|
||||
|
||||
namespace Thelia\Command;
|
||||
|
||||
use Thelia\Model\Module;
|
||||
|
||||
/**
|
||||
* base class for module commands
|
||||
*
|
||||
* Class BaseModuleGenerate
|
||||
* @package Thelia\Command
|
||||
* @author Manuel Raynaud <mraynaud@openstudio.fr>
|
||||
* @author Manuel Raynaud <manu@raynaud.io>
|
||||
*/
|
||||
abstract class BaseModuleGenerate extends ContainerAwareCommand
|
||||
{
|
||||
protected $module;
|
||||
protected $moduleDirectory;
|
||||
protected $module;
|
||||
protected $moduleDirectory;
|
||||
|
||||
protected $reservedKeyWords = array(
|
||||
protected $reservedKeyWords = array(
|
||||
'thelia'
|
||||
);
|
||||
|
||||
protected $neededDirectories = array(
|
||||
protected $neededDirectories = array(
|
||||
'Config',
|
||||
'Model',
|
||||
'Loop',
|
||||
@@ -38,23 +36,37 @@ abstract class BaseModuleGenerate extends ContainerAwareCommand
|
||||
'Controller',
|
||||
'EventListeners',
|
||||
'I18n',
|
||||
Module::ADMIN_INCLUDES_DIRECTORY_NAME,
|
||||
'templates',
|
||||
'Hook',
|
||||
);
|
||||
|
||||
protected function verifyExistingModule()
|
||||
{
|
||||
if (file_exists($this->moduleDirectory)) {
|
||||
throw new \RuntimeException(sprintf("%s module already exists", $this->module));
|
||||
}
|
||||
}
|
||||
protected function verifyExistingModule()
|
||||
{
|
||||
if (file_exists($this->moduleDirectory)) {
|
||||
throw new \RuntimeException(
|
||||
sprintf(
|
||||
"%s module already exists. Use --force option to force generation.",
|
||||
$this->module
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected function formatModuleName($name)
|
||||
{
|
||||
if (in_array(strtolower($name), $this->reservedKeyWords)) {
|
||||
throw new \RuntimeException(sprintf("%s module name is a reserved keyword", $name));
|
||||
}
|
||||
protected function formatModuleName($name)
|
||||
{
|
||||
if (in_array(strtolower($name), $this->reservedKeyWords)) {
|
||||
throw new \RuntimeException(sprintf("%s module name is a reserved keyword", $name));
|
||||
}
|
||||
|
||||
return ucfirst($name);
|
||||
}
|
||||
return ucfirst($name);
|
||||
}
|
||||
|
||||
protected function validModuleName($name)
|
||||
{
|
||||
if (!preg_match('#^[A-Z]([A-Za-z\d])+$#', $name)) {
|
||||
throw new \RuntimeException(
|
||||
sprintf("%s module name is not a valid name, it must be in CamelCase. (ex: MyModuleName)", $name)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,18 +15,17 @@ namespace Thelia\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
use Symfony\Component\Filesystem\Exception\IOException;
|
||||
|
||||
use Thelia\Core\Event\Cache\CacheEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Model\ConfigQuery;
|
||||
|
||||
/**
|
||||
* clear the cache
|
||||
*
|
||||
* Class CacheClear
|
||||
* @package Thelia\Command
|
||||
* @author Manuel Raynaud <mraynaud@openstudio.fr>
|
||||
* @author Manuel Raynaud <manu@raynaud.io>
|
||||
*
|
||||
*/
|
||||
class CacheClear extends ContainerAwareCommand
|
||||
@@ -46,26 +45,46 @@ class CacheClear extends ContainerAwareCommand
|
||||
'with-images',
|
||||
null,
|
||||
InputOption::VALUE_NONE,
|
||||
'clear images generated in web/cache directory'
|
||||
'clear images generated in `image_cache_dir_from_web_root` or web/cache/images directory'
|
||||
)
|
||||
->addOption(
|
||||
'with-documents',
|
||||
null,
|
||||
InputOption::VALUE_NONE,
|
||||
'clear documents generated in `document_cache_dir_from_web_root` or web/cache/documents directory'
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
|
||||
$cacheDir = $this->getContainer()->getParameter("kernel.cache_dir");
|
||||
|
||||
$this->clearCache($cacheDir, $output);
|
||||
|
||||
if (!$input->getOption("without-assets")) {
|
||||
$this->clearCache(THELIA_WEB_DIR . "assets", $output);
|
||||
if (!$input->getOption('without-assets')) {
|
||||
$this->clearCache(THELIA_WEB_DIR . ConfigQuery::read('asset_dir_from_web_root', 'assets'), $output);
|
||||
}
|
||||
|
||||
if ($input->getOption('with-images')) {
|
||||
$this->clearCache(THELIA_CACHE_DIR, $output);
|
||||
$this->clearCache(
|
||||
THELIA_WEB_DIR . ConfigQuery::read(
|
||||
'image_cache_dir_from_web_root',
|
||||
'cache' . DS . 'images'
|
||||
),
|
||||
$output
|
||||
);
|
||||
}
|
||||
|
||||
if ($input->getOption('with-documents')) {
|
||||
$this->clearCache(
|
||||
THELIA_WEB_DIR . ConfigQuery::read(
|
||||
'document_cache_dir_from_web_root',
|
||||
'cache' . DS . 'documents'
|
||||
),
|
||||
$output
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected function clearCache($dir, OutputInterface $output)
|
||||
@@ -74,10 +93,7 @@ class CacheClear extends ContainerAwareCommand
|
||||
|
||||
try {
|
||||
$cacheEvent = new CacheEvent($dir);
|
||||
$this->
|
||||
getContainer()
|
||||
->get('event_dispatcher')
|
||||
->dispatch(TheliaEvents::CACHE_CLEAR, $cacheEvent);
|
||||
$this->getDispatcher()->dispatch(TheliaEvents::CACHE_CLEAR, $cacheEvent);
|
||||
} catch (\UnexpectedValueException $e) {
|
||||
// throws same exception code for does not exist and permission denied ...
|
||||
if (!file_exists($dir)) {
|
||||
@@ -92,6 +108,5 @@ class CacheClear extends ContainerAwareCommand
|
||||
}
|
||||
|
||||
$output->writeln(sprintf("<info>%s cache directory cleared successfully</info>", $dir));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,8 +32,6 @@ class ClearImageCache extends ContainerAwareCommand
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$dispatcher = $this->getContainer()->get('event_dispatcher');
|
||||
|
||||
$request = new Request();
|
||||
|
||||
try {
|
||||
@@ -41,13 +39,15 @@ class ClearImageCache extends ContainerAwareCommand
|
||||
|
||||
$subdir = $input->getArgument('subdir');
|
||||
|
||||
if (! is_null($subdir)) $event->setCacheSubdirectory($subdir);
|
||||
if (! is_null($subdir)) {
|
||||
$event->setCacheSubdirectory($subdir);
|
||||
}
|
||||
|
||||
$dispatcher->dispatch(TheliaEvents::IMAGE_CLEAR_CACHE, $event);
|
||||
$this->getDispatcher()->dispatch(TheliaEvents::IMAGE_CLEAR_CACHE, $event);
|
||||
|
||||
$output->writeln(sprintf('%s image cache successfully cleared.', is_null($subdir) ? 'Entire' : ucfirst($subdir)));
|
||||
} catch (\Exception $ex) {
|
||||
$output->writeln(sprintf("Failed to clear image cache: %s", $ex->getMessage()));
|
||||
$output->writeln(sprintf("Failed to clear image cache: %s", $ex->getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
225
core/lib/Thelia/Command/ConfigCommand.php
Normal file
225
core/lib/Thelia/Command/ConfigCommand.php
Normal file
@@ -0,0 +1,225 @@
|
||||
<?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 Thelia\Command;
|
||||
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Thelia\Model\Config;
|
||||
use Thelia\Model\ConfigQuery;
|
||||
|
||||
/**
|
||||
* command line for managing configuration variables
|
||||
*
|
||||
* php Thelia thelia:config COMMAND [name] [value] [--secured] [--visible]
|
||||
*
|
||||
* Where COMMAND is list, get, set or delete.
|
||||
*
|
||||
* For command get and delete, you should also set the name attribute.
|
||||
*
|
||||
* For command set, you should set the name and value attributes and optionally add
|
||||
* --secured and/or --visible arguments.
|
||||
*
|
||||
* Class ConfigCommand
|
||||
* @package Thelia\Command
|
||||
* @author Julien Chanséaume <jchanseaume@openstudio.fr>
|
||||
*/
|
||||
class ConfigCommand extends ContainerAwareCommand
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName("thelia:config")
|
||||
->setDescription("Manage configuration variables")
|
||||
->addArgument(
|
||||
'COMMAND',
|
||||
InputArgument::REQUIRED,
|
||||
'Command : list, get, set, delete'
|
||||
)
|
||||
->addArgument(
|
||||
'name',
|
||||
InputArgument::OPTIONAL,
|
||||
'The variable name'
|
||||
)
|
||||
->addArgument(
|
||||
'value',
|
||||
InputArgument::OPTIONAL,
|
||||
'The variable value'
|
||||
)
|
||||
->addOption(
|
||||
'secured',
|
||||
null,
|
||||
InputOption::VALUE_NONE,
|
||||
'When setting a new variable tell variable is secured.'
|
||||
)
|
||||
->addOption(
|
||||
'visible',
|
||||
null,
|
||||
InputOption::VALUE_NONE,
|
||||
'When setting a new variable tell variable is visible.'
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$command = $input->getArgument("COMMAND");
|
||||
|
||||
switch ($command) {
|
||||
case "list":
|
||||
$this->listConfig($input, $output);
|
||||
break;
|
||||
|
||||
case "get":
|
||||
$this->getConfig($input, $output);
|
||||
break;
|
||||
|
||||
case "set":
|
||||
$this->setConfig($input, $output);
|
||||
break;
|
||||
|
||||
case "delete":
|
||||
$this->deleteConfig($input, $output);
|
||||
break;
|
||||
|
||||
default:
|
||||
$output->writeln(
|
||||
"<error>Unknown argument 'COMMAND' : list, get, set, delete</error>"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function listConfig(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$output->writeln([
|
||||
"",
|
||||
"<error>Variables list</error>",
|
||||
""
|
||||
]);
|
||||
|
||||
$vars = ConfigQuery::create()
|
||||
->orderByName()
|
||||
->find()
|
||||
;
|
||||
|
||||
$rows = [];
|
||||
|
||||
/** @var Config $var */
|
||||
foreach ($vars as $var) {
|
||||
$rows[] = [
|
||||
$var->getName(),
|
||||
$var->getValue(),
|
||||
$var->getSecured() !== 0 ? "yes" : "no",
|
||||
$var->getHidden() !== 0 ? "yes" : "no"
|
||||
];
|
||||
}
|
||||
|
||||
$table = new Table($output);
|
||||
$table
|
||||
->setHeaders(['Name', 'Value', 'secured', 'hidden'])
|
||||
->setRows($rows)
|
||||
;
|
||||
$table->render();
|
||||
}
|
||||
|
||||
private function getConfig(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$varName = $input->getArgument("name");
|
||||
|
||||
if (null === $varName) {
|
||||
$output->writeln(
|
||||
"<error>Need argument 'name' for get command</error>"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
$var = ConfigQuery::create()->findOneByName($varName);
|
||||
|
||||
$out = [];
|
||||
|
||||
if (null === $var) {
|
||||
$out[] = sprintf(
|
||||
"<error>Unknown variable '%s'</error>",
|
||||
$varName
|
||||
);
|
||||
} else {
|
||||
$out = [
|
||||
sprintf('%12s: <%3$s>%s</%3$s>', "Name", $var->getName(), "info"),
|
||||
sprintf('%12s: <%3$s>%s</%3$s>', "Value", $var->getValue(), "info"),
|
||||
sprintf('%12s: <%3$s>%s</%3$s>', "Secured", $var->getSecured() ? "yes" : "no", "info"),
|
||||
sprintf('%12s: <%3$s>%s</%3$s>', "Hidden", $var->getHidden() ? "yes" : "no", "info"),
|
||||
sprintf('%12s: <%3$s>%s</%3$s>', "Title", $var->getTitle(), "info"),
|
||||
sprintf('%12s: <%3$s>%s</%3$s>', "Description", $var->getDescription(), "info"),
|
||||
];
|
||||
}
|
||||
|
||||
$output->writeln($out);
|
||||
}
|
||||
|
||||
|
||||
private function setConfig(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$varName = $input->getArgument("name");
|
||||
$varValue = $input->getArgument("value");
|
||||
|
||||
if (null === $varName || null === $varValue) {
|
||||
$output->writeln(
|
||||
"<error>Need argument 'name' and 'value' for set command</error>"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
ConfigQuery::write(
|
||||
$varName,
|
||||
$varValue,
|
||||
$input->getOption("secured"),
|
||||
!$input->getOption("visible")
|
||||
);
|
||||
|
||||
$output->writeln("<info>Variable has been set</info>");
|
||||
}
|
||||
|
||||
private function deleteConfig(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$varName = $input->getArgument("name");
|
||||
|
||||
if (null === $varName) {
|
||||
$output->writeln(
|
||||
"<error>Need argument 'name' for get command</error>"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
$var = ConfigQuery::create()->findOneByName($varName);
|
||||
|
||||
if (null === $var) {
|
||||
$output->writeln(
|
||||
sprintf(
|
||||
"<error>Unknown variable '%s'</error>",
|
||||
$varName
|
||||
)
|
||||
);
|
||||
} else {
|
||||
$var->delete();
|
||||
$output->writeln(
|
||||
sprintf(
|
||||
"<info>Variable '%s' has been deleted</info>",
|
||||
$varName
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,11 +15,23 @@ namespace Thelia\Command;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
|
||||
use Symfony\Component\Routing\RequestContext;
|
||||
use Thelia\Core\Application;
|
||||
use Thelia\Core\HttpFoundation\Request;
|
||||
use Thelia\Core\HttpFoundation\Session\Session;
|
||||
use Thelia\Core\Translation\Translator;
|
||||
use Thelia\Model\ConfigQuery;
|
||||
use Thelia\Model\Lang;
|
||||
use Thelia\Model\LangQuery;
|
||||
use Thelia\Tools\URL;
|
||||
|
||||
/**
|
||||
* Command.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Gilles Bourgeat <gbourgeat@openstudio.fr>
|
||||
*/
|
||||
class ContainerAwareCommand extends Command implements ContainerAwareInterface
|
||||
{
|
||||
@@ -34,7 +46,9 @@ class ContainerAwareCommand extends Command implements ContainerAwareInterface
|
||||
protected function getContainer()
|
||||
{
|
||||
if (null === $this->container) {
|
||||
$this->container = $this->getApplication()->getKernel()->getContainer();
|
||||
/** @var Application $application */
|
||||
$application = $this->getApplication();
|
||||
$this->container = $application->getKernel()->getContainer();
|
||||
}
|
||||
|
||||
return $this->container;
|
||||
@@ -42,9 +56,78 @@ class ContainerAwareCommand extends Command implements ContainerAwareInterface
|
||||
|
||||
/**
|
||||
* @see ContainerAwareInterface::setContainer()
|
||||
* @param ContainerInterface $container
|
||||
*/
|
||||
public function setContainer(ContainerInterface $container = null)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Symfony\Component\EventDispatcher\EventDispatcher
|
||||
*/
|
||||
public function getDispatcher()
|
||||
{
|
||||
$container = $this->getContainer();
|
||||
|
||||
// Initialize Thelia translator, if not already done.
|
||||
try {
|
||||
Translator::getInstance();
|
||||
} catch (\Exception $ex) {
|
||||
$this->container->get('thelia.translator');
|
||||
}
|
||||
|
||||
return $container->get('event_dispatcher');
|
||||
}
|
||||
|
||||
/**
|
||||
* For init an Request, if your command has need an Request
|
||||
* @param Lang|null $lang
|
||||
* @since 2.3
|
||||
*/
|
||||
protected function initRequest(Lang $lang = null)
|
||||
{
|
||||
$container = $this->getContainer();
|
||||
|
||||
$request = Request::create($this->getBaseUrl($lang));
|
||||
$request->setSession(new Session(new MockArraySessionStorage()));
|
||||
$container->set("request_stack", new RequestStack());
|
||||
$container->get('request_stack')->push($request);
|
||||
|
||||
$requestContext = new RequestContext();
|
||||
$requestContext->fromRequest($request);
|
||||
$url = $container->get('thelia.url.manager');
|
||||
$url->setRequestContext($requestContext);
|
||||
$this->getContainer()->get('router.admin')->setContext($requestContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Lang|null $lang
|
||||
* @return string
|
||||
* @since 2.3
|
||||
*/
|
||||
protected function getBaseUrl(Lang $lang = null)
|
||||
{
|
||||
$baseUrl = '';
|
||||
|
||||
if ((int) ConfigQuery::read('one_domain_foreach_lang') === 1) {
|
||||
if ($lang === null) {
|
||||
$lang = LangQuery::create()->findOneByByDefault(true);
|
||||
}
|
||||
|
||||
$baseUrl = $lang->getUrl();
|
||||
}
|
||||
|
||||
$baseUrl = trim($baseUrl);
|
||||
|
||||
if (empty($baseUrl)) {
|
||||
$baseUrl = ConfigQuery::read('url_site');
|
||||
}
|
||||
|
||||
if (empty($baseUrl)) {
|
||||
$baseUrl = 'http://localhost';
|
||||
}
|
||||
|
||||
return $baseUrl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,11 +12,13 @@
|
||||
|
||||
namespace Thelia\Command;
|
||||
|
||||
use Symfony\Component\Console\Helper\QuestionHelper;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
use Symfony\Component\Console\Question\Question;
|
||||
use Thelia\Model\Admin;
|
||||
use Thelia\Model\AdminQuery;
|
||||
|
||||
class CreateAdminUser extends ContainerAwareCommand
|
||||
{
|
||||
@@ -50,6 +52,13 @@ class CreateAdminUser extends ContainerAwareCommand
|
||||
'User last name',
|
||||
null
|
||||
)
|
||||
->addOption(
|
||||
"email",
|
||||
null,
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
'Admin email address',
|
||||
null
|
||||
)
|
||||
->addOption(
|
||||
"locale",
|
||||
null,
|
||||
@@ -65,13 +74,13 @@ class CreateAdminUser extends ContainerAwareCommand
|
||||
null
|
||||
)
|
||||
;
|
||||
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$output->writeln('Please enter the admin user information:');
|
||||
|
||||
/** @var Admin $admin */
|
||||
$admin = $this->getAdminInfo($input, $output);
|
||||
|
||||
$admin->save();
|
||||
@@ -83,22 +92,30 @@ class CreateAdminUser extends ContainerAwareCommand
|
||||
));
|
||||
}
|
||||
|
||||
protected function enterData($dialog, $output, $label, $error_message, $hidden = false)
|
||||
{
|
||||
$command = $hidden ? 'askHiddenResponse' : 'askAndValidate';
|
||||
protected function enterData(
|
||||
QuestionHelper $helper,
|
||||
InputInterface $input,
|
||||
OutputInterface $output,
|
||||
$label,
|
||||
$errorMessage,
|
||||
$hidden = false
|
||||
) {
|
||||
$question = new Question($this->decorateInfo($label));
|
||||
|
||||
return $dialog->$command(
|
||||
$output,
|
||||
$this->decorateInfo($label),
|
||||
function ($answer) {
|
||||
$answer = trim($answer);
|
||||
if (empty($answer)) {
|
||||
throw new \RuntimeException("This information is mandatory.");
|
||||
}
|
||||
if ($hidden) {
|
||||
$question->setHidden(true);
|
||||
$question->setHiddenFallback(false);
|
||||
}
|
||||
|
||||
return $answer;
|
||||
$question->setValidator(function ($value) use (&$errorMessage) {
|
||||
if (trim($value) == '') {
|
||||
throw new \Exception($errorMessage);
|
||||
}
|
||||
);
|
||||
|
||||
return $value;
|
||||
});
|
||||
|
||||
return $helper->ask($input, $output, $question);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -110,21 +127,23 @@ class CreateAdminUser extends ContainerAwareCommand
|
||||
*/
|
||||
protected function getAdminInfo(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$dialog = $this->getHelperSet()->get('dialog');
|
||||
/** @var QuestionHelper $helper */
|
||||
$helper = $this->getHelper('question');
|
||||
|
||||
$admin = new Admin();
|
||||
|
||||
$admin->setLogin($input->getOption("login_name") ?: $this->enterData($dialog, $output, "Admin login name : ", "Please enter a login name."));
|
||||
$admin->setFirstname($input->getOption("first_name") ?: $this->enterData($dialog, $output, "User first name : ", "Please enter user first name."));
|
||||
$admin->setLastname($input->getOption("last_name") ?: $this->enterData($dialog, $output, "User last name : ", "Please enter user last name."));
|
||||
$admin->setLogin($input->getOption("login_name") ?: $this->enterLogin($helper, $input, $output));
|
||||
$admin->setFirstname($input->getOption("first_name") ?: $this->enterData($helper, $input, $output, "User first name : ", "Please enter user first name."));
|
||||
$admin->setLastname($input->getOption("last_name") ?: $this->enterData($helper, $input, $output, "User last name : ", "Please enter user last name."));
|
||||
|
||||
$admin->setLocale($input->getOption("locale") ?: 'en_US');
|
||||
$admin->setEmail($input->getOption("email") ?: $this->enterEmail($helper, $input, $output));
|
||||
|
||||
do {
|
||||
$password = $input->getOption("password") ?: $this->enterData($dialog, $output, "Password : ", "Please enter a password.", true);
|
||||
$password_again = $input->getOption("password") ?: $this->enterData($dialog, $output, "Password (again): ", "Please enter the password again.", true);
|
||||
$password = $input->getOption("password") ?: $this->enterData($helper, $input, $output, "Password : ", "Please enter a password.", true);
|
||||
$password_again = $input->getOption("password") ?: $this->enterData($helper, $input, $output, "Password (again): ", "Please enter the password again.", true);
|
||||
|
||||
if (! empty($password) && $password == $password_again) {
|
||||
|
||||
$admin->setPassword($password);
|
||||
|
||||
break;
|
||||
@@ -143,4 +162,44 @@ class CreateAdminUser extends ContainerAwareCommand
|
||||
return sprintf("<info>%s</info>", $text);
|
||||
}
|
||||
|
||||
|
||||
protected function enterLogin(QuestionHelper $helper, InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$question = new Question($this->decorateInfo("Admin login name : "));
|
||||
|
||||
$question->setValidator(function ($answer) {
|
||||
$answer = trim($answer);
|
||||
if (empty($answer)) {
|
||||
throw new \RuntimeException("Please enter a login name.");
|
||||
}
|
||||
|
||||
if (AdminQuery::create()->findOneByLogin($answer)) {
|
||||
throw new \RuntimeException("An administrator with this login already exists.");
|
||||
}
|
||||
|
||||
return $answer;
|
||||
});
|
||||
|
||||
return $helper->ask($input, $output, $question);
|
||||
}
|
||||
|
||||
protected function enterEmail(QuestionHelper $helper, InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$question = new Question($this->decorateInfo("Admin email or empty value : "));
|
||||
|
||||
$question->setValidator(function ($answer) {
|
||||
$answer = trim($answer);
|
||||
if (!empty($answer) && !filter_var($answer, FILTER_VALIDATE_EMAIL)) {
|
||||
throw new \RuntimeException("Please enter an email or an empty value.");
|
||||
}
|
||||
|
||||
if (AdminQuery::create()->findOneByEmail($answer)) {
|
||||
throw new \RuntimeException("An administrator with this email already exists.");
|
||||
}
|
||||
|
||||
return !empty($answer) ? $answer : uniqid('CHANGE_ME_');
|
||||
});
|
||||
|
||||
return $helper->ask($input, $output, $question);
|
||||
}
|
||||
}
|
||||
|
||||
241
core/lib/Thelia/Command/ExportCommand.php
Normal file
241
core/lib/Thelia/Command/ExportCommand.php
Normal file
@@ -0,0 +1,241 @@
|
||||
<?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 Thelia\Command;
|
||||
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Thelia\Core\Archiver\ArchiverInterface;
|
||||
use Thelia\Core\Archiver\ArchiverManager;
|
||||
use Thelia\Core\DependencyInjection\Compiler\RegisterArchiverPass;
|
||||
use Thelia\Core\DependencyInjection\Compiler\RegisterSerializerPass;
|
||||
use Thelia\Core\Serializer\SerializerInterface;
|
||||
use Thelia\Core\Serializer\SerializerManager;
|
||||
use Thelia\Model\ExportQuery;
|
||||
use Thelia\Model\LangQuery;
|
||||
|
||||
/**
|
||||
* Class ExportCommand
|
||||
* @author Jérôme Billiras <jbilliras@openstudio.fr>
|
||||
*/
|
||||
class ExportCommand extends ContainerAwareCommand
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('export')
|
||||
->setDescription('Export data')
|
||||
->setHelp('The <info>export</info> command run selected export')
|
||||
->addArgument(
|
||||
'ref',
|
||||
InputArgument::OPTIONAL,
|
||||
'Export reference.'
|
||||
)
|
||||
->addArgument(
|
||||
'serializer',
|
||||
InputArgument::OPTIONAL,
|
||||
'Serializer identifier.'
|
||||
)
|
||||
->addArgument(
|
||||
'archiver',
|
||||
InputArgument::OPTIONAL,
|
||||
'Archiver identifier.'
|
||||
)
|
||||
->addOption(
|
||||
'locale',
|
||||
null,
|
||||
InputOption::VALUE_REQUIRED,
|
||||
'Locale for export',
|
||||
'en_US'
|
||||
)
|
||||
->addOption(
|
||||
'list-export',
|
||||
null,
|
||||
InputOption::VALUE_NONE,
|
||||
'List available exports and exit.'
|
||||
)
|
||||
->addOption(
|
||||
'list-serializer',
|
||||
null,
|
||||
InputOption::VALUE_NONE,
|
||||
'List available serializers and exit.'
|
||||
)
|
||||
->addOption(
|
||||
'list-archiver',
|
||||
null,
|
||||
InputOption::VALUE_NONE,
|
||||
'List available archivers and exit.'
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
if ($input->getOption('list-export')) {
|
||||
$this->listExport($output);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($input->getOption('list-serializer')) {
|
||||
$this->listSerializer($output);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($input->getOption('list-archiver')) {
|
||||
$this->listArchiver($output);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$exportRef = $input->getArgument('ref');
|
||||
$serializer = $input->getArgument('serializer');
|
||||
if ($exportRef === null || $serializer === null) {
|
||||
throw new \RuntimeException(
|
||||
'Not enough arguments.' . PHP_EOL . 'If no options are provided, ref and serializer arguments are required.'
|
||||
);
|
||||
}
|
||||
|
||||
/** @var \Thelia\Handler\ExportHandler $exportHandler */
|
||||
$exportHandler = $this->getContainer()->get('thelia.export.handler');
|
||||
|
||||
$export = $exportHandler->getExportByRef($exportRef);
|
||||
if ($export === null) {
|
||||
throw new \RuntimeException(
|
||||
$exportRef . ' export doesn\'t exist.'
|
||||
);
|
||||
}
|
||||
|
||||
$serializerManager = $this->getContainer()->get(RegisterSerializerPass::MANAGER_SERVICE_ID);
|
||||
$serializer = $serializerManager->get($serializer);
|
||||
|
||||
$archiver = null;
|
||||
if ($input->getArgument('archiver')) {
|
||||
/** @var \Thelia\Core\Archiver\ArchiverManager $archiverManager */
|
||||
$archiverManager = $this->getContainer()->get(RegisterArchiverPass::MANAGER_SERVICE_ID);
|
||||
$archiver = $archiverManager->get($input->getArgument('archiver'));
|
||||
}
|
||||
|
||||
$exportEvent = $exportHandler->export(
|
||||
$export,
|
||||
$serializer,
|
||||
$archiver,
|
||||
(new LangQuery)->findOneByLocale($input->getOption('locale'))
|
||||
);
|
||||
|
||||
$formattedLine = $this->getHelper('formatter')->formatBlock(
|
||||
'Export finish',
|
||||
'fg=black;bg=green',
|
||||
true
|
||||
);
|
||||
$output->writeln($formattedLine);
|
||||
$output->writeln('<info>Export available at path:</info>');
|
||||
$output->writeln('<comment>' . $exportEvent->getFilePath() . '</comment>');
|
||||
}
|
||||
|
||||
/**
|
||||
* Output available exports
|
||||
*
|
||||
* @param \Symfony\Component\Console\Output\OutputInterface $output An output interface
|
||||
*/
|
||||
protected function listExport(OutputInterface $output)
|
||||
{
|
||||
$table = new Table($output);
|
||||
|
||||
foreach ((new ExportQuery)->find() as $export) {
|
||||
$table->addRow([
|
||||
$export->getRef(),
|
||||
$export->getTitle(),
|
||||
$export->getDescription()
|
||||
]);
|
||||
}
|
||||
|
||||
$table
|
||||
->setHeaders([
|
||||
'Reference',
|
||||
'Title',
|
||||
'Description'
|
||||
])
|
||||
->render()
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Output available serializers
|
||||
*
|
||||
* @param \Symfony\Component\Console\Output\OutputInterface $output An output interface
|
||||
*/
|
||||
protected function listSerializer(OutputInterface $output)
|
||||
{
|
||||
$table = new Table($output);
|
||||
|
||||
/** @var SerializerManager $serializerManager */
|
||||
$serializerManager = $this->getContainer()->get(RegisterSerializerPass::MANAGER_SERVICE_ID);
|
||||
|
||||
/** @var SerializerInterface $serializer */
|
||||
foreach ($serializerManager->getSerializers() as $serializer) {
|
||||
$table->addRow([
|
||||
$serializer->getId(),
|
||||
$serializer->getName(),
|
||||
$serializer->getExtension(),
|
||||
$serializer->getMimeType()
|
||||
]);
|
||||
}
|
||||
|
||||
$table
|
||||
->setHeaders([
|
||||
'Id',
|
||||
'Name',
|
||||
'Extension',
|
||||
'MIME type'
|
||||
])
|
||||
->render()
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Output available archivers
|
||||
*
|
||||
* @param \Symfony\Component\Console\Output\OutputInterface $output An output interface
|
||||
*/
|
||||
protected function listArchiver(OutputInterface $output)
|
||||
{
|
||||
$table = new Table($output);
|
||||
|
||||
/** @var ArchiverManager $archiverManager */
|
||||
$archiverManager = $this->getContainer()->get(RegisterArchiverPass::MANAGER_SERVICE_ID);
|
||||
|
||||
/** @var ArchiverInterface $archiver */
|
||||
foreach ($archiverManager->getArchivers(true) as $archiver) {
|
||||
$table->addRow([
|
||||
$archiver->getId(),
|
||||
$archiver->getName(),
|
||||
$archiver->getExtension(),
|
||||
$archiver->getMimeType()
|
||||
]);
|
||||
}
|
||||
|
||||
$table
|
||||
->setHeaders([
|
||||
'Id',
|
||||
'Name',
|
||||
'Extension',
|
||||
'MIME type'
|
||||
])
|
||||
->render()
|
||||
;
|
||||
}
|
||||
}
|
||||
@@ -15,9 +15,7 @@ namespace Thelia\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
use Thelia\Core\Security\Resource\AdminResources;
|
||||
|
||||
use Thelia\Model\Map\ResourceI18nTableMap;
|
||||
use Thelia\Model\Map\ResourceTableMap;
|
||||
|
||||
@@ -40,7 +38,6 @@ class GenerateResources extends ContainerAwareCommand
|
||||
null
|
||||
)
|
||||
;
|
||||
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
@@ -65,7 +62,7 @@ class GenerateResources extends ContainerAwareCommand
|
||||
}
|
||||
$compteur++;
|
||||
$output->writeln(
|
||||
"($compteur, '$value', NOW(), NOW())" . ($constant === key( array_slice( $constants, -1, 1, true ) ) ? ';' : ',')
|
||||
"($compteur, '$value', NOW(), NOW())" . ($constant === key(array_slice($constants, -1, 1, true)) ? ';' : ',')
|
||||
);
|
||||
}
|
||||
break;
|
||||
@@ -81,17 +78,17 @@ class GenerateResources extends ContainerAwareCommand
|
||||
|
||||
$compteur++;
|
||||
|
||||
$title = ucwords( str_replace('.', ' / ', str_replace('admin.', '', $value) ) );
|
||||
$title = ucwords(str_replace('.', ' / ', str_replace('admin.', '', $value)));
|
||||
|
||||
$output->writeln(
|
||||
"($compteur, 'en_US', '$title'),"
|
||||
);
|
||||
$output->writeln(
|
||||
"($compteur, 'fr_FR', '$title')" . ($constant === key( array_slice( $constants, -1, 1, true ) ) ? ';' : ',')
|
||||
"($compteur, 'fr_FR', '$title')" . ($constant === key(array_slice($constants, -1, 1, true)) ? ';' : ',')
|
||||
);
|
||||
}
|
||||
break;
|
||||
default :
|
||||
default:
|
||||
foreach ($constants as $constant => $value) {
|
||||
if ($constant == AdminResources::SUPERADMINISTRATOR) {
|
||||
continue;
|
||||
@@ -101,5 +98,4 @@ class GenerateResources extends ContainerAwareCommand
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
221
core/lib/Thelia/Command/GenerateSQLCommand.php
Normal file
221
core/lib/Thelia/Command/GenerateSQLCommand.php
Normal file
@@ -0,0 +1,221 @@
|
||||
<?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 Thelia\Command;
|
||||
|
||||
use Imagine\Exception\RuntimeException;
|
||||
use Propel\Runtime\Propel;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Thelia\Core\Translation\Translator;
|
||||
use Thelia\Model\CustomerQuery;
|
||||
use Thelia\Model\Map\ProductTableMap;
|
||||
use Thelia\Tools\URL;
|
||||
use Thelia\Tools\Version\Version;
|
||||
use TheliaSmarty\Template\SmartyParser;
|
||||
|
||||
/**
|
||||
* Class GenerateSQLCommand
|
||||
* @package Thelia\Command
|
||||
* @author Julien Chanséaume <jchanseaume@openstudio.fr>
|
||||
*/
|
||||
class GenerateSQLCommand extends ContainerAwareCommand
|
||||
{
|
||||
/** @var Translator $translator */
|
||||
protected $translator = null;
|
||||
|
||||
/** @var SmartyParser $parser */
|
||||
protected $parser = null;
|
||||
|
||||
/** @var \PDO */
|
||||
protected $con;
|
||||
|
||||
/** @var array */
|
||||
protected $locales;
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName("generate:sql")
|
||||
->setDescription("Generate SQL files (insert.sql, update*.sql)")
|
||||
->addOption(
|
||||
"locales",
|
||||
null,
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
"generate only for only specific locales (separated by a ,) : fr_FR,es_ES or es_ES"
|
||||
);
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->init($input);
|
||||
|
||||
// Main insert.sql file
|
||||
$content = file_get_contents(THELIA_SETUP_DIRECTORY . 'insert.sql.tpl');
|
||||
$version = Version::parse();
|
||||
$content = $this->parser->renderString($content, $version, false);
|
||||
|
||||
if (false === file_put_contents(THELIA_SETUP_DIRECTORY . 'insert.sql', $content)) {
|
||||
$output->writeln("Can't write file " . THELIA_SETUP_DIRECTORY . 'insert.sql');
|
||||
} else {
|
||||
$output->writeln("File " . THELIA_SETUP_DIRECTORY . 'insert.sql generated successfully.');
|
||||
}
|
||||
|
||||
// sql update files
|
||||
$finder = Finder::create()
|
||||
->name('*.tpl')
|
||||
->depth(0)
|
||||
->in(THELIA_SETUP_DIRECTORY . 'update' . DS . 'tpl');
|
||||
|
||||
/** @var \SplFileInfo $file */
|
||||
foreach ($finder as $file) {
|
||||
$content = file_get_contents($file->getRealPath());
|
||||
$content = $this->parser->renderString($content, [], false);
|
||||
|
||||
$destination = THELIA_SETUP_DIRECTORY . 'update' . DS . 'sql' . DS . $file->getBasename('.tpl');
|
||||
|
||||
if (false === file_put_contents($destination, $content)) {
|
||||
$output->writeln("Can't write file " . $destination);
|
||||
} else {
|
||||
$output->writeln("File " . $destination . ' generated successfully.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function init(InputInterface $input)
|
||||
{
|
||||
$this->initRequest();
|
||||
|
||||
$container = $this->getContainer();
|
||||
|
||||
$this->translator = $container->get('thelia.translator');
|
||||
$this->parser = $container->get('thelia.parser');
|
||||
|
||||
$this->con = Propel::getConnection(ProductTableMap::DATABASE_NAME);
|
||||
|
||||
$this->initLocales($input);
|
||||
|
||||
$this->initParser();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @return array
|
||||
*/
|
||||
protected function initLocales(InputInterface $input)
|
||||
{
|
||||
$this->locales = [];
|
||||
$availableLocales = [];
|
||||
|
||||
$finder = Finder::create()
|
||||
->name('*.php')
|
||||
->depth(0)
|
||||
->sortByName()
|
||||
->in(THELIA_SETUP_DIRECTORY . 'I18n');
|
||||
|
||||
// limit to only some locale(s)
|
||||
$localesToKeep = $input->getOption("locales");
|
||||
if (!empty($localesToKeep)) {
|
||||
$localesToKeep = explode(',', $localesToKeep);
|
||||
} else {
|
||||
$localesToKeep = null;
|
||||
}
|
||||
|
||||
/** @var \SplFileInfo $file */
|
||||
foreach ($finder as $file) {
|
||||
$locale = $file->getBasename('.php');
|
||||
$availableLocales[] = $locale;
|
||||
|
||||
if (empty($localesToKeep) || in_array($locale, $localesToKeep)) {
|
||||
$this->locales[] = $locale;
|
||||
$this->translator->addResource(
|
||||
'php',
|
||||
$file->getRealPath(),
|
||||
$locale,
|
||||
'install'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($this->locales)) {
|
||||
throw new \RuntimeException(
|
||||
sprintf(
|
||||
"You should at least generate sql for one locale. Available locales : %s",
|
||||
implode(', ', $availableLocales)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the smarty parser.
|
||||
*
|
||||
* The intl function is replaced, and locales are assigned.
|
||||
*
|
||||
* @throws \SmartyException
|
||||
*/
|
||||
protected function initParser()
|
||||
{
|
||||
$this->parser->unregisterPlugin('function', 'intl');
|
||||
$this->parser->registerPlugin('function', 'intl', [$this, 'translate']);
|
||||
$this->parser->assign("locales", $this->locales);
|
||||
}
|
||||
|
||||
/**
|
||||
* Smarty function that replace the classic `intl` function.
|
||||
*
|
||||
* The attributes of the function are:
|
||||
* - `l`: the key
|
||||
* - `locale`: the locale. eg.: fr_FR
|
||||
* - `in_string`: set to 1 not add simple quote around the string. (default = 0)
|
||||
* - `use_default`: set to 1 to use the `l` string as a fallback. (default = 0)
|
||||
*
|
||||
* @param $params
|
||||
* @param $smarty
|
||||
* @return string
|
||||
*/
|
||||
public function translate($params, $smarty)
|
||||
{
|
||||
$translation = '';
|
||||
|
||||
if (empty($params["l"])) {
|
||||
throw new RuntimeException('Translation Error. Key is empty.');
|
||||
} elseif (empty($params["locale"])) {
|
||||
throw new RuntimeException('Translation Error. Locale is empty.');
|
||||
} else {
|
||||
$inString = (0 !== intval($params["in_string"]));
|
||||
$useDefault = (0 !== intval($params["use_default"]));
|
||||
|
||||
$translation = $this->translator->trans(
|
||||
$params["l"],
|
||||
[],
|
||||
'install',
|
||||
$params["locale"],
|
||||
$useDefault
|
||||
);
|
||||
|
||||
if (empty($translation)) {
|
||||
$translation = ($inString) ? '' : "NULL";
|
||||
} else {
|
||||
$translation = $this->con->quote($translation);
|
||||
// remove quote
|
||||
if ($inString) {
|
||||
$translation = substr($translation, 1, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $translation;
|
||||
}
|
||||
}
|
||||
157
core/lib/Thelia/Command/HookCleanCommand.php
Normal file
157
core/lib/Thelia/Command/HookCleanCommand.php
Normal file
@@ -0,0 +1,157 @@
|
||||
<?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 Thelia\Command;
|
||||
|
||||
use Symfony\Component\Console\Helper\QuestionHelper;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Question\ConfirmationQuestion;
|
||||
use Thelia\Core\Event\Cache\CacheEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Model\IgnoredModuleHookQuery;
|
||||
use Thelia\Model\Module;
|
||||
use Thelia\Model\ModuleHookQuery;
|
||||
use Thelia\Model\ModuleQuery;
|
||||
|
||||
/**
|
||||
* Clean hook
|
||||
*
|
||||
* Class HookCleanCommand
|
||||
* @package Thelia\Command
|
||||
*
|
||||
* @author Julien Chanséaume <julien@thelia.net>
|
||||
*
|
||||
*/
|
||||
class HookCleanCommand extends ContainerAwareCommand
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName("hook:clean")
|
||||
->setDescription("Clean hooks. It will delete all hooks, then recreate it.")
|
||||
->addOption(
|
||||
"assume-yes",
|
||||
'y',
|
||||
InputOption::VALUE_NONE,
|
||||
'Assume to answer yes to all questions'
|
||||
)
|
||||
->addArgument(
|
||||
"module",
|
||||
InputArgument::OPTIONAL,
|
||||
"The module code to clean up"
|
||||
);
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
try {
|
||||
$module = $this->getModule($input);
|
||||
|
||||
if (!$this->askConfirmation($input, $output)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->deleteHooks($module);
|
||||
|
||||
$output->writeln("<info>Hooks have been successfully deleted</info>");
|
||||
|
||||
$this->clearCache($output);
|
||||
} catch (\Exception $ex) {
|
||||
$output->writeln(sprintf("<error>%s</error>", $ex->getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
private function getModule(InputInterface $input)
|
||||
{
|
||||
$module = null;
|
||||
$moduleCode = $input->getArgument("module");
|
||||
|
||||
if (!empty($moduleCode)) {
|
||||
if (null === $module = ModuleQuery::create()->findOneByCode($moduleCode)) {
|
||||
throw new \RuntimeException(sprintf("Module %s does not exist.", $moduleCode));
|
||||
}
|
||||
}
|
||||
|
||||
return $module;
|
||||
}
|
||||
|
||||
private function askConfirmation(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$assumeYes = $input->getOption("assume-yes");
|
||||
$moduleCode = $input->getArgument("module");
|
||||
|
||||
if (!$assumeYes) {
|
||||
/** @var QuestionHelper $helper */
|
||||
$helper = $this->getHelper('question');
|
||||
$questionText = "Would you like to delete all hooks ";
|
||||
$questionText .= (empty($moduleCode))
|
||||
? "of all modules"
|
||||
: "of module " . $moduleCode;
|
||||
$questionText .= " ? (yes, or no) ";
|
||||
|
||||
$question = new ConfirmationQuestion($questionText, false);
|
||||
|
||||
if (!$helper->ask($input, $output, $question)) {
|
||||
$output->writeln("<info>No hooks deleted</info>");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete module hooks
|
||||
*
|
||||
* @param Module|null $module if specified it will only delete hooks related to this module.
|
||||
* @throws \Exception
|
||||
* @throws \Propel\Runtime\Exception\PropelException
|
||||
*/
|
||||
protected function deleteHooks($module)
|
||||
{
|
||||
$query = ModuleHookQuery::create();
|
||||
if (null !== $module) {
|
||||
$query
|
||||
->filterByModule($module)
|
||||
->delete();
|
||||
} else {
|
||||
$query->deleteAll();
|
||||
}
|
||||
|
||||
$query = IgnoredModuleHookQuery::create();
|
||||
if (null !== $module) {
|
||||
$query
|
||||
->filterByModule($module)
|
||||
->delete();
|
||||
} else {
|
||||
$query->deleteAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OutputInterface $output
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function clearCache(OutputInterface $output)
|
||||
{
|
||||
try {
|
||||
$cacheDir = $this->getContainer()->getParameter("kernel.cache_dir");
|
||||
$cacheEvent = new CacheEvent($cacheDir);
|
||||
$this->getDispatcher()->dispatch(TheliaEvents::CACHE_CLEAR, $cacheEvent);
|
||||
} catch (\Exception $ex) {
|
||||
throw new \Exception(sprintf("Error during clearing of cache : %s", $ex->getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
141
core/lib/Thelia/Command/ImportCommand.php
Normal file
141
core/lib/Thelia/Command/ImportCommand.php
Normal file
@@ -0,0 +1,141 @@
|
||||
<?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 Thelia\Command;
|
||||
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\HttpFoundation\File\File;
|
||||
use Thelia\Model\ImportQuery;
|
||||
use Thelia\Model\LangQuery;
|
||||
|
||||
/**
|
||||
* Class ImportCommand
|
||||
* @author Jérôme Billiras <jbilliras@openstudio.fr>
|
||||
*/
|
||||
class ImportCommand extends ContainerAwareCommand
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('import')
|
||||
->setDescription('Import data')
|
||||
->setHelp('The <info>import</info> command run selected import')
|
||||
->addArgument(
|
||||
'ref',
|
||||
InputArgument::OPTIONAL,
|
||||
'Import reference.'
|
||||
)
|
||||
->addArgument(
|
||||
'filePath',
|
||||
InputArgument::OPTIONAL,
|
||||
'File path to import'
|
||||
)
|
||||
->addOption(
|
||||
'locale',
|
||||
null,
|
||||
InputOption::VALUE_REQUIRED,
|
||||
'Locale for export',
|
||||
'en_US'
|
||||
)
|
||||
->addOption(
|
||||
'list',
|
||||
null,
|
||||
InputOption::VALUE_NONE,
|
||||
'List available imports and exit.'
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
if ($input->getOption('list')) {
|
||||
$this->listImport($output);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$importRef = $input->getArgument('ref');
|
||||
$path = $input->getArgument('filePath');
|
||||
if ($importRef === null || $path === null) {
|
||||
throw new \RuntimeException(
|
||||
'Not enough arguments.' . PHP_EOL . 'If no options are provided, ref and filePath arguments are required.'
|
||||
);
|
||||
}
|
||||
|
||||
/** @var \Thelia\Handler\ImportHandler $importHandler */
|
||||
$importHandler = $this->getContainer()->get('thelia.import.handler');
|
||||
|
||||
$import = $importHandler->getImportByRef($importRef);
|
||||
if ($import === null) {
|
||||
throw new \RuntimeException(
|
||||
$importRef . ' import doesn\'t exist.'
|
||||
);
|
||||
}
|
||||
|
||||
$importEvent = $importHandler->import(
|
||||
$import,
|
||||
new File($input->getArgument('filePath')),
|
||||
(new LangQuery)->findOneByLocale($input->getOption('locale'))
|
||||
);
|
||||
|
||||
$formattedLine = $this->getHelper('formatter')->formatBlock(
|
||||
'Successfully import ' . $importEvent->getImport()->getImportedRows() . ' row(s)',
|
||||
'fg=black;bg=green',
|
||||
true
|
||||
);
|
||||
$output->writeln($formattedLine);
|
||||
|
||||
if (count($importEvent->getErrors()) > 0) {
|
||||
$formattedLine = $this->getHelper('formatter')->formatBlock(
|
||||
'With error',
|
||||
'fg=black;bg=yellow',
|
||||
true
|
||||
);
|
||||
$output->writeln($formattedLine);
|
||||
|
||||
foreach ($importEvent->getErrors() as $error) {
|
||||
$output->writeln('<comment>' . $error . '</comment>');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Output available imports
|
||||
*
|
||||
* @param \Symfony\Component\Console\Output\OutputInterface $output An output interface
|
||||
*/
|
||||
protected function listImport(OutputInterface $output)
|
||||
{
|
||||
$table = new Table($output);
|
||||
|
||||
foreach ((new ImportQuery)->find() as $import) {
|
||||
$table->addRow([
|
||||
$import->getRef(),
|
||||
$import->getTitle(),
|
||||
$import->getDescription()
|
||||
]);
|
||||
}
|
||||
|
||||
$table
|
||||
->setHeaders([
|
||||
'Reference',
|
||||
'Title',
|
||||
'Description'
|
||||
])
|
||||
->render()
|
||||
;
|
||||
}
|
||||
}
|
||||
@@ -12,20 +12,23 @@
|
||||
|
||||
namespace Thelia\Command;
|
||||
|
||||
use Symfony\Component\Console\Helper\QuestionHelper;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Question\Question;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
|
||||
use Thelia\Core\Translation\Translator;
|
||||
use Thelia\Install\CheckPermission;
|
||||
use Thelia\Install\Database;
|
||||
use Thelia\Tools\TokenProvider;
|
||||
|
||||
/**
|
||||
* try to install a new instance of Thelia
|
||||
*
|
||||
* Class Install
|
||||
* @package Thelia\Command
|
||||
* @author Manuel Raynaud <mraynaud@openstudio.fr>
|
||||
* @author Manuel Raynaud <manu@raynaud.io>
|
||||
*/
|
||||
class Install extends ContainerAwareCommand
|
||||
{
|
||||
@@ -42,7 +45,8 @@ class Install extends ContainerAwareCommand
|
||||
"db_host",
|
||||
null,
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
"host for your database"
|
||||
"host for your database",
|
||||
"localhost"
|
||||
)
|
||||
->addOption(
|
||||
"db_username",
|
||||
@@ -62,8 +66,14 @@ class Install extends ContainerAwareCommand
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
"database name"
|
||||
)
|
||||
->addOption(
|
||||
"db_port",
|
||||
null,
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
"database port",
|
||||
"3306"
|
||||
)
|
||||
;
|
||||
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
@@ -84,11 +94,12 @@ class Install extends ContainerAwareCommand
|
||||
"host" => $input->getOption("db_host"),
|
||||
"dbName" => $input->getOption("db_name"),
|
||||
"username" => $input->getOption("db_username"),
|
||||
"password" => $input->getOption("db_password")
|
||||
"password" => $input->getOption("db_password"),
|
||||
"port" => $input->getOption("db_port")
|
||||
);
|
||||
|
||||
while (false === $connection = $this->tryConnection($connectionInfo, $output)) {
|
||||
$connectionInfo = $this->getConnectionInfo($input, $output);
|
||||
$connectionInfo = $this->getConnectionInfo($input, $output);
|
||||
}
|
||||
|
||||
$database = new Database($connection);
|
||||
@@ -101,6 +112,7 @@ class Install extends ContainerAwareCommand
|
||||
""
|
||||
));
|
||||
$database->insertSql($connectionInfo["dbName"]);
|
||||
$this->manageSecret($database);
|
||||
|
||||
$output->writeln(array(
|
||||
"",
|
||||
@@ -118,6 +130,13 @@ class Install extends ContainerAwareCommand
|
||||
));
|
||||
}
|
||||
|
||||
protected function manageSecret(Database $database)
|
||||
{
|
||||
$secret = TokenProvider::generateToken();
|
||||
$sql = "UPDATE `config` SET `value`=? WHERE `name`='form.secret'";
|
||||
$database->execute($sql, [$secret]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if needed directories have write permission
|
||||
*
|
||||
@@ -129,26 +148,32 @@ class Install extends ContainerAwareCommand
|
||||
"Checking some permissions"
|
||||
));
|
||||
|
||||
$permissions = new CheckPermission(false, $this->getContainer()->get('thelia.translator'));
|
||||
/** @var Translator $translator */
|
||||
$translator = $this->getContainer()->get('thelia.translator');
|
||||
|
||||
$permissions = new CheckPermission(false, $translator);
|
||||
$isValid = $permissions->exec();
|
||||
|
||||
foreach ($permissions->getValidationMessages() as $item => $data) {
|
||||
if ($data['status']) {
|
||||
$output->writeln(array(
|
||||
sprintf("<info>%s ...</info> %s",
|
||||
$data['text'],
|
||||
"<info>Ok</info>")
|
||||
$output->writeln(
|
||||
array(
|
||||
sprintf(
|
||||
"<info>%s ...</info> %s",
|
||||
$data['text'],
|
||||
"<info>Ok</info>"
|
||||
)
|
||||
)
|
||||
);
|
||||
} else {
|
||||
$output->writeln(array(
|
||||
sprintf("<error>%s </error>%s",
|
||||
sprintf(
|
||||
"<error>%s </error>%s",
|
||||
$data['text'],
|
||||
sprintf("<error>%s</error>", $data["hint"])
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (false === $isValid) {
|
||||
@@ -177,14 +202,13 @@ class Install extends ContainerAwareCommand
|
||||
$configContent = str_replace("%PASSWORD%", $connectionInfo["password"], $configContent);
|
||||
$configContent = str_replace(
|
||||
"%DSN%",
|
||||
sprintf("mysql:host=%s;dbname=%s", $connectionInfo["host"], $connectionInfo["dbName"]),
|
||||
sprintf("mysql:host=%s;dbname=%s;port=%s", $connectionInfo["host"], $connectionInfo["dbName"], $connectionInfo['port']),
|
||||
$configContent
|
||||
);
|
||||
|
||||
file_put_contents($configFile, $configContent);
|
||||
|
||||
$fs->remove($this->getContainer()->getParameter("kernel.cache_dir"));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -196,16 +220,15 @@ class Install extends ContainerAwareCommand
|
||||
*/
|
||||
protected function tryConnection($connectionInfo, OutputInterface $output)
|
||||
{
|
||||
|
||||
if (is_null($connectionInfo["dbName"])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$dsn = "mysql:host=%s";
|
||||
$dsn = "mysql:host=%s;port=%s";
|
||||
|
||||
try {
|
||||
$connection = new \PDO(
|
||||
sprintf($dsn, $connectionInfo["host"]),
|
||||
sprintf($dsn, $connectionInfo["host"], $connectionInfo["port"]),
|
||||
$connectionInfo["username"],
|
||||
$connectionInfo["password"]
|
||||
);
|
||||
@@ -230,62 +253,93 @@ class Install extends ContainerAwareCommand
|
||||
*/
|
||||
protected function getConnectionInfo(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$dialog = $this->getHelperSet()->get('dialog');
|
||||
/** @var QuestionHelper $helper */
|
||||
$helper = $this->getHelper('question');
|
||||
|
||||
$connectionInfo = array();
|
||||
|
||||
$connectionInfo["host"] = $dialog->askAndValidate(
|
||||
$connectionInfo['host'] = $this->enterData(
|
||||
$helper,
|
||||
$input,
|
||||
$output,
|
||||
$this->decorateInfo("Database host : "),
|
||||
function ($answer) {
|
||||
$answer = trim($answer);
|
||||
if (is_null($answer)) {
|
||||
throw new \RuntimeException("You must specify a database host");
|
||||
}
|
||||
|
||||
return $answer;
|
||||
}
|
||||
"Database host [default: localhost] : ",
|
||||
"You must specify a database host",
|
||||
false,
|
||||
"localhost"
|
||||
);
|
||||
|
||||
$connectionInfo["dbName"] = $dialog->askAndValidate(
|
||||
$connectionInfo['port'] = $this->enterData(
|
||||
$helper,
|
||||
$input,
|
||||
$output,
|
||||
$this->decorateInfo("Database name (if database does not exist, Thelia will try to create it) : "),
|
||||
function ($answer) {
|
||||
$answer = trim($answer);
|
||||
|
||||
if (is_null($answer)) {
|
||||
throw new \RuntimeException("You must specify a database name");
|
||||
}
|
||||
|
||||
return $answer;
|
||||
}
|
||||
"Database port [default: 3306] : ",
|
||||
"You must specify a database port",
|
||||
false,
|
||||
"3306"
|
||||
);
|
||||
|
||||
$connectionInfo["username"] = $dialog->askAndValidate(
|
||||
$connectionInfo['dbName'] = $this->enterData(
|
||||
$helper,
|
||||
$input,
|
||||
$output,
|
||||
$this->decorateInfo("Database username : "),
|
||||
function ($answer) {
|
||||
$answer = trim($answer);
|
||||
|
||||
if (is_null($answer)) {
|
||||
throw new \RuntimeException("You must specify a database username");
|
||||
}
|
||||
|
||||
return $answer;
|
||||
}
|
||||
"Database name (if database does not exist, Thelia will try to create it) : ",
|
||||
"You must specify a database name"
|
||||
);
|
||||
|
||||
$connectionInfo["password"] = $dialog->askHiddenResponse(
|
||||
$connectionInfo['username'] = $this->enterData(
|
||||
$helper,
|
||||
$input,
|
||||
$output,
|
||||
$this->decorateInfo("Database password : ")
|
||||
"Database username : ",
|
||||
"You must specify a database username"
|
||||
);
|
||||
|
||||
$connectionInfo['password'] = $this->enterData(
|
||||
$helper,
|
||||
$input,
|
||||
$output,
|
||||
"Database password : ",
|
||||
"You must specify a database username",
|
||||
true,
|
||||
null,
|
||||
true
|
||||
);
|
||||
|
||||
return $connectionInfo;
|
||||
}
|
||||
|
||||
protected function enterData(
|
||||
QuestionHelper $helper,
|
||||
InputInterface $input,
|
||||
OutputInterface $output,
|
||||
$label,
|
||||
$errorMessage,
|
||||
$hidden = false,
|
||||
$defaultValue = null,
|
||||
$beEmpty = false
|
||||
) {
|
||||
$question = new Question($label, $defaultValue);
|
||||
|
||||
if ($hidden) {
|
||||
$question->setHidden(true);
|
||||
$question->setHiddenFallback(false);
|
||||
}
|
||||
|
||||
$question->setValidator(function ($value) use (&$errorMessage, &$beEmpty) {
|
||||
if (trim($value) == '') {
|
||||
if (is_null($value) && !$beEmpty) {
|
||||
throw new \Exception($errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
});
|
||||
|
||||
return $helper->ask($input, $output, $question);
|
||||
}
|
||||
|
||||
protected function decorateInfo($text)
|
||||
{
|
||||
return sprintf("<info>%s</info>", $text);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,8 +15,11 @@ namespace Thelia\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Thelia\Core\Event\Module\ModuleToggleActivationEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Model\ModuleQuery;
|
||||
use Thelia\Module\BaseModule;
|
||||
|
||||
/**
|
||||
* activates a module
|
||||
@@ -33,12 +36,17 @@ class ModuleActivateCommand extends BaseModuleGenerate
|
||||
$this
|
||||
->setName("module:activate")
|
||||
->setDescription("Activates a module")
|
||||
->addOption(
|
||||
"with-dependencies",
|
||||
null,
|
||||
InputOption::VALUE_NONE,
|
||||
'activate module recursively'
|
||||
)
|
||||
->addArgument(
|
||||
"module" ,
|
||||
"module",
|
||||
InputArgument::REQUIRED,
|
||||
"module to activate"
|
||||
)
|
||||
;
|
||||
);
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
@@ -51,12 +59,26 @@ class ModuleActivateCommand extends BaseModuleGenerate
|
||||
throw new \RuntimeException(sprintf("module %s not found", $moduleCode));
|
||||
}
|
||||
|
||||
try {
|
||||
$moduleInstance = $module->createInstance();
|
||||
if ($module->getActivate() == BaseModule::IS_ACTIVATED) {
|
||||
throw new \RuntimeException(sprintf("module %s is already actived", $moduleCode));
|
||||
}
|
||||
|
||||
$moduleInstance->activate();
|
||||
|
||||
try {
|
||||
$event = new ModuleToggleActivationEvent($module->getId());
|
||||
if ($input->getOption("with-dependencies")) {
|
||||
$event->setRecursive(true);
|
||||
}
|
||||
|
||||
$this->getDispatcher()->dispatch(TheliaEvents::MODULE_TOGGLE_ACTIVATION, $event);
|
||||
} catch (\Exception $e) {
|
||||
throw new \RuntimeException(sprintf("Activation fail with Exception : [%d] %s", $e->getCode(), $e->getMessage()));
|
||||
throw new \RuntimeException(
|
||||
sprintf(
|
||||
"Activation fail with Exception : [%d] %s",
|
||||
$e->getCode(),
|
||||
$e->getMessage()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
//impossible to change output class in CommandTester...
|
||||
|
||||
@@ -12,11 +12,17 @@
|
||||
|
||||
namespace Thelia\Command;
|
||||
|
||||
use Symfony\Component\Console\Helper\QuestionHelper;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Question\ConfirmationQuestion;
|
||||
use Thelia\Action\Module;
|
||||
use Thelia\Core\Event\Module\ModuleToggleActivationEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Model\ModuleQuery;
|
||||
use Thelia\Module\BaseModule;
|
||||
|
||||
/**
|
||||
* Deactivates a module
|
||||
@@ -33,11 +39,23 @@ class ModuleDeactivateCommand extends BaseModuleGenerate
|
||||
$this
|
||||
->setName("module:deactivate")
|
||||
->setDescription("Deactivate a module")
|
||||
->addOption(
|
||||
"with-dependencies",
|
||||
null,
|
||||
InputOption::VALUE_NONE,
|
||||
'activate module recursively'
|
||||
)
|
||||
->addArgument(
|
||||
"module" ,
|
||||
"module",
|
||||
InputArgument::REQUIRED,
|
||||
"module to deactivate"
|
||||
)
|
||||
->addOption(
|
||||
"assume-yes",
|
||||
'y',
|
||||
InputOption::VALUE_NONE,
|
||||
'Assume to deactivate a mandatory module'
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
@@ -51,10 +69,26 @@ class ModuleDeactivateCommand extends BaseModuleGenerate
|
||||
throw new \RuntimeException(sprintf("module %s not found", $moduleCode));
|
||||
}
|
||||
|
||||
try {
|
||||
$moduleInstance = $module->createInstance();
|
||||
if ($module->getActivate() == BaseModule::IS_NOT_ACTIVATED) {
|
||||
throw new \RuntimeException(sprintf("module %s is already deactivated", $moduleCode));
|
||||
}
|
||||
|
||||
$moduleInstance->deActivate();
|
||||
|
||||
try {
|
||||
$event = new ModuleToggleActivationEvent($module->getId());
|
||||
|
||||
$module = ModuleQuery::create()->findPk($module->getId());
|
||||
if ($module->getMandatory() == BaseModule::IS_MANDATORY) {
|
||||
if (!$this->askConfirmation($input, $output)) {
|
||||
return;
|
||||
}
|
||||
$event->setAssumeDeactivate(true);
|
||||
}
|
||||
|
||||
if ($input->getOption("with-dependencies")) {
|
||||
$event->setRecursive(true);
|
||||
}
|
||||
$this->getDispatcher()->dispatch(TheliaEvents::MODULE_TOGGLE_ACTIVATION, $event);
|
||||
} catch (\Exception $e) {
|
||||
throw new \RuntimeException(sprintf("Deactivation fail with Exception : [%d] %s", $e->getCode(), $e->getMessage()));
|
||||
}
|
||||
@@ -68,4 +102,33 @@ class ModuleDeactivateCommand extends BaseModuleGenerate
|
||||
), "bg=green;fg=black");
|
||||
}
|
||||
}
|
||||
|
||||
private function askConfirmation(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$assumeYes = $input->getOption("assume-yes");
|
||||
$moduleCode = $input->getArgument("module");
|
||||
|
||||
if (!$assumeYes) {
|
||||
/** @var QuestionHelper $helper */
|
||||
$helper = $this->getHelper('question');
|
||||
$questionText = "Module ";
|
||||
$questionText .= (empty($moduleCode))
|
||||
? ""
|
||||
: $moduleCode;
|
||||
$questionText .= " is mandatory.\n";
|
||||
$questionText .= "Would you like to deactivate the module ";
|
||||
$questionText .= (empty($moduleCode))
|
||||
? ""
|
||||
: $moduleCode;
|
||||
$questionText .= " ? (yes, or no) ";
|
||||
|
||||
$question = new ConfirmationQuestion($questionText, false);
|
||||
|
||||
if (!$helper->ask($input, $output, $question)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Thelia\Command;
|
||||
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
|
||||
@@ -22,7 +23,7 @@ use Symfony\Component\Filesystem\Filesystem;
|
||||
*
|
||||
* Class ModuleGenerateCommand
|
||||
* @package Thelia\Command
|
||||
* @author Manuel Raynaud <mraynaud@openstudio.fr>
|
||||
* @author Manuel Raynaud <manu@raynaud.io>
|
||||
*/
|
||||
class ModuleGenerateCommand extends BaseModuleGenerate
|
||||
{
|
||||
@@ -32,23 +33,38 @@ class ModuleGenerateCommand extends BaseModuleGenerate
|
||||
->setName("module:generate")
|
||||
->setDescription("generate all needed files for creating a new Module")
|
||||
->addArgument(
|
||||
"name" ,
|
||||
"name",
|
||||
InputArgument::REQUIRED,
|
||||
"name wanted for your Module"
|
||||
)
|
||||
->addOption(
|
||||
'force',
|
||||
null,
|
||||
InputOption::VALUE_NONE,
|
||||
'If defined, it will update the module with missing directories and files (no overrides).'
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->module = $this->formatModuleName($input->getArgument("name"));
|
||||
$this->moduleDirectory = THELIA_MODULE_DIR . DIRECTORY_SEPARATOR . $this->module;
|
||||
$this->verifyExistingModule();
|
||||
$this->moduleDirectory = THELIA_MODULE_DIR . $this->module;
|
||||
|
||||
$this->validModuleName($this->module);
|
||||
|
||||
try {
|
||||
$this->verifyExistingModule();
|
||||
} catch (\RuntimeException $ex) {
|
||||
if (false === $input->getOption('force')) {
|
||||
throw $ex;
|
||||
}
|
||||
}
|
||||
|
||||
$this->createDirectories();
|
||||
$this->createFiles();
|
||||
if (method_exists($this, "renderBlock")) {
|
||||
//impossible to change output class in CommandTester...
|
||||
if (method_exists($output, "renderBlock")) {
|
||||
// impossible to change output class in CommandTester...
|
||||
$output->renderBlock(array(
|
||||
'',
|
||||
sprintf("module %s create with success", $this->module),
|
||||
@@ -56,19 +72,38 @@ class ModuleGenerateCommand extends BaseModuleGenerate
|
||||
''
|
||||
), "bg=green;fg=black");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function createDirectories()
|
||||
{
|
||||
$fs = new Filesystem();
|
||||
|
||||
$fs->mkdir($this->moduleDirectory);
|
||||
|
||||
foreach ($this->neededDirectories as $directory) {
|
||||
$fs->mkdir($this->moduleDirectory . DIRECTORY_SEPARATOR . $directory);
|
||||
if (!$fs->exists($this->moduleDirectory)) {
|
||||
$fs->mkdir($this->moduleDirectory);
|
||||
}
|
||||
|
||||
foreach ($this->neededDirectories as $directory) {
|
||||
if (!$fs->exists($this->moduleDirectory . DIRECTORY_SEPARATOR . $directory)) {
|
||||
$fs->mkdir($this->moduleDirectory . DIRECTORY_SEPARATOR . $directory);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function copyConfigFile($filename, $skeletonDir, Filesystem $fs)
|
||||
{
|
||||
$filename = $this->moduleDirectory . DIRECTORY_SEPARATOR . "Config" . DIRECTORY_SEPARATOR . $filename;
|
||||
if (!$fs->exists($filename)) {
|
||||
$configContent = file_get_contents($skeletonDir . "config.xml");
|
||||
|
||||
$configContent = str_replace("%%CLASSNAME%%", $this->module, $configContent);
|
||||
$configContent = str_replace("%%NAMESPACE%%", $this->module, $configContent);
|
||||
$configContent = str_replace("%%NAMESPACE_LOWER%%", strtolower($this->module), $configContent);
|
||||
|
||||
file_put_contents(
|
||||
$filename,
|
||||
$configContent
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function createFiles()
|
||||
@@ -76,56 +111,116 @@ class ModuleGenerateCommand extends BaseModuleGenerate
|
||||
$fs = new Filesystem();
|
||||
|
||||
try {
|
||||
$skeletonDir = str_replace("/", DIRECTORY_SEPARATOR, THELIA_ROOT . "/core/lib/Thelia/Command/Skeleton/Module/");
|
||||
$skeletonDir = str_replace("/", DIRECTORY_SEPARATOR, __DIR__ . "/Skeleton/Module/");
|
||||
|
||||
// config.xml file
|
||||
$fs->copy($skeletonDir . "config.xml", $this->moduleDirectory . DIRECTORY_SEPARATOR . "Config" . DIRECTORY_SEPARATOR . "config.xml");
|
||||
$this->copyConfigFile("config.xml", $skeletonDir, $fs);
|
||||
$this->copyConfigFile("config_prod.xml", $skeletonDir, $fs);
|
||||
$this->copyConfigFile("config_dev.xml", $skeletonDir, $fs);
|
||||
$this->copyConfigFile("config_test.xml", $skeletonDir, $fs);
|
||||
|
||||
$moduleContent = file_get_contents($skeletonDir . "module.xml");
|
||||
// Readme.md file
|
||||
$filename = $this->moduleDirectory . DIRECTORY_SEPARATOR . "Readme.md";
|
||||
if (!$fs->exists($filename)) {
|
||||
$readmeContent = file_get_contents($skeletonDir . "Readme.md");
|
||||
|
||||
$moduleContent = str_replace("%%CLASSNAME%%", $this->module, $moduleContent);
|
||||
$moduleContent = str_replace("%%NAMESPACE%%", $this->module, $moduleContent);
|
||||
// generate title for readme
|
||||
preg_match_all('!([A-Z][A-Z0-9]*(?=$|[A-Z][a-z0-9])|[A-Za-z][a-z0-9]+)!', $this->module, $readmeTitle);
|
||||
$composerFinalName = strtolower(implode("-", $readmeTitle[0]));
|
||||
|
||||
file_put_contents($this->moduleDirectory . DIRECTORY_SEPARATOR . "Config". DIRECTORY_SEPARATOR . "module.xml", $moduleContent);
|
||||
$readmeContent = str_replace("%%MODULENAME%%", $this->module, $readmeContent);
|
||||
$readmeContent = str_replace("%%MODULENAMETITLE%%", implode(" ", $readmeTitle[0]), $readmeContent);
|
||||
$readmeContent = str_replace("%%COMPOSERNAME%%", $composerFinalName, $readmeContent);
|
||||
|
||||
file_put_contents($filename, $readmeContent);
|
||||
}
|
||||
|
||||
// composer.json file
|
||||
$filename = $this->moduleDirectory . DIRECTORY_SEPARATOR . "composer.json";
|
||||
if (!$fs->exists($filename)) {
|
||||
$composerContent = file_get_contents($skeletonDir . "composer.json");
|
||||
|
||||
// generate composer module name
|
||||
preg_match_all('!([A-Z][A-Z0-9]*(?=$|[A-Z][a-z0-9])|[A-Za-z][a-z0-9]+)!', $this->module, $composerName);
|
||||
|
||||
$composerContent = str_replace("%%MODULENAME%%", $this->module, $composerContent);
|
||||
$composerContent = str_replace("%%COMPOSERNAME%%", strtolower(implode("-", $composerName[0])), $composerContent);
|
||||
|
||||
file_put_contents($filename, $composerContent);
|
||||
}
|
||||
|
||||
// module.xml file
|
||||
$filename = $this->moduleDirectory . DIRECTORY_SEPARATOR . "Config". DIRECTORY_SEPARATOR . "module.xml";
|
||||
if (!$fs->exists($filename)) {
|
||||
$moduleContent = file_get_contents($skeletonDir . "module.xml");
|
||||
|
||||
$moduleContent = str_replace("%%CLASSNAME%%", $this->module, $moduleContent);
|
||||
$moduleContent = str_replace("%%NAMESPACE%%", $this->module, $moduleContent);
|
||||
|
||||
file_put_contents($filename, $moduleContent);
|
||||
}
|
||||
|
||||
// PHP Class template
|
||||
$classContent = file_get_contents($skeletonDir . "Class.php.template");
|
||||
$filename = $this->moduleDirectory . DIRECTORY_SEPARATOR . $this->module . ".php";
|
||||
if (!$fs->exists($filename)) {
|
||||
$classContent = file_get_contents($skeletonDir . "Class.php.template");
|
||||
|
||||
$classContent = str_replace("%%CLASSNAME%%", $this->module, $classContent);
|
||||
$classContent = str_replace("%%NAMESPACE%%", $this->module, $classContent);
|
||||
$classContent = str_replace("%%CLASSNAME%%", $this->module, $classContent);
|
||||
$classContent = str_replace("%%NAMESPACE%%", $this->module, $classContent);
|
||||
$classContent = str_replace("%%DOMAINNAME%%", strtolower($this->module), $classContent);
|
||||
|
||||
file_put_contents($this->moduleDirectory . DIRECTORY_SEPARATOR . $this->module.".php", $classContent);
|
||||
file_put_contents($filename, $classContent);
|
||||
}
|
||||
|
||||
// schema.xml file
|
||||
$schemaContent = file_get_contents($skeletonDir . "schema.xml");
|
||||
$filename = $this->moduleDirectory . DIRECTORY_SEPARATOR . "Config" . DIRECTORY_SEPARATOR . "schema.xml";
|
||||
if (!$fs->exists($filename)) {
|
||||
$schemaContent = file_get_contents($skeletonDir . "schema.xml");
|
||||
|
||||
$schemaContent = str_replace("%%NAMESPACE%%", $this->module, $schemaContent);
|
||||
$schemaContent = str_replace("%%NAMESPACE%%", $this->module, $schemaContent);
|
||||
$schemaContent = str_replace(
|
||||
'%%XSD_LOCATION%%',
|
||||
$fs->makePathRelative(
|
||||
THELIA_VENDOR . 'propel/propel/resources/xsd/',
|
||||
$this->moduleDirectory
|
||||
) . 'database.xsd',
|
||||
$schemaContent
|
||||
);
|
||||
|
||||
file_put_contents($this->moduleDirectory . DIRECTORY_SEPARATOR . "Config". DIRECTORY_SEPARATOR . "schema.xml", $schemaContent);
|
||||
file_put_contents($filename, $schemaContent);
|
||||
}
|
||||
|
||||
// routing.xml file
|
||||
$routingContent = file_get_contents($skeletonDir . "routing.xml");
|
||||
$filename = $this->moduleDirectory . DIRECTORY_SEPARATOR . "Config" . DIRECTORY_SEPARATOR . "routing.xml";
|
||||
if (!$fs->exists($filename)) {
|
||||
$routingContent = file_get_contents($skeletonDir . "routing.xml");
|
||||
|
||||
$routingContent = str_replace("%%NAMESPACE%%", $this->module, $routingContent);
|
||||
$routingContent = str_replace("%%CLASSNAME_LOWER%%", strtolower($this->module), $routingContent);
|
||||
$routingContent = str_replace("%%NAMESPACE%%", $this->module, $routingContent);
|
||||
$routingContent = str_replace("%%CLASSNAME_LOWER%%", strtolower($this->module), $routingContent);
|
||||
|
||||
file_put_contents($this->moduleDirectory . DIRECTORY_SEPARATOR . "Config". DIRECTORY_SEPARATOR . "routing.xml", $routingContent);
|
||||
file_put_contents($filename, $routingContent);
|
||||
}
|
||||
|
||||
// I18n sample files
|
||||
$fs->copy(
|
||||
$skeletonDir . DIRECTORY_SEPARATOR . "I18n" . DIRECTORY_SEPARATOR . "fr_FR.php",
|
||||
$this->moduleDirectory . DIRECTORY_SEPARATOR . "I18n" . DIRECTORY_SEPARATOR . "fr_FR.php"
|
||||
);
|
||||
$filename = $this->moduleDirectory . DIRECTORY_SEPARATOR . "I18n" . DIRECTORY_SEPARATOR . "fr_FR.php";
|
||||
if (!$fs->exists($filename)) {
|
||||
$fs->copy(
|
||||
$skeletonDir . DIRECTORY_SEPARATOR . "I18n" . DIRECTORY_SEPARATOR . "fr_FR.php",
|
||||
$filename
|
||||
);
|
||||
}
|
||||
|
||||
$fs->copy(
|
||||
$skeletonDir . DIRECTORY_SEPARATOR . "I18n" . DIRECTORY_SEPARATOR . "en_US.php",
|
||||
$this->moduleDirectory . DIRECTORY_SEPARATOR . "I18n" . DIRECTORY_SEPARATOR . "en_US.php"
|
||||
);
|
||||
$filename = $this->moduleDirectory . DIRECTORY_SEPARATOR . "I18n" . DIRECTORY_SEPARATOR . "en_US.php";
|
||||
if (!$fs->exists($filename)) {
|
||||
$fs->copy(
|
||||
$skeletonDir . DIRECTORY_SEPARATOR . "I18n" . DIRECTORY_SEPARATOR . "en_US.php",
|
||||
$this->moduleDirectory . DIRECTORY_SEPARATOR . "I18n" . DIRECTORY_SEPARATOR . "en_US.php"
|
||||
);
|
||||
}
|
||||
} catch (\Exception $ex) {
|
||||
$fs->remove($this->moduleDirectory);
|
||||
|
||||
throw $ex;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
namespace Thelia\Command;
|
||||
|
||||
use Propel\Generator\Command\ModelBuildCommand;
|
||||
use Symfony\Component\Console\Helper\FormatterHelper;
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
@@ -25,7 +26,7 @@ use Symfony\Component\Filesystem\Filesystem;
|
||||
*
|
||||
* Class ModuleGenerateModelCommand
|
||||
* @package Thelia\Command
|
||||
* @author Manuel Raynaud <mraynaud@openstudio.fr>
|
||||
* @author Manuel Raynaud <manu@raynaud.io>
|
||||
*/
|
||||
class ModuleGenerateModelCommand extends BaseModuleGenerate
|
||||
{
|
||||
@@ -46,13 +47,12 @@ class ModuleGenerateModelCommand extends BaseModuleGenerate
|
||||
"with this option generate sql file at the same time"
|
||||
)
|
||||
;
|
||||
|
||||
}
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->module = $this->formatModuleName($input->getArgument("name"));
|
||||
$this->moduleDirectory = THELIA_MODULE_DIR . DS . $this->module;
|
||||
$this->moduleDirectory = THELIA_MODULE_DIR . $this->module;
|
||||
|
||||
$fs = new Filesystem();
|
||||
|
||||
@@ -66,11 +66,13 @@ class ModuleGenerateModelCommand extends BaseModuleGenerate
|
||||
|
||||
$this->generateModel($output);
|
||||
|
||||
$output->renderBlock(array(
|
||||
'',
|
||||
'Model generated successfuly',
|
||||
''
|
||||
), 'bg=green;fg=black');
|
||||
/** @var FormatterHelper $formatter */
|
||||
$formatter = $this->getHelper('formatter');
|
||||
$formattedBlock = $formatter->formatBlock(
|
||||
'Model generated successfully',
|
||||
'bg=green;fg=black'
|
||||
);
|
||||
$output->writeln($formattedBlock);
|
||||
|
||||
if ($input->getOption("generate-sql")) {
|
||||
$output->writeln(' ');
|
||||
@@ -80,7 +82,6 @@ class ModuleGenerateModelCommand extends BaseModuleGenerate
|
||||
|
||||
protected function generateSql(OutputInterface $output)
|
||||
{
|
||||
|
||||
$command = $this->getApplication()->find("module:generate:sql");
|
||||
|
||||
$command->run(
|
||||
@@ -108,7 +109,7 @@ class ModuleGenerateModelCommand extends BaseModuleGenerate
|
||||
);
|
||||
|
||||
$verifyDirectories = array(
|
||||
THELIA_MODULE_DIR . DS . "Thelia",
|
||||
THELIA_MODULE_DIR . "Thelia",
|
||||
$this->moduleDirectory . DS . "Model" . DS . "Thelia"
|
||||
);
|
||||
|
||||
@@ -117,7 +118,5 @@ class ModuleGenerateModelCommand extends BaseModuleGenerate
|
||||
$fs->remove($directory);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
namespace Thelia\Command;
|
||||
|
||||
use Propel\Generator\Command\SqlBuildCommand;
|
||||
use Symfony\Component\Console\Helper\FormatterHelper;
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
@@ -24,7 +25,7 @@ use Symfony\Component\Filesystem\Filesystem;
|
||||
*
|
||||
* Class ModuleGenerateSqlCommand
|
||||
* @package Thelia\Command
|
||||
* @author Manuel Raynaud <mraynaud@openstudio.fr>
|
||||
* @author Manuel Raynaud <manu@raynaud.io>
|
||||
*/
|
||||
class ModuleGenerateSqlCommand extends BaseModuleGenerate
|
||||
{
|
||||
@@ -44,7 +45,7 @@ class ModuleGenerateSqlCommand extends BaseModuleGenerate
|
||||
public function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->module = $this->formatModuleName($input->getArgument("name"));
|
||||
$this->moduleDirectory = THELIA_MODULE_DIR . DS . $this->module;
|
||||
$this->moduleDirectory = THELIA_MODULE_DIR . $this->module;
|
||||
|
||||
$fs = new Filesystem();
|
||||
|
||||
@@ -68,12 +69,15 @@ class ModuleGenerateSqlCommand extends BaseModuleGenerate
|
||||
$output
|
||||
);
|
||||
|
||||
$output->renderBlock(array(
|
||||
'',
|
||||
'Sql generated successfuly',
|
||||
'File available in your module config directory',
|
||||
''
|
||||
), 'bg=green;fg=black');
|
||||
|
||||
/** @var FormatterHelper $formatter */
|
||||
$formatter = $this->getHelper('formatter');
|
||||
$formattedBlock = $formatter->formatBlock(
|
||||
[
|
||||
'Sql generated successfully',
|
||||
'File available in your module config directory',
|
||||
],
|
||||
'bg=green;fg=black'
|
||||
);
|
||||
$output->writeln($formattedBlock);
|
||||
}
|
||||
}
|
||||
|
||||
87
core/lib/Thelia/Command/ModuleListCommand.php
Normal file
87
core/lib/Thelia/Command/ModuleListCommand.php
Normal file
@@ -0,0 +1,87 @@
|
||||
<?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 Thelia\Command;
|
||||
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Thelia\Model\Map\ModuleTableMap;
|
||||
use Thelia\Model\ModuleQuery;
|
||||
use Thelia\Module\BaseModule;
|
||||
|
||||
/**
|
||||
* Class ModuleListCommand
|
||||
* @package Thelia\Command
|
||||
* @author Benjamin Perche <bperche@openstudio.fr>
|
||||
*/
|
||||
class ModuleListCommand extends ContainerAwareCommand
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('module:list')
|
||||
->setDescription('List the modules')
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return int|null|void
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$helper = new Table($output);
|
||||
$helper->addRows($this->getModulesData());
|
||||
|
||||
$helper
|
||||
->setHeaders(["Code", "Active", "Type", "Version"])
|
||||
->render()
|
||||
;
|
||||
}
|
||||
|
||||
protected function getModulesData()
|
||||
{
|
||||
$moduleData = ModuleQuery::create()
|
||||
->orderByType()
|
||||
->addAsColumn("code", ModuleTableMap::CODE)
|
||||
->addAsColumn("active", "IF(".ModuleTableMap::ACTIVATE.", \"Yes\", \"No\")")
|
||||
->addAsColumn("type", ModuleTableMap::TYPE)
|
||||
->addAsColumn("version", ModuleTableMap::VERSION)
|
||||
->select([
|
||||
"code",
|
||||
"active",
|
||||
"type",
|
||||
"version",
|
||||
])
|
||||
->find()
|
||||
->toArray()
|
||||
;
|
||||
|
||||
foreach ($moduleData as &$row) {
|
||||
switch ($row["type"]) {
|
||||
case BaseModule::CLASSIC_MODULE_TYPE:
|
||||
$row["type"] = "classic";
|
||||
break;
|
||||
case BaseModule::DELIVERY_MODULE_TYPE:
|
||||
$row["type"] = "delivery";
|
||||
break;
|
||||
case BaseModule::PAYMENT_MODULE_TYPE:
|
||||
$row["type"] = "payment";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $moduleData;
|
||||
}
|
||||
}
|
||||
219
core/lib/Thelia/Command/ModulePositionCommand.php
Normal file
219
core/lib/Thelia/Command/ModulePositionCommand.php
Normal file
@@ -0,0 +1,219 @@
|
||||
<?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 Thelia\Command;
|
||||
|
||||
use Propel\Runtime\ActiveQuery\Criteria;
|
||||
use Symfony\Component\Console\Helper\FormatterHelper;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Question\ConfirmationQuestion;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\Event\UpdatePositionEvent;
|
||||
use Thelia\Model\ModuleQuery;
|
||||
use Symfony\Component\Console\Helper\QuestionHelper;
|
||||
|
||||
/**
|
||||
* Class ModulePositionCommand
|
||||
* Set modules position
|
||||
*
|
||||
* @package Thelia\Command
|
||||
* @author Jérôme Billiras <jerome.billiras+github@gmail.com>
|
||||
*/
|
||||
class ModulePositionCommand extends ContainerAwareCommand
|
||||
{
|
||||
/**
|
||||
* @var \Thelia\Model\ModuleQuery
|
||||
*/
|
||||
protected $moduleQuery;
|
||||
|
||||
/**
|
||||
* @var array Modules list
|
||||
*/
|
||||
protected $modulesList = [];
|
||||
|
||||
/**
|
||||
* @var array Modules positions list
|
||||
*/
|
||||
protected $positionsList = [];
|
||||
|
||||
public function __construct($name = null)
|
||||
{
|
||||
parent::__construct($name);
|
||||
|
||||
$this->moduleQuery = new ModuleQuery;
|
||||
}
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('module:position')
|
||||
->setDescription('Set module(s) position')
|
||||
->addArgument(
|
||||
'modules',
|
||||
InputArgument::REQUIRED | InputArgument::IS_ARRAY,
|
||||
'Module in format moduleName:[+|-]position where position is an integer or up or down.'
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$argsList = $input->getArgument('modules');
|
||||
array_walk($argsList, [$this, 'checkModuleArgument']);
|
||||
|
||||
if (!$this->checkPositions($input, $output, $isAbsolute)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($isAbsolute) {
|
||||
array_multisort($this->positionsList, SORT_ASC, SORT_REGULAR, $this->modulesList);
|
||||
}
|
||||
|
||||
$maxPositionByType = $this->cleanPosition();
|
||||
|
||||
foreach ($this->modulesList as $moduleIdx => $moduleName) {
|
||||
$this->moduleQuery->clear();
|
||||
$module = $this->moduleQuery->findOneByCode($moduleName);
|
||||
$position = $this->positionsList[$moduleIdx];
|
||||
|
||||
if ($position === 'up') {
|
||||
$event = new UpdatePositionEvent($module->getId(), UpdatePositionEvent::POSITION_UP);
|
||||
} elseif ($position === 'down') {
|
||||
$event = new UpdatePositionEvent($module->getId(), UpdatePositionEvent::POSITION_DOWN);
|
||||
} else {
|
||||
if ($position[0] === '+' || $position[0] === '-') {
|
||||
$position = $module->getPosition() + $position;
|
||||
}
|
||||
|
||||
if ($position < 1) {
|
||||
$position = 1;
|
||||
}
|
||||
|
||||
$maxPosition = $maxPositionByType[$module->getType()];
|
||||
if ($position > $maxPosition) {
|
||||
$position = $maxPosition;
|
||||
}
|
||||
|
||||
$event = new UpdatePositionEvent($module->getId(), UpdatePositionEvent::POSITION_ABSOLUTE, $position);
|
||||
}
|
||||
|
||||
$this->getDispatcher()->dispatch(TheliaEvents::MODULE_UPDATE_POSITION, $event);
|
||||
}
|
||||
|
||||
/** @var FormatterHelper $formatter */
|
||||
$formatter = $this->getHelper('formatter');
|
||||
$formattedBlock = $formatter->formatBlock('Module position(s) updated', 'bg=green;fg=black', true);
|
||||
$output->writeln($formattedBlock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check a module argument format
|
||||
*
|
||||
* @param string $paramValue
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function checkModuleArgument($paramValue)
|
||||
{
|
||||
if (!preg_match('#^([a-z0-9]+):([\+-]?[0-9]+|up|down)$#i', $paramValue, $matches)) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Arguments must be in format moduleName:[+|-]position where position is an integer or up or down.'
|
||||
);
|
||||
}
|
||||
|
||||
$this->moduleQuery->clear();
|
||||
$module = $this->moduleQuery->findOneByCode($matches[1]);
|
||||
if ($module === null) {
|
||||
throw new \RuntimeException(sprintf('%s module does not exists. Try to refresh first.', $matches[1]));
|
||||
}
|
||||
|
||||
$this->modulesList[] = $matches[1];
|
||||
$this->positionsList[] = $matches[2];
|
||||
}
|
||||
|
||||
/**
|
||||
* Reorder modules positions (without holes)
|
||||
*
|
||||
* @return array Maximum position by type
|
||||
*/
|
||||
protected function cleanPosition()
|
||||
{
|
||||
$modulesType = [];
|
||||
|
||||
$this->moduleQuery->clear();
|
||||
$modules = $this->moduleQuery->orderByPosition(Criteria::ASC);
|
||||
|
||||
/** @var \Thelia\Model\Module $module */
|
||||
foreach ($modules as $module) {
|
||||
if (!isset($modulesType[$module->getType()])) {
|
||||
$modulesType[$module->getType()] = 0;
|
||||
}
|
||||
|
||||
$module
|
||||
->setPosition(++$modulesType[$module->getType()])
|
||||
->save()
|
||||
;
|
||||
}
|
||||
|
||||
return $modulesType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check positions consistency
|
||||
*
|
||||
* @param InputInterface $input An InputInterface instance
|
||||
* @param OutputInterface $output An OutputInterface instance
|
||||
* @param bool $isAbsolute Set to true or false according to position values
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return bool Continue or stop command
|
||||
*/
|
||||
protected function checkPositions(InputInterface $input, OutputInterface $output, &$isAbsolute = false)
|
||||
{
|
||||
$isRelative = false;
|
||||
foreach (array_count_values($this->positionsList) as $value => $count) {
|
||||
if (is_int($value) && $value[0] !== '+' && $value[0] !== '-') {
|
||||
$isAbsolute = true;
|
||||
|
||||
if ($count > 1) {
|
||||
throw new \InvalidArgumentException('Two (or more) absolute positions are identical.');
|
||||
}
|
||||
} else {
|
||||
$isRelative = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($isAbsolute && $isRelative) {
|
||||
/** @var FormatterHelper $formatter */
|
||||
$formatter = $this->getHelper('formatter');
|
||||
$formattedBlock = $formatter->formatBlock(
|
||||
'Mix absolute and relative positions may produce unexpected results !',
|
||||
'bg=yellow;fg=black',
|
||||
true
|
||||
);
|
||||
$output->writeln($formattedBlock);
|
||||
|
||||
/** @var QuestionHelper $helper */
|
||||
$helper = $this->getHelper('question');
|
||||
|
||||
$question = new ConfirmationQuestion('<question>Do you want to continue ? y/[n]<question>', false);
|
||||
|
||||
return $helper->ask($input, $output, $question);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ namespace Thelia\Command;
|
||||
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Thelia\Exception\InvalidModuleException;
|
||||
use Thelia\Module\ModuleManagement;
|
||||
|
||||
/**
|
||||
@@ -36,13 +37,20 @@ class ModuleRefreshCommand extends ContainerAwareCommand
|
||||
{
|
||||
try {
|
||||
$moduleManagement = new ModuleManagement;
|
||||
$moduleManagement->updateModules();
|
||||
$moduleManagement->updateModules($this->getContainer());
|
||||
} catch (InvalidModuleException $ime) {
|
||||
throw new \RuntimeException(
|
||||
sprintf('One or more modules could not be refreshed : %s', $ime->getErrorsAsString("\n"))
|
||||
);
|
||||
} catch (\Exception $e) {
|
||||
throw new \RuntimeException(sprintf('Refresh modules list fail with Exception : [%d] %s', $e->getCode(), $e->getMessage()));
|
||||
throw new \RuntimeException(
|
||||
sprintf('Refresh modules list fail with Exception : [%d] %s', $e->getCode(), $e->getMessage())
|
||||
);
|
||||
}
|
||||
|
||||
if (method_exists($output, 'renderBlock')) {
|
||||
$output->renderBlock([
|
||||
$output->renderBlock(
|
||||
[
|
||||
'',
|
||||
'Modules list successfully refreshed',
|
||||
''
|
||||
|
||||
@@ -40,5 +40,4 @@ class TheliaConsoleOutput extends ConsoleOutput
|
||||
|
||||
$this->writeln($output);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,16 +11,18 @@
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Thelia\Command;
|
||||
|
||||
use Propel\Runtime\Connection\ConnectionWrapper;
|
||||
use \Thelia\Model\Map\ProductTableMap;
|
||||
use Propel\Runtime\Propel;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Thelia\Install\Database;
|
||||
|
||||
/**
|
||||
* Class ReloadDatabasesCommand
|
||||
* @package Thelia\Command
|
||||
* @author Manuel Raynaud <mraynaud@openstudio.fr>
|
||||
* @author Manuel Raynaud <manu@raynaud.io>
|
||||
*/
|
||||
class ReloadDatabaseCommand extends BaseModuleGenerate
|
||||
{
|
||||
@@ -40,7 +42,8 @@ class ReloadDatabaseCommand extends BaseModuleGenerate
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$connection = Propel::getConnection(\Thelia\Model\Map\ProductTableMap::DATABASE_NAME);
|
||||
/** @var ConnectionWrapper $connection */
|
||||
$connection = Propel::getConnection(ProductTableMap::DATABASE_NAME);
|
||||
$connection = $connection->getWrappedConnection();
|
||||
|
||||
$tables = $connection->query("SHOW TABLES");
|
||||
|
||||
47
core/lib/Thelia/Command/SaleCheckActivationCommand.php
Normal file
47
core/lib/Thelia/Command/SaleCheckActivationCommand.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 Thelia\Command;
|
||||
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Thelia\Core\Event\Sale\SaleActiveStatusCheckEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
|
||||
/**
|
||||
* Class SaleCheckActivationCommand
|
||||
* @package Thelia\Command
|
||||
* @author manuel raynaud <manu@raynaud.io>
|
||||
*/
|
||||
class SaleCheckActivationCommand extends ContainerAwareCommand
|
||||
{
|
||||
public function configure()
|
||||
{
|
||||
$this
|
||||
->setName("sale:check-activation")
|
||||
->setDescription("check the activation and deactivation dates of sales, and perform the required action depending on the current date.");
|
||||
}
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
try {
|
||||
$this->getDispatcher()->dispatch(
|
||||
TheliaEvents::CHECK_SALE_ACTIVATION_EVENT,
|
||||
new SaleActiveStatusCheckEvent()
|
||||
);
|
||||
|
||||
$output->writeln("<info>Sale verification processed successfully</info>");
|
||||
} catch (\Exception $ex) {
|
||||
$output->writeln(sprintf("<error>Error : %s</error>", $ex->getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,9 @@ use Thelia\Module\BaseModule;
|
||||
|
||||
class %%CLASSNAME%% extends BaseModule
|
||||
{
|
||||
/** @var string */
|
||||
const DOMAIN_NAME = '%%DOMAINNAME%%';
|
||||
|
||||
/*
|
||||
* You may now override BaseModuleInterface methods, such as:
|
||||
* install, destroy, preActivation, postActivation, preDeactivation, postDeactivation
|
||||
|
||||
55
core/lib/Thelia/Command/Skeleton/Module/Readme.md
Normal file
55
core/lib/Thelia/Command/Skeleton/Module/Readme.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# %%MODULENAMETITLE%%
|
||||
|
||||
Add a short description here. You can also add a screenshot if needed.
|
||||
|
||||
## Installation
|
||||
|
||||
### Manually
|
||||
|
||||
* Copy the module into ```<thelia_root>/local/modules/``` directory and be sure that the name of the module is %%MODULENAME%%.
|
||||
* Activate it in your thelia administration panel
|
||||
|
||||
### Composer
|
||||
|
||||
Add it in your main thelia composer.json file
|
||||
|
||||
```
|
||||
composer require your-vendor/%%COMPOSERNAME%%-module:~1.0
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Explain here how to use your module, how to configure it, etc.
|
||||
|
||||
## Hook
|
||||
|
||||
If your module use one or more hook, fill this part. Explain which hooks are used.
|
||||
|
||||
|
||||
## Loop
|
||||
|
||||
If your module declare one or more loop, describe them here like this :
|
||||
|
||||
[loop name]
|
||||
|
||||
### Input arguments
|
||||
|
||||
|Argument |Description |
|
||||
|--- |--- |
|
||||
|**arg1** | describe arg1 with an exemple. |
|
||||
|**arg2** | describe arg2 with an exemple. |
|
||||
|
||||
### Output arguments
|
||||
|
||||
|Variable |Description |
|
||||
|--- |--- |
|
||||
|$VAR1 | describe $VAR1 variable |
|
||||
|$VAR2 | describe $VAR2 variable |
|
||||
|
||||
### Exemple
|
||||
|
||||
Add a complete exemple of your loop
|
||||
|
||||
## Other ?
|
||||
|
||||
If you have other think to put, feel free to complete your readme as you want.
|
||||
11
core/lib/Thelia/Command/Skeleton/Module/composer.json
Normal file
11
core/lib/Thelia/Command/Skeleton/Module/composer.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "your-vendor/%%COMPOSERNAME%%-module",
|
||||
"license": "LGPL-3.0+",
|
||||
"type": "thelia-module",
|
||||
"require": {
|
||||
"thelia/installer": "~1.1"
|
||||
},
|
||||
"extra": {
|
||||
"installer-name": "%%MODULENAME%%"
|
||||
}
|
||||
}
|
||||
@@ -6,19 +6,19 @@
|
||||
|
||||
<loops>
|
||||
<!-- sample definition
|
||||
<loop name="MySuperLoop" class="MyModule\Loop\MySuperLoop" />
|
||||
<loop name="MySuperLoop" class="%%NAMESPACE%%\Loop\MySuperLoop" />
|
||||
-->
|
||||
</loops>
|
||||
|
||||
<forms>
|
||||
<!--
|
||||
<form name="MyFormName" class="MyModule\Form\MySuperForm" />
|
||||
<form name="MyFormName" class="%%NAMESPACE%%\Form\MySuperForm" />
|
||||
-->
|
||||
</forms>
|
||||
|
||||
<commands>
|
||||
<!--
|
||||
<command class="MyModule\Command\MySuperCommand" />
|
||||
<command class="%%NAMESPACE%%\Command\MySuperCommand" />
|
||||
-->
|
||||
</commands>
|
||||
|
||||
@@ -28,6 +28,14 @@
|
||||
</services>
|
||||
-->
|
||||
|
||||
<!--
|
||||
<hooks>
|
||||
<hook id="%%NAMESPACE_LOWER%%.hook" class="%%NAMESPACE%%\Hook\MySuperHook">
|
||||
<tag name="hook.event_listener" event="main.body.bottom" type="front|back|pdf|email" method="onMainBodyBottom" />
|
||||
</hook>
|
||||
</hooks>
|
||||
-->
|
||||
|
||||
<!--
|
||||
<exports>
|
||||
|
||||
|
||||
50
core/lib/Thelia/Command/Skeleton/Module/config_dev.xml
Normal file
50
core/lib/Thelia/Command/Skeleton/Module/config_dev.xml
Normal file
@@ -0,0 +1,50 @@
|
||||
<?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">
|
||||
|
||||
<loops>
|
||||
<!-- sample definition
|
||||
<loop name="MySuperLoop" class="%%NAMESPACE%%\Loop\MySuperLoop" />
|
||||
-->
|
||||
</loops>
|
||||
|
||||
<forms>
|
||||
<!--
|
||||
<form name="MyFormName" class="%%NAMESPACE%%\Form\MySuperForm" />
|
||||
-->
|
||||
</forms>
|
||||
|
||||
<commands>
|
||||
<!--
|
||||
<command class="%%NAMESPACE%%\Command\MySuperCommand" />
|
||||
-->
|
||||
</commands>
|
||||
|
||||
<!--
|
||||
<services>
|
||||
|
||||
</services>
|
||||
-->
|
||||
|
||||
<!--
|
||||
<hooks>
|
||||
<hook id="%%NAMESPACE_LOWER%%.hook" class="%%NAMESPACE%%\Hook\MySuperHook">
|
||||
<tag name="hook.event_listener" event="main.body.bottom" type="front|back|pdf|email" method="onMainBodyBottom" />
|
||||
</hook>
|
||||
</hooks>
|
||||
-->
|
||||
|
||||
<!--
|
||||
<exports>
|
||||
|
||||
</exports>
|
||||
-->
|
||||
|
||||
<!--
|
||||
<imports>
|
||||
|
||||
</imports>
|
||||
-->
|
||||
</config>
|
||||
50
core/lib/Thelia/Command/Skeleton/Module/config_prod.xml
Normal file
50
core/lib/Thelia/Command/Skeleton/Module/config_prod.xml
Normal file
@@ -0,0 +1,50 @@
|
||||
<?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">
|
||||
|
||||
<loops>
|
||||
<!-- sample definition
|
||||
<loop name="MySuperLoop" class="%%NAMESPACE%%\Loop\MySuperLoop" />
|
||||
-->
|
||||
</loops>
|
||||
|
||||
<forms>
|
||||
<!--
|
||||
<form name="MyFormName" class="%%NAMESPACE%%\Form\MySuperForm" />
|
||||
-->
|
||||
</forms>
|
||||
|
||||
<commands>
|
||||
<!--
|
||||
<command class="%%NAMESPACE%%\Command\MySuperCommand" />
|
||||
-->
|
||||
</commands>
|
||||
|
||||
<!--
|
||||
<services>
|
||||
|
||||
</services>
|
||||
-->
|
||||
|
||||
<!--
|
||||
<hooks>
|
||||
<hook id="%%NAMESPACE_LOWER%%.hook" class="%%NAMESPACE%%\Hook\MySuperHook">
|
||||
<tag name="hook.event_listener" event="main.body.bottom" type="front|back|pdf|email" method="onMainBodyBottom" />
|
||||
</hook>
|
||||
</hooks>
|
||||
-->
|
||||
|
||||
<!--
|
||||
<exports>
|
||||
|
||||
</exports>
|
||||
-->
|
||||
|
||||
<!--
|
||||
<imports>
|
||||
|
||||
</imports>
|
||||
-->
|
||||
</config>
|
||||
50
core/lib/Thelia/Command/Skeleton/Module/config_test.xml
Normal file
50
core/lib/Thelia/Command/Skeleton/Module/config_test.xml
Normal file
@@ -0,0 +1,50 @@
|
||||
<?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">
|
||||
|
||||
<loops>
|
||||
<!-- sample definition
|
||||
<loop name="MySuperLoop" class="%%NAMESPACE%%\Loop\MySuperLoop" />
|
||||
-->
|
||||
</loops>
|
||||
|
||||
<forms>
|
||||
<!--
|
||||
<form name="MyFormName" class="%%NAMESPACE%%\Form\MySuperForm" />
|
||||
-->
|
||||
</forms>
|
||||
|
||||
<commands>
|
||||
<!--
|
||||
<command class="%%NAMESPACE%%\Command\MySuperCommand" />
|
||||
-->
|
||||
</commands>
|
||||
|
||||
<!--
|
||||
<services>
|
||||
|
||||
</services>
|
||||
-->
|
||||
|
||||
<!--
|
||||
<hooks>
|
||||
<hook id="%%NAMESPACE_LOWER%%.hook" class="%%NAMESPACE%%\Hook\MySuperHook">
|
||||
<tag name="hook.event_listener" event="main.body.bottom" type="front|back|pdf|email" method="onMainBodyBottom" />
|
||||
</hook>
|
||||
</hooks>
|
||||
-->
|
||||
|
||||
<!--
|
||||
<exports>
|
||||
|
||||
</exports>
|
||||
-->
|
||||
|
||||
<!--
|
||||
<imports>
|
||||
|
||||
</imports>
|
||||
-->
|
||||
</config>
|
||||
@@ -1,18 +1,43 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module>
|
||||
<module xmlns="http://thelia.net/schema/dic/module"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://thelia.net/schema/dic/module http://thelia.net/schema/dic/module/module-2_2.xsd">
|
||||
<fullnamespace>%%NAMESPACE%%\%%CLASSNAME%%</fullnamespace>
|
||||
<descriptive locale="en_US">
|
||||
<title>Automatically generated module - please update module.xml file</title>
|
||||
<!--
|
||||
<subtitle></subtitle>
|
||||
<description></description>
|
||||
<postscriptum></postscriptum>
|
||||
-->
|
||||
</descriptive>
|
||||
<descriptive locale="fr_FR">
|
||||
<title>Module généré autromatiquement - editez le fichier module.xml</title>
|
||||
<title>Module généré automatiquement - éditez le fichier module.xml</title>
|
||||
</descriptive>
|
||||
<!-- <logo></logo> -->
|
||||
<!--<images-folder>images</images-folder>-->
|
||||
<languages>
|
||||
<language>en_US</language>
|
||||
<language>fr_FR</language>
|
||||
</languages>
|
||||
<version></version>
|
||||
<author>
|
||||
<name></name>
|
||||
<email></email>
|
||||
</author>
|
||||
<authors>
|
||||
<author>
|
||||
<name></name>
|
||||
<email></email>
|
||||
</author>
|
||||
</authors>
|
||||
<type>classic</type>
|
||||
<thelia>2.0.0</thelia>
|
||||
<!--
|
||||
module dependencies
|
||||
<required>
|
||||
<module version=">=0.1">Front</module>
|
||||
<module version="~1.0">HookCart</module>
|
||||
<module version=">0.2">HookSearch</module>
|
||||
</required>
|
||||
-->
|
||||
<thelia>2.2.0</thelia>
|
||||
<stability>other</stability>
|
||||
<mandatory>0</mandatory>
|
||||
<hidden>0</hidden>
|
||||
</module>
|
||||
|
||||
@@ -1,7 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<database defaultIdMethod="native" name="thelia" namespace="%%NAMESPACE%%\Model">
|
||||
<database defaultIdMethod="native" name="thelia"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="%%XSD_LOCATION%%" >
|
||||
<!--
|
||||
See propel documentation on http://propelorm.org for all information about schema file
|
||||
|
||||
<table name="product_rel" namespace="%%NAMESPACE%%\Model">
|
||||
<column autoIncrement="true" name="id" primaryKey="true" required="true" type="INTEGER" />
|
||||
<column defaultValue="0" name="visible" required="true" type="TINYINT" />
|
||||
<column defaultValue="0" name="position" required="true" type="INTEGER" />
|
||||
<column name="title" size="255" type="VARCHAR" />
|
||||
<column name="description" type="CLOB" />
|
||||
<column name="chapo" type="LONGVARCHAR" />
|
||||
<column name="postscriptum" type="LONGVARCHAR" />
|
||||
<foreign-key foreignTable="product" name="fk_product_id" onDelete="CASCADE" onUpdate="RESTRICT">
|
||||
<reference foreign="id" local="product_id" />
|
||||
</foreign-key>
|
||||
<behavior name="timestampable" />
|
||||
<behavior name="i18n">
|
||||
<parameter name="i18n_columns" value="title, description, chapo, postscriptum" />
|
||||
</behavior>
|
||||
<behavior name="versionable">
|
||||
<parameter name="log_created_at" value="true" />
|
||||
<parameter name="log_created_by" value="true" />
|
||||
</behavior>
|
||||
</table>
|
||||
-->
|
||||
<external-schema filename="local/config/schema.xml" referenceOnly="true" />
|
||||
</database>
|
||||
|
||||
@@ -26,7 +26,7 @@ use Thelia\Condition\Implementation\ConditionInterface;
|
||||
*/
|
||||
class ConditionCollection implements Iterator, Countable, ArrayAccess
|
||||
{
|
||||
/** @var array Array of ConditionInterface */
|
||||
/** @var ConditionInterface[] */
|
||||
protected $conditions = [];
|
||||
|
||||
/**
|
||||
@@ -188,5 +188,4 @@ class ConditionCollection implements Iterator, Countable, ArrayAccess
|
||||
|
||||
return json_encode($arrayToSerialize);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,13 +36,11 @@ class ConditionEvaluator
|
||||
/** @var ConditionInterface $condition */
|
||||
foreach ($conditions as $condition) {
|
||||
if (!$condition->isMatching()) {
|
||||
$isMatching = false;
|
||||
break;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return $isMatching;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,7 +60,7 @@ class ConditionEvaluator
|
||||
}
|
||||
|
||||
switch ($o) {
|
||||
case Operators::SUPERIOR :
|
||||
case Operators::SUPERIOR:
|
||||
// >
|
||||
if ($v1 > $v2) {
|
||||
return true;
|
||||
@@ -70,7 +68,7 @@ class ConditionEvaluator
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case Operators::SUPERIOR_OR_EQUAL :
|
||||
case Operators::SUPERIOR_OR_EQUAL:
|
||||
// >=
|
||||
if ($v1 >= $v2) {
|
||||
return true;
|
||||
@@ -78,7 +76,7 @@ class ConditionEvaluator
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case Operators::INFERIOR :
|
||||
case Operators::INFERIOR:
|
||||
// <
|
||||
if ($v1 < $v2) {
|
||||
return true;
|
||||
@@ -86,7 +84,7 @@ class ConditionEvaluator
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case Operators::INFERIOR_OR_EQUAL :
|
||||
case Operators::INFERIOR_OR_EQUAL:
|
||||
// <=
|
||||
if ($v1 <= $v2) {
|
||||
return true;
|
||||
@@ -94,7 +92,7 @@ class ConditionEvaluator
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case Operators::EQUAL :
|
||||
case Operators::EQUAL:
|
||||
// ==
|
||||
if ($v1 == $v2) {
|
||||
return true;
|
||||
|
||||
@@ -84,7 +84,6 @@ class ConditionFactory
|
||||
$collection = new ConditionCollection();
|
||||
|
||||
if (!empty($unserializedConditions)) {
|
||||
|
||||
/** @var SerializableCondition $condition */
|
||||
foreach ($unserializedConditions as $condition) {
|
||||
if ($this->container->has($condition->conditionServiceId)) {
|
||||
|
||||
@@ -32,5 +32,4 @@ class ConditionOrganizer implements ConditionOrganizerInterface
|
||||
{
|
||||
// @todo: Implement organize() method.
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ use Thelia\Model\CountryQuery;
|
||||
abstract class AbstractMatchCountries extends ConditionAbstract
|
||||
{
|
||||
/** Condition 1st parameter : quantity */
|
||||
CONST COUNTRIES_LIST = 'countries';
|
||||
const COUNTRIES_LIST = 'countries';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
@@ -70,7 +70,8 @@ abstract class AbstractMatchCountries extends ConditionAbstract
|
||||
// Check that at least one category is selected
|
||||
if (empty($values[self::COUNTRIES_LIST])) {
|
||||
throw new InvalidConditionValueException(
|
||||
get_class(), self::COUNTRIES_LIST
|
||||
get_class(),
|
||||
self::COUNTRIES_LIST
|
||||
);
|
||||
}
|
||||
|
||||
@@ -102,7 +103,8 @@ abstract class AbstractMatchCountries extends ConditionAbstract
|
||||
public function getSummary()
|
||||
{
|
||||
$i18nOperator = Operators::getI18n(
|
||||
$this->translator, $this->operators[self::COUNTRIES_LIST]
|
||||
$this->translator,
|
||||
$this->operators[self::COUNTRIES_LIST]
|
||||
);
|
||||
|
||||
$cntryStrList = '';
|
||||
@@ -110,10 +112,9 @@ abstract class AbstractMatchCountries extends ConditionAbstract
|
||||
$cntryIds = $this->values[self::COUNTRIES_LIST];
|
||||
|
||||
if (null !== $cntryList = CountryQuery::create()->findPks($cntryIds)) {
|
||||
|
||||
/** @var Country $cntry */
|
||||
foreach ($cntryList as $cntry) {
|
||||
$cntryStrList .= $cntry->getTitle() . ', ';
|
||||
$cntryStrList .= $cntry->setLocale($this->getCurrentLocale())->getTitle() . ', ';
|
||||
}
|
||||
|
||||
$cntryStrList = rtrim($cntryStrList, ', ');
|
||||
@@ -141,7 +142,9 @@ abstract class AbstractMatchCountries extends ConditionAbstract
|
||||
*/
|
||||
public function drawBackOfficeInputs()
|
||||
{
|
||||
return $this->facade->getParser()->render('coupon/condition-fragments/countries-condition.html', [
|
||||
return $this->facade->getParser()->render(
|
||||
'coupon/condition-fragments/countries-condition.html',
|
||||
[
|
||||
'operatorSelectHtml' => $this->drawBackOfficeInputOperators(self::COUNTRIES_LIST),
|
||||
'countries_field_name' => self::COUNTRIES_LIST,
|
||||
'values' => isset($this->values[self::COUNTRIES_LIST]) ? $this->values[self::COUNTRIES_LIST] : array(),
|
||||
|
||||
@@ -29,7 +29,7 @@ use Thelia\Model\CategoryQuery;
|
||||
class CartContainsCategories extends ConditionAbstract
|
||||
{
|
||||
/** Condition 1st parameter : quantity */
|
||||
CONST CATEGORIES_LIST = 'categories';
|
||||
const CATEGORIES_LIST = 'categories';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
@@ -75,7 +75,8 @@ class CartContainsCategories extends ConditionAbstract
|
||||
// Check that at least one category is selected
|
||||
if (empty($values[self::CATEGORIES_LIST])) {
|
||||
throw new InvalidConditionValueException(
|
||||
get_class(), self::CATEGORIES_LIST
|
||||
get_class(),
|
||||
self::CATEGORIES_LIST
|
||||
);
|
||||
}
|
||||
|
||||
@@ -94,23 +95,22 @@ class CartContainsCategories extends ConditionAbstract
|
||||
|
||||
/** @var CartItem $cartItem */
|
||||
foreach ($cartItems as $cartItem) {
|
||||
|
||||
$categories = $cartItem->getProduct()->getCategories();
|
||||
|
||||
/** @var Category $category */
|
||||
foreach ($categories as $category) {
|
||||
$catecoryInCart = $this->conditionValidator->variableOpComparison(
|
||||
if (! $this->conditionValidator->variableOpComparison(
|
||||
$category->getId(),
|
||||
$this->operators[self::CATEGORIES_LIST],
|
||||
$this->values[self::CATEGORIES_LIST]
|
||||
);
|
||||
|
||||
if ($catecoryInCart) {
|
||||
return true;
|
||||
)) {
|
||||
// cart item doesn't match go to next cart item
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// cart item match
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -144,7 +144,8 @@ class CartContainsCategories extends ConditionAbstract
|
||||
public function getSummary()
|
||||
{
|
||||
$i18nOperator = Operators::getI18n(
|
||||
$this->translator, $this->operators[self::CATEGORIES_LIST]
|
||||
$this->translator,
|
||||
$this->operators[self::CATEGORIES_LIST]
|
||||
);
|
||||
|
||||
$catStrList = '';
|
||||
@@ -152,17 +153,17 @@ class CartContainsCategories extends ConditionAbstract
|
||||
$catIds = $this->values[self::CATEGORIES_LIST];
|
||||
|
||||
if (null !== $catList = CategoryQuery::create()->findPks($catIds)) {
|
||||
|
||||
/** @var Category $cat */
|
||||
foreach ($catList as $cat) {
|
||||
$catStrList .= $cat->getTitle() . ', ';
|
||||
$catStrList .= $cat->setLocale($this->getCurrentLocale())->getTitle() . ', ';
|
||||
}
|
||||
|
||||
$catStrList = rtrim($catStrList, ', ');
|
||||
}
|
||||
|
||||
$toolTip = $this->translator->trans(
|
||||
'At least one of cart products categories is %op% <strong>%categories_list%</strong>', [
|
||||
'At least one of cart products categories is %op% <strong>%categories_list%</strong>',
|
||||
[
|
||||
'%categories_list%' => $catStrList,
|
||||
'%op%' => $i18nOperator
|
||||
]
|
||||
@@ -190,7 +191,9 @@ class CartContainsCategories extends ConditionAbstract
|
||||
*/
|
||||
public function drawBackOfficeInputs()
|
||||
{
|
||||
return $this->facade->getParser()->render('coupon/condition-fragments/cart-contains-categories-condition.html', [
|
||||
return $this->facade->getParser()->render(
|
||||
'coupon/condition-fragments/cart-contains-categories-condition.html',
|
||||
[
|
||||
'operatorSelectHtml' => $this->drawBackOfficeInputOperators(self::CATEGORIES_LIST),
|
||||
'categories_field_name' => self::CATEGORIES_LIST,
|
||||
'values' => isset($this->values[self::CATEGORIES_LIST]) ? $this->values[self::CATEGORIES_LIST] : array()
|
||||
|
||||
@@ -75,7 +75,8 @@ class CartContainsProducts extends ConditionAbstract
|
||||
// Check that at least one product is selected
|
||||
if (empty($values[self::PRODUCTS_LIST])) {
|
||||
throw new InvalidConditionValueException(
|
||||
get_class(), self::PRODUCTS_LIST
|
||||
get_class(),
|
||||
self::PRODUCTS_LIST
|
||||
);
|
||||
}
|
||||
|
||||
@@ -94,15 +95,14 @@ class CartContainsProducts extends ConditionAbstract
|
||||
|
||||
/** @var CartItem $cartItem */
|
||||
foreach ($cartItems as $cartItem) {
|
||||
|
||||
if ($this->conditionValidator->variableOpComparison(
|
||||
$cartItem->getProduct()->getId(),
|
||||
$this->operators[self::PRODUCTS_LIST],
|
||||
$this->values[self::PRODUCTS_LIST])) {
|
||||
return true;
|
||||
$cartItem->getProduct()->getId(),
|
||||
$this->operators[self::PRODUCTS_LIST],
|
||||
$this->values[self::PRODUCTS_LIST]
|
||||
)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -136,7 +136,8 @@ class CartContainsProducts extends ConditionAbstract
|
||||
public function getSummary()
|
||||
{
|
||||
$i18nOperator = Operators::getI18n(
|
||||
$this->translator, $this->operators[self::PRODUCTS_LIST]
|
||||
$this->translator,
|
||||
$this->operators[self::PRODUCTS_LIST]
|
||||
);
|
||||
|
||||
$prodStrList = '';
|
||||
@@ -144,17 +145,17 @@ class CartContainsProducts extends ConditionAbstract
|
||||
$prodIds = $this->values[self::PRODUCTS_LIST];
|
||||
|
||||
if (null !== $prodList = ProductQuery::create()->findPks($prodIds)) {
|
||||
|
||||
/** @var Product $prod */
|
||||
foreach ($prodList as $prod) {
|
||||
$prodStrList .= $prod->getTitle() . ', ';
|
||||
$prodStrList .= $prod->setLocale($this->getCurrentLocale())->getTitle() . ', ';
|
||||
}
|
||||
|
||||
$prodStrList = rtrim($prodStrList, ', ');
|
||||
}
|
||||
|
||||
$toolTip = $this->translator->trans(
|
||||
'Cart contains at least a product %op% <strong>%products_list%</strong>', [
|
||||
'Cart contains at least a product %op% <strong>%products_list%</strong>',
|
||||
[
|
||||
'%products_list%' => $prodStrList,
|
||||
'%op%' => $i18nOperator
|
||||
]
|
||||
@@ -182,7 +183,9 @@ class CartContainsProducts extends ConditionAbstract
|
||||
*/
|
||||
public function drawBackOfficeInputs()
|
||||
{
|
||||
return $this->facade->getParser()->render('coupon/condition-fragments/cart-contains-products-condition.html', [
|
||||
return $this->facade->getParser()->render(
|
||||
'coupon/condition-fragments/cart-contains-products-condition.html',
|
||||
[
|
||||
'operatorSelectHtml' => $this->drawBackOfficeInputOperators(self::PRODUCTS_LIST),
|
||||
'products_field_name' => self::PRODUCTS_LIST,
|
||||
'values' => isset($this->values[self::PRODUCTS_LIST]) ? $this->values[self::PRODUCTS_LIST] : array()
|
||||
|
||||
@@ -82,7 +82,8 @@ abstract class ConditionAbstract implements ConditionInterface
|
||||
|
||||
if (!$isOperator1Legit) {
|
||||
throw new InvalidConditionOperatorException(
|
||||
get_class(), $parameterName
|
||||
get_class(),
|
||||
$parameterName
|
||||
);
|
||||
}
|
||||
|
||||
@@ -101,7 +102,6 @@ abstract class ConditionAbstract implements ConditionInterface
|
||||
$translatedInputs = [];
|
||||
|
||||
foreach ($this->validators as $key => $validator) {
|
||||
|
||||
$translatedOperators = [];
|
||||
|
||||
foreach ($validator['availableOperators'] as $availableOperators) {
|
||||
@@ -162,7 +162,7 @@ abstract class ConditionAbstract implements ConditionInterface
|
||||
*/
|
||||
protected function isOperatorLegit($operator, array $availableOperators)
|
||||
{
|
||||
return in_array($operator, $availableOperators);
|
||||
return in_array($operator, $availableOperators);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -201,7 +201,8 @@ abstract class ConditionAbstract implements ConditionInterface
|
||||
}
|
||||
if (!$currencyFound) {
|
||||
throw new InvalidConditionValueException(
|
||||
get_class(), 'currency'
|
||||
get_class(),
|
||||
'currency'
|
||||
);
|
||||
}
|
||||
|
||||
@@ -221,7 +222,8 @@ abstract class ConditionAbstract implements ConditionInterface
|
||||
$floatType = new FloatType();
|
||||
if (!$floatType->isValid($priceValue) || $priceValue <= 0) {
|
||||
throw new InvalidConditionValueException(
|
||||
get_class(), 'price'
|
||||
get_class(),
|
||||
'price'
|
||||
);
|
||||
}
|
||||
|
||||
@@ -243,8 +245,9 @@ abstract class ConditionAbstract implements ConditionInterface
|
||||
$inputs = $this->getValidators();
|
||||
|
||||
if (isset($inputs['inputs'][$inputKey])) {
|
||||
|
||||
$html = $this->facade->getParser()->render('coupon/condition-fragments/condition-selector.html', [
|
||||
$html = $this->facade->getParser()->render(
|
||||
'coupon/condition-fragments/condition-selector.html',
|
||||
[
|
||||
'operators' => $inputs['inputs'][$inputKey]['availableOperators'],
|
||||
'value' => isset($this->operators[$inputKey]) ? $this->operators[$inputKey] : '',
|
||||
'inputKey' => $inputKey
|
||||
@@ -273,7 +276,9 @@ abstract class ConditionAbstract implements ConditionInterface
|
||||
$currentValue = $this->values[$inputKey];
|
||||
}
|
||||
|
||||
return $this->facade->getParser()->render('coupon/conditions-fragments/base-input-text.html', [
|
||||
return $this->facade->getParser()->render(
|
||||
'coupon/conditions-fragments/base-input-text.html',
|
||||
[
|
||||
'label' => $label,
|
||||
'inputKey' => $inputKey,
|
||||
'currentValue' => $currentValue,
|
||||
@@ -294,7 +299,9 @@ abstract class ConditionAbstract implements ConditionInterface
|
||||
*/
|
||||
protected function drawBackOfficeInputQuantityValues($inputKey, $max = 10, $min = 0)
|
||||
{
|
||||
return $this->facade->getParser()->render('coupon/condition-fragments/quantity-selector.html', [
|
||||
return $this->facade->getParser()->render(
|
||||
'coupon/condition-fragments/quantity-selector.html',
|
||||
[
|
||||
'min' => $min,
|
||||
'max' => $max,
|
||||
'value' => isset($this->values[$inputKey]) ? $this->values[$inputKey] : '',
|
||||
@@ -322,11 +329,23 @@ abstract class ConditionAbstract implements ConditionInterface
|
||||
$cleanedCurrencies[$currency->getCode()] = $currency->getSymbol();
|
||||
}
|
||||
|
||||
return $this->facade->getParser()->render('coupon/condition-fragments/currency-selector.html', [
|
||||
return $this->facade->getParser()->render(
|
||||
'coupon/condition-fragments/currency-selector.html',
|
||||
[
|
||||
'currencies' => $cleanedCurrencies,
|
||||
'value' => isset($this->values[$inputKey]) ? $this->values[$inputKey] : '',
|
||||
'inputKey' => $inputKey
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper to het the current locale.
|
||||
*
|
||||
* @return string the current locale.
|
||||
*/
|
||||
protected function getCurrentLocale()
|
||||
{
|
||||
return $this->facade->getRequest()->getSession()->getLang()->getLocale();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace Thelia\Condition\Implementation;
|
||||
use Thelia\Condition\Operators;
|
||||
use Thelia\Coupon\FacadeInterface;
|
||||
use Thelia\Exception\InvalidConditionValueException;
|
||||
use Thelia\Exception\UnmatchableConditionException;
|
||||
use Thelia\Model\Customer;
|
||||
use Thelia\Model\CustomerQuery;
|
||||
|
||||
@@ -73,7 +74,8 @@ class ForSomeCustomers extends ConditionAbstract
|
||||
// Check that at least one product is selected
|
||||
if (empty($values[self::CUSTOMERS_LIST])) {
|
||||
throw new InvalidConditionValueException(
|
||||
get_class(), self::CUSTOMERS_LIST
|
||||
get_class(),
|
||||
self::CUSTOMERS_LIST
|
||||
);
|
||||
}
|
||||
|
||||
@@ -88,13 +90,15 @@ class ForSomeCustomers extends ConditionAbstract
|
||||
*/
|
||||
public function isMatching()
|
||||
{
|
||||
$customer = $this->facade->getCustomer();
|
||||
if (null === $customer = $this->facade->getCustomer()) {
|
||||
throw new UnmatchableConditionException();
|
||||
}
|
||||
|
||||
return $this->conditionValidator->variableOpComparison(
|
||||
$customer->getId(),
|
||||
$this->operators[self::CUSTOMERS_LIST],
|
||||
$this->values[self::CUSTOMERS_LIST]
|
||||
);
|
||||
return $this->conditionValidator->variableOpComparison(
|
||||
$customer->getId(),
|
||||
$this->operators[self::CUSTOMERS_LIST],
|
||||
$this->values[self::CUSTOMERS_LIST]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -127,7 +131,8 @@ class ForSomeCustomers extends ConditionAbstract
|
||||
public function getSummary()
|
||||
{
|
||||
$i18nOperator = Operators::getI18n(
|
||||
$this->translator, $this->operators[self::CUSTOMERS_LIST]
|
||||
$this->translator,
|
||||
$this->operators[self::CUSTOMERS_LIST]
|
||||
);
|
||||
|
||||
$custStrList = '';
|
||||
@@ -135,7 +140,6 @@ class ForSomeCustomers extends ConditionAbstract
|
||||
$custIds = $this->values[self::CUSTOMERS_LIST];
|
||||
|
||||
if (null !== $custList = CustomerQuery::create()->findPks($custIds)) {
|
||||
|
||||
/** @var Customer $cust */
|
||||
foreach ($custList as $cust) {
|
||||
$custStrList .= $cust->getLastname() . ' ' . $cust->getFirstname() . ' ('.$cust->getRef().'), ';
|
||||
@@ -145,7 +149,8 @@ class ForSomeCustomers extends ConditionAbstract
|
||||
}
|
||||
|
||||
$toolTip = $this->translator->trans(
|
||||
'Customer is %op% <strong>%customer_list%</strong>', [
|
||||
'Customer is %op% <strong>%customer_list%</strong>',
|
||||
[
|
||||
'%customer_list%' => $custStrList,
|
||||
'%op%' => $i18nOperator
|
||||
]
|
||||
@@ -173,7 +178,9 @@ class ForSomeCustomers extends ConditionAbstract
|
||||
*/
|
||||
public function drawBackOfficeInputs()
|
||||
{
|
||||
return $this->facade->getParser()->render('coupon/condition-fragments/customers-condition.html', [
|
||||
return $this->facade->getParser()->render(
|
||||
'coupon/condition-fragments/customers-condition.html',
|
||||
[
|
||||
'operatorSelectHtml' => $this->drawBackOfficeInputOperators(self::CUSTOMERS_LIST),
|
||||
'customers_field_name' => self::CUSTOMERS_LIST,
|
||||
'values' => isset($this->values[self::CUSTOMERS_LIST]) ? $this->values[self::CUSTOMERS_LIST] : array()
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user