Rajout du dossier core + MAJ .gitignore
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,4 +1,3 @@
|
||||
/web/cache/
|
||||
/cache/
|
||||
/core/
|
||||
/log/
|
||||
|
||||
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.
|
||||
35
core/Readme.md
Normal file
35
core/Readme.md
Normal file
@@ -0,0 +1,35 @@
|
||||
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.4
|
||||
* Required extensions :
|
||||
* PDO_Mysql
|
||||
* mcrypt
|
||||
* intl
|
||||
* gd
|
||||
* curl
|
||||
* safe_mode off
|
||||
* memory_limit at least 128M, preferably 256.
|
||||
* post_max_size 20M
|
||||
* upload_max_filesize 2M
|
||||
* apache 2
|
||||
* mysql
|
||||
54
core/Thelia
Normal file
54
core/Thelia
Normal file
@@ -0,0 +1,54 @@
|
||||
#!/usr/bin/env php
|
||||
<?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());
|
||||
92
core/bootstrap.php
Normal file
92
core/bootstrap.php
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
// 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
|
||||
*/
|
||||
|
||||
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);
|
||||
} 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"
|
||||
));
|
||||
}
|
||||
}
|
||||
78
core/composer.json
Normal file
78
core/composer.json
Normal file
@@ -0,0 +1,78 @@
|
||||
{
|
||||
"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.*"
|
||||
},
|
||||
"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"
|
||||
]
|
||||
}
|
||||
}
|
||||
108
core/lib/Thelia/Action/Address.php
Normal file
108
core/lib/Thelia/Action/Address.php
Normal file
@@ -0,0 +1,108 @@
|
||||
<?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\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;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Model\Address as AddressModel;
|
||||
use Thelia\Model\Map\AddressTableMap;
|
||||
|
||||
/**
|
||||
* Class Address
|
||||
* @package Thelia\Action
|
||||
* @author Manuel Raynaud <manu@raynaud.io>
|
||||
*/
|
||||
class Address extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
public function create(AddressCreateOrUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$address = new AddressModel();
|
||||
$address->setCustomer($event->getCustomer());
|
||||
$this->createOrUpdate($address, $event, $dispatcher);
|
||||
}
|
||||
|
||||
public function update(AddressCreateOrUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$addressModel = $event->getAddress();
|
||||
|
||||
$this->createOrUpdate($addressModel, $event, $dispatcher);
|
||||
}
|
||||
|
||||
public function delete(AddressEvent $event)
|
||||
{
|
||||
$address = $event->getAddress();
|
||||
|
||||
$address->delete();
|
||||
}
|
||||
|
||||
public function useDefault(AddressEvent $event)
|
||||
{
|
||||
$address = $event->getAddress();
|
||||
|
||||
$address->makeItDefault();
|
||||
}
|
||||
|
||||
protected function createOrUpdate(AddressModel $addressModel, AddressCreateOrUpdateEvent $event, $dispatcher)
|
||||
{
|
||||
$addressModel->setDispatcher($dispatcher);
|
||||
$con = Propel::getWriteConnection(AddressTableMap::DATABASE_NAME);
|
||||
$con->beginTransaction();
|
||||
try {
|
||||
$addressModel
|
||||
->setLabel($event->getLabel())
|
||||
->setTitleId($event->getTitle())
|
||||
->setFirstname($event->getFirstname())
|
||||
->setLastname($event->getLastname())
|
||||
->setAddress1($event->getAddress1())
|
||||
->setAddress2($event->getAddress2())
|
||||
->setAddress3($event->getAddress3())
|
||||
->setZipcode($event->getZipcode())
|
||||
->setCity($event->getCity())
|
||||
->setCountryId($event->getCountry())
|
||||
->setStateId($event->getState())
|
||||
->setCellphone($event->getCellphone())
|
||||
->setPhone($event->getPhone())
|
||||
->setCompany($event->getCompany())
|
||||
->save()
|
||||
;
|
||||
|
||||
if ($event->getIsDefault() && !$addressModel->getIsDefault()) {
|
||||
$addressModel->makeItDefault();
|
||||
}
|
||||
|
||||
$event->setAddress($addressModel);
|
||||
$con->commit();
|
||||
} catch (PropelException $e) {
|
||||
$con->rollback();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::ADDRESS_CREATE => array("create", 128),
|
||||
TheliaEvents::ADDRESS_UPDATE => array("update", 128),
|
||||
TheliaEvents::ADDRESS_DELETE => array("delete", 128),
|
||||
TheliaEvents::ADDRESS_DEFAULT => array('useDefault', 128),
|
||||
);
|
||||
}
|
||||
}
|
||||
155
core/lib/Thelia/Action/Administrator.php
Normal file
155
core/lib/Thelia/Action/Administrator.php
Normal file
@@ -0,0 +1,155 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace 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, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$administrator = new AdminModel();
|
||||
|
||||
$administrator
|
||||
->setDispatcher($dispatcher)
|
||||
->setFirstname($event->getFirstname())
|
||||
->setLastname($event->getLastname())
|
||||
->setEmail($event->getEmail())
|
||||
->setLogin($event->getLogin())
|
||||
->setPassword($event->getPassword())
|
||||
->setProfileId($event->getProfile())
|
||||
->setLocale($event->getLocale())
|
||||
;
|
||||
|
||||
$administrator->save();
|
||||
|
||||
$event->setAdministrator($administrator);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AdministratorEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function update(AdministratorEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $administrator = AdminQuery::create()->findPk($event->getId())) {
|
||||
$administrator
|
||||
->setDispatcher($dispatcher)
|
||||
->setFirstname($event->getFirstname())
|
||||
->setLastname($event->getLastname())
|
||||
->setLogin($event->getLogin())
|
||||
->setEmail($event->getEmail())
|
||||
->setProfileId($event->getProfile())
|
||||
->setLocale($event->getLocale())
|
||||
;
|
||||
|
||||
if ('' !== $event->getPassword()) {
|
||||
$administrator->setPassword($event->getPassword());
|
||||
}
|
||||
|
||||
$administrator->save();
|
||||
|
||||
$event->setAdministrator($administrator);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AdministratorEvent $event
|
||||
*/
|
||||
public function delete(AdministratorEvent $event)
|
||||
{
|
||||
if (null !== $administrator = AdminQuery::create()->findPk($event->getId())) {
|
||||
$administrator
|
||||
->delete()
|
||||
;
|
||||
|
||||
$event->setAdministrator($administrator);
|
||||
}
|
||||
}
|
||||
|
||||
public function updatePassword(AdministratorUpdatePasswordEvent $event)
|
||||
{
|
||||
$admin = $event->getAdmin();
|
||||
|
||||
$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}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
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_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],
|
||||
];
|
||||
}
|
||||
}
|
||||
137
core/lib/Thelia/Action/Area.php
Normal file
137
core/lib/Thelia/Action/Area.php
Normal file
@@ -0,0 +1,137 @@
|
||||
<?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\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\Area as AreaModel;
|
||||
use Thelia\Model\AreaQuery;
|
||||
use Thelia\Model\CountryArea;
|
||||
use Thelia\Model\CountryAreaQuery;
|
||||
|
||||
/**
|
||||
* Class Area
|
||||
* @package Thelia\Action
|
||||
* @author Manuel Raynaud <manu@raynaud.io>
|
||||
*/
|
||||
class Area extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
public function addCountry(AreaAddCountryEvent $event)
|
||||
{
|
||||
$countryIds = $event->getCountryId();
|
||||
|
||||
$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)
|
||||
{
|
||||
CountryAreaQuery::create()
|
||||
->filterByCountryId($event->getCountryId())
|
||||
->filterByStateId($event->getStateId())
|
||||
->filterByAreaId($event->getAreaId())
|
||||
->delete();
|
||||
|
||||
if (null !== $area = AreaQuery::create()->findPk($event->getAreaId())) {
|
||||
$event->setArea($area);
|
||||
}
|
||||
}
|
||||
|
||||
public function updatePostage(AreaUpdatePostageEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $area = AreaQuery::create()->findPk($event->getAreaId())) {
|
||||
$area->setDispatcher($dispatcher);
|
||||
$area
|
||||
->setPostage($event->getPostage())
|
||||
->save();
|
||||
|
||||
$event->setArea($area);
|
||||
}
|
||||
}
|
||||
|
||||
public function delete(AreaDeleteEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $area = AreaQuery::create()->findPk($event->getAreaId())) {
|
||||
$area->setDispatcher($dispatcher);
|
||||
$area->delete();
|
||||
|
||||
$event->setArea($area);
|
||||
}
|
||||
}
|
||||
|
||||
public function create(AreaCreateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$area = new AreaModel();
|
||||
|
||||
$area
|
||||
->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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::AREA_ADD_COUNTRY => array('addCountry', 128),
|
||||
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_UPDATE => array('update', 128)
|
||||
);
|
||||
}
|
||||
}
|
||||
157
core/lib/Thelia/Action/Attribute.php
Normal file
157
core/lib/Thelia/Action/Attribute.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\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;
|
||||
use Thelia\Core\Event\UpdatePositionEvent;
|
||||
use Thelia\Core\Event\Attribute\AttributeEvent;
|
||||
use Thelia\Model\AttributeTemplate;
|
||||
use Thelia\Model\AttributeTemplateQuery;
|
||||
use Thelia\Model\TemplateQuery;
|
||||
|
||||
class Attribute extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
/**
|
||||
* Create a new attribute entry
|
||||
*
|
||||
* @param AttributeCreateEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function create(AttributeCreateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$attribute = new AttributeModel();
|
||||
|
||||
$attribute
|
||||
->setDispatcher($dispatcher)
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
->save()
|
||||
;
|
||||
|
||||
$event->setAttribute($attribute);
|
||||
|
||||
// Add atribute to all product templates if required
|
||||
if ($event->getAddToAllTemplates() != 0) {
|
||||
$this->doAddToAllTemplates($attribute);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Change a product attribute
|
||||
*
|
||||
* @param AttributeUpdateEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function update(AttributeUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $attribute = AttributeQuery::create()->findPk($event->getAttributeId())) {
|
||||
$attribute
|
||||
->setDispatcher($dispatcher)
|
||||
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
->setDescription($event->getDescription())
|
||||
->setChapo($event->getChapo())
|
||||
->setPostscriptum($event->getPostscriptum())
|
||||
|
||||
->save();
|
||||
|
||||
$event->setAttribute($attribute);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a product attribute entry
|
||||
*
|
||||
* @param AttributeDeleteEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function delete(AttributeDeleteEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== ($attribute = AttributeQuery::create()->findPk($event->getAttributeId()))) {
|
||||
$attribute
|
||||
->setDispatcher($dispatcher)
|
||||
->delete()
|
||||
;
|
||||
|
||||
$event->setAttribute($attribute);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(AttributeQuery::create(), $event, $dispatcher);
|
||||
}
|
||||
|
||||
protected function doAddToAllTemplates(AttributeModel $attribute)
|
||||
{
|
||||
$templates = TemplateQuery::create()->find();
|
||||
|
||||
foreach ($templates as $template) {
|
||||
$attribute_template = new AttributeTemplate();
|
||||
|
||||
if (null === AttributeTemplateQuery::create()->filterByAttribute($attribute)->filterByTemplate($template)->findOne()) {
|
||||
$attribute_template
|
||||
->setAttribute($attribute)
|
||||
->setTemplate($template)
|
||||
->save()
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function addToAllTemplates(AttributeEvent $event)
|
||||
{
|
||||
$this->doAddToAllTemplates($event->getAttribute());
|
||||
}
|
||||
|
||||
public function removeFromAllTemplates(AttributeEvent $event)
|
||||
{
|
||||
// Delete this attribute from all product templates
|
||||
AttributeTemplateQuery::create()->filterByAttribute($event->getAttribute())->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::ATTRIBUTE_CREATE => array("create", 128),
|
||||
TheliaEvents::ATTRIBUTE_UPDATE => array("update", 128),
|
||||
TheliaEvents::ATTRIBUTE_DELETE => array("delete", 128),
|
||||
TheliaEvents::ATTRIBUTE_UPDATE_POSITION => array("updatePosition", 128),
|
||||
|
||||
TheliaEvents::ATTRIBUTE_REMOVE_FROM_ALL_TEMPLATES => array("removeFromAllTemplates", 128),
|
||||
TheliaEvents::ATTRIBUTE_ADD_TO_ALL_TEMPLATES => array("addToAllTemplates", 128),
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
119
core/lib/Thelia/Action/AttributeAv.php
Normal file
119
core/lib/Thelia/Action/AttributeAv.php
Normal file
@@ -0,0 +1,119 @@
|
||||
<?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\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;
|
||||
use Thelia\Core\Event\UpdatePositionEvent;
|
||||
|
||||
class AttributeAv extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
/**
|
||||
* Create a new attribute entry
|
||||
*
|
||||
* @param AttributeAvCreateEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function create(AttributeAvCreateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$attribute = new AttributeAvModel();
|
||||
|
||||
$attribute
|
||||
->setDispatcher($dispatcher)
|
||||
|
||||
->setAttributeId($event->getAttributeId())
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
|
||||
->save()
|
||||
;
|
||||
|
||||
$event->setAttributeAv($attribute);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change a product attribute
|
||||
*
|
||||
* @param AttributeAvUpdateEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function update(AttributeAvUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $attribute = AttributeAvQuery::create()->findPk($event->getAttributeAvId())) {
|
||||
$attribute
|
||||
->setDispatcher($dispatcher)
|
||||
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
->setDescription($event->getDescription())
|
||||
->setChapo($event->getChapo())
|
||||
->setPostscriptum($event->getPostscriptum())
|
||||
|
||||
->save();
|
||||
|
||||
$event->setAttributeAv($attribute);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a product attribute entry
|
||||
*
|
||||
* @param AttributeAvDeleteEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function delete(AttributeAvDeleteEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== ($attribute = AttributeAvQuery::create()->findPk($event->getAttributeAvId()))) {
|
||||
$attribute
|
||||
->setDispatcher($dispatcher)
|
||||
->delete()
|
||||
;
|
||||
|
||||
$event->setAttributeAv($attribute);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(AttributeAvQuery::create(), $event);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::ATTRIBUTE_AV_CREATE => array("create", 128),
|
||||
TheliaEvents::ATTRIBUTE_AV_UPDATE => array("update", 128),
|
||||
TheliaEvents::ATTRIBUTE_AV_DELETE => array("delete", 128),
|
||||
TheliaEvents::ATTRIBUTE_AV_UPDATE_POSITION => array("updatePosition", 128),
|
||||
);
|
||||
}
|
||||
}
|
||||
146
core/lib/Thelia/Action/BaseAction.php
Normal file
146
core/lib/Thelia/Action/BaseAction.php
Normal file
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
namespace 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
|
||||
{
|
||||
/**
|
||||
* Changes object position, selecting absolute ou relative change.
|
||||
*
|
||||
* @param ModelCriteria $query
|
||||
* @param UpdatePositionEvent $event
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
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($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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes SEO Fields for an object.
|
||||
*
|
||||
* @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, EventDispatcherInterface $dispatcher = null)
|
||||
{
|
||||
if (null !== $object = $query->findPk($event->getObjectId())) {
|
||||
$object
|
||||
//for backward compatibility
|
||||
->setDispatcher($dispatcher !== null ? $dispatcher : $event->getDispatcher())
|
||||
|
||||
->setLocale($event->getLocale())
|
||||
->setMetaTitle($event->getMetaTitle())
|
||||
->setMetaDescription($event->getMetaDescription())
|
||||
->setMetaKeywords($event->getMetaKeywords())
|
||||
|
||||
->save()
|
||||
;
|
||||
|
||||
// Update the rewritten URL, if required
|
||||
try {
|
||||
$object->setRewrittenUrl($event->getLocale(), $event->getUrl());
|
||||
} catch (UrlRewritingException $e) {
|
||||
throw new FormValidationException($e->getMessage(), $e->getCode());
|
||||
}
|
||||
|
||||
$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;
|
||||
}
|
||||
}
|
||||
276
core/lib/Thelia/Action/BaseCachedFile.php
Normal file
276
core/lib/Thelia/Action/BaseCachedFile.php
Normal file
@@ -0,0 +1,276 @@
|
||||
<?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\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;
|
||||
|
||||
/**
|
||||
*
|
||||
* Cached file management actions. This class handles file caching in the web space
|
||||
*
|
||||
* Basically, files are stored outside the web space (by default in local/media/<dirname>),
|
||||
* and cached in the web space (by default in web/local/<dirname>).
|
||||
*
|
||||
* In the file cache directory, a subdirectory for files categories (eg. product, category, folder, etc.) is
|
||||
* automatically created, and the cached file is created here. Plugin may use their own subdirectory as required.
|
||||
*
|
||||
* A copy (or symbolic link, by default) of the original file is created in the cache.
|
||||
*
|
||||
* @package Thelia\Action
|
||||
* @author Franck Allimant <franck@cqfdev.fr>
|
||||
*
|
||||
*/
|
||||
abstract class BaseCachedFile extends BaseAction
|
||||
{
|
||||
/**
|
||||
* @var FileManager
|
||||
*/
|
||||
protected $fileManager;
|
||||
|
||||
public function __construct(FileManager $fileManager)
|
||||
{
|
||||
$this->fileManager = $fileManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string root of the file cache directory in web space
|
||||
*/
|
||||
abstract protected function getCacheDirFromWebRoot();
|
||||
|
||||
/**
|
||||
* Clear the file cache. Is a subdirectory is specified, only this directory is cleared.
|
||||
* If no directory is specified, the whole cache is cleared.
|
||||
* Only files are deleted, directories will remain.
|
||||
*
|
||||
* @param CachedFileEvent $event
|
||||
*/
|
||||
public function clearCache(CachedFileEvent $event)
|
||||
{
|
||||
$path = $this->getCachePath($event->getCacheSubdirectory(), false);
|
||||
|
||||
$this->clearDirectory($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively clears the specified directory.
|
||||
*
|
||||
* @param string $path the directory path
|
||||
*/
|
||||
protected function clearDirectory($path)
|
||||
{
|
||||
$iterator = new \DirectoryIterator($path);
|
||||
|
||||
/** @var \DirectoryIterator $fileinfo */
|
||||
foreach ($iterator as $fileinfo) {
|
||||
if ($fileinfo->isDot()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($fileinfo->isFile() || $fileinfo->isLink()) {
|
||||
@unlink($fileinfo->getPathname());
|
||||
} elseif ($fileinfo->isDir()) {
|
||||
$this->clearDirectory($fileinfo->getPathname());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the absolute URL to the cached file
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
protected function getCacheFileURL($subdir, $safe_filename)
|
||||
{
|
||||
$path = $this->getCachePathFromWebRoot($subdir);
|
||||
|
||||
return URL::getInstance()->absoluteUrl(sprintf("%s/%s", $path, $safe_filename), null, URL::PATH_TO_FILE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the full path of the cached file
|
||||
*
|
||||
* @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
|
||||
* @return string the cache directory path relative to Web Root
|
||||
*/
|
||||
protected function getCacheFilePath($subdir, $filename, $forceOriginalFile = false, $hashed_options = null)
|
||||
{
|
||||
$path = $this->getCachePath($subdir);
|
||||
|
||||
$safe_filename = preg_replace("[^:alnum:\-\._]", "-", strtolower(basename($filename)));
|
||||
|
||||
// Keep original safe name if no tranformations are applied
|
||||
if ($forceOriginalFile || $hashed_options == null) {
|
||||
return sprintf("%s/%s", $path, $safe_filename);
|
||||
} else {
|
||||
return sprintf("%s/%s-%s", $path, $hashed_options, $safe_filename);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the cache directory path relative to Web Root
|
||||
*
|
||||
* @param string $subdir the subdirectory related to cache base, or null to get the cache directory only.
|
||||
* @return string the cache directory path relative to Web Root
|
||||
*/
|
||||
protected function getCachePathFromWebRoot($subdir = null)
|
||||
{
|
||||
$cache_dir_from_web_root = $this->getCacheDirFromWebRoot();
|
||||
|
||||
if ($subdir != null) {
|
||||
$safe_subdir = basename($subdir);
|
||||
|
||||
$path = sprintf("%s/%s", $cache_dir_from_web_root, $safe_subdir);
|
||||
} else {
|
||||
$path = $cache_dir_from_web_root;
|
||||
}
|
||||
|
||||
// Check if path is valid, e.g. in the cache dir
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* @throws \RuntimeException if cache directory cannot be created
|
||||
* @throws \InvalidArgumentException ii path is invalid, e.g. not in the cache dir
|
||||
*
|
||||
* @return string the absolute cache directory path
|
||||
*/
|
||||
protected function getCachePath($subdir = null, $create_if_not_exists = true)
|
||||
{
|
||||
$cache_base = $this->getCachePathFromWebRoot($subdir);
|
||||
|
||||
$web_root = rtrim(THELIA_WEB_DIR, '/');
|
||||
|
||||
$path = sprintf("%s/%s", $web_root, $cache_base);
|
||||
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
|
||||
// Check if path is valid, e.g. in the cache dir
|
||||
$cache_base = realpath(sprintf("%s/%s", $web_root, $this->getCachePathFromWebRoot()));
|
||||
|
||||
if (strpos(realpath($path), $cache_base) !== 0) {
|
||||
throw new \InvalidArgumentException(sprintf("Invalid cache path %s, with subdirectory %s", $path, $subdir));
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Take care of saving a file in the database and file storage
|
||||
*
|
||||
* @param FileCreateOrUpdateEvent $event Image event
|
||||
*
|
||||
* @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();
|
||||
|
||||
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()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$newUploadedFile = $this->fileManager->copyUploadedFile($event->getModel(), $event->getUploadedFile());
|
||||
|
||||
$event->setUploadedFile($newUploadedFile);
|
||||
$con->commit();
|
||||
} catch (\Exception $e) {
|
||||
$con->rollBack();
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Take care of updating file in the database and file storage
|
||||
*
|
||||
* @param FileCreateOrUpdateEvent $event Image event
|
||||
*
|
||||
* @throws \Thelia\Exception\FileException
|
||||
*/
|
||||
public function updateFile(FileCreateOrUpdateEvent $event)
|
||||
{
|
||||
// Copy and save file
|
||||
if ($event->getUploadedFile()) {
|
||||
// Remove old picture file from file storage
|
||||
$url = $event->getModel()->getUploadDir() . '/' . $event->getOldModel()->getFile();
|
||||
unlink(str_replace('..', '', $url));
|
||||
|
||||
$newUploadedFile = $this->fileManager->copyUploadedFile($event->getModel(), $event->getUploadedFile());
|
||||
$event->setUploadedFile($newUploadedFile);
|
||||
}
|
||||
|
||||
// Update image modifications
|
||||
$event->getModel()->save();
|
||||
|
||||
$event->setModel($event->getModel());
|
||||
}
|
||||
|
||||
/**
|
||||
* Deleting file in the database and in storage
|
||||
*
|
||||
* @param FileDeleteEvent $event Image event
|
||||
*/
|
||||
public function deleteFile(FileDeleteEvent $event)
|
||||
{
|
||||
$this->fileManager->deleteFile($event->getFileToDelete());
|
||||
}
|
||||
|
||||
public function updatePosition(UpdateFilePositionEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$this->genericUpdatePosition($event->getQuery(), $event, $dispatcher);
|
||||
}
|
||||
|
||||
public function toggleVisibility(FileToggleVisibilityEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$this->genericToggleVisibility($event->getQuery(), $event, $dispatcher);
|
||||
}
|
||||
}
|
||||
140
core/lib/Thelia/Action/Brand.php
Normal file
140
core/lib/Thelia/Action/Brand.php
Normal file
@@ -0,0 +1,140 @@
|
||||
<?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\Brand\BrandCreateEvent;
|
||||
use Thelia\Core\Event\Brand\BrandDeleteEvent;
|
||||
use Thelia\Core\Event\Brand\BrandToggleVisibilityEvent;
|
||||
use Thelia\Core\Event\Brand\BrandUpdateEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\Event\UpdatePositionEvent;
|
||||
use Thelia\Core\Event\UpdateSeoEvent;
|
||||
use Thelia\Model\Brand as BrandModel;
|
||||
use Thelia\Model\BrandQuery;
|
||||
|
||||
/**
|
||||
* Class Brand
|
||||
*
|
||||
* @package Thelia\Action
|
||||
* @author Franck Allimant <franck@cqfdev.fr>
|
||||
*/
|
||||
class Brand extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
public function create(BrandCreateEvent $event)
|
||||
{
|
||||
$brand = new BrandModel();
|
||||
|
||||
$brand
|
||||
->setVisible($event->getVisible())
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
->save()
|
||||
;
|
||||
|
||||
$event->setBrand($brand);
|
||||
}
|
||||
|
||||
/**
|
||||
* process update brand
|
||||
*
|
||||
* @param BrandUpdateEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function update(BrandUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $brand = BrandQuery::create()->findPk($event->getBrandId())) {
|
||||
$brand->setDispatcher($dispatcher);
|
||||
|
||||
$brand
|
||||
->setVisible($event->getVisible())
|
||||
->setLogoImageId(intval($event->getLogoImageId()) == 0 ? null : $event->getLogoImageId())
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
->setDescription($event->getDescription())
|
||||
->setChapo($event->getChapo())
|
||||
->setPostscriptum($event->getPostscriptum())
|
||||
->save()
|
||||
;
|
||||
|
||||
$event->setBrand($brand);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle Brand visibility
|
||||
*
|
||||
* @param BrandToggleVisibilityEvent $event
|
||||
* @param string $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
* @throws \Exception
|
||||
* @throws \Propel\Runtime\Exception\PropelException
|
||||
*/
|
||||
public function toggleVisibility(BrandToggleVisibilityEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$brand = $event->getBrand();
|
||||
|
||||
$brand
|
||||
->setDispatcher($dispatcher)
|
||||
->setVisible(!$brand->getVisible())
|
||||
->save();
|
||||
|
||||
$event->setBrand($brand);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change Brand SEO
|
||||
*
|
||||
* @param UpdateSeoEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
* @return Object
|
||||
*/
|
||||
public function updateSeo(UpdateSeoEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
return $this->genericUpdateSeo(BrandQuery::create(), $event, $dispatcher);
|
||||
}
|
||||
|
||||
public function delete(BrandDeleteEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $brand = BrandQuery::create()->findPk($event->getBrandId())) {
|
||||
$brand->setDispatcher($dispatcher)->delete();
|
||||
|
||||
$event->setBrand($brand);
|
||||
}
|
||||
}
|
||||
|
||||
public function updatePosition(UpdatePositionEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$this->genericUpdatePosition(BrandQuery::create(), $event, $dispatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::BRAND_CREATE => array('create', 128),
|
||||
TheliaEvents::BRAND_UPDATE => array('update', 128),
|
||||
TheliaEvents::BRAND_DELETE => array('delete', 128),
|
||||
|
||||
TheliaEvents::BRAND_UPDATE_SEO => array('updateSeo', 128),
|
||||
|
||||
TheliaEvents::BRAND_UPDATE_POSITION => array('updatePosition', 128),
|
||||
TheliaEvents::BRAND_TOGGLE_VISIBILITY => array('toggleVisibility', 128),
|
||||
);
|
||||
}
|
||||
}
|
||||
44
core/lib/Thelia/Action/Cache.php
Normal file
44
core/lib/Thelia/Action/Cache.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?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\Filesystem\Filesystem;
|
||||
use Thelia\Core\Event\Cache\CacheEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
|
||||
/**
|
||||
* Class Cache
|
||||
* @package Thelia\Action
|
||||
* @author Manuel Raynaud <manu@raynaud.io>
|
||||
*/
|
||||
class Cache extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
public function cacheClear(CacheEvent $event)
|
||||
{
|
||||
$dir = $event->getDir();
|
||||
|
||||
$fs = new Filesystem();
|
||||
$fs->remove($dir);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::CACHE_CLEAR => array('cacheClear', 128)
|
||||
);
|
||||
}
|
||||
}
|
||||
538
core/lib/Thelia/Action/Cart.php
Normal file
538
core/lib/Thelia/Action/Cart.php
Normal file
@@ -0,0 +1,538 @@
|
||||
<?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\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\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\Customer as CustomerModel;
|
||||
use Thelia\Model\ProductSaleElements;
|
||||
use Thelia\Model\Tools\ProductPriceTools;
|
||||
use Thelia\Tools\TokenProvider;
|
||||
|
||||
/**
|
||||
*
|
||||
* Class Cart where all actions are manage like adding, modifying or delete items.
|
||||
*
|
||||
* Class Cart
|
||||
* @package Thelia\Action
|
||||
* @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, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$cart = $event->getCart();
|
||||
$newness = $event->getNewness();
|
||||
$append = $event->getAppend();
|
||||
$quantity = $event->getQuantity();
|
||||
$currency = $cart->getCurrency();
|
||||
$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();
|
||||
}
|
||||
|
||||
$productSaleElementsId = $event->getProductSaleElementsId();
|
||||
$productId = $event->getProduct();
|
||||
|
||||
// Search for an identical item in the cart
|
||||
$dispatcher->dispatch(TheliaEvents::CART_FINDITEM, $event);
|
||||
|
||||
$cartItem = $event->getCartItem();
|
||||
|
||||
if ($cartItem === null || $newness) {
|
||||
$productSaleElements = ProductSaleElementsQuery::create()->findPk($productSaleElementsId);
|
||||
|
||||
if (null !== $productSaleElements) {
|
||||
$productPrices = $productSaleElements->getPricesByCurrency($currency, $discount);
|
||||
|
||||
$cartItem = $this->doAddItem($dispatcher, $cart, $productId, $productSaleElements, $quantity, $productPrices);
|
||||
}
|
||||
} elseif ($append && $cartItem !== null) {
|
||||
$cartItem->addQuantity($quantity)->save();
|
||||
}
|
||||
|
||||
$event->setCartItem($cartItem);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Delete specify article present into cart
|
||||
*
|
||||
* @param \Thelia\Core\Event\Cart\CartEvent $event
|
||||
*/
|
||||
public function deleteItem(CartEvent $event)
|
||||
{
|
||||
if (null !== $cartItemId = $event->getCartItemId()) {
|
||||
$cart = $event->getCart();
|
||||
CartItemQuery::create()
|
||||
->filterByCartId($cart->getId())
|
||||
->filterById($cartItemId)
|
||||
->delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the cart
|
||||
* @param CartEvent $event
|
||||
*/
|
||||
public function clear(CartEvent $event)
|
||||
{
|
||||
if (null !== $cart = $event->getCart()) {
|
||||
$cart->delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Modify article's quantity
|
||||
*
|
||||
* 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, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if ((null !== $cartItemId = $event->getCartItemId()) && (null !== $quantity = $event->getQuantity())) {
|
||||
$cart = $event->getCart();
|
||||
|
||||
$cartItem = CartItemQuery::create()
|
||||
->filterByCartId($cart->getId())
|
||||
->filterById($cartItemId)
|
||||
->findOne();
|
||||
|
||||
if ($cartItem) {
|
||||
$event->setCartItem(
|
||||
$this->updateQuantity($dispatcher, $cartItem, $quantity)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function updateCart(CurrencyChangeEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$cart = $event->getRequest()->getSession()->getSessionCart($dispatcher);
|
||||
|
||||
if (null !== $cart) {
|
||||
$this->updateCartPrices($cart, $event->getCurrency());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Refresh article's price
|
||||
*
|
||||
* @param \Thelia\Model\Cart $cart
|
||||
* @param \Thelia\Model\Currency $currency
|
||||
*/
|
||||
public function updateCartPrices(CartModel $cart, CurrencyModel $currency)
|
||||
{
|
||||
$customer = $cart->getCustomer();
|
||||
$discount = 0;
|
||||
|
||||
if (null !== $customer && $customer->getDiscount() > 0) {
|
||||
$discount = $customer->getDiscount();
|
||||
}
|
||||
|
||||
// cart item
|
||||
foreach ($cart->getCartItems() as $cartItem) {
|
||||
$productSaleElements = $cartItem->getProductSaleElements();
|
||||
|
||||
$productPrice = $productSaleElements->getPricesByCurrency($currency, $discount);
|
||||
|
||||
$cartItem
|
||||
->setPrice($productPrice->getPrice())
|
||||
->setPromoPrice($productPrice->getPromoPrice());
|
||||
|
||||
$cartItem->save();
|
||||
}
|
||||
|
||||
// update the currency cart
|
||||
$cart->setCurrencyId($currency->getId());
|
||||
$cart->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* increase the quantity for an existing cartItem
|
||||
*
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
* @param CartItem $cartItem
|
||||
* @param float $quantity
|
||||
*
|
||||
* @throws \Exception
|
||||
* @throws \Propel\Runtime\Exception\PropelException
|
||||
* @return CartItem
|
||||
*/
|
||||
protected function updateQuantity(EventDispatcherInterface $dispatcher, CartItem $cartItem, $quantity)
|
||||
{
|
||||
$cartItem->setDisptacher($dispatcher);
|
||||
$cartItem->updateQuantity($quantity)
|
||||
->save();
|
||||
|
||||
return $cartItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* try to attach a new item to an existing cart
|
||||
*
|
||||
* @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,
|
||||
CartModel $cart,
|
||||
$productId,
|
||||
ProductSaleElements $productSaleElements,
|
||||
$quantity,
|
||||
ProductPriceTools $productPrices
|
||||
) {
|
||||
$cartItem = new CartItem();
|
||||
$cartItem->setDisptacher($dispatcher);
|
||||
$cartItem
|
||||
->setCart($cart)
|
||||
->setProductId($productId)
|
||||
->setProductSaleElementsId($productSaleElements->getId())
|
||||
->setQuantity($quantity)
|
||||
->setPrice($productPrices->getPrice())
|
||||
->setPromoPrice($productPrices->getPromoPrice())
|
||||
->setPromo($productSaleElements->getPromo())
|
||||
->setPriceEndOfLife(time() + ConfigQuery::read("cart.priceEOF", 60*60*24*30))
|
||||
->save();
|
||||
|
||||
return $cartItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* find a specific record in CartItem table using the Cart id, the product id
|
||||
* and the product_sale_elements id
|
||||
*
|
||||
* @param int $cartId
|
||||
* @param int $productId
|
||||
* @param int $productSaleElementsId
|
||||
* @return CartItem
|
||||
*
|
||||
* @deprecated this method is deprecated. Dispatch a TheliaEvents::CART_FINDITEM instead
|
||||
*/
|
||||
protected function findItem($cartId, $productId, $productSaleElementsId)
|
||||
{
|
||||
return CartItemQuery::create()
|
||||
->filterByCartId($cartId)
|
||||
->filterByProductId($productId)
|
||||
->filterByProductSaleElementsId($productSaleElementsId)
|
||||
->findOne();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a specific record in CartItem table using the current CartEvent
|
||||
*
|
||||
* @param CartEvent $event the cart event
|
||||
*/
|
||||
public function findCartItem(CartEvent $event)
|
||||
{
|
||||
if (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();
|
||||
}
|
||||
}
|
||||
234
core/lib/Thelia/Action/Category.php
Normal file
234
core/lib/Thelia/Action/Category.php
Normal file
@@ -0,0 +1,234 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Thelia\Action;
|
||||
|
||||
use Propel\Runtime\Propel;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
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;
|
||||
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\Model\CategoryAssociatedContent;
|
||||
use Thelia\Model\CategoryAssociatedContentQuery;
|
||||
use Thelia\Model\Map\CategoryTableMap;
|
||||
|
||||
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, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$category = new CategoryModel();
|
||||
|
||||
$category
|
||||
->setDispatcher($dispatcher)
|
||||
|
||||
->setLocale($event->getLocale())
|
||||
->setParent($event->getParent())
|
||||
->setVisible($event->getVisible())
|
||||
->setTitle($event->getTitle())
|
||||
|
||||
->save()
|
||||
;
|
||||
|
||||
$event->setCategory($category);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change a category
|
||||
*
|
||||
* @param \Thelia\Core\Event\Category\CategoryUpdateEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function update(CategoryUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $category = CategoryQuery::create()->findPk($event->getCategoryId())) {
|
||||
$category
|
||||
->setDispatcher($dispatcher)
|
||||
->setDefaultTemplateId($event->getDefaultTemplateId() == 0 ? null : $event->getDefaultTemplateId())
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
->setDescription($event->getDescription())
|
||||
->setChapo($event->getChapo())
|
||||
->setPostscriptum($event->getPostscriptum())
|
||||
|
||||
->setParent($event->getParent())
|
||||
->setVisible($event->getVisible())
|
||||
|
||||
->save();
|
||||
|
||||
$event->setCategory($category);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Change a Category SEO
|
||||
*
|
||||
* @param UpdateSeoEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
* @return Object
|
||||
*/
|
||||
public function updateSeo(UpdateSeoEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
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, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $category = CategoryQuery::create()->findPk($event->getCategoryId())) {
|
||||
$con = Propel::getWriteConnection(CategoryTableMap::DATABASE_NAME);
|
||||
$con->beginTransaction();
|
||||
|
||||
try {
|
||||
$fileList = ['images' => [], 'documentList' => []];
|
||||
|
||||
// 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 CategoryToggleVisibilityEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function toggleVisibility(CategoryToggleVisibilityEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$category = $event->getCategory();
|
||||
|
||||
$category
|
||||
->setDispatcher($dispatcher)
|
||||
->setVisible($category->getVisible() ? false : true)
|
||||
->save()
|
||||
;
|
||||
|
||||
$event->setCategory($category);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(CategoryQuery::create(), $event, $dispatcher);
|
||||
}
|
||||
|
||||
public function addContent(CategoryAddContentEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (CategoryAssociatedContentQuery::create()
|
||||
->filterByContentId($event->getContentId())
|
||||
->filterByCategory($event->getCategory())->count() <= 0) {
|
||||
$content = new CategoryAssociatedContent();
|
||||
|
||||
$content
|
||||
->setDispatcher($dispatcher)
|
||||
->setCategory($event->getCategory())
|
||||
->setContentId($event->getContentId())
|
||||
->save()
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
public function removeContent(CategoryDeleteContentEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$content = CategoryAssociatedContentQuery::create()
|
||||
->filterByContentId($event->getContentId())
|
||||
->filterByCategory($event->getCategory())->findOne()
|
||||
;
|
||||
|
||||
if ($content !== null) {
|
||||
$content
|
||||
->setDispatcher($dispatcher)
|
||||
->delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::CATEGORY_CREATE => array("create", 128),
|
||||
TheliaEvents::CATEGORY_UPDATE => array("update", 128),
|
||||
TheliaEvents::CATEGORY_DELETE => array("delete", 128),
|
||||
TheliaEvents::CATEGORY_TOGGLE_VISIBILITY => array("toggleVisibility", 128),
|
||||
|
||||
TheliaEvents::CATEGORY_UPDATE_POSITION => array("updatePosition", 128),
|
||||
TheliaEvents::CATEGORY_UPDATE_SEO => array("updateSeo", 128),
|
||||
|
||||
TheliaEvents::CATEGORY_ADD_CONTENT => array("addContent", 128),
|
||||
TheliaEvents::CATEGORY_REMOVE_CONTENT => array("removeContent", 128),
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
128
core/lib/Thelia/Action/Config.php
Normal file
128
core/lib/Thelia/Action/Config.php
Normal file
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Thelia\Action;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Core\Event\Config\ConfigCreateEvent;
|
||||
use Thelia\Core\Event\Config\ConfigDeleteEvent;
|
||||
use Thelia\Core\Event\Config\ConfigUpdateEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Model\Config as ConfigModel;
|
||||
use Thelia\Model\ConfigQuery;
|
||||
|
||||
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, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$config = new ConfigModel();
|
||||
|
||||
$config->setDispatcher($dispatcher)
|
||||
->setName($event->getEventName())
|
||||
->setValue($event->getValue())
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
->setHidden($event->getHidden())
|
||||
->setSecured($event->getSecured())
|
||||
->save();
|
||||
|
||||
$event->setConfig($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change a configuration entry value
|
||||
*
|
||||
* @param \Thelia\Core\Event\Config\ConfigUpdateEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function setValue(ConfigUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $config = ConfigQuery::create()->findPk($event->getConfigId())) {
|
||||
if ($event->getValue() !== $config->getValue()) {
|
||||
$config->setDispatcher($dispatcher)->setValue($event->getValue())->save();
|
||||
|
||||
$event->setConfig($config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Change a configuration entry
|
||||
*
|
||||
* @param \Thelia\Core\Event\Config\ConfigUpdateEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function modify(ConfigUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $config = ConfigQuery::create()->findPk($event->getConfigId())) {
|
||||
$config->setDispatcher($dispatcher)
|
||||
->setName($event->getEventName())
|
||||
->setValue($event->getValue())
|
||||
->setHidden($event->getHidden())
|
||||
->setSecured($event->getSecured())
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
->setDescription($event->getDescription())
|
||||
->setChapo($event->getChapo())
|
||||
->setPostscriptum($event->getPostscriptum())
|
||||
->save();
|
||||
|
||||
$event->setConfig($config);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a configuration entry
|
||||
*
|
||||
* @param \Thelia\Core\Event\Config\ConfigDeleteEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function delete(ConfigDeleteEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== ($config = ConfigQuery::create()->findPk($event->getConfigId()))) {
|
||||
if (!$config->getSecured()) {
|
||||
$config->setDispatcher($dispatcher)->delete();
|
||||
|
||||
$event->setConfig($config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::CONFIG_CREATE => array(
|
||||
"create", 128
|
||||
), TheliaEvents::CONFIG_SETVALUE => array(
|
||||
"setValue", 128
|
||||
), TheliaEvents::CONFIG_UPDATE => array(
|
||||
"modify", 128
|
||||
), TheliaEvents::CONFIG_DELETE => array(
|
||||
"delete", 128
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
228
core/lib/Thelia/Action/Content.php
Normal file
228
core/lib/Thelia/Action/Content.php
Normal file
@@ -0,0 +1,228 @@
|
||||
<?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\Exception\PropelException;
|
||||
use Propel\Runtime\Propel;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
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\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 <manu@raynaud.io>
|
||||
*/
|
||||
class Content extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
public function create(ContentCreateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$content = (new ContentModel)
|
||||
->setDispatcher($dispatcher)
|
||||
->setVisible($event->getVisible())
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
->create($event->getDefaultFolder())
|
||||
;
|
||||
|
||||
$event->setContent($content);
|
||||
}
|
||||
|
||||
/**
|
||||
* process update content
|
||||
*
|
||||
* @param ContentUpdateEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
* @throws PropelException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function update(ContentUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $content = ContentQuery::create()->findPk($event->getContentId())) {
|
||||
$con = Propel::getWriteConnection(ContentTableMap::DATABASE_NAME);
|
||||
$con->beginTransaction();
|
||||
|
||||
$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->setDefaultFolder($event->getDefaultFolder());
|
||||
|
||||
$event->setContent($content);
|
||||
$con->commit();
|
||||
} catch (PropelException $e) {
|
||||
$con->rollBack();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Change Content SEO
|
||||
*
|
||||
* @param UpdateSeoEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
* @return Object
|
||||
*/
|
||||
public function updateSeo(UpdateSeoEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
return $this->genericUpdateSeo(ContentQuery::create(), $event, $dispatcher);
|
||||
}
|
||||
|
||||
public function updatePosition(UpdatePositionEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$this->genericUpdateDelegatePosition(
|
||||
ContentFolderQuery::create()
|
||||
->filterByContentId($event->getObjectId())
|
||||
->filterByFolderId($event->getReferrerId()),
|
||||
$event,
|
||||
$dispatcher
|
||||
);
|
||||
}
|
||||
|
||||
public function toggleVisibility(ContentToggleVisibilityEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$content = $event->getContent();
|
||||
|
||||
$content
|
||||
->setDispatcher($dispatcher)
|
||||
->setVisible(!$content->getVisible())
|
||||
->save();
|
||||
|
||||
$event->setContent($content);
|
||||
}
|
||||
|
||||
public function delete(ContentDeleteEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $content = ContentQuery::create()->findPk($event->getContentId())) {
|
||||
$con = Propel::getWriteConnection(ContentTableMap::DATABASE_NAME);
|
||||
$con->beginTransaction();
|
||||
|
||||
try {
|
||||
$fileList = ['images' => [], 'documentList' => []];
|
||||
|
||||
$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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* associate a folder to a content if the association already does not exists
|
||||
*
|
||||
* @param ContentAddFolderEvent $event
|
||||
*/
|
||||
public function addFolder(ContentAddFolderEvent $event)
|
||||
{
|
||||
if (ContentFolderQuery::create()
|
||||
->filterByContent($event->getContent())
|
||||
->filterByFolderId($event->getFolderId())
|
||||
->count() <= 0
|
||||
) {
|
||||
$contentFolder = (new ContentFolder())
|
||||
->setFolderId($event->getFolderId())
|
||||
->setContent($event->getContent())
|
||||
->setDefaultFolder(false);
|
||||
|
||||
$contentFolder
|
||||
->setPosition($contentFolder->getNextPosition())
|
||||
->save();
|
||||
}
|
||||
}
|
||||
|
||||
public function removeFolder(ContentRemoveFolderEvent $event)
|
||||
{
|
||||
$contentFolder = ContentFolderQuery::create()
|
||||
->filterByContent($event->getContent())
|
||||
->filterByFolderId($event->getFolderId())
|
||||
->findOne();
|
||||
|
||||
if (null !== $contentFolder) {
|
||||
$contentFolder->delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
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),
|
||||
|
||||
TheliaEvents::CONTENT_UPDATE_POSITION => array('updatePosition', 128),
|
||||
TheliaEvents::CONTENT_UPDATE_SEO => array('updateSeo', 128),
|
||||
|
||||
TheliaEvents::CONTENT_ADD_FOLDER => array('addFolder', 128),
|
||||
TheliaEvents::CONTENT_REMOVE_FOLDER => array('removeFolder', 128),
|
||||
);
|
||||
}
|
||||
}
|
||||
121
core/lib/Thelia/Action/Country.php
Normal file
121
core/lib/Thelia/Action/Country.php
Normal file
@@ -0,0 +1,121 @@
|
||||
<?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\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;
|
||||
use Thelia\Model\CountryQuery;
|
||||
|
||||
/**
|
||||
* Class Country
|
||||
* @package Thelia\Action
|
||||
* @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())
|
||||
->setDescription($event->getDescription())
|
||||
->save();
|
||||
|
||||
$event->setCountry($country);
|
||||
}
|
||||
}
|
||||
|
||||
public function delete(CountryDeleteEvent $event)
|
||||
{
|
||||
if (null !== $country = CountryQuery::create()->findPk($event->getCountryId())) {
|
||||
$country->delete();
|
||||
|
||||
$event->setCountry($country);
|
||||
}
|
||||
}
|
||||
|
||||
public function toggleDefault(CountryToggleDefaultEvent $event)
|
||||
{
|
||||
if (null !== $country = CountryQuery::create()->findPk($event->getCountryId())) {
|
||||
$country->toggleDefault();
|
||||
|
||||
$event->setCountry($country);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle Country visibility
|
||||
*
|
||||
* @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()
|
||||
{
|
||||
return array(
|
||||
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_VISIBILITY => array('toggleVisibility', 128)
|
||||
);
|
||||
}
|
||||
}
|
||||
410
core/lib/Thelia/Action/Coupon.php
Normal file
410
core/lib/Thelia/Action/Coupon.php
Normal file
@@ -0,0 +1,410 @@
|
||||
<?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\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\Coupon\CouponFactory;
|
||||
use Thelia\Coupon\CouponManager;
|
||||
use Thelia\Coupon\Type\CouponInterface;
|
||||
use Thelia\Model\Coupon as CouponModel;
|
||||
use Thelia\Model\CouponCountry;
|
||||
use Thelia\Model\CouponCountryQuery;
|
||||
use Thelia\Model\CouponModule;
|
||||
use Thelia\Model\CouponModuleQuery;
|
||||
use Thelia\Model\CouponQuery;
|
||||
use Thelia\Model\Map\OrderCouponTableMap;
|
||||
use Thelia\Model\OrderCoupon;
|
||||
use Thelia\Model\OrderCouponCountry;
|
||||
use Thelia\Model\OrderCouponModule;
|
||||
|
||||
/**
|
||||
* Process Coupon Events
|
||||
*
|
||||
* @package Coupon
|
||||
* @author Guillaume MOREL <gmorel@openstudio.fr>, Franck Allimant <franck@cqfdev.fr>
|
||||
*
|
||||
*/
|
||||
class Coupon extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
/** @var RequestStack */
|
||||
protected $requestStack;
|
||||
|
||||
/** @var CouponFactory $couponFactory */
|
||||
protected $couponFactory;
|
||||
|
||||
/** @var CouponManager $couponManager */
|
||||
protected $couponManager;
|
||||
|
||||
/** @var ConditionInterface $noConditionRule */
|
||||
protected $noConditionRule;
|
||||
|
||||
/** @var ConditionFactory $conditionFactory */
|
||||
protected $conditionFactory;
|
||||
|
||||
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;
|
||||
$this->conditionFactory = $conditionFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$coupon = new CouponModel();
|
||||
|
||||
$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, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$coupon = $event->getCouponModel();
|
||||
|
||||
$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, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$modelCoupon = $event->getCouponModel();
|
||||
|
||||
$this->createOrUpdateCondition($modelCoupon, $event, $dispatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all coupons in session.
|
||||
*
|
||||
* @param Event $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function clearAllCoupons(Event $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
// Tell coupons to clear any data they may have stored
|
||||
$this->couponManager->clear();
|
||||
|
||||
$this->getSession()->setConsumedCoupons(array());
|
||||
|
||||
$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, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$totalDiscount = 0;
|
||||
$isValid = false;
|
||||
|
||||
/** @var CouponInterface $coupon */
|
||||
$coupon = $this->couponFactory->buildCouponFromCode($event->getCode());
|
||||
|
||||
if ($coupon) {
|
||||
$isValid = $coupon->isMatching();
|
||||
|
||||
if ($isValid) {
|
||||
$this->couponManager->pushCouponInSession($event->getCode());
|
||||
$totalDiscount = $this->couponManager->getDiscount();
|
||||
|
||||
$this->getSession()
|
||||
->getSessionCart($dispatcher)
|
||||
->setDiscount($totalDiscount)
|
||||
->save();
|
||||
|
||||
$this->getSession()
|
||||
->getOrder()
|
||||
->setDiscount($totalDiscount)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
$event->setIsValid($isValid);
|
||||
$event->setDiscount($totalDiscount);
|
||||
}
|
||||
|
||||
public function updateOrderDiscount(Event $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$discount = $this->couponManager->getDiscount();
|
||||
|
||||
$this->getSession()
|
||||
->getSessionCart($dispatcher)
|
||||
->setDiscount($discount)
|
||||
->save();
|
||||
|
||||
$this->getSession()
|
||||
->getOrder()
|
||||
->setDiscount($discount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the Model and delegate the create or delete action
|
||||
* Feed the Event with the updated model
|
||||
*
|
||||
* @param CouponModel $coupon Model to save
|
||||
* @param CouponCreateOrUpdateEvent $event Event containing data
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
protected function createOrUpdate(CouponModel $coupon, CouponCreateOrUpdateEvent $event, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$coupon->setDispatcher($dispatcher);
|
||||
|
||||
// Set default condition if none found
|
||||
/** @var ConditionInterface $noConditionRule */
|
||||
$noConditionRule = $this->noConditionRule;
|
||||
/** @var ConditionFactory $conditionFactory */
|
||||
$conditionFactory = $this->conditionFactory;
|
||||
$couponRuleCollection = new ConditionCollection();
|
||||
$couponRuleCollection[] = $noConditionRule;
|
||||
$defaultSerializedRule = $conditionFactory->serializeConditionCollection(
|
||||
$couponRuleCollection
|
||||
);
|
||||
|
||||
$coupon->createOrUpdate(
|
||||
$event->getCode(),
|
||||
$event->getTitle(),
|
||||
$event->getEffects(),
|
||||
$event->getServiceId(),
|
||||
$event->isRemovingPostage(),
|
||||
$event->getShortDescription(),
|
||||
$event->getDescription(),
|
||||
$event->isEnabled(),
|
||||
$event->getExpirationDate(),
|
||||
$event->isAvailableOnSpecialOffers(),
|
||||
$event->isCumulative(),
|
||||
$event->getMaxUsage(),
|
||||
$defaultSerializedRule,
|
||||
$event->getLocale(),
|
||||
$event->getFreeShippingForCountries(),
|
||||
$event->getFreeShippingForMethods(),
|
||||
$event->getPerCustomerUsageCount(),
|
||||
$event->getStartDate()
|
||||
);
|
||||
|
||||
$event->setCouponModel($coupon);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the Model and delegate the create or delete action
|
||||
* Feed the Event with the updated model
|
||||
*
|
||||
* @param CouponModel $coupon Model to save
|
||||
* @param CouponCreateOrUpdateEvent $event Event containing data
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
protected function createOrUpdateCondition(CouponModel $coupon, CouponCreateOrUpdateEvent $event, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$coupon->setDispatcher($dispatcher);
|
||||
|
||||
/** @var ConditionFactory $conditionFactory */
|
||||
$conditionFactory = $this->conditionFactory;
|
||||
|
||||
$coupon->createOrUpdateConditions(
|
||||
$conditionFactory->serializeConditionCollection($event->getConditions()),
|
||||
$event->getLocale()
|
||||
);
|
||||
|
||||
$event->setCouponModel($coupon);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Thelia\Core\Event\Order\OrderEvent $event
|
||||
*/
|
||||
public function testFreePostage(OrderEvent $event)
|
||||
{
|
||||
$order = $event->getOrder();
|
||||
|
||||
if ($this->couponManager->isCouponRemovingPostage($order)) {
|
||||
$order->setPostage(0);
|
||||
|
||||
$event->setOrder($order);
|
||||
|
||||
$event->stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Thelia\Core\Event\Order\OrderEvent $event
|
||||
*
|
||||
* @throws \Exception if something goes wrong.
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function afterOrder(OrderEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
/** @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->getCode());
|
||||
$couponModel->setLocale($this->getSession()->getLang()->getLocale());
|
||||
|
||||
/* decrease coupon quantity */
|
||||
$this->couponManager->decrementQuantity($couponModel, $event->getOrder()->getCustomerId());
|
||||
|
||||
/* memorize coupon */
|
||||
$orderCoupon = new OrderCoupon();
|
||||
$orderCoupon->setOrder($event->getOrder())
|
||||
->setCode($couponModel->getCode())
|
||||
->setType($couponModel->getType())
|
||||
->setAmount($couponModel->getAmount())
|
||||
|
||||
->setTitle($couponModel->getTitle())
|
||||
->setShortDescription($couponModel->getShortDescription())
|
||||
->setDescription($couponModel->getDescription())
|
||||
|
||||
->setStartDate($couponModel->getStartDate())
|
||||
->setExpirationDate($couponModel->getExpirationDate())
|
||||
->setIsCumulative($couponModel->getIsCumulative())
|
||||
->setIsRemovingPostage($couponModel->getIsRemovingPostage())
|
||||
->setIsAvailableOnSpecialOffers($couponModel->getIsAvailableOnSpecialOffers())
|
||||
->setSerializedConditions($couponModel->getSerializedConditions())
|
||||
->setPerCustomerUsageCount($couponModel->getPerCustomerUsageCount())
|
||||
;
|
||||
$orderCoupon->save();
|
||||
|
||||
// Copy order coupon free shipping data for countries and modules
|
||||
$couponCountries = CouponCountryQuery::create()->filterByCouponId($couponModel->getId())->find();
|
||||
|
||||
/** @var CouponCountry $couponCountry */
|
||||
foreach ($couponCountries as $couponCountry) {
|
||||
$occ = new OrderCouponCountry();
|
||||
|
||||
$occ
|
||||
->setCouponId($orderCoupon->getId())
|
||||
->setCountryId($couponCountry->getCountryId())
|
||||
->save();
|
||||
;
|
||||
}
|
||||
|
||||
$couponModules = CouponModuleQuery::create()->filterByCouponId($couponModel->getId())->find();
|
||||
|
||||
/** @var CouponModule $couponModule */
|
||||
foreach ($couponModules as $couponModule) {
|
||||
$ocm = new OrderCouponModule();
|
||||
|
||||
$ocm
|
||||
->setCouponId($orderCoupon->getId())
|
||||
->setModuleId($couponModule->getModuleId())
|
||||
->save();
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
$con->commit();
|
||||
} catch (\Exception $ex) {
|
||||
$con->rollBack();
|
||||
|
||||
throw($ex);
|
||||
}
|
||||
}
|
||||
|
||||
// Clear all coupons.
|
||||
$dispatcher->dispatch(TheliaEvents::COUPON_CLEAR_ALL);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@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::CART_ADDITEM => array("updateOrderDiscount", 10),
|
||||
TheliaEvents::CART_UPDATEITEM => array("updateOrderDiscount", 10),
|
||||
TheliaEvents::CART_DELETEITEM => array("updateOrderDiscount", 10),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the session from the current request
|
||||
*
|
||||
* @return \Thelia\Core\HttpFoundation\Session\Session
|
||||
*/
|
||||
protected function getSession()
|
||||
{
|
||||
return $this->requestStack->getCurrentRequest()->getSession();
|
||||
}
|
||||
}
|
||||
219
core/lib/Thelia/Action/Currency.php
Normal file
219
core/lib/Thelia/Action/Currency.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\Action;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Core\Event\Currency\CurrencyCreateEvent;
|
||||
use Thelia\Core\Event\Currency\CurrencyDeleteEvent;
|
||||
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, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$currency = new CurrencyModel();
|
||||
|
||||
$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()
|
||||
;
|
||||
|
||||
$event->setCurrency($currency);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change a currency
|
||||
*
|
||||
* @param \Thelia\Core\Event\Currency\CurrencyUpdateEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function update(CurrencyUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $currency = CurrencyQuery::create()->findPk($event->getCurrencyId())) {
|
||||
$currency
|
||||
->setDispatcher($dispatcher)
|
||||
|
||||
->setLocale($event->getLocale())
|
||||
->setName($event->getCurrencyName())
|
||||
->setSymbol($event->getSymbol())
|
||||
->setFormat($event->getFormat())
|
||||
->setRate($event->getRate())
|
||||
->setCode(strtoupper($event->getCode()))
|
||||
|
||||
->save();
|
||||
|
||||
$event->setCurrency($currency);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default currency
|
||||
*
|
||||
* @param CurrencyUpdateEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
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($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, $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($dispatcher)
|
||||
->delete()
|
||||
;
|
||||
|
||||
$event->setCurrency($currency);
|
||||
}
|
||||
}
|
||||
|
||||
public function updateRates(CurrencyUpdateRateEvent $event)
|
||||
{
|
||||
if (null === $defaultCurrency = CurrencyQuery::create()->findOneByByDefault(true)) {
|
||||
throw new \RuntimeException('Unable to find a default currency, please define a default currency.');
|
||||
}
|
||||
|
||||
$defaultCurrency->setRate(1)->save();
|
||||
|
||||
$currencies = CurrencyQuery::create()->filterByByDefault(false);
|
||||
$baseValue = new Number('1');
|
||||
|
||||
/** @var \Thelia\Model\Currency $currency */
|
||||
foreach ($currencies as $currency) {
|
||||
try {
|
||||
$rate = $this->currencyConverter
|
||||
->from($defaultCurrency->getCode())
|
||||
->to($currency->getCode())
|
||||
->convert($baseValue);
|
||||
|
||||
$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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes position, selecting absolute ou relative change.
|
||||
*
|
||||
* @param UpdatePositionEvent $event
|
||||
* @param string $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function updatePosition(UpdatePositionEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$this->genericUpdatePosition(CurrencyQuery::create(), $event, $dispatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::CURRENCY_CREATE => array("create", 128),
|
||||
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)
|
||||
);
|
||||
}
|
||||
}
|
||||
215
core/lib/Thelia/Action/Customer.php
Normal file
215
core/lib/Thelia/Action/Customer.php
Normal file
@@ -0,0 +1,215 @@
|
||||
<?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\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\Translation\Translator;
|
||||
use Thelia\Exception\CustomerException;
|
||||
use Thelia\Mailer\MailerFactory;
|
||||
use Thelia\Model\Customer as CustomerModel;
|
||||
use Thelia\Model\CustomerQuery;
|
||||
use Thelia\Tools\Password;
|
||||
|
||||
/**
|
||||
*
|
||||
* customer class where all actions are managed
|
||||
*
|
||||
* Class Customer
|
||||
* @package Thelia\Action
|
||||
* @author Manuel Raynaud <manu@raynaud.io>
|
||||
*/
|
||||
class Customer extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
/** @var SecurityContext */
|
||||
protected $securityContext;
|
||||
|
||||
/** @var MailerFactory */
|
||||
protected $mailer;
|
||||
|
||||
public function __construct(SecurityContext $securityContext, MailerFactory $mailer)
|
||||
{
|
||||
$this->securityContext = $securityContext;
|
||||
$this->mailer = $mailer;
|
||||
}
|
||||
|
||||
public function create(CustomerCreateOrUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$customer = new CustomerModel();
|
||||
|
||||
$plainPassword = $event->getPassword();
|
||||
|
||||
$this->createOrUpdateCustomer($customer, $event, $dispatcher);
|
||||
|
||||
if ($event->getNotifyCustomerOfAccountCreation()) {
|
||||
$this->mailer->sendEmailToCustomer('customer_account_created', $customer, [ 'password' => $plainPassword ]);
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
if ($event->getFirstname() !== null) {
|
||||
$customer->setFirstname($event->getFirstname());
|
||||
}
|
||||
|
||||
if ($event->getLastname() !== null) {
|
||||
$customer->setLastname($event->getLastname());
|
||||
}
|
||||
|
||||
if ($event->getEmail() !== null) {
|
||||
$customer->setEmail($event->getEmail(), $event->getEmailUpdateAllowed());
|
||||
}
|
||||
|
||||
if ($event->getPassword() !== null) {
|
||||
$customer->setPassword($event->getPassword());
|
||||
}
|
||||
|
||||
if ($event->getReseller() !== null) {
|
||||
$customer->setReseller($event->getReseller());
|
||||
}
|
||||
|
||||
if ($event->getSponsor() !== null) {
|
||||
$customer->setSponsor($event->getSponsor());
|
||||
}
|
||||
|
||||
if ($event->getDiscount() !== null) {
|
||||
$customer->setDiscount($event->getDiscount());
|
||||
}
|
||||
|
||||
$customer->save();
|
||||
|
||||
$event->setCustomer($customer);
|
||||
}
|
||||
|
||||
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"));
|
||||
}
|
||||
|
||||
$customer->delete();
|
||||
}
|
||||
}
|
||||
|
||||
private function createOrUpdateCustomer(CustomerModel $customer, CustomerCreateOrUpdateEvent $event, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$customer->setDispatcher($dispatcher);
|
||||
|
||||
$customer->createOrUpdate(
|
||||
$event->getTitle(),
|
||||
$event->getFirstname(),
|
||||
$event->getLastname(),
|
||||
$event->getAddress1(),
|
||||
$event->getAddress2(),
|
||||
$event->getAddress3(),
|
||||
$event->getPhone(),
|
||||
$event->getCellphone(),
|
||||
$event->getZipcode(),
|
||||
$event->getCity(),
|
||||
$event->getCountry(),
|
||||
$event->getEmail(),
|
||||
$event->getPassword(),
|
||||
$event->getLangId(),
|
||||
$event->getReseller(),
|
||||
$event->getSponsor(),
|
||||
$event->getDiscount(),
|
||||
$event->getCompany(),
|
||||
$event->getRef(),
|
||||
$event->getEmailUpdateAllowed(),
|
||||
$event->getState()
|
||||
);
|
||||
|
||||
$event->setCustomer($customer);
|
||||
}
|
||||
|
||||
public function login(CustomerLoginEvent $event)
|
||||
{
|
||||
$customer = $event->getCustomer();
|
||||
|
||||
if (method_exists($customer, 'clearDispatcher')) {
|
||||
$customer->clearDispatcher();
|
||||
}
|
||||
$this->securityContext->setCustomerUser($event->getCustomer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform user logout. The user is redirected to the provided view, if any.
|
||||
*
|
||||
* @param ActionEvent $event
|
||||
*/
|
||||
public function logout(/** @noinspection PhpUnusedParameterInspection */ ActionEvent $event)
|
||||
{
|
||||
$this->securityContext->clearCustomerUser();
|
||||
}
|
||||
|
||||
public function lostPassword(LostPasswordEvent $event)
|
||||
{
|
||||
if (null !== $customer = CustomerQuery::create()->filterByEmail($event->getEmail())->findOne()) {
|
||||
$password = Password::generateRandom(8);
|
||||
|
||||
$customer
|
||||
->setPassword($password)
|
||||
->save()
|
||||
;
|
||||
|
||||
$this->mailer->sendEmailToCustomer('lost_password', $customer, ['password' => $password]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::CUSTOMER_CREATEACCOUNT => array('create', 128),
|
||||
TheliaEvents::CUSTOMER_UPDATEACCOUNT => array('modify', 128),
|
||||
TheliaEvents::CUSTOMER_UPDATEPROFILE => array('updateProfile', 128),
|
||||
TheliaEvents::CUSTOMER_LOGOUT => array('logout', 128),
|
||||
TheliaEvents::CUSTOMER_LOGIN => array('login', 128),
|
||||
TheliaEvents::CUSTOMER_DELETEACCOUNT => array('delete', 128),
|
||||
TheliaEvents::LOST_PASSWORD => array('lostPassword', 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]
|
||||
];
|
||||
}
|
||||
}
|
||||
125
core/lib/Thelia/Action/Document.php
Normal file
125
core/lib/Thelia/Action/Document.php
Normal file
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
namespace Thelia\Action;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Core\Event\Document\DocumentEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Exception\DocumentException;
|
||||
use Thelia\Model\ConfigQuery;
|
||||
use Thelia\Tools\URL;
|
||||
|
||||
/**
|
||||
*
|
||||
* Document management actions. This class handles document processing an caching.
|
||||
*
|
||||
* Basically, documents are stored outside the web space (by default in local/media/documents),
|
||||
* and cached in the web space (by default in web/local/documents).
|
||||
*
|
||||
* In the documents caches directory, a subdirectory for documents categories (eg. product, category, folder, etc.) is
|
||||
* automatically created, and the cached document is created here. Plugin may use their own subdirectory as required.
|
||||
*
|
||||
* The cached document name contains a hash of the processing options, and the original (normalized) name of the document.
|
||||
*
|
||||
* A copy (or symbolic link, by default) of the original document is always created in the cache, so that the full
|
||||
* resolution document is always available.
|
||||
*
|
||||
* If a problem occurs, an DocumentException may be thrown.
|
||||
*
|
||||
* @package Thelia\Action
|
||||
* @author Franck Allimant <franck@cqfdev.fr>
|
||||
*
|
||||
*/
|
||||
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' . DS . 'documents');
|
||||
}
|
||||
|
||||
/**
|
||||
* Process document and write the result in the document cache.
|
||||
*
|
||||
* When the original document is required, create either a symbolic link with the
|
||||
* original document in the cache dir, or copy it in the cache dir if it's not already done.
|
||||
*
|
||||
* This method updates the cache_file_path and file_url attributes of the event
|
||||
*
|
||||
* @param DocumentEvent $event Event
|
||||
*
|
||||
* @throws \Thelia\Exception\DocumentException
|
||||
* @throws \InvalidArgumentException , DocumentException
|
||||
*/
|
||||
public function processDocument(DocumentEvent $event)
|
||||
{
|
||||
$subdir = $event->getCacheSubdirectory();
|
||||
$sourceFile = $event->getSourceFilepath();
|
||||
|
||||
if (null == $subdir || null == $sourceFile) {
|
||||
throw new \InvalidArgumentException("Cache sub-directory and source file path cannot be null");
|
||||
}
|
||||
|
||||
$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(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));
|
||||
}
|
||||
} else {
|
||||
// mode = 'copy'
|
||||
if (false === @copy($sourceFile, $originalDocumentPathInCache)) {
|
||||
throw new DocumentException(sprintf("Failed to copy %s in %s document cache directory", basename($sourceFile), $subdir));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the document URL
|
||||
$documentUrl = $this->getCacheFileURL($subdir, basename($originalDocumentPathInCache));
|
||||
|
||||
// Update the event with file path and file URL
|
||||
$event->setDocumentPath($documentUrl);
|
||||
$event->setDocumentUrl(URL::getInstance()->absoluteUrl($documentUrl, null, URL::PATH_TO_FILE));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::DOCUMENT_PROCESS => array("processDocument", 128),
|
||||
|
||||
// Implemented in parent class BaseCachedFile
|
||||
TheliaEvents::DOCUMENT_CLEAR_CACHE => array("clearCache", 128),
|
||||
TheliaEvents::DOCUMENT_DELETE => array("deleteFile", 128),
|
||||
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),
|
||||
);
|
||||
}
|
||||
}
|
||||
79
core/lib/Thelia/Action/Export.php
Normal file
79
core/lib/Thelia/Action/Export.php
Normal file
@@ -0,0 +1,79 @@
|
||||
<?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\TheliaEvents;
|
||||
use Thelia\Core\Event\UpdatePositionEvent;
|
||||
use Thelia\Handler\ExportHandler;
|
||||
use Thelia\Model\ExportCategoryQuery;
|
||||
use Thelia\Model\ExportQuery;
|
||||
|
||||
/**
|
||||
* Class Export
|
||||
* @author Jérôme Billiras <jbilliras@openstudio.fr>
|
||||
*/
|
||||
class Export extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
/**
|
||||
* @var \Thelia\Handler\ExportHandler The export handler
|
||||
*/
|
||||
protected $handler;
|
||||
|
||||
/**
|
||||
* @param \Thelia\Handler\ExportHandler $exportHandler The export handler
|
||||
*/
|
||||
public function __construct(ExportHandler $exportHandler)
|
||||
{
|
||||
$this->handler = $exportHandler;
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return [
|
||||
TheliaEvents::EXPORT_CHANGE_POSITION => [
|
||||
['exportChangePosition', 128]
|
||||
],
|
||||
TheliaEvents::EXPORT_CATEGORY_CHANGE_POSITION => [
|
||||
['exportCategoryChangePosition', 128]
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle export change position event
|
||||
*
|
||||
* @param UpdatePositionEvent $updatePositionEvent
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function exportChangePosition(UpdatePositionEvent $updatePositionEvent, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$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);
|
||||
}
|
||||
}
|
||||
159
core/lib/Thelia/Action/Feature.php
Normal file
159
core/lib/Thelia/Action/Feature.php
Normal file
@@ -0,0 +1,159 @@
|
||||
<?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\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;
|
||||
use Thelia\Core\Event\UpdatePositionEvent;
|
||||
use Thelia\Core\Event\Feature\FeatureEvent;
|
||||
use Thelia\Model\FeatureTemplate;
|
||||
use Thelia\Model\FeatureTemplateQuery;
|
||||
use Thelia\Model\TemplateQuery;
|
||||
|
||||
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, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$feature = new FeatureModel();
|
||||
|
||||
$feature
|
||||
->setDispatcher($dispatcher)
|
||||
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
|
||||
->save()
|
||||
;
|
||||
|
||||
$event->setFeature($feature);
|
||||
|
||||
// Add atribute to all product templates if required
|
||||
if ($event->getAddToAllTemplates() != 0) {
|
||||
$this->doAddToAllTemplates($feature);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Change a product feature
|
||||
*
|
||||
* @param \Thelia\Core\Event\Feature\FeatureUpdateEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function update(FeatureUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $feature = FeatureQuery::create()->findPk($event->getFeatureId())) {
|
||||
$feature
|
||||
->setDispatcher($dispatcher)
|
||||
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
->setDescription($event->getDescription())
|
||||
->setChapo($event->getChapo())
|
||||
->setPostscriptum($event->getPostscriptum())
|
||||
|
||||
->save();
|
||||
|
||||
$event->setFeature($feature);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a product feature entry
|
||||
*
|
||||
* @param FeatureDeleteEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function delete(FeatureDeleteEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== ($feature = FeatureQuery::create()->findPk($event->getFeatureId()))) {
|
||||
$feature
|
||||
->setDispatcher($dispatcher)
|
||||
->delete()
|
||||
;
|
||||
|
||||
$event->setFeature($feature);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(FeatureQuery::create(), $event, $dispatcher);
|
||||
}
|
||||
|
||||
protected function doAddToAllTemplates(FeatureModel $feature)
|
||||
{
|
||||
$templates = TemplateQuery::create()->find();
|
||||
|
||||
foreach ($templates as $template) {
|
||||
$feature_template = new FeatureTemplate();
|
||||
|
||||
if (null === FeatureTemplateQuery::create()->filterByFeature($feature)->filterByTemplate($template)->findOne()) {
|
||||
$feature_template
|
||||
->setFeature($feature)
|
||||
->setTemplate($template)
|
||||
->save()
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function addToAllTemplates(FeatureEvent $event)
|
||||
{
|
||||
$this->doAddToAllTemplates($event->getFeature());
|
||||
}
|
||||
|
||||
public function removeFromAllTemplates(FeatureEvent $event)
|
||||
{
|
||||
// Delete this feature from all product templates
|
||||
FeatureTemplateQuery::create()->filterByFeature($event->getFeature())->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::FEATURE_CREATE => array("create", 128),
|
||||
TheliaEvents::FEATURE_UPDATE => array("update", 128),
|
||||
TheliaEvents::FEATURE_DELETE => array("delete", 128),
|
||||
TheliaEvents::FEATURE_UPDATE_POSITION => array("updatePosition", 128),
|
||||
|
||||
TheliaEvents::FEATURE_REMOVE_FROM_ALL_TEMPLATES => array("removeFromAllTemplates", 128),
|
||||
TheliaEvents::FEATURE_ADD_TO_ALL_TEMPLATES => array("addToAllTemplates", 128),
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
119
core/lib/Thelia/Action/FeatureAv.php
Normal file
119
core/lib/Thelia/Action/FeatureAv.php
Normal file
@@ -0,0 +1,119 @@
|
||||
<?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\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;
|
||||
use Thelia\Core\Event\UpdatePositionEvent;
|
||||
|
||||
class FeatureAv extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
/**
|
||||
* Create a new feature entry
|
||||
*
|
||||
* @param FeatureAvCreateEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function create(FeatureAvCreateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$feature = new FeatureAvModel();
|
||||
|
||||
$feature
|
||||
->setDispatcher($dispatcher)
|
||||
|
||||
->setFeatureId($event->getFeatureId())
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
|
||||
->save()
|
||||
;
|
||||
|
||||
$event->setFeatureAv($feature);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change a product feature
|
||||
*
|
||||
* @param FeatureAvUpdateEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function update(FeatureAvUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $feature = FeatureAvQuery::create()->findPk($event->getFeatureAvId())) {
|
||||
$feature
|
||||
->setDispatcher($dispatcher)
|
||||
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
->setDescription($event->getDescription())
|
||||
->setChapo($event->getChapo())
|
||||
->setPostscriptum($event->getPostscriptum())
|
||||
|
||||
->save();
|
||||
|
||||
$event->setFeatureAv($feature);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a product feature entry
|
||||
*
|
||||
* @param FeatureAvDeleteEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function delete(FeatureAvDeleteEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== ($feature = FeatureAvQuery::create()->findPk($event->getFeatureAvId()))) {
|
||||
$feature
|
||||
->setDispatcher($dispatcher)
|
||||
->delete()
|
||||
;
|
||||
|
||||
$event->setFeatureAv($feature);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(FeatureAvQuery::create(), $event, $dispatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::FEATURE_AV_CREATE => array("create", 128),
|
||||
TheliaEvents::FEATURE_AV_UPDATE => array("update", 128),
|
||||
TheliaEvents::FEATURE_AV_DELETE => array("delete", 128),
|
||||
TheliaEvents::FEATURE_AV_UPDATE_POSITION => array("updatePosition", 128),
|
||||
);
|
||||
}
|
||||
}
|
||||
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)
|
||||
);
|
||||
}
|
||||
}
|
||||
173
core/lib/Thelia/Action/Folder.php
Normal file
173
core/lib/Thelia/Action/Folder.php
Normal file
@@ -0,0 +1,173 @@
|
||||
<?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\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Core\Event\File\FileDeleteEvent;
|
||||
use Thelia\Core\Event\Folder\FolderCreateEvent;
|
||||
use Thelia\Core\Event\Folder\FolderDeleteEvent;
|
||||
use Thelia\Core\Event\Folder\FolderToggleVisibilityEvent;
|
||||
use Thelia\Core\Event\Folder\FolderUpdateEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\Event\UpdatePositionEvent;
|
||||
use Thelia\Core\Event\UpdateSeoEvent;
|
||||
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 <manu@raynaud.io>
|
||||
*/
|
||||
class Folder extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
public function update(FolderUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $folder = FolderQuery::create()->findPk($event->getFolderId())) {
|
||||
$folder->setDispatcher($dispatcher);
|
||||
|
||||
$folder
|
||||
->setParent($event->getParent())
|
||||
->setVisible($event->getVisible())
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
->setDescription($event->getDescription())
|
||||
->setChapo($event->getChapo())
|
||||
->setPostscriptum($event->getPostscriptum())
|
||||
->save();
|
||||
;
|
||||
|
||||
$event->setFolder($folder);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Change Folder SEO
|
||||
*
|
||||
* @param UpdateSeoEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
* @return Object
|
||||
*/
|
||||
public function updateSeo(UpdateSeoEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
return $this->genericUpdateSeo(FolderQuery::create(), $event, $dispatcher);
|
||||
}
|
||||
|
||||
public function delete(FolderDeleteEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $folder = FolderQuery::create()->findPk($event->getFolderId())) {
|
||||
$con = Propel::getWriteConnection(FolderTableMap::DATABASE_NAME);
|
||||
$con->beginTransaction();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function create(FolderCreateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$folder = new FolderModel();
|
||||
$folder->setDispatcher($dispatcher);
|
||||
|
||||
$folder
|
||||
->setParent($event->getParent())
|
||||
->setVisible($event->getVisible())
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
->save();
|
||||
|
||||
$event->setFolder($folder);
|
||||
}
|
||||
|
||||
public function toggleVisibility(FolderToggleVisibilityEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$folder = $event->getFolder();
|
||||
|
||||
$folder
|
||||
->setDispatcher($dispatcher)
|
||||
->setVisible(!$folder->getVisible())
|
||||
->save();
|
||||
|
||||
$event->setFolder($folder);
|
||||
}
|
||||
|
||||
public function updatePosition(UpdatePositionEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $folder = FolderQuery::create()->findPk($event->getObjectId())) {
|
||||
$folder->setDispatcher($dispatcher);
|
||||
|
||||
switch ($event->getMode()) {
|
||||
case UpdatePositionEvent::POSITION_ABSOLUTE:
|
||||
$folder->changeAbsolutePosition($event->getPosition());
|
||||
break;
|
||||
case UpdatePositionEvent::POSITION_DOWN:
|
||||
$folder->movePositionDown();
|
||||
break;
|
||||
case UpdatePositionEvent::POSITION_UP:
|
||||
$folder->movePositionUp();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::FOLDER_CREATE => array("create", 128),
|
||||
TheliaEvents::FOLDER_UPDATE => array("update", 128),
|
||||
TheliaEvents::FOLDER_DELETE => array("delete", 128),
|
||||
TheliaEvents::FOLDER_TOGGLE_VISIBILITY => array("toggleVisibility", 128),
|
||||
|
||||
TheliaEvents::FOLDER_UPDATE_POSITION => array("updatePosition", 128),
|
||||
TheliaEvents::FOLDER_UPDATE_SEO => array('updateSeo', 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),
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
114
core/lib/Thelia/Action/HttpException.php
Normal file
114
core/lib/Thelia/Action/HttpException.php
Normal file
@@ -0,0 +1,114 @@
|
||||
<?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\HttpKernel\Event\GetResponseForExceptionEvent;
|
||||
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;
|
||||
|
||||
/**
|
||||
*
|
||||
* 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 */
|
||||
protected $parser;
|
||||
|
||||
public function __construct(ParserInterface $parser)
|
||||
{
|
||||
$this->parser = $parser;
|
||||
}
|
||||
|
||||
public function checkHttpException(GetResponseForExceptionEvent $event)
|
||||
{
|
||||
$exception = $event->getException();
|
||||
if ($exception instanceof NotFoundHttpException) {
|
||||
$this->display404($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(
|
||||
$this->parser->getTemplateHelper()->getActiveAdminTemplate()
|
||||
);
|
||||
|
||||
$message = $event->getException()->getMessage();
|
||||
|
||||
$response = Response::create(
|
||||
$this->parser->render(
|
||||
'general_error.html',
|
||||
array(
|
||||
"error_message" => $message
|
||||
)
|
||||
),
|
||||
403
|
||||
);
|
||||
|
||||
$event->setResponse($response);
|
||||
}
|
||||
|
||||
protected function display404(GetResponseForExceptionEvent $event)
|
||||
{
|
||||
// Define the template thant shoud be used
|
||||
$this->parser->setTemplateDefinition(
|
||||
$this->parser->getTemplateHelper()->getActiveFrontTemplate()
|
||||
);
|
||||
|
||||
$response = new Response($this->parser->render(ConfigQuery::getPageNotFoundView()), 404);
|
||||
|
||||
$event->setResponse($response);
|
||||
}
|
||||
|
||||
protected function displayException(GetResponseForExceptionEvent $event)
|
||||
{
|
||||
/** @var \Symfony\Component\HttpKernel\Exception\HttpException $exception */
|
||||
$exception = $event->getException();
|
||||
$event->setResponse(
|
||||
new Response(
|
||||
$exception->getMessage(),
|
||||
$exception->getStatusCode(),
|
||||
$exception->getHeaders()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
KernelEvents::EXCEPTION => ["checkHttpException", 128],
|
||||
);
|
||||
}
|
||||
}
|
||||
416
core/lib/Thelia/Action/Image.php
Normal file
416
core/lib/Thelia/Action/Image.php
Normal file
@@ -0,0 +1,416 @@
|
||||
<?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 Imagine\Image\Box;
|
||||
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;
|
||||
|
||||
/**
|
||||
*
|
||||
* Image management actions. This class handles image processing and caching.
|
||||
*
|
||||
* Basically, images are stored outside of the web space (by default in local/media/images),
|
||||
* and cached inside the web space (by default in web/local/images).
|
||||
*
|
||||
* In the images caches directory, a subdirectory for images categories (eg. product, category, folder, etc.) is
|
||||
* automatically created, and the cached image is created here. Plugin may use their own subdirectory as required.
|
||||
*
|
||||
* The cached image name contains a hash of the processing options, and the original (normalized) name of the image.
|
||||
*
|
||||
* A copy (or symbolic link, by default) of the original image is always created in the cache, so that the full
|
||||
* resolution image is always available.
|
||||
*
|
||||
* Various image processing options are available :
|
||||
*
|
||||
* - resizing, with border, crop, or by keeping image aspect ratio
|
||||
* - rotation, in degrees, positive or negative
|
||||
* - background color, applyed to empty background when creating borders or rotating
|
||||
* - effects. The effects are applied in the specified order. The following effects are available:
|
||||
* - gamma:value : change the image Gamma to the specified value. Example: gamma:0.7
|
||||
* - grayscale or greyscale: switch image to grayscale
|
||||
* - colorize:color : apply a color mask to the image. Exemple: colorize:#ff2244
|
||||
* - negative : transform the image in its negative equivalent
|
||||
* - vflip or vertical_flip : vertical flip
|
||||
* - hflip or horizontal_flip : horizontal flip
|
||||
*
|
||||
* If a problem occurs, an ImageException may be thrown.
|
||||
*
|
||||
* @package Thelia\Action
|
||||
* @author Franck Allimant <franck@cqfdev.fr>
|
||||
*
|
||||
*/
|
||||
class Image extends BaseCachedFile implements EventSubscriberInterface
|
||||
{
|
||||
// Resize mode constants
|
||||
const EXACT_RATIO_WITH_BORDERS = 1;
|
||||
const EXACT_RATIO_WITH_CROP = 2;
|
||||
const KEEP_IMAGE_RATIO = 3;
|
||||
|
||||
/**
|
||||
* @return string root of the image cache directory in web space
|
||||
*/
|
||||
protected function getCacheDirFromWebRoot()
|
||||
{
|
||||
return ConfigQuery::read('image_cache_dir_from_web_root', 'cache' . DS . 'images');
|
||||
}
|
||||
|
||||
/**
|
||||
* Process image and write the result in the image cache.
|
||||
*
|
||||
* If the image already exists in cache, the cache file is immediately returned, without any processing
|
||||
* If the original (full resolution) image is required, create either a symbolic link with the
|
||||
* original image in the cache dir, or copy it in the cache dir.
|
||||
*
|
||||
* 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, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$subdir = $event->getCacheSubdirectory();
|
||||
$source_file = $event->getSourceFilepath();
|
||||
|
||||
if (null == $subdir || null == $source_file) {
|
||||
throw new \InvalidArgumentException("Cache sub-directory and source file path cannot be null");
|
||||
}
|
||||
|
||||
// Find cached file path
|
||||
$cacheFilePath = $this->getCacheFilePath($subdir, $source_file, $event->isOriginalImage(), $event->getOptionsHash());
|
||||
|
||||
$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 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));
|
||||
}
|
||||
} 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
$dispatcher->dispatch(TheliaEvents::IMAGE_PREPROCESSING, $event);
|
||||
$image = $event->getImageObject();
|
||||
|
||||
$background_color = $event->getBackgroundColor();
|
||||
|
||||
$palette = new RGB();
|
||||
|
||||
if ($background_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,
|
||||
$event->getAllowZoom()
|
||||
);
|
||||
|
||||
// Rotate if required
|
||||
$rotation = intval($event->getRotation());
|
||||
|
||||
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 'negative':
|
||||
$image->effects()->negative();
|
||||
break;
|
||||
|
||||
case 'horizontal_flip':
|
||||
case 'hflip':
|
||||
$image->flipHorizontally();
|
||||
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]);
|
||||
|
||||
$image->effects()->gamma($gamma);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'colorize':
|
||||
// Syntax: colorize:couleur. Exemple: colorize:#ff00cc
|
||||
if (isset($params[1])) {
|
||||
$the_color = $palette->color($params[1]);
|
||||
|
||||
$image->effects()->colorize($the_color);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$quality = $event->getQuality();
|
||||
|
||||
if (is_null($quality)) {
|
||||
$quality = ConfigQuery::read('default_images_quality_percent', 75);
|
||||
}
|
||||
|
||||
// Allow image post-processing (watermarging, or other stuff...)
|
||||
$event->setImageObject($image);
|
||||
$dispatcher->dispatch(TheliaEvents::IMAGE_POSTPROCESSING, $event);
|
||||
$image = $event->getImageObject();
|
||||
|
||||
$image->save(
|
||||
$cacheFilePath,
|
||||
array('quality' => $quality)
|
||||
);
|
||||
} else {
|
||||
throw new ImageException(sprintf("Source file %s cannot be opened.", basename($source_file)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the image URL
|
||||
$processed_image_url = $this->getCacheFileURL($subdir, basename($cacheFilePath));
|
||||
|
||||
// compute the full resolution image path in cache
|
||||
$original_image_url = $this->getCacheFileURL($subdir, basename($originalImagePathInCache));
|
||||
|
||||
// Update the event with file path and file URL
|
||||
$event->setCacheFilepath($cacheFilePath);
|
||||
$event->setCacheOriginalFilepath($originalImagePathInCache);
|
||||
|
||||
$event->setFileUrl(URL::getInstance()->absoluteUrl($processed_image_url, null, URL::PATH_TO_FILE));
|
||||
$event->setOriginalFileUrl(URL::getInstance()->absoluteUrl($original_image_url, null, URL::PATH_TO_FILE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Process image resizing, with borders or cropping. If $dest_width and $dest_height
|
||||
* are both null, no resize is performed.
|
||||
*
|
||||
* @param ImagineInterface $imagine the Imagine instance
|
||||
* @param ImageInterface $image the image to process
|
||||
* @param int $dest_width the required width
|
||||
* @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,
|
||||
$allow_zoom = false
|
||||
) {
|
||||
if (! (is_null($dest_width) && is_null($dest_height))) {
|
||||
$width_orig = $image->getSize()->getWidth();
|
||||
$height_orig = $image->getSize()->getHeight();
|
||||
|
||||
$ratio = $width_orig / $height_orig;
|
||||
|
||||
if (is_null($dest_width)) {
|
||||
$dest_width = $dest_height * $ratio;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
$delta_x = $delta_y = $border_width = $border_height = 0;
|
||||
|
||||
if ($width_diff > 1 && $height_diff > 1) {
|
||||
$resize_width = $width_orig;
|
||||
$resize_height = $height_orig;
|
||||
|
||||
// When cropping, be sure to always generate an image which is
|
||||
// no smaller than the required size, zooming it if required.
|
||||
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
|
||||
$resize_height = $dest_height;
|
||||
$resize_width = intval(($width_orig * $resize_height) / $height_orig);
|
||||
|
||||
if ($resize_mode == self::EXACT_RATIO_WITH_CROP) {
|
||||
$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 = $resize_width;
|
||||
}
|
||||
} else {
|
||||
// Image width > image height
|
||||
$resize_width = $dest_width;
|
||||
$resize_height = intval($height_orig * $dest_width / $width_orig);
|
||||
|
||||
if ($resize_mode == self::EXACT_RATIO_WITH_CROP) {
|
||||
$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 = $resize_height;
|
||||
}
|
||||
}
|
||||
|
||||
$image->resize(new Box($resize_width, $resize_height));
|
||||
|
||||
if ($resize_mode == self::EXACT_RATIO_WITH_BORDERS) {
|
||||
$border_width = intval(($dest_width - $resize_width) / 2);
|
||||
$border_height = intval(($dest_height - $resize_height) / 2);
|
||||
|
||||
$canvas = new Box($dest_width, $dest_height);
|
||||
|
||||
return $imagine->create($canvas, $bg_color)
|
||||
->paste($image, new Point($border_width, $border_height));
|
||||
} elseif ($resize_mode == self::EXACT_RATIO_WITH_CROP) {
|
||||
$image->crop(
|
||||
new Point($delta_x, $delta_y),
|
||||
new Box($dest_width, $dest_height)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Imagine object using current driver configuration
|
||||
*
|
||||
* @return ImagineInterface
|
||||
*/
|
||||
protected function createImagineInstance()
|
||||
{
|
||||
$driver = ConfigQuery::read("imagine_graphic_driver", "gd");
|
||||
|
||||
switch ($driver) {
|
||||
case 'imagick':
|
||||
$image = new ImagickImagine();
|
||||
break;
|
||||
|
||||
case 'gmagick':
|
||||
$image = new GmagickImagine();
|
||||
break;
|
||||
|
||||
case 'gd':
|
||||
default:
|
||||
$image = new Imagine();
|
||||
}
|
||||
|
||||
return $image;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::IMAGE_PROCESS => array("processImage", 128),
|
||||
|
||||
// Implemented in parent class BaseCachedFile
|
||||
TheliaEvents::IMAGE_CLEAR_CACHE => array("clearCache", 128),
|
||||
TheliaEvents::IMAGE_DELETE => array("deleteFile", 128),
|
||||
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),
|
||||
);
|
||||
}
|
||||
}
|
||||
79
core/lib/Thelia/Action/Import.php
Normal file
79
core/lib/Thelia/Action/Import.php
Normal file
@@ -0,0 +1,79 @@
|
||||
<?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\TheliaEvents;
|
||||
use Thelia\Core\Event\UpdatePositionEvent;
|
||||
use Thelia\Handler\ImportHandler;
|
||||
use Thelia\Model\ImportCategoryQuery;
|
||||
use Thelia\Model\ImportQuery;
|
||||
|
||||
/**
|
||||
* Class Import
|
||||
* @author Jérôme Billiras <jbilliras@openstudio.fr>
|
||||
*/
|
||||
class Import extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
/**
|
||||
* @var \Thelia\Handler\ImportHandler The import handler
|
||||
*/
|
||||
protected $handler;
|
||||
|
||||
/**
|
||||
* @param \Thelia\Handler\ImportHandler $importHandler The import handler
|
||||
*/
|
||||
public function __construct(ImportHandler $importHandler)
|
||||
{
|
||||
$this->handler = $importHandler;
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return [
|
||||
TheliaEvents::IMPORT_CHANGE_POSITION => [
|
||||
['importChangePosition', 128]
|
||||
],
|
||||
TheliaEvents::IMPORT_CATEGORY_CHANGE_POSITION => [
|
||||
['importCategoryChangePosition', 128]
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle import change position event
|
||||
*
|
||||
* @param UpdatePositionEvent $updatePositionEvent
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function importChangePosition(UpdatePositionEvent $updatePositionEvent, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$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);
|
||||
}
|
||||
}
|
||||
238
core/lib/Thelia/Action/Lang.php
Normal file
238
core/lib/Thelia/Action/Lang.php
Normal file
@@ -0,0 +1,238 @@
|
||||
<?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\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;
|
||||
use Thelia\Model\Lang as LangModel;
|
||||
|
||||
/**
|
||||
* Class Lang
|
||||
* @package Thelia\Action
|
||||
* @author Manuel Raynaud <manu@raynaud.io>
|
||||
*/
|
||||
class Lang extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
/** @var TemplateHelperInterface */
|
||||
protected $templateHelper;
|
||||
|
||||
/** @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($dispatcher);
|
||||
|
||||
$lang->setTitle($event->getTitle())
|
||||
->setLocale($event->getLocale())
|
||||
->setCode($event->getCode())
|
||||
->setDateTimeFormat($event->getDateTimeFormat())
|
||||
->setDateFormat($event->getDateFormat())
|
||||
->setTimeFormat($event->getTimeFormat())
|
||||
->setDecimalSeparator($event->getDecimalSeparator())
|
||||
->setThousandsSeparator($event->getThousandsSeparator())
|
||||
->setDecimals($event->getDecimals())
|
||||
->save();
|
||||
|
||||
$event->setLang($lang);
|
||||
}
|
||||
}
|
||||
|
||||
public function toggleDefault(LangToggleDefaultEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $lang = LangQuery::create()->findPk($event->getLangId())) {
|
||||
$lang->setDispatcher($dispatcher);
|
||||
|
||||
$lang->toggleDefault();
|
||||
|
||||
$event->setLang($lang);
|
||||
}
|
||||
}
|
||||
|
||||
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($dispatcher)
|
||||
->setTitle($event->getTitle())
|
||||
->setCode($event->getCode())
|
||||
->setLocale($event->getLocale())
|
||||
->setDateTimeFormat($event->getDateTimeFormat())
|
||||
->setDateFormat($event->getDateFormat())
|
||||
->setTimeFormat($event->getTimeFormat())
|
||||
->setDecimalSeparator($event->getDecimalSeparator())
|
||||
->setThousandsSeparator($event->getThousandsSeparator())
|
||||
->setDecimals($event->getDecimals())
|
||||
->save();
|
||||
|
||||
$event->setLang($lang);
|
||||
}
|
||||
|
||||
public function delete(LangDeleteEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $lang = LangQuery::create()->findPk($event->getLangId())) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
public function defaultBehavior(LangDefaultBehaviorEvent $event)
|
||||
{
|
||||
ConfigQuery::create()
|
||||
->filterByName('default_lang_without_translation')
|
||||
->update(array('Value' => $event->getDefaultBehavior()));
|
||||
}
|
||||
|
||||
public function langUrl(LangUrlEvent $event)
|
||||
{
|
||||
foreach ($event->getUrl() as $id => $url) {
|
||||
LangQuery::create()
|
||||
->filterById($id)
|
||||
->update(array('Url' => $url));
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@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_FIX_MISSING_FLAG => array('fixMissingFlag', 128)
|
||||
);
|
||||
}
|
||||
}
|
||||
51
core/lib/Thelia/Action/MailingSystem.php
Normal file
51
core/lib/Thelia/Action/MailingSystem.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?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\MailingSystem\MailingSystemEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Model\ConfigQuery;
|
||||
|
||||
class MailingSystem extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
/**
|
||||
* @param MailingSystemEvent $event
|
||||
*/
|
||||
public function update(MailingSystemEvent $event)
|
||||
{
|
||||
if ($event->getEnabled()) {
|
||||
ConfigQuery::enableSmtp();
|
||||
} else {
|
||||
ConfigQuery::disableSmtp();
|
||||
}
|
||||
ConfigQuery::setSmtpHost($event->getHost());
|
||||
ConfigQuery::setSmtpPort($event->getPort());
|
||||
ConfigQuery::setSmtpEncryption($event->getEncryption());
|
||||
ConfigQuery::setSmtpUsername($event->getUsername());
|
||||
ConfigQuery::setSmtpPassword($event->getPassword());
|
||||
ConfigQuery::setSmtpAuthMode($event->getAuthMode());
|
||||
ConfigQuery::setSmtpTimeout($event->getTimeout());
|
||||
ConfigQuery::setSmtpSourceIp($event->getSourceIp());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::MAILING_SYSTEM_UPDATE => array("update", 128),
|
||||
);
|
||||
}
|
||||
}
|
||||
116
core/lib/Thelia/Action/Message.php
Normal file
116
core/lib/Thelia/Action/Message.php
Normal file
@@ -0,0 +1,116 @@
|
||||
<?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\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;
|
||||
|
||||
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, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$message = new MessageModel();
|
||||
|
||||
$message
|
||||
->setDispatcher($dispatcher)
|
||||
|
||||
->setName($event->getMessageName())
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
->setSecured($event->getSecured())
|
||||
|
||||
->save()
|
||||
;
|
||||
|
||||
$event->setMessage($message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change a message
|
||||
*
|
||||
* @param \Thelia\Core\Event\Message\MessageUpdateEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function modify(MessageUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $message = MessageQuery::create()->findPk($event->getMessageId())) {
|
||||
$message
|
||||
->setDispatcher($dispatcher)
|
||||
|
||||
->setName($event->getMessageName())
|
||||
->setSecured($event->getSecured())
|
||||
|
||||
->setLocale($event->getLocale())
|
||||
|
||||
->setTitle($event->getTitle())
|
||||
->setSubject($event->getSubject())
|
||||
|
||||
->setHtmlMessage($event->getHtmlMessage())
|
||||
->setTextMessage($event->getTextMessage())
|
||||
|
||||
->setHtmlLayoutFileName($event->getHtmlLayoutFileName())
|
||||
->setHtmlTemplateFileName($event->getHtmlTemplateFileName())
|
||||
->setTextLayoutFileName($event->getTextLayoutFileName())
|
||||
->setTextTemplateFileName($event->getTextTemplateFileName())
|
||||
|
||||
->save();
|
||||
|
||||
$event->setMessage($message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a messageuration entry
|
||||
*
|
||||
* @param \Thelia\Core\Event\Message\MessageDeleteEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function delete(MessageDeleteEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== ($message = MessageQuery::create()->findPk($event->getMessageId()))) {
|
||||
$message
|
||||
->setDispatcher($dispatcher)
|
||||
->delete()
|
||||
;
|
||||
|
||||
$event->setMessage($message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::MESSAGE_CREATE => array("create", 128),
|
||||
TheliaEvents::MESSAGE_UPDATE => array("modify", 128),
|
||||
TheliaEvents::MESSAGE_DELETE => array("delete", 128),
|
||||
);
|
||||
}
|
||||
}
|
||||
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),
|
||||
);
|
||||
}
|
||||
}
|
||||
456
core/lib/Thelia/Action/Module.php
Normal file
456
core/lib/Thelia/Action/Module.php
Normal file
@@ -0,0 +1,456 @@
|
||||
<?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 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 <manu@raynaud.io>
|
||||
*/
|
||||
class Module extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
/** @var ContainerInterface */
|
||||
protected $container;
|
||||
|
||||
public function __construct(ContainerInterface $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
public function toggleActivation(ModuleToggleActivationEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $module = ModuleQuery::create()->findPk($event->getModuleId())) {
|
||||
$moduleInstance = $module->createInstance();
|
||||
|
||||
if (method_exists($moduleInstance, 'setContainer')) {
|
||||
$moduleInstance->setContainer($this->container);
|
||||
if ($module->getActivate() == BaseModule::IS_ACTIVATED) {
|
||||
$moduleInstance->deActivate($module);
|
||||
} else {
|
||||
$moduleInstance->activate($module);
|
||||
}
|
||||
}
|
||||
|
||||
$event->setModule($module);
|
||||
|
||||
$this->cacheClear($dispatcher);
|
||||
}
|
||||
}
|
||||
|
||||
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 ($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())) {
|
||||
$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 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 {
|
||||
// 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();
|
||||
|
||||
$instance->destroy($con, $event->getDeleteData());
|
||||
|
||||
$fs = new Filesystem();
|
||||
$fs->remove($path);
|
||||
} catch (\ReflectionException $ex) {
|
||||
// Happens probably because the module directory has been deleted.
|
||||
// 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',
|
||||
['%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);
|
||||
|
||||
$con->commit();
|
||||
|
||||
$event->setModule($module);
|
||||
$this->cacheClear($dispatcher);
|
||||
} catch (\Exception $e) {
|
||||
$con->rollBack();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ModuleEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function update(ModuleEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $module = ModuleQuery::create()->findPk($event->getId())) {
|
||||
$module
|
||||
->setDispatcher($dispatcher)
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
->setChapo($event->getChapo())
|
||||
->setDescription($event->getDescription())
|
||||
->setPostscriptum($event->getPostscriptum());
|
||||
|
||||
$module->save();
|
||||
|
||||
$event->setModule($module);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
*
|
||||
* @throws \RuntimeException if no payment module can be found.
|
||||
*/
|
||||
public function pay(OrderPaymentEvent $event)
|
||||
{
|
||||
$order = $event->getOrder();
|
||||
|
||||
/* call pay method */
|
||||
if (null === $paymentModule = ModuleQuery::create()->findPk($order->getPaymentModuleId())) {
|
||||
throw new \RuntimeException(
|
||||
Translator::getInstance()->trans(
|
||||
"Failed to find a payment Module with ID=%mid for order ID=%oid",
|
||||
[
|
||||
"%mid" => $order->getPaymentModuleId(),
|
||||
"%oid" => $order->getId()
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$paymentModuleInstance = $paymentModule->getPaymentModuleInstance($this->container);
|
||||
|
||||
$response = $paymentModuleInstance->pay($order);
|
||||
|
||||
if (null !== $response && $response instanceof Response) {
|
||||
$event->setResponse($response);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(ModuleQuery::create(), $event, $dispatcher);
|
||||
|
||||
$this->cacheClear($dispatcher);
|
||||
}
|
||||
|
||||
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 [
|
||||
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),
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
119
core/lib/Thelia/Action/Newsletter.php
Normal file
119
core/lib/Thelia/Action/Newsletter.php
Normal file
@@ -0,0 +1,119 @@
|
||||
<?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\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 <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)
|
||||
{
|
||||
// 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
|
||||
->setUnsubscribed(true)
|
||||
->save();
|
||||
|
||||
$event->setNewsletter($nl);
|
||||
}
|
||||
}
|
||||
|
||||
public function update(NewsletterEvent $event)
|
||||
{
|
||||
if (null !== $nl = NewsletterQuery::create()->findPk($event->getId())) {
|
||||
$nl->setEmail($event->getEmail())
|
||||
->setFirstname($event->getFirstname())
|
||||
->setLastname($event->getLastname())
|
||||
->setLocale($event->getLocale())
|
||||
->save();
|
||||
|
||||
$event->setNewsletter($nl);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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_CONFIRM_SUBSCRIPTION => array('confirmSubscription', 128)
|
||||
);
|
||||
}
|
||||
}
|
||||
727
core/lib/Thelia/Action/Order.php
Normal file
727
core/lib/Thelia/Action/Order.php
Normal file
@@ -0,0 +1,727 @@
|
||||
<?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\EventDispatcher;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
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\Security\SecurityContext;
|
||||
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\Lang as LangModel;
|
||||
use Thelia\Model\Map\OrderTableMap;
|
||||
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;
|
||||
|
||||
/**
|
||||
*
|
||||
* Class Order
|
||||
* @package Thelia\Action
|
||||
* @author Etienne Roudeix <eroudeix@openstudio.fr>
|
||||
*/
|
||||
class Order extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
/** @var RequestStack */
|
||||
protected $requestStack;
|
||||
|
||||
/** @var MailerFactory */
|
||||
protected $mailer;
|
||||
|
||||
/** @var SecurityContext */
|
||||
protected $securityContext;
|
||||
|
||||
public function __construct(RequestStack $requestStack, MailerFactory $mailer, SecurityContext $securityContext)
|
||||
{
|
||||
$this->requestStack = $requestStack;
|
||||
$this->mailer = $mailer;
|
||||
$this->securityContext = $securityContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Thelia\Core\Event\Order\OrderEvent $event
|
||||
*/
|
||||
public function setDeliveryAddress(OrderEvent $event)
|
||||
{
|
||||
$order = $event->getOrder();
|
||||
|
||||
$order->setChoosenDeliveryAddress($event->getDeliveryAddress());
|
||||
|
||||
$event->setOrder($order);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Thelia\Core\Event\Order\OrderEvent $event
|
||||
*/
|
||||
public function setDeliveryModule(OrderEvent $event)
|
||||
{
|
||||
$order = $event->getOrder();
|
||||
|
||||
$deliveryModuleId = $event->getDeliveryModule();
|
||||
|
||||
$order->setDeliveryModuleId($deliveryModuleId);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Thelia\Core\Event\Order\OrderEvent $event
|
||||
*/
|
||||
public function setPostage(OrderEvent $event)
|
||||
{
|
||||
$order = $event->getOrder();
|
||||
|
||||
$order->setPostage($event->getPostage());
|
||||
$order->setPostageTax($event->getPostageTax());
|
||||
$order->setPostageTaxRuleTitle($event->getPostageTaxRuleTitle());
|
||||
|
||||
$event->setOrder($order);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Thelia\Core\Event\Order\OrderEvent $event
|
||||
*/
|
||||
public function setInvoiceAddress(OrderEvent $event)
|
||||
{
|
||||
$order = $event->getOrder();
|
||||
|
||||
$order->setChoosenInvoiceAddress($event->getInvoiceAddress());
|
||||
|
||||
$event->setOrder($order);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Thelia\Core\Event\Order\OrderEvent $event
|
||||
*/
|
||||
public function setPaymentModule(OrderEvent $event)
|
||||
{
|
||||
$order = $event->getOrder();
|
||||
|
||||
$order->setPaymentModuleId($event->getPaymentModule());
|
||||
|
||||
$event->setOrder($order);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
$cartItems = $cart->getCartItems();
|
||||
|
||||
/* fulfill order */
|
||||
$placedOrder->setCustomerId($customer->getId());
|
||||
$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())
|
||||
->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())
|
||||
->setCellphone($invoiceAddress->getCellphone())
|
||||
->setCountryId($invoiceAddress->getCountryId())
|
||||
->setStateId($deliveryAddress->getStateId())
|
||||
->save($con);
|
||||
|
||||
$placedOrder->setDeliveryOrderAddressId($deliveryOrderAddress->getId());
|
||||
$placedOrder->setInvoiceOrderAddressId($invoiceOrderAddress->getId());
|
||||
|
||||
$taxCountry = $deliveryAddress->getCountry();
|
||||
}
|
||||
|
||||
$placedOrder->setStatusId(
|
||||
OrderStatusQuery::getNotPaidStatus()->getId()
|
||||
);
|
||||
|
||||
$placedOrder->setCartId($cart->getId());
|
||||
|
||||
/* memorize discount */
|
||||
$placedOrder->setDiscount(
|
||||
$cart->getDiscount()
|
||||
);
|
||||
|
||||
$placedOrder->save($con);
|
||||
|
||||
/* fulfill order_products and decrease stock */
|
||||
|
||||
foreach ($cartItems as $cartItem) {
|
||||
$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()
|
||||
&& true === ConfigQuery::checkAvailableStock()
|
||||
&& $useStock) {
|
||||
throw new TheliaProcessException("Not enough stock", TheliaProcessException::CART_ITEM_NOT_ENOUGH_STOCK, $cartItem);
|
||||
}
|
||||
|
||||
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()
|
||||
);
|
||||
|
||||
$orderProduct = new OrderProduct();
|
||||
$orderProduct
|
||||
->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())
|
||||
->setWasNew($pse->getNewness())
|
||||
->setWasInPromo($cartItem->getPromo())
|
||||
->setWeight($pse->getWeight())
|
||||
->setTaxRuleTitle($taxRuleI18n->getTitle())
|
||||
->setTaxRuleDescription($taxRuleI18n->getDescription())
|
||||
->setEanCode($pse->getEanCode())
|
||||
->setCartItemId($cartItem->getId())
|
||||
->setDispatcher($dispatcher)
|
||||
->save($con)
|
||||
;
|
||||
|
||||
/* fulfill order_product_tax */
|
||||
/** @var OrderProductTax $tax */
|
||||
foreach ($taxDetail as $tax) {
|
||||
$tax->setOrderProductId($orderProduct->getId());
|
||||
$tax->save($con);
|
||||
}
|
||||
|
||||
/* 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();
|
||||
$orderAttributeCombination
|
||||
->setOrderProductId($orderProduct->getId())
|
||||
->setAttributeTitle($attribute->getTitle())
|
||||
->setAttributeChapo($attribute->getChapo())
|
||||
->setAttributeDescription($attribute->getDescription())
|
||||
->setAttributePostscriptum($attribute->getPostscriptum())
|
||||
->setAttributeAvTitle($attributeAv->getTitle())
|
||||
->setAttributeAvChapo($attributeAv->getChapo())
|
||||
->setAttributeAvDescription($attributeAv->getDescription())
|
||||
->setAttributeAvPostscriptum($attributeAv->getPostscriptum())
|
||||
->save($con);
|
||||
}
|
||||
}
|
||||
|
||||
$con->commit();
|
||||
|
||||
return $placedOrder;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$paymentModule = ModuleQuery::create()->findPk($event->getOrder()->getPaymentModuleId());
|
||||
|
||||
/** @var \Thelia\Module\PaymentModuleInterface $paymentModuleInstance */
|
||||
$paymentModuleInstance = $paymentModule->createInstance();
|
||||
|
||||
$event->setPlacedOrder(
|
||||
$this->createOrder(
|
||||
$dispatcher,
|
||||
$event->getOrder(),
|
||||
$event->getCurrency(),
|
||||
$event->getLang(),
|
||||
$event->getCart(),
|
||||
$event->getCustomer(),
|
||||
$this->isModuleManageStockOnCreation(
|
||||
$dispatcher,
|
||||
$paymentModuleInstance
|
||||
),
|
||||
$event->getUseOrderDefinedAddresses()
|
||||
)
|
||||
);
|
||||
|
||||
$event->setOrder(new OrderModel());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OrderEvent $event
|
||||
*
|
||||
* @throws \Thelia\Exception\TheliaProcessException
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
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(
|
||||
$dispatcher,
|
||||
$event->getOrder(),
|
||||
$session->getCurrency(),
|
||||
$session->getLang(),
|
||||
$session->getSessionCart($dispatcher),
|
||||
$this->securityContext->getCustomerUser(),
|
||||
$this->isModuleManageStockOnCreation(
|
||||
$dispatcher,
|
||||
$paymentModuleInstance
|
||||
)
|
||||
);
|
||||
|
||||
$dispatcher->dispatch(TheliaEvents::ORDER_BEFORE_PAYMENT, new OrderEvent($placedOrder));
|
||||
|
||||
/* but memorize placed order */
|
||||
$event->setOrder(new OrderModel());
|
||||
$event->setPlacedOrder($placedOrder);
|
||||
|
||||
/* call pay method */
|
||||
$payEvent = new OrderPaymentEvent($placedOrder);
|
||||
|
||||
$dispatcher->dispatch(TheliaEvents::MODULE_PAY, $payEvent);
|
||||
|
||||
if ($payEvent->hasResponse()) {
|
||||
$event->setResponse($payEvent->getResponse());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OrderEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function orderBeforePayment(OrderEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$dispatcher ->dispatch(TheliaEvents::ORDER_SEND_CONFIRMATION_EMAIL, clone $event);
|
||||
|
||||
$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.
|
||||
*
|
||||
* @param OrderEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function orderCartClear(/** @noinspection PhpUnusedParameterInspection */ OrderEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
// 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, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$order = $event->getOrder();
|
||||
$newStatus = $event->getStatus();
|
||||
$paymentModule = ModuleQuery::create()->findPk($order->getPaymentModuleId());
|
||||
/** @var PaymentModuleInterface $paymentModuleInstance */
|
||||
$paymentModuleInstance = $paymentModule->createInstance();
|
||||
|
||||
$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
|
||||
*/
|
||||
public function updateDeliveryRef(OrderEvent $event)
|
||||
{
|
||||
$order = $event->getOrder();
|
||||
|
||||
$order->setDeliveryRef($event->getDeliveryRef());
|
||||
$order->save();
|
||||
|
||||
$event->setOrder($order);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OrderAddressEvent $event
|
||||
*/
|
||||
public function updateAddress(OrderAddressEvent $event)
|
||||
{
|
||||
$orderAddress = $event->getOrderAddress();
|
||||
|
||||
$orderAddress
|
||||
->setCustomerTitleId($event->getTitle())
|
||||
->setCompany($event->getCompany())
|
||||
->setFirstname($event->getFirstname())
|
||||
->setLastname($event->getLastname())
|
||||
->setAddress1($event->getAddress1())
|
||||
->setAddress2($event->getAddress2())
|
||||
->setAddress3($event->getAddress3())
|
||||
->setZipcode($event->getZipcode())
|
||||
->setCity($event->getCity())
|
||||
->setCountryId($event->getCountry())
|
||||
->setStateId($event->getState())
|
||||
->setPhone($event->getPhone())
|
||||
->setCellphone($event->getCellphone())
|
||||
;
|
||||
$orderAddress->save();
|
||||
|
||||
$event->setOrderAddress($orderAddress);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a payment module manage stock on creation
|
||||
*
|
||||
* @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()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::ORDER_SET_DELIVERY_ADDRESS => array("setDeliveryAddress", 128),
|
||||
TheliaEvents::ORDER_SET_DELIVERY_MODULE => array("setDeliveryModule", 128),
|
||||
TheliaEvents::ORDER_SET_POSTAGE => array("setPostage", 128),
|
||||
TheliaEvents::ORDER_SET_INVOICE_ADDRESS => array("setInvoiceAddress", 128),
|
||||
TheliaEvents::ORDER_SET_PAYMENT_MODULE => array("setPaymentModule", 128),
|
||||
TheliaEvents::ORDER_PAY => array("create", 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_ADDRESS => array("updateAddress", 128),
|
||||
TheliaEvents::ORDER_CREATE_MANUAL => array("createManual", 128),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the session from the current request
|
||||
*
|
||||
* @return \Thelia\Core\HttpFoundation\Session\Session
|
||||
*/
|
||||
protected function getSession()
|
||||
{
|
||||
return $this->requestStack->getCurrentRequest()->getSession();
|
||||
}
|
||||
}
|
||||
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],
|
||||
];
|
||||
}
|
||||
}
|
||||
54
core/lib/Thelia/Action/Pdf.php
Normal file
54
core/lib/Thelia/Action/Pdf.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?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\PdfEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
|
||||
/**
|
||||
* Class Pdf
|
||||
* @package Thelia\Action
|
||||
* @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->setDefaultFont($event->getFontName());
|
||||
|
||||
$html2pdf->pdf->SetDisplayMode('real');
|
||||
|
||||
$html2pdf->writeHTML($event->getContent());
|
||||
$event->setPdf($html2pdf->output(null, 'S'));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::GENERATE_PDF => array("generatePdf", 128)
|
||||
);
|
||||
}
|
||||
}
|
||||
821
core/lib/Thelia/Action/Product.php
Normal file
821
core/lib/Thelia/Action/Product.php
Normal file
@@ -0,0 +1,821 @@
|
||||
<?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\Exception\PropelException;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Core\Event\Feature\FeatureAvCreateEvent;
|
||||
use Thelia\Core\Event\Feature\FeatureAvDeleteEvent;
|
||||
use Thelia\Core\Event\File\FileDeleteEvent;
|
||||
use Thelia\Core\Event\Product\ProductCloneEvent;
|
||||
use Thelia\Model\AttributeCombinationQuery;
|
||||
use Thelia\Model\FeatureAvI18n;
|
||||
use Thelia\Model\FeatureAvI18nQuery;
|
||||
use Thelia\Model\FeatureAvQuery;
|
||||
use Thelia\Model\Map\ProductTableMap;
|
||||
use Thelia\Model\ProductDocument;
|
||||
use Thelia\Model\ProductDocumentQuery;
|
||||
use Thelia\Model\ProductI18n;
|
||||
use Thelia\Model\ProductI18nQuery;
|
||||
use Thelia\Model\ProductImage;
|
||||
use Thelia\Model\ProductImageQuery;
|
||||
use Thelia\Model\ProductPrice;
|
||||
use Thelia\Model\ProductPriceQuery;
|
||||
use Thelia\Model\ProductQuery;
|
||||
use Thelia\Model\Product as ProductModel;
|
||||
use Thelia\Model\ProductAssociatedContent;
|
||||
use Thelia\Model\ProductAssociatedContentQuery;
|
||||
use Thelia\Model\ProductCategory;
|
||||
use Thelia\Model\TaxRuleQuery;
|
||||
use Thelia\Model\AccessoryQuery;
|
||||
use Thelia\Model\Accessory;
|
||||
use Thelia\Model\FeatureProduct;
|
||||
use Thelia\Model\FeatureProductQuery;
|
||||
use Thelia\Model\ProductCategoryQuery;
|
||||
use Thelia\Model\ProductSaleElementsQuery;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\Event\Product\ProductUpdateEvent;
|
||||
use Thelia\Core\Event\Product\ProductCreateEvent;
|
||||
use Thelia\Core\Event\Product\ProductDeleteEvent;
|
||||
use Thelia\Core\Event\Product\ProductToggleVisibilityEvent;
|
||||
use Thelia\Core\Event\Product\ProductAddContentEvent;
|
||||
use Thelia\Core\Event\Product\ProductDeleteContentEvent;
|
||||
use Thelia\Core\Event\UpdatePositionEvent;
|
||||
use Thelia\Core\Event\UpdateSeoEvent;
|
||||
use Thelia\Core\Event\FeatureProduct\FeatureProductUpdateEvent;
|
||||
use Thelia\Core\Event\FeatureProduct\FeatureProductDeleteEvent;
|
||||
use Thelia\Core\Event\Product\ProductSetTemplateEvent;
|
||||
use Thelia\Core\Event\Product\ProductDeleteCategoryEvent;
|
||||
use Thelia\Core\Event\Product\ProductAddCategoryEvent;
|
||||
use Thelia\Core\Event\Product\ProductAddAccessoryEvent;
|
||||
use Thelia\Core\Event\Product\ProductDeleteAccessoryEvent;
|
||||
use Propel\Runtime\Propel;
|
||||
|
||||
class Product extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
/** @var EventDispatcherInterface */
|
||||
protected $eventDispatcher;
|
||||
|
||||
public function __construct(EventDispatcherInterface $eventDispatcher)
|
||||
{
|
||||
$this->eventDispatcher = $eventDispatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new product entry
|
||||
*
|
||||
* @param \Thelia\Core\Event\Product\ProductCreateEvent $event
|
||||
*/
|
||||
public function create(ProductCreateEvent $event)
|
||||
{
|
||||
$product = new ProductModel();
|
||||
|
||||
$product
|
||||
->setDispatcher($this->eventDispatcher)
|
||||
|
||||
->setRef($event->getRef())
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
->setVisible($event->getVisible() ? 1 : 0)
|
||||
->setVirtual($event->getVirtual() ? 1 : 0)
|
||||
|
||||
// Set the default tax rule to this product
|
||||
->setTaxRule(TaxRuleQuery::create()->findOneByIsDefault(true))
|
||||
|
||||
->setTemplateId($event->getTemplateId())
|
||||
|
||||
->create(
|
||||
$event->getDefaultCategory(),
|
||||
$event->getBasePrice(),
|
||||
$event->getCurrencyId(),
|
||||
$event->getTaxRuleId(),
|
||||
$event->getBaseWeight(),
|
||||
$event->getBaseQuantity()
|
||||
)
|
||||
;
|
||||
|
||||
$event->setProduct($product);
|
||||
}
|
||||
|
||||
/*******************
|
||||
* CLONING PROCESS *
|
||||
*******************/
|
||||
|
||||
/**
|
||||
* @param ProductCloneEvent $event
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function cloneProduct(ProductCloneEvent $event)
|
||||
{
|
||||
$con = Propel::getWriteConnection(ProductTableMap::DATABASE_NAME);
|
||||
$con->beginTransaction();
|
||||
|
||||
try {
|
||||
// Get important datas
|
||||
$lang = $event->getLang();
|
||||
$originalProduct = $event->getOriginalProduct();
|
||||
|
||||
if (null === $originalProductDefaultI18n = ProductI18nQuery::create()
|
||||
->findPk([$originalProduct->getId(), $lang])) {
|
||||
// No i18n entry for the current language. Try to find one for creating the product.
|
||||
// It will be updated later by updateClone()
|
||||
$originalProductDefaultI18n = ProductI18nQuery::create()
|
||||
->findOneById($originalProduct->getId())
|
||||
;
|
||||
}
|
||||
|
||||
$originalProductDefaultPrice = ProductPriceQuery::create()
|
||||
->findOneByProductSaleElementsId($originalProduct->getDefaultSaleElements()->getId());
|
||||
|
||||
// Cloning process
|
||||
|
||||
$this->createClone($event, $originalProductDefaultI18n, $originalProductDefaultPrice);
|
||||
|
||||
$this->updateClone($event, $originalProductDefaultPrice);
|
||||
|
||||
$this->cloneFeatureCombination($event);
|
||||
|
||||
$this->cloneAssociatedContent($event);
|
||||
|
||||
$this->cloneAccessories($event);
|
||||
|
||||
// Dispatch event for file cloning
|
||||
$this->eventDispatcher->dispatch(TheliaEvents::FILE_CLONE, $event);
|
||||
|
||||
// Dispatch event for PSE cloning
|
||||
$this->eventDispatcher->dispatch(TheliaEvents::PSE_CLONE, $event);
|
||||
|
||||
$con->commit();
|
||||
} catch (\Exception $e) {
|
||||
$con->rollBack();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
public function createClone(ProductCloneEvent $event, ProductI18n $originalProductDefaultI18n, ProductPrice $originalProductDefaultPrice)
|
||||
{
|
||||
// Build event and dispatch creation of the clone product
|
||||
$createCloneEvent = new ProductCreateEvent();
|
||||
$createCloneEvent
|
||||
->setTitle($originalProductDefaultI18n->getTitle())
|
||||
->setRef($event->getRef())
|
||||
->setLocale($event->getLang())
|
||||
->setVisible(0)
|
||||
->setVirtual($event->getOriginalProduct()->getVirtual())
|
||||
->setTaxRuleId($event->getOriginalProduct()->getTaxRuleId())
|
||||
->setDefaultCategory($event->getOriginalProduct()->getDefaultCategoryId())
|
||||
->setBasePrice($originalProductDefaultPrice->getPrice())
|
||||
->setCurrencyId($originalProductDefaultPrice->getCurrencyId())
|
||||
->setBaseWeight($event->getOriginalProduct()->getDefaultSaleElements()->getWeight());
|
||||
|
||||
$this->eventDispatcher->dispatch(TheliaEvents::PRODUCT_CREATE, $createCloneEvent);
|
||||
|
||||
$event->setClonedProduct($createCloneEvent->getProduct());
|
||||
}
|
||||
|
||||
public function updateClone(ProductCloneEvent $event, ProductPrice $originalProductDefaultPrice)
|
||||
{
|
||||
// Get original product's I18ns
|
||||
$originalProductI18ns = ProductI18nQuery::create()
|
||||
->findById($event->getOriginalProduct()->getId());
|
||||
|
||||
/** @var ProductI18n $originalProductI18n */
|
||||
foreach ($originalProductI18ns as $originalProductI18n) {
|
||||
$clonedProductUpdateEvent = new ProductUpdateEvent($event->getClonedProduct()->getId());
|
||||
$clonedProductUpdateEvent
|
||||
->setRef($event->getClonedProduct()->getRef())
|
||||
->setVisible($event->getClonedProduct()->getVisible())
|
||||
->setVirtual($event->getClonedProduct()->getVirtual())
|
||||
|
||||
->setLocale($originalProductI18n->getLocale())
|
||||
->setTitle($originalProductI18n->getTitle())
|
||||
->setChapo($originalProductI18n->getChapo())
|
||||
->setDescription($originalProductI18n->getDescription())
|
||||
->setPostscriptum($originalProductI18n->getPostscriptum())
|
||||
|
||||
->setBasePrice($originalProductDefaultPrice->getPrice())
|
||||
->setCurrencyId($originalProductDefaultPrice->getCurrencyId())
|
||||
->setBaseWeight($event->getOriginalProduct()->getDefaultSaleElements()->getWeight())
|
||||
->setTaxRuleId($event->getOriginalProduct()->getTaxRuleId())
|
||||
->setBrandId($event->getOriginalProduct()->getBrandId())
|
||||
->setDefaultCategory($event->getOriginalProduct()->getDefaultCategoryId());
|
||||
|
||||
$this->eventDispatcher->dispatch(TheliaEvents::PRODUCT_UPDATE, $clonedProductUpdateEvent);
|
||||
|
||||
// SEO info
|
||||
$clonedProductUpdateSeoEvent = new UpdateSeoEvent($event->getClonedProduct()->getId());
|
||||
$clonedProductUpdateSeoEvent
|
||||
->setLocale($originalProductI18n->getLocale())
|
||||
->setMetaTitle($originalProductI18n->getMetaTitle())
|
||||
->setMetaDescription($originalProductI18n->getMetaDescription())
|
||||
->setMetaKeywords($originalProductI18n->getMetaKeywords())
|
||||
->setUrl(null);
|
||||
$this->eventDispatcher->dispatch(TheliaEvents::PRODUCT_UPDATE_SEO, $clonedProductUpdateSeoEvent);
|
||||
}
|
||||
|
||||
$event->setClonedProduct($clonedProductUpdateEvent->getProduct());
|
||||
|
||||
// Set clone's template
|
||||
$clonedProductUpdateTemplateEvent = new ProductSetTemplateEvent(
|
||||
$event->getClonedProduct(),
|
||||
$event->getOriginalProduct()->getTemplateId(),
|
||||
$originalProductDefaultPrice->getCurrencyId()
|
||||
);
|
||||
|
||||
$this->eventDispatcher->dispatch(TheliaEvents::PRODUCT_SET_TEMPLATE, $clonedProductUpdateTemplateEvent);
|
||||
}
|
||||
|
||||
public function cloneFeatureCombination(ProductCloneEvent $event)
|
||||
{
|
||||
// Get original product FeatureProduct list
|
||||
$originalProductFeatureList = FeatureProductQuery::create()
|
||||
->findByProductId($event->getOriginalProduct()->getId());
|
||||
|
||||
// Set clone product FeatureProducts
|
||||
/** @var FeatureProduct $originalProductFeature */
|
||||
foreach ($originalProductFeatureList as $originalProductFeature) {
|
||||
// Get original FeatureAvI18n list
|
||||
$originalProductFeatureAvI18nList = FeatureAvI18nQuery::create()
|
||||
->findById($originalProductFeature->getFeatureAvId());
|
||||
|
||||
/** @var FeatureAvI18n $originalProductFeatureAvI18n */
|
||||
foreach ($originalProductFeatureAvI18nList as $originalProductFeatureAvI18n) {
|
||||
// Create a FeatureProduct for each FeatureAv (not for each FeatureAvI18n)
|
||||
$clonedProductCreateFeatureEvent = new FeatureProductUpdateEvent(
|
||||
$event->getClonedProduct()->getId(),
|
||||
$originalProductFeature->getFeatureId(),
|
||||
$originalProductFeature->getFeatureAvId()
|
||||
);
|
||||
$clonedProductCreateFeatureEvent->setLocale($originalProductFeatureAvI18n->getLocale());
|
||||
|
||||
// If it's a free text value, pass the FeatureAvI18n's title as featureValue to the event
|
||||
if ($originalProductFeature->getFreeTextValue() !== null) {
|
||||
$clonedProductCreateFeatureEvent->setFeatureValue($originalProductFeatureAvI18n->getTitle());
|
||||
$clonedProductCreateFeatureEvent->setIsTextValue(true);
|
||||
}
|
||||
|
||||
$this->eventDispatcher->dispatch(TheliaEvents::PRODUCT_FEATURE_UPDATE_VALUE, $clonedProductCreateFeatureEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function cloneAssociatedContent(ProductCloneEvent $event)
|
||||
{
|
||||
// Get original product associated contents
|
||||
$originalProductAssocConts = ProductAssociatedContentQuery::create()
|
||||
->findByProductId($event->getOriginalProduct()->getId());
|
||||
|
||||
// Set clone product associated contents
|
||||
foreach ($originalProductAssocConts as $originalProductAssocCont) {
|
||||
$clonedProductCreatePAC = new ProductAddContentEvent($event->getClonedProduct(), $originalProductAssocCont->getContentId());
|
||||
$this->eventDispatcher->dispatch(TheliaEvents::PRODUCT_ADD_CONTENT, $clonedProductCreatePAC);
|
||||
}
|
||||
}
|
||||
|
||||
public function cloneAccessories(ProductCloneEvent $event)
|
||||
{
|
||||
// Get original product accessories
|
||||
$originalProductAccessoryList = AccessoryQuery::create()
|
||||
->findByProductId($event->getOriginalProduct()->getId());
|
||||
|
||||
// Set clone product accessories
|
||||
foreach ($originalProductAccessoryList as $originalProductAccessory) {
|
||||
$clonedProductAddAccessoryEvent = new ProductAddAccessoryEvent($event->getClonedProduct(), $originalProductAccessory->getAccessory());
|
||||
$this->eventDispatcher->dispatch(TheliaEvents::PRODUCT_ADD_ACCESSORY, $clonedProductAddAccessoryEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/***************
|
||||
* END CLONING *
|
||||
***************/
|
||||
|
||||
/**
|
||||
* Change a product
|
||||
*
|
||||
* @param \Thelia\Core\Event\Product\ProductUpdateEvent $event
|
||||
* @throws PropelException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function update(ProductUpdateEvent $event)
|
||||
{
|
||||
if (null !== $product = ProductQuery::create()->findPk($event->getProductId())) {
|
||||
$con = Propel::getWriteConnection(ProductTableMap::DATABASE_NAME);
|
||||
$con->beginTransaction();
|
||||
|
||||
try {
|
||||
$prevRef = $product->getRef();
|
||||
|
||||
$product
|
||||
->setDispatcher($this->eventDispatcher)
|
||||
->setRef($event->getRef())
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
->setDescription($event->getDescription())
|
||||
->setChapo($event->getChapo())
|
||||
->setPostscriptum($event->getPostscriptum())
|
||||
->setVisible($event->getVisible() ? 1 : 0)
|
||||
->setVirtual($event->getVirtual() ? 1 : 0)
|
||||
->setBrandId($event->getBrandId() <= 0 ? null : $event->getBrandId())
|
||||
|
||||
->save($con)
|
||||
;
|
||||
|
||||
// Update default PSE (if product has no attributes and the product's ref change)
|
||||
$defaultPseRefChange = $prevRef !== $product->getRef()
|
||||
&& 0 === $product->getDefaultSaleElements()->countAttributeCombinations();
|
||||
if ($defaultPseRefChange) {
|
||||
$defaultPse = $product->getDefaultSaleElements();
|
||||
$defaultPse->setRef($product->getRef())->save();
|
||||
}
|
||||
|
||||
// Update default category (if required)
|
||||
$product->setDefaultCategory($event->getDefaultCategory());
|
||||
|
||||
$event->setProduct($product);
|
||||
$con->commit();
|
||||
} catch (PropelException $e) {
|
||||
$con->rollBack();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param UpdateSeoEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
* @return mixed
|
||||
*/
|
||||
public function updateSeo(UpdateSeoEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
return $this->genericUpdateSeo(ProductQuery::create(), $event, $dispatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a product entry
|
||||
*
|
||||
* @param \Thelia\Core\Event\Product\ProductDeleteEvent $event
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function delete(ProductDeleteEvent $event)
|
||||
{
|
||||
if (null !== $product = ProductQuery::create()->findPk($event->getProductId())) {
|
||||
$con = Propel::getWriteConnection(ProductTableMap::DATABASE_NAME);
|
||||
$con->beginTransaction();
|
||||
|
||||
try {
|
||||
$fileList = ['images' => [], 'documentList' => []];
|
||||
|
||||
// Get product's files to delete after product deletion
|
||||
$fileList['images']['list'] = ProductImageQuery::create()
|
||||
->findByProductId($event->getProductId());
|
||||
$fileList['images']['type'] = TheliaEvents::IMAGE_DELETE;
|
||||
|
||||
$fileList['documentList']['list'] = ProductDocumentQuery::create()
|
||||
->findByProductId($event->getProductId());
|
||||
$fileList['documentList']['type'] = TheliaEvents::DOCUMENT_DELETE;
|
||||
|
||||
// Delete free_text_feature AV (see issue #2061)
|
||||
$featureAvs = FeatureAvQuery::create()
|
||||
->useFeatureProductQuery()
|
||||
->filterByFreeTextValue(true)
|
||||
->filterByProductId($event->getProductId())
|
||||
->endUse()
|
||||
->find($con)
|
||||
;
|
||||
|
||||
foreach ($featureAvs as $featureAv) {
|
||||
$featureAv
|
||||
->setDispatcher($this->eventDispatcher)
|
||||
->delete($con)
|
||||
;
|
||||
}
|
||||
|
||||
// Delete product
|
||||
$product
|
||||
->setDispatcher($this->eventDispatcher)
|
||||
->delete($con)
|
||||
;
|
||||
|
||||
$event->setProduct($product);
|
||||
|
||||
// Dispatch delete product's files event
|
||||
foreach ($fileList as $fileTypeList) {
|
||||
foreach ($fileTypeList['list'] as $fileToDelete) {
|
||||
$fileDeleteEvent = new FileDeleteEvent($fileToDelete);
|
||||
$this->eventDispatcher->dispatch($fileTypeList['type'], $fileDeleteEvent);
|
||||
}
|
||||
}
|
||||
|
||||
$con->commit();
|
||||
} catch (\Exception $e) {
|
||||
$con->rollBack();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle product visibility. No form used here
|
||||
*
|
||||
* @param ProductToggleVisibilityEvent $event
|
||||
*/
|
||||
public function toggleVisibility(ProductToggleVisibilityEvent $event)
|
||||
{
|
||||
$product = $event->getProduct();
|
||||
|
||||
$product
|
||||
->setDispatcher($this->eventDispatcher)
|
||||
->setVisible($product->getVisible() ? false : true)
|
||||
->save()
|
||||
;
|
||||
|
||||
$event->setProduct($product);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes position, selecting absolute ou relative change.
|
||||
*
|
||||
* @param UpdatePositionEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function updatePosition(UpdatePositionEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$this->genericUpdateDelegatePosition(
|
||||
ProductCategoryQuery::create()
|
||||
->filterByProductId($event->getObjectId())
|
||||
->filterByCategoryId($event->getReferrerId()),
|
||||
$event,
|
||||
$dispatcher
|
||||
);
|
||||
}
|
||||
|
||||
public function addContent(ProductAddContentEvent $event)
|
||||
{
|
||||
if (ProductAssociatedContentQuery::create()
|
||||
->filterByContentId($event->getContentId())
|
||||
->filterByProduct($event->getProduct())->count() <= 0) {
|
||||
$content = new ProductAssociatedContent();
|
||||
|
||||
$content
|
||||
->setDispatcher($this->eventDispatcher)
|
||||
->setProduct($event->getProduct())
|
||||
->setContentId($event->getContentId())
|
||||
->save()
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
public function removeContent(ProductDeleteContentEvent $event)
|
||||
{
|
||||
$content = ProductAssociatedContentQuery::create()
|
||||
->filterByContentId($event->getContentId())
|
||||
->filterByProduct($event->getProduct())->findOne()
|
||||
;
|
||||
|
||||
if ($content !== null) {
|
||||
$content
|
||||
->setDispatcher($this->eventDispatcher)
|
||||
->delete()
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
public function addCategory(ProductAddCategoryEvent $event)
|
||||
{
|
||||
if (ProductCategoryQuery::create()
|
||||
->filterByProduct($event->getProduct())
|
||||
->filterByCategoryId($event->getCategoryId())
|
||||
->count() <= 0) {
|
||||
$productCategory = (new ProductCategory())
|
||||
->setProduct($event->getProduct())
|
||||
->setCategoryId($event->getCategoryId())
|
||||
->setDefaultCategory(false);
|
||||
|
||||
$productCategory
|
||||
->setPosition($productCategory->getNextPosition())
|
||||
->save();
|
||||
}
|
||||
}
|
||||
|
||||
public function removeCategory(ProductDeleteCategoryEvent $event)
|
||||
{
|
||||
$productCategory = ProductCategoryQuery::create()
|
||||
->filterByProduct($event->getProduct())
|
||||
->filterByCategoryId($event->getCategoryId())
|
||||
->findOne();
|
||||
|
||||
if ($productCategory != null) {
|
||||
$productCategory->delete();
|
||||
}
|
||||
}
|
||||
|
||||
public function addAccessory(ProductAddAccessoryEvent $event)
|
||||
{
|
||||
if (AccessoryQuery::create()
|
||||
->filterByAccessory($event->getAccessoryId())
|
||||
->filterByProductId($event->getProduct()->getId())->count() <= 0) {
|
||||
$accessory = new Accessory();
|
||||
|
||||
$accessory
|
||||
->setDispatcher($this->eventDispatcher)
|
||||
->setProductId($event->getProduct()->getId())
|
||||
->setAccessory($event->getAccessoryId())
|
||||
->save()
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
public function removeAccessory(ProductDeleteAccessoryEvent $event)
|
||||
{
|
||||
$accessory = AccessoryQuery::create()
|
||||
->filterByAccessory($event->getAccessoryId())
|
||||
->filterByProductId($event->getProduct()->getId())->findOne()
|
||||
;
|
||||
|
||||
if ($accessory !== null) {
|
||||
$accessory
|
||||
->setDispatcher($this->eventDispatcher)
|
||||
->delete()
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
public function setProductTemplate(ProductSetTemplateEvent $event)
|
||||
{
|
||||
$con = Propel::getWriteConnection(ProductTableMap::DATABASE_NAME);
|
||||
|
||||
$con->beginTransaction();
|
||||
|
||||
try {
|
||||
$product = $event->getProduct();
|
||||
|
||||
// Delete all product feature relations
|
||||
if (null !== $featureProducts = FeatureProductQuery::create()->findByProductId($product->getId())) {
|
||||
/** @var \Thelia\Model\FeatureProduct $featureProduct */
|
||||
foreach ($featureProducts as $featureProduct) {
|
||||
$eventDelete = new FeatureProductDeleteEvent($product->getId(), $featureProduct->getFeatureId());
|
||||
|
||||
$this->eventDispatcher->dispatch(TheliaEvents::PRODUCT_FEATURE_DELETE_VALUE, $eventDelete);
|
||||
}
|
||||
}
|
||||
|
||||
// Delete all product attributes sale elements
|
||||
AttributeCombinationQuery::create()
|
||||
->filterByProductSaleElements($product->getProductSaleElementss())
|
||||
->delete($con)
|
||||
;
|
||||
|
||||
//Delete all productSaleElements except the default one (to keep price, weight, ean, etc...)
|
||||
ProductSaleElementsQuery::create()
|
||||
->filterByProduct($product)
|
||||
->filterByIsDefault(1, Criteria::NOT_EQUAL)
|
||||
->delete($con)
|
||||
;
|
||||
|
||||
// Update the product template
|
||||
$template_id = $event->getTemplateId();
|
||||
|
||||
// Set it to null if it's zero.
|
||||
if ($template_id <= 0) {
|
||||
$template_id = null;
|
||||
}
|
||||
|
||||
$product->setTemplateId($template_id)->save($con);
|
||||
|
||||
//Be sure that the product has a default productSaleElements
|
||||
/** @var \Thelia\Model\ProductSaleElements $defaultPse */
|
||||
if (null == $defaultPse = ProductSaleElementsQuery::create()
|
||||
->filterByProduct($product)
|
||||
->filterByIsDefault(1)
|
||||
->findOne()) {
|
||||
// Create a new default product sale element
|
||||
$product->createProductSaleElement($con, 0, 0, 0, $event->getCurrencyId(), true);
|
||||
}
|
||||
|
||||
$product->clearProductSaleElementss();
|
||||
|
||||
$event->setProduct($product);
|
||||
|
||||
// Store all the stuff !
|
||||
$con->commit();
|
||||
} catch (\Exception $ex) {
|
||||
$con->rollBack();
|
||||
|
||||
throw $ex;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes accessry position, selecting absolute ou relative change.
|
||||
*
|
||||
* @param UpdatePositionEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
* @return Object
|
||||
*/
|
||||
public function updateAccessoryPosition(UpdatePositionEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
return $this->genericUpdatePosition(AccessoryQuery::create(), $event, $dispatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes position, selecting absolute ou relative change.
|
||||
*
|
||||
* @param UpdatePositionEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
* @return Object
|
||||
*/
|
||||
public function updateContentPosition(UpdatePositionEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
return $this->genericUpdatePosition(ProductAssociatedContentQuery::create(), $event, $dispatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the value of a product feature.
|
||||
*
|
||||
* @param FeatureProductUpdateEvent $event
|
||||
*/
|
||||
public function updateFeatureProductValue(FeatureProductUpdateEvent $event)
|
||||
{
|
||||
// Prepare the FeatureAv's ID
|
||||
$featureAvId = $event->getFeatureValue();
|
||||
|
||||
// Search for existing FeatureProduct
|
||||
$featureProductQuery = FeatureProductQuery::create()
|
||||
->filterByProductId($event->getProductId())
|
||||
->filterByFeatureId($event->getFeatureId())
|
||||
;
|
||||
|
||||
// If it's not a free text value, we can filter by the event's featureValue (which is an ID)
|
||||
if ($event->getFeatureValue() !== null && $event->getIsTextValue() === false) {
|
||||
$featureProductQuery->filterByFeatureAvId($featureAvId);
|
||||
}
|
||||
|
||||
$featureProduct = $featureProductQuery->findOne();
|
||||
|
||||
// If the FeatureProduct does not exist, create it
|
||||
if ($featureProduct === null) {
|
||||
$featureProduct = new FeatureProduct();
|
||||
|
||||
$featureProduct
|
||||
->setDispatcher($this->eventDispatcher)
|
||||
->setProductId($event->getProductId())
|
||||
->setFeatureId($event->getFeatureId())
|
||||
;
|
||||
|
||||
// If it's a free text value, create a FeatureAv to handle i18n
|
||||
if ($event->getIsTextValue() === true) {
|
||||
$featureProduct->setFreeTextValue(true);
|
||||
|
||||
$createFeatureAvEvent = new FeatureAvCreateEvent();
|
||||
$createFeatureAvEvent
|
||||
->setFeatureId($event->getFeatureId())
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getFeatureValue());
|
||||
$this->eventDispatcher->dispatch(TheliaEvents::FEATURE_AV_CREATE, $createFeatureAvEvent);
|
||||
|
||||
$featureAvId = $createFeatureAvEvent->getFeatureAv()->getId();
|
||||
}
|
||||
} // Else if the FeatureProduct exists and is a free text value
|
||||
elseif ($featureProduct !== null && $event->getIsTextValue() === true) {
|
||||
// Get the FeatureAv
|
||||
$freeTextFeatureAv = FeatureAvQuery::create()
|
||||
->filterByFeatureProduct($featureProduct)
|
||||
->findOneByFeatureId($event->getFeatureId());
|
||||
|
||||
// Get the FeatureAvI18n by locale
|
||||
$freeTextFeatureAvI18n = FeatureAvI18nQuery::create()
|
||||
->filterById($freeTextFeatureAv->getId())
|
||||
->findOneByLocale($event->getLocale());
|
||||
|
||||
// Nothing found for this lang and the new value is not empty : create FeatureAvI18n
|
||||
if ($freeTextFeatureAvI18n === null && !empty($featureAvId)) {
|
||||
$featureAvI18n = new FeatureAvI18n();
|
||||
$featureAvI18n
|
||||
->setId($freeTextFeatureAv->getId())
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getFeatureValue())
|
||||
->save();
|
||||
|
||||
$featureAvId = $featureAvI18n->getId();
|
||||
} // Else if i18n exists but new value is empty : delete FeatureAvI18n
|
||||
elseif ($freeTextFeatureAvI18n !== null && empty($featureAvId)) {
|
||||
$freeTextFeatureAvI18n->delete();
|
||||
|
||||
// Check if there are still some FeatureAvI18n for this FeatureAv
|
||||
$freeTextFeatureAvI18ns = FeatureAvI18nQuery::create()
|
||||
->findById($freeTextFeatureAv->getId());
|
||||
|
||||
// If there are no more FeatureAvI18ns for this FeatureAv, remove the corresponding FeatureProduct & FeatureAv
|
||||
if (count($freeTextFeatureAvI18ns) == 0) {
|
||||
$deleteFeatureProductEvent = new FeatureProductDeleteEvent($event->getProductId(), $event->getFeatureId());
|
||||
$this->eventDispatcher->dispatch(TheliaEvents::PRODUCT_FEATURE_DELETE_VALUE, $deleteFeatureProductEvent);
|
||||
|
||||
$deleteFeatureAvEvent = new FeatureAvDeleteEvent($freeTextFeatureAv->getId());
|
||||
$this->eventDispatcher->dispatch(TheliaEvents::FEATURE_AV_DELETE, $deleteFeatureAvEvent);
|
||||
|
||||
return;
|
||||
}
|
||||
} // Else if a FeatureAvI18n is found and the new value is not empty : update existing FeatureAvI18n
|
||||
elseif ($freeTextFeatureAvI18n !== null && !empty($featureAvId)) {
|
||||
$freeTextFeatureAvI18n->setTitle($featureAvId);
|
||||
$freeTextFeatureAvI18n->save();
|
||||
|
||||
$featureAvId = $freeTextFeatureAvI18n->getId();
|
||||
}
|
||||
} // Else the FeatureProduct exists and is not a free text value
|
||||
else {
|
||||
$featureAvId = $event->getFeatureValue();
|
||||
}
|
||||
|
||||
$featureProduct->setFeatureAvId($featureAvId);
|
||||
|
||||
$featureProduct->save();
|
||||
|
||||
$event->setFeatureProduct($featureProduct);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a product feature value
|
||||
*
|
||||
* @param FeatureProductDeleteEvent $event
|
||||
*/
|
||||
public function deleteFeatureProductValue(FeatureProductDeleteEvent $event)
|
||||
{
|
||||
FeatureProductQuery::create()
|
||||
->filterByProductId($event->getProductId())
|
||||
->filterByFeatureId($event->getFeatureId())
|
||||
->delete()
|
||||
;
|
||||
}
|
||||
|
||||
public function deleteImagePSEAssociations(FileDeleteEvent $event)
|
||||
{
|
||||
$model = $event->getFileToDelete();
|
||||
|
||||
if ($model instanceof ProductImage) {
|
||||
$model->getProductSaleElementsProductImages()->delete();
|
||||
}
|
||||
}
|
||||
|
||||
public function deleteDocumentPSEAssociations(FileDeleteEvent $event)
|
||||
{
|
||||
$model = $event->getFileToDelete();
|
||||
|
||||
if ($model instanceof ProductDocument) {
|
||||
$model->getProductSaleElementsProductDocuments()->delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::PRODUCT_CREATE => array("create", 128),
|
||||
TheliaEvents::PRODUCT_CLONE => array("cloneProduct", 128),
|
||||
TheliaEvents::PRODUCT_UPDATE => array("update", 128),
|
||||
TheliaEvents::PRODUCT_DELETE => array("delete", 128),
|
||||
TheliaEvents::PRODUCT_TOGGLE_VISIBILITY => array("toggleVisibility", 128),
|
||||
|
||||
TheliaEvents::PRODUCT_UPDATE_POSITION => array("updatePosition", 128),
|
||||
TheliaEvents::PRODUCT_UPDATE_SEO => array("updateSeo", 128),
|
||||
|
||||
TheliaEvents::PRODUCT_ADD_CONTENT => array("addContent", 128),
|
||||
TheliaEvents::PRODUCT_REMOVE_CONTENT => array("removeContent", 128),
|
||||
TheliaEvents::PRODUCT_UPDATE_CONTENT_POSITION => array("updateContentPosition", 128),
|
||||
|
||||
TheliaEvents::PRODUCT_ADD_ACCESSORY => array("addAccessory", 128),
|
||||
TheliaEvents::PRODUCT_REMOVE_ACCESSORY => array("removeAccessory", 128),
|
||||
TheliaEvents::PRODUCT_UPDATE_ACCESSORY_POSITION => array("updateAccessoryPosition", 128),
|
||||
|
||||
TheliaEvents::PRODUCT_ADD_CATEGORY => array("addCategory", 128),
|
||||
TheliaEvents::PRODUCT_REMOVE_CATEGORY => array("removeCategory", 128),
|
||||
|
||||
TheliaEvents::PRODUCT_SET_TEMPLATE => array("setProductTemplate", 128),
|
||||
|
||||
TheliaEvents::PRODUCT_FEATURE_UPDATE_VALUE => array("updateFeatureProductValue", 128),
|
||||
TheliaEvents::PRODUCT_FEATURE_DELETE_VALUE => array("deleteFeatureProductValue", 128),
|
||||
|
||||
// Those two have to be executed before
|
||||
TheliaEvents::IMAGE_DELETE => array("deleteImagePSEAssociations", 192),
|
||||
TheliaEvents::DOCUMENT_DELETE => array("deleteDocumentPSEAssociations", 192),
|
||||
);
|
||||
}
|
||||
}
|
||||
484
core/lib/Thelia/Action/ProductSaleElement.php
Normal file
484
core/lib/Thelia/Action/ProductSaleElement.php
Normal file
@@ -0,0 +1,484 @@
|
||||
<?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\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;
|
||||
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
|
||||
*/
|
||||
public function create(ProductSaleElementCreateEvent $event)
|
||||
{
|
||||
$con = Propel::getWriteConnection(ProductSaleElementsTableMap::DATABASE_NAME);
|
||||
|
||||
$con->beginTransaction();
|
||||
|
||||
try {
|
||||
// Check if we have a PSE without combination, this is the "default" PSE. Attach the combination to this PSE
|
||||
$salesElement = ProductSaleElementsQuery::create()
|
||||
->filterByProductId($event->getProduct()->getId())
|
||||
->joinAttributeCombination(null, Criteria::LEFT_JOIN)
|
||||
->add(AttributeCombinationTableMap::PRODUCT_SALE_ELEMENTS_ID, null, Criteria::ISNULL)
|
||||
->findOne($con);
|
||||
|
||||
if ($salesElement == null) {
|
||||
// Create a new default product sale element
|
||||
$salesElement = $event->getProduct()->createProductSaleElement($con, 0, 0, 0, $event->getCurrencyId(), false);
|
||||
} else {
|
||||
// This (new) one is the default
|
||||
$salesElement->setIsDefault(true)->save($con);
|
||||
}
|
||||
|
||||
// Attach combination, if defined.
|
||||
$combinationAttributes = $event->getAttributeAvList();
|
||||
|
||||
if (count($combinationAttributes) > 0) {
|
||||
foreach ($combinationAttributes as $attributeAvId) {
|
||||
$attributeAv = AttributeAvQuery::create()->findPk($attributeAvId);
|
||||
|
||||
if ($attributeAv !== null) {
|
||||
$attributeCombination = new AttributeCombination();
|
||||
|
||||
$attributeCombination
|
||||
->setAttributeAvId($attributeAvId)
|
||||
->setAttribute($attributeAv->getAttribute())
|
||||
->setProductSaleElements($salesElement)
|
||||
->save($con);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$event->setProductSaleElement($salesElement);
|
||||
|
||||
// Store all the stuff !
|
||||
$con->commit();
|
||||
} catch (\Exception $ex) {
|
||||
$con->rollback();
|
||||
|
||||
throw $ex;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an existing product sale element
|
||||
*
|
||||
* @param ProductSaleElementUpdateEvent $event
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function update(ProductSaleElementUpdateEvent $event)
|
||||
{
|
||||
$salesElement = ProductSaleElementsQuery::create()->findPk($event->getProductSaleElementId());
|
||||
|
||||
$con = Propel::getWriteConnection(ProductSaleElementsTableMap::DATABASE_NAME);
|
||||
|
||||
$con->beginTransaction();
|
||||
|
||||
try {
|
||||
// Update the product's tax rule
|
||||
$event->getProduct()->setTaxRuleId($event->getTaxRuleId())->save($con);
|
||||
|
||||
// If product sale element is not defined, create it.
|
||||
if ($salesElement == null) {
|
||||
$salesElement = new ProductSaleElements();
|
||||
|
||||
$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())
|
||||
->setQuantity($event->getQuantity())
|
||||
->setPromo($event->getOnsale())
|
||||
->setNewness($event->getIsnew())
|
||||
->setWeight($event->getWeight())
|
||||
->setIsDefault($event->getIsDefault())
|
||||
->setEanCode($event->getEanCode())
|
||||
->save()
|
||||
;
|
||||
|
||||
// Update/create price for current currency
|
||||
$productPrice = ProductPriceQuery::create()
|
||||
->filterByCurrencyId($event->getCurrencyId())
|
||||
->filterByProductSaleElementsId($salesElement->getId())
|
||||
->findOne($con);
|
||||
|
||||
// If price is not defined, create it.
|
||||
if ($productPrice == null) {
|
||||
$productPrice = new ProductPrice();
|
||||
|
||||
$productPrice
|
||||
->setProductSaleElements($salesElement)
|
||||
->setCurrencyId($event->getCurrencyId())
|
||||
;
|
||||
}
|
||||
|
||||
// Check if we have to store the price
|
||||
$productPrice->setFromDefaultCurrency($event->getFromDefaultCurrency());
|
||||
|
||||
if ($event->getFromDefaultCurrency() == 0) {
|
||||
// Store the price
|
||||
$productPrice
|
||||
->setPromoPrice($event->getSalePrice())
|
||||
->setPrice($event->getPrice())
|
||||
;
|
||||
} else {
|
||||
// Do not store the price.
|
||||
$productPrice
|
||||
->setPromoPrice(0)
|
||||
->setPrice(0)
|
||||
;
|
||||
}
|
||||
|
||||
$productPrice->save($con);
|
||||
|
||||
// Store all the stuff !
|
||||
$con->commit();
|
||||
} catch (\Exception $ex) {
|
||||
$con->rollback();
|
||||
|
||||
throw $ex;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a product sale element
|
||||
*
|
||||
* @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);
|
||||
|
||||
$con->beginTransaction();
|
||||
|
||||
try {
|
||||
$pse->delete($con);
|
||||
|
||||
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
|
||||
$newDefaultPse = ProductSaleElementsQuery::create()
|
||||
->filterByProductId($product->getId())
|
||||
->filterById($pse->getId(), Criteria::NOT_EQUAL)
|
||||
->orderByCreatedAt(Criteria::DESC)
|
||||
->findOne($con)
|
||||
;
|
||||
|
||||
if (null !== $newDefaultPse) {
|
||||
$newDefaultPse->setIsDefault(true)->save($con);
|
||||
}
|
||||
}
|
||||
|
||||
// Store all the stuff !
|
||||
$con->commit();
|
||||
} catch (\Exception $ex) {
|
||||
$con->rollback();
|
||||
|
||||
throw $ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate combinations. All existing combinations for the product are deleted.
|
||||
*
|
||||
* @param ProductCombinationGenerationEvent $event
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function generateCombinations(ProductCombinationGenerationEvent $event)
|
||||
{
|
||||
$con = Propel::getWriteConnection(ProductSaleElementsTableMap::DATABASE_NAME);
|
||||
|
||||
$con->beginTransaction();
|
||||
|
||||
try {
|
||||
// Delete all product's productSaleElement
|
||||
ProductSaleElementsQuery::create()->filterByProductId($event->product->getId())->delete();
|
||||
|
||||
$isDefault = true;
|
||||
|
||||
// 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()
|
||||
);
|
||||
|
||||
$isDefault = false;
|
||||
|
||||
$this->createCombination($con, $saleElement, $combinationAttributesAvIds);
|
||||
}
|
||||
|
||||
// Store all the stuff !
|
||||
$con->commit();
|
||||
} catch (\Exception $ex) {
|
||||
$con->rollback();
|
||||
|
||||
throw $ex;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a combination for a given product sale element
|
||||
*
|
||||
* @param ConnectionInterface $con the Propel connection
|
||||
* @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) {
|
||||
$attributeCombination = new AttributeCombination();
|
||||
|
||||
$attributeCombination
|
||||
->setAttributeAvId($attributeAvId)
|
||||
->setAttribute($attributeAv->getAttribute())
|
||||
->setProductSaleElements($salesElement)
|
||||
->save($con);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*******************
|
||||
* 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}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::PRODUCT_ADD_PRODUCT_SALE_ELEMENT => array("create", 128),
|
||||
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)
|
||||
);
|
||||
}
|
||||
}
|
||||
151
core/lib/Thelia/Action/Profile.php
Normal file
151
core/lib/Thelia/Action/Profile.php
Normal file
@@ -0,0 +1,151 @@
|
||||
<?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\Profile\ProfileEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\Security\AccessManager;
|
||||
use Thelia\Model\ModuleQuery;
|
||||
use Thelia\Model\Profile as ProfileModel;
|
||||
use Thelia\Model\ProfileModule;
|
||||
use Thelia\Model\ProfileModuleQuery;
|
||||
use Thelia\Model\ProfileQuery;
|
||||
use Thelia\Model\ProfileResource;
|
||||
use Thelia\Model\ProfileResourceQuery;
|
||||
use Thelia\Model\ResourceQuery;
|
||||
|
||||
class Profile extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
/**
|
||||
* @param ProfileEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function create(ProfileEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$profile = new ProfileModel();
|
||||
|
||||
$profile
|
||||
->setDispatcher($dispatcher)
|
||||
->setCode($event->getCode())
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
->setChapo($event->getChapo())
|
||||
->setDescription($event->getDescription())
|
||||
->setPostscriptum($event->getPostscriptum())
|
||||
;
|
||||
|
||||
$profile->save();
|
||||
|
||||
$event->setProfile($profile);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ProfileEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function update(ProfileEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $profile = ProfileQuery::create()->findPk($event->getId())) {
|
||||
$profile
|
||||
->setDispatcher($dispatcher)
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
->setChapo($event->getChapo())
|
||||
->setDescription($event->getDescription())
|
||||
->setPostscriptum($event->getPostscriptum())
|
||||
;
|
||||
|
||||
$profile->save();
|
||||
|
||||
$event->setProfile($profile);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ProfileEvent $event
|
||||
*/
|
||||
public function updateResourceAccess(ProfileEvent $event)
|
||||
{
|
||||
if (null !== $profile = ProfileQuery::create()->findPk($event->getId())) {
|
||||
ProfileResourceQuery::create()->filterByProfileId($event->getId())->delete();
|
||||
foreach ($event->getResourceAccess() as $resourceCode => $accesses) {
|
||||
$manager = new AccessManager(0);
|
||||
$manager->build($accesses);
|
||||
|
||||
$profileResource = new ProfileResource();
|
||||
$profileResource->setProfileId($event->getId())
|
||||
->setResource(ResourceQuery::create()->findOneByCode($resourceCode))
|
||||
->setAccess($manager->getAccessValue());
|
||||
|
||||
$profileResource->save();
|
||||
}
|
||||
|
||||
$event->setProfile($profile);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ProfileEvent $event
|
||||
*/
|
||||
public function updateModuleAccess(ProfileEvent $event)
|
||||
{
|
||||
if (null !== $profile = ProfileQuery::create()->findPk($event->getId())) {
|
||||
ProfileModuleQuery::create()->filterByProfileId($event->getId())->delete();
|
||||
foreach ($event->getModuleAccess() as $moduleCode => $accesses) {
|
||||
$manager = new AccessManager(0);
|
||||
$manager->build($accesses);
|
||||
|
||||
$profileModule = new ProfileModule();
|
||||
$profileModule->setProfileId($event->getId())
|
||||
->setModule(ModuleQuery::create()->findOneByCode($moduleCode))
|
||||
->setAccess($manager->getAccessValue());
|
||||
|
||||
$profileModule->save();
|
||||
}
|
||||
|
||||
$event->setProfile($profile);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ProfileEvent $event
|
||||
*/
|
||||
public function delete(ProfileEvent $event)
|
||||
{
|
||||
if (null !== $profile = ProfileQuery::create()->findPk($event->getId())) {
|
||||
$profile
|
||||
->delete()
|
||||
;
|
||||
|
||||
$event->setProfile($profile);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::PROFILE_CREATE => array("create", 128),
|
||||
TheliaEvents::PROFILE_UPDATE => array("update", 128),
|
||||
TheliaEvents::PROFILE_DELETE => array("delete", 128),
|
||||
TheliaEvents::PROFILE_RESOURCE_ACCESS_UPDATE => array("updateResourceAccess", 128),
|
||||
TheliaEvents::PROFILE_MODULE_ACCESS_UPDATE => array("updateModuleAccess", 128),
|
||||
);
|
||||
}
|
||||
}
|
||||
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),
|
||||
);
|
||||
}
|
||||
}
|
||||
63
core/lib/Thelia/Action/ShippingZone.php
Normal file
63
core/lib/Thelia/Action/ShippingZone.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\EventSubscriberInterface;
|
||||
use Thelia\Core\Event\ShippingZone\ShippingZoneAddAreaEvent;
|
||||
use Thelia\Core\Event\ShippingZone\ShippingZoneRemoveAreaEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Model\AreaDeliveryModule;
|
||||
use Thelia\Model\AreaDeliveryModuleQuery;
|
||||
|
||||
/**
|
||||
* Class ShippingZone
|
||||
* @package Thelia\Action
|
||||
* @author Manuel Raynaud <manu@raynaud.io>
|
||||
*/
|
||||
class ShippingZone extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
public function addArea(ShippingZoneAddAreaEvent $event)
|
||||
{
|
||||
$areaDelivery = new AreaDeliveryModule();
|
||||
|
||||
$areaDelivery
|
||||
->setAreaId($event->getAreaId())
|
||||
->setDeliveryModuleId($event->getShippingZoneId())
|
||||
->save();
|
||||
}
|
||||
|
||||
public function removeArea(ShippingZoneRemoveAreaEvent $event)
|
||||
{
|
||||
$areaDelivery = AreaDeliveryModuleQuery::create()
|
||||
->filterByAreaId($event->getAreaId())
|
||||
->filterByDeliveryModuleId($event->getShippingZoneId())
|
||||
->findOne();
|
||||
|
||||
if ($areaDelivery) {
|
||||
$areaDelivery->delete();
|
||||
} else {
|
||||
throw new \RuntimeException(sprintf('areaDeliveryModule not found with area_id = %d and delivery_module_id = %d', $event->getAreaId(), $event->getShippingZoneId()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::SHIPPING_ZONE_ADD_AREA => array('addArea', 128),
|
||||
TheliaEvents::SHIPPING_ZONE_REMOVE_AREA => array('removeArea', 128),
|
||||
);
|
||||
}
|
||||
}
|
||||
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)
|
||||
);
|
||||
}
|
||||
}
|
||||
95
core/lib/Thelia/Action/Tax.php
Normal file
95
core/lib/Thelia/Action/Tax.php
Normal file
@@ -0,0 +1,95 @@
|
||||
<?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\Tax\TaxEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Model\Tax as TaxModel;
|
||||
use Thelia\Model\TaxQuery;
|
||||
|
||||
class Tax extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
/**
|
||||
* @param TaxEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function create(TaxEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$tax = new TaxModel();
|
||||
|
||||
$tax
|
||||
->setDispatcher($dispatcher)
|
||||
->setRequirements($event->getRequirements())
|
||||
->setType($event->getType())
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
->setDescription($event->getDescription())
|
||||
;
|
||||
|
||||
$tax->save();
|
||||
|
||||
$event->setTax($tax);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TaxEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function update(TaxEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $tax = TaxQuery::create()->findPk($event->getId())) {
|
||||
$tax
|
||||
->setDispatcher($dispatcher)
|
||||
->setRequirements($event->getRequirements())
|
||||
->setType($event->getType())
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
->setDescription($event->getDescription())
|
||||
;
|
||||
|
||||
$tax->save();
|
||||
|
||||
$event->setTax($tax);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TaxEvent $event
|
||||
*/
|
||||
public function delete(TaxEvent $event)
|
||||
{
|
||||
if (null !== $tax = TaxQuery::create()->findPk($event->getId())) {
|
||||
$tax
|
||||
->delete()
|
||||
;
|
||||
|
||||
$event->setTax($tax);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::TAX_CREATE => array("create", 128),
|
||||
TheliaEvents::TAX_UPDATE => array("update", 128),
|
||||
TheliaEvents::TAX_DELETE => array("delete", 128),
|
||||
);
|
||||
}
|
||||
}
|
||||
205
core/lib/Thelia/Action/TaxRule.php
Normal file
205
core/lib/Thelia/Action/TaxRule.php
Normal file
@@ -0,0 +1,205 @@
|
||||
<?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\Tax\TaxRuleEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Model\TaxRuleCountry;
|
||||
use Thelia\Model\TaxRuleCountryQuery;
|
||||
use Thelia\Model\TaxRule as TaxRuleModel;
|
||||
use Thelia\Model\TaxRuleQuery;
|
||||
|
||||
class TaxRule extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
/**
|
||||
* @param TaxRuleEvent $event
|
||||
*/
|
||||
public function create(TaxRuleEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$taxRule = new TaxRuleModel();
|
||||
|
||||
$taxRule
|
||||
->setDispatcher($dispatcher)
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
->setDescription($event->getDescription())
|
||||
;
|
||||
|
||||
$taxRule->save();
|
||||
|
||||
$event->setTaxRule($taxRule)->setId($taxRule->getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TaxRuleEvent $event
|
||||
*/
|
||||
public function update(TaxRuleEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $taxRule = TaxRuleQuery::create()->findPk($event->getId())) {
|
||||
$taxRule
|
||||
->setDispatcher($dispatcher)
|
||||
->setLocale($event->getLocale())
|
||||
->setTitle($event->getTitle())
|
||||
->setDescription($event->getDescription())
|
||||
->save()
|
||||
;
|
||||
|
||||
$event->setTaxRule($taxRule);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TaxRuleEvent $event
|
||||
*/
|
||||
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());
|
||||
|
||||
/* 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 ($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($countryId)
|
||||
->setStateId($stateId ?: null)
|
||||
->setTaxId($samePositionTax)
|
||||
->setPosition($position);
|
||||
$taxModel->save();
|
||||
}
|
||||
} else {
|
||||
$taxModel = new TaxRuleCountry();
|
||||
$taxModel->setTaxRule($taxRule)
|
||||
->setCountryId($countryId)
|
||||
->setStateId($stateId ?: null)
|
||||
->setTaxId($tax)
|
||||
->setPosition($position);
|
||||
$taxModel->save();
|
||||
}
|
||||
$position++;
|
||||
}
|
||||
}
|
||||
|
||||
$event->setTaxRule($taxRule);
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
;
|
||||
|
||||
$event->setTaxRule($taxRule);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TaxRuleEvent $event
|
||||
*/
|
||||
public function setDefault(TaxRuleEvent $event)
|
||||
{
|
||||
if (null !== $taxRule = TaxRuleQuery::create()->findPk($event->getId())) {
|
||||
TaxRuleQuery::create()->update(array(
|
||||
"IsDefault" => 0
|
||||
));
|
||||
|
||||
$taxRule->setIsDefault(1)->save();
|
||||
|
||||
$event->setTaxRule($taxRule);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::TAX_RULE_CREATE => array("create", 128),
|
||||
TheliaEvents::TAX_RULE_UPDATE => array("update", 128),
|
||||
TheliaEvents::TAX_RULE_TAXES_UPDATE => array("updateTaxes", 128),
|
||||
TheliaEvents::TAX_RULE_DELETE => array("delete", 128),
|
||||
TheliaEvents::TAX_RULE_SET_DEFAULT => array("setDefault", 128),
|
||||
);
|
||||
}
|
||||
}
|
||||
229
core/lib/Thelia/Action/Template.php
Normal file
229
core/lib/Thelia/Action/Template.php
Normal file
@@ -0,0 +1,229 @@
|
||||
<?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\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Model\CategoryQuery;
|
||||
use Thelia\Model\Map\TemplateTableMap;
|
||||
use Thelia\Model\TemplateQuery;
|
||||
use Thelia\Model\Template as TemplateModel;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\Event\Template\TemplateUpdateEvent;
|
||||
use Thelia\Core\Event\Template\TemplateCreateEvent;
|
||||
use Thelia\Core\Event\Template\TemplateDeleteEvent;
|
||||
use Thelia\Core\Event\UpdatePositionEvent;
|
||||
use Thelia\Model\ProductQuery;
|
||||
use Thelia\Core\Event\Template\TemplateAddAttributeEvent;
|
||||
use Thelia\Core\Event\Template\TemplateDeleteAttributeEvent;
|
||||
use Thelia\Model\AttributeTemplateQuery;
|
||||
use Thelia\Model\AttributeTemplate;
|
||||
use Thelia\Core\Event\Template\TemplateDeleteFeatureEvent;
|
||||
use Thelia\Core\Event\Template\TemplateAddFeatureEvent;
|
||||
use Thelia\Model\FeatureTemplateQuery;
|
||||
use Thelia\Model\FeatureTemplate;
|
||||
|
||||
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, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$template = new TemplateModel();
|
||||
|
||||
$template
|
||||
->setDispatcher($dispatcher)
|
||||
|
||||
->setLocale($event->getLocale())
|
||||
->setName($event->getTemplateName())
|
||||
|
||||
->save()
|
||||
;
|
||||
|
||||
$event->setTemplate($template);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change a product template
|
||||
*
|
||||
* @param \Thelia\Core\Event\Template\TemplateUpdateEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function update(TemplateUpdateEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
if (null !== $template = TemplateQuery::create()->findPk($event->getTemplateId())) {
|
||||
$template
|
||||
->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, $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) {
|
||||
$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);
|
||||
}
|
||||
}
|
||||
|
||||
public function addAttribute(TemplateAddAttributeEvent $event)
|
||||
{
|
||||
if (null === AttributeTemplateQuery::create()
|
||||
->filterByAttributeId($event->getAttributeId())
|
||||
->filterByTemplate($event->getTemplate())
|
||||
->findOne()) {
|
||||
$attribute_template = new AttributeTemplate();
|
||||
|
||||
$attribute_template
|
||||
->setAttributeId($event->getAttributeId())
|
||||
->setTemplate($event->getTemplate())
|
||||
->save()
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes position, selecting absolute ou relative change.
|
||||
*
|
||||
* @param UpdatePositionEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function updateAttributePosition(UpdatePositionEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$this->genericUpdatePosition(AttributeTemplateQuery::create(), $event, $dispatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes position, selecting absolute ou relative change.
|
||||
*
|
||||
* @param UpdatePositionEvent $event
|
||||
* @param $eventName
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
*/
|
||||
public function updateFeaturePosition(UpdatePositionEvent $event, $eventName, EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
$this->genericUpdatePosition(FeatureTemplateQuery::create(), $event, $dispatcher);
|
||||
}
|
||||
|
||||
public function deleteAttribute(TemplateDeleteAttributeEvent $event)
|
||||
{
|
||||
$attribute_template = AttributeTemplateQuery::create()
|
||||
->filterByAttributeId($event->getAttributeId())
|
||||
->filterByTemplate($event->getTemplate())->findOne()
|
||||
;
|
||||
|
||||
if ($attribute_template !== null) {
|
||||
$attribute_template->delete();
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
public function deleteFeature(TemplateDeleteFeatureEvent $event)
|
||||
{
|
||||
$feature_template = FeatureTemplateQuery::create()
|
||||
->filterByFeatureId($event->getFeatureId())
|
||||
->filterByTemplate($event->getTemplate())->findOne()
|
||||
;
|
||||
|
||||
if ($feature_template !== null) {
|
||||
$feature_template->delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::TEMPLATE_CREATE => array("create", 128),
|
||||
TheliaEvents::TEMPLATE_UPDATE => array("update", 128),
|
||||
TheliaEvents::TEMPLATE_DELETE => array("delete", 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]
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
54
core/lib/Thelia/Cart/CartTrait.php
Normal file
54
core/lib/Thelia/Cart/CartTrait.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?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\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 Thelia\Core\HttpFoundation\Session\Session;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\Event\Cart\CartEvent;
|
||||
|
||||
/**
|
||||
* managed cart
|
||||
*
|
||||
* Trait CartTrait
|
||||
* @package Thelia\Cart
|
||||
* @author Manuel Raynaud <manu@raynaud.io>
|
||||
*
|
||||
* @deprecated CartTrait is deprecated, please use Session::getSessionCart method instead
|
||||
*/
|
||||
trait CartTrait
|
||||
{
|
||||
/**
|
||||
*
|
||||
* search if cart already exists in session. If not try to create a new one or duplicate an old one.
|
||||
*
|
||||
* @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)
|
||||
{
|
||||
trigger_error(
|
||||
'CartTrait is deprecated, please use Session::getSessionCart method instead',
|
||||
E_USER_DEPRECATED
|
||||
);
|
||||
|
||||
return $request->getSession()->getSessionCart($dispatcher);
|
||||
}
|
||||
}
|
||||
98
core/lib/Thelia/Command/AdminUpdatePasswordCommand.php
Normal file
98
core/lib/Thelia/Command/AdminUpdatePasswordCommand.php
Normal file
@@ -0,0 +1,98 @@
|
||||
<?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\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;
|
||||
|
||||
/**
|
||||
* command line for updating admin password
|
||||
*
|
||||
* php Thelia admin:updatePassword
|
||||
*
|
||||
* Class AdminUpdatePasswordCommand
|
||||
* @package Thelia\Command
|
||||
* @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.
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('admin:updatePassword')
|
||||
->setDescription('change administrator password')
|
||||
->setHelp('The <info>admin:updatePassword</info> command allows you to change the password for a given administrator')
|
||||
->addArgument(
|
||||
'login',
|
||||
InputArgument::REQUIRED,
|
||||
'Login for administrator you want to change the password'
|
||||
)
|
||||
->addOption(
|
||||
'password',
|
||||
null,
|
||||
InputOption::VALUE_REQUIRED,
|
||||
'Desired password. If this option is omitted, a random password is generated and shown in this prompt after'
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->init();
|
||||
|
||||
$login = $input->getArgument('login');
|
||||
|
||||
if (null === $admin = AdminQuery::create()->filterByLogin($login)->findOne()) {
|
||||
throw new \RuntimeException(sprintf('Admin with login %s does not exists', $login));
|
||||
}
|
||||
|
||||
$password = $input->getOption('password') ?: Password::generateRandom();
|
||||
|
||||
$event = new AdministratorUpdatePasswordEvent($admin);
|
||||
$event->setPassword($password);
|
||||
|
||||
$this->getDispatcher()->dispatch(TheliaEvents::ADMINISTRATOR_UPDATEPASSWORD, $event);
|
||||
|
||||
$output->writeln(array(
|
||||
'',
|
||||
sprintf('<info>admin %s password updated</info>', $login),
|
||||
sprintf('<info>new password is : %s</info>', $password),
|
||||
''
|
||||
));
|
||||
}
|
||||
}
|
||||
72
core/lib/Thelia/Command/BaseModuleGenerate.php
Normal file
72
core/lib/Thelia/Command/BaseModuleGenerate.php
Normal file
@@ -0,0 +1,72 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* base class for module commands
|
||||
*
|
||||
* Class BaseModuleGenerate
|
||||
* @package Thelia\Command
|
||||
* @author Manuel Raynaud <manu@raynaud.io>
|
||||
*/
|
||||
abstract class BaseModuleGenerate extends ContainerAwareCommand
|
||||
{
|
||||
protected $module;
|
||||
protected $moduleDirectory;
|
||||
|
||||
protected $reservedKeyWords = array(
|
||||
'thelia'
|
||||
);
|
||||
|
||||
protected $neededDirectories = array(
|
||||
'Config',
|
||||
'Model',
|
||||
'Loop',
|
||||
'Command',
|
||||
'Controller',
|
||||
'EventListeners',
|
||||
'I18n',
|
||||
'templates',
|
||||
'Hook',
|
||||
);
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
112
core/lib/Thelia/Command/CacheClear.php
Normal file
112
core/lib/Thelia/Command/CacheClear.php
Normal file
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace 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 <manu@raynaud.io>
|
||||
*
|
||||
*/
|
||||
class CacheClear extends ContainerAwareCommand
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName("cache:clear")
|
||||
->setDescription("Invalidate all caches")
|
||||
->addOption(
|
||||
"without-assets",
|
||||
null,
|
||||
InputOption::VALUE_NONE,
|
||||
"do not clear the assets cache in the web space"
|
||||
)
|
||||
->addOption(
|
||||
'with-images',
|
||||
null,
|
||||
InputOption::VALUE_NONE,
|
||||
'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 . ConfigQuery::read('asset_dir_from_web_root', 'assets'), $output);
|
||||
}
|
||||
|
||||
if ($input->getOption('with-images')) {
|
||||
$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)
|
||||
{
|
||||
$output->writeln(sprintf("Clearing cache in <info>%s</info> directory", $dir));
|
||||
|
||||
try {
|
||||
$cacheEvent = new CacheEvent($dir);
|
||||
$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)) {
|
||||
$output->writeln(sprintf("<info>%s cache dir already cleared</info>", $dir));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
throw $e;
|
||||
} catch (IOException $e) {
|
||||
$output->writeln(sprintf("Error during clearing of cache : %s", $e->getMessage()));
|
||||
}
|
||||
|
||||
$output->writeln(sprintf("<info>%s cache directory cleared successfully</info>", $dir));
|
||||
}
|
||||
}
|
||||
53
core/lib/Thelia/Command/ClearImageCache.php
Normal file
53
core/lib/Thelia/Command/ClearImageCache.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<?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\Image\ImageEvent;
|
||||
use Thelia\Core\HttpFoundation\Request;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
|
||||
class ClearImageCache extends ContainerAwareCommand
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName("image-cache:clear")
|
||||
->setDescription("Empty part or whole web space image cache")
|
||||
->addArgument("subdir", InputArgument::OPTIONAL, "Clear only the specified subdirectory")
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$request = new Request();
|
||||
|
||||
try {
|
||||
$event = new ImageEvent($request);
|
||||
|
||||
$subdir = $input->getArgument('subdir');
|
||||
|
||||
if (! is_null($subdir)) {
|
||||
$event->setCacheSubdirectory($subdir);
|
||||
}
|
||||
|
||||
$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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
132
core/lib/Thelia/Command/ContainerAwareCommand.php
Normal file
132
core/lib/Thelia/Command/ContainerAwareCommand.php
Normal file
@@ -0,0 +1,132 @@
|
||||
<?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\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
|
||||
{
|
||||
/**
|
||||
* @var ContainerInterface
|
||||
*/
|
||||
private $container;
|
||||
|
||||
/**
|
||||
* @return ContainerInterface
|
||||
*/
|
||||
protected function getContainer()
|
||||
{
|
||||
if (null === $this->container) {
|
||||
/** @var Application $application */
|
||||
$application = $this->getApplication();
|
||||
$this->container = $application->getKernel()->getContainer();
|
||||
}
|
||||
|
||||
return $this->container;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 = new URL($container);
|
||||
$url->setRequestContext($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;
|
||||
}
|
||||
}
|
||||
205
core/lib/Thelia/Command/CreateAdminUser.php
Normal file
205
core/lib/Thelia/Command/CreateAdminUser.php
Normal file
@@ -0,0 +1,205 @@
|
||||
<?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\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
|
||||
{
|
||||
/**
|
||||
* Configure the command
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName("admin:create")
|
||||
->setDescription("Create a new administrator user")
|
||||
->setHelp("The <info>admin:create</info> command create a new administration user.")
|
||||
->addOption(
|
||||
'login_name',
|
||||
null,
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
'Admin login name',
|
||||
null
|
||||
)
|
||||
->addOption(
|
||||
'first_name',
|
||||
null,
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
'User first name',
|
||||
null
|
||||
)
|
||||
->addOption(
|
||||
"last_name",
|
||||
null,
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
'User last name',
|
||||
null
|
||||
)
|
||||
->addOption(
|
||||
"email",
|
||||
null,
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
'Admin email address',
|
||||
null
|
||||
)
|
||||
->addOption(
|
||||
"locale",
|
||||
null,
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
'Preferred locale (default: en_US)',
|
||||
null
|
||||
)
|
||||
->addOption(
|
||||
'password',
|
||||
null,
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
'Password',
|
||||
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();
|
||||
|
||||
$output->writeln(array(
|
||||
"",
|
||||
"<info>User ".$admin->getLogin()." successfully created.</info>",
|
||||
""
|
||||
));
|
||||
}
|
||||
|
||||
protected function enterData(
|
||||
QuestionHelper $helper,
|
||||
InputInterface $input,
|
||||
OutputInterface $output,
|
||||
$label,
|
||||
$errorMessage,
|
||||
$hidden = false
|
||||
) {
|
||||
$question = new Question($this->decorateInfo($label));
|
||||
|
||||
if ($hidden) {
|
||||
$question->setHidden(true);
|
||||
$question->setHiddenFallback(false);
|
||||
}
|
||||
|
||||
$question->setValidator(function ($value) use (&$errorMessage) {
|
||||
if (trim($value) == '') {
|
||||
throw new \Exception($errorMessage);
|
||||
}
|
||||
|
||||
return $value;
|
||||
});
|
||||
|
||||
return $helper->ask($input, $output, $question);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ask to user all needed information
|
||||
*
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return array
|
||||
*/
|
||||
protected function getAdminInfo(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
/** @var QuestionHelper $helper */
|
||||
$helper = $this->getHelper('question');
|
||||
|
||||
$admin = new Admin();
|
||||
|
||||
$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($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;
|
||||
}
|
||||
|
||||
$output->writeln("Passwords are different, please try again.");
|
||||
} while (true);
|
||||
|
||||
$admin->setProfile(null);
|
||||
|
||||
return $admin;
|
||||
}
|
||||
|
||||
protected function decorateInfo($text)
|
||||
{
|
||||
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()
|
||||
;
|
||||
}
|
||||
}
|
||||
101
core/lib/Thelia/Command/GenerateResources.php
Normal file
101
core/lib/Thelia/Command/GenerateResources.php
Normal file
@@ -0,0 +1,101 @@
|
||||
<?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\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Thelia\Core\Security\Resource\AdminResources;
|
||||
use Thelia\Model\Map\ResourceI18nTableMap;
|
||||
use Thelia\Model\Map\ResourceTableMap;
|
||||
|
||||
class GenerateResources extends ContainerAwareCommand
|
||||
{
|
||||
/**
|
||||
* Configure the command
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName("thelia:generate-resources")
|
||||
->setDescription("Outputs admin resources")
|
||||
->setHelp("The <info>thelia:generate-resources</info> outputs admin resources.")
|
||||
->addOption(
|
||||
'output',
|
||||
null,
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
'Output format amid (string, sql, sql-i18n)',
|
||||
null
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$class = new \ReflectionClass('Thelia\Core\Security\Resource\AdminResources');
|
||||
|
||||
$constants = $class->getConstants();
|
||||
|
||||
if (count($constants) == 0) {
|
||||
throw new \RuntimeException('No resources found');
|
||||
}
|
||||
|
||||
switch ($input->getOption("output")) {
|
||||
case 'sql':
|
||||
$output->writeln(
|
||||
'INSERT INTO ' . ResourceTableMap::TABLE_NAME . ' (`id`, `code`, `created_at`, `updated_at`) VALUES '
|
||||
);
|
||||
$compteur = 0;
|
||||
foreach ($constants as $constant => $value) {
|
||||
if ($constant == AdminResources::SUPERADMINISTRATOR) {
|
||||
continue;
|
||||
}
|
||||
$compteur++;
|
||||
$output->writeln(
|
||||
"($compteur, '$value', NOW(), NOW())" . ($constant === key(array_slice($constants, -1, 1, true)) ? ';' : ',')
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 'sql-i18n':
|
||||
$output->writeln(
|
||||
'INSERT INTO ' . ResourceI18nTableMap::TABLE_NAME . ' (`id`, `locale`, `title`) VALUES '
|
||||
);
|
||||
$compteur = 0;
|
||||
foreach ($constants as $constant => $value) {
|
||||
if ($constant == AdminResources::SUPERADMINISTRATOR) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$compteur++;
|
||||
|
||||
$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)) ? ';' : ',')
|
||||
);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
foreach ($constants as $constant => $value) {
|
||||
if ($constant == AdminResources::SUPERADMINISTRATOR) {
|
||||
continue;
|
||||
}
|
||||
$output->writeln('[' . $constant . "] => " . $value);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
158
core/lib/Thelia/Command/HookCleanCommand.php
Normal file
158
core/lib/Thelia/Command/HookCleanCommand.php
Normal file
@@ -0,0 +1,158 @@
|
||||
<?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()
|
||||
;
|
||||
}
|
||||
}
|
||||
345
core/lib/Thelia/Command/Install.php
Normal file
345
core/lib/Thelia/Command/Install.php
Normal file
@@ -0,0 +1,345 @@
|
||||
<?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\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 <manu@raynaud.io>
|
||||
*/
|
||||
class Install extends ContainerAwareCommand
|
||||
{
|
||||
/**
|
||||
* Configure the command
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName("thelia:install")
|
||||
->setDescription("Install thelia using cli tools. For now Thelia only use mysql database")
|
||||
->setHelp("The <info>thelia:install</info> command install Thelia database and create config file needed.")
|
||||
->addOption(
|
||||
"db_host",
|
||||
null,
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
"host for your database",
|
||||
"localhost"
|
||||
)
|
||||
->addOption(
|
||||
"db_username",
|
||||
null,
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
"username for your database"
|
||||
)
|
||||
->addOption(
|
||||
"db_password",
|
||||
null,
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
"password for your database"
|
||||
)
|
||||
->addOption(
|
||||
"db_name",
|
||||
null,
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
"database name"
|
||||
)
|
||||
->addOption(
|
||||
"db_port",
|
||||
null,
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
"database port",
|
||||
"3306"
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$output->writeln(array(
|
||||
'',
|
||||
'Welcome to Thelia install process',
|
||||
'You need information about your database configuration (host, username, password, database name, etc)',
|
||||
'',
|
||||
'<info>Caution : You are installing Thelia in cli mode, we verify some information, but this information are only available for the cli php sapi</info>',
|
||||
'<info>This informations can be different in your apache or cgi php.ini files</info>',
|
||||
''
|
||||
));
|
||||
|
||||
$this->checkPermission($output);
|
||||
|
||||
$connectionInfo = array(
|
||||
"host" => $input->getOption("db_host"),
|
||||
"dbName" => $input->getOption("db_name"),
|
||||
"username" => $input->getOption("db_username"),
|
||||
"password" => $input->getOption("db_password"),
|
||||
"port" => $input->getOption("db_port")
|
||||
);
|
||||
|
||||
while (false === $connection = $this->tryConnection($connectionInfo, $output)) {
|
||||
$connectionInfo = $this->getConnectionInfo($input, $output);
|
||||
}
|
||||
|
||||
$database = new Database($connection);
|
||||
|
||||
$database->createDatabase($connectionInfo["dbName"]);
|
||||
|
||||
$output->writeln(array(
|
||||
"",
|
||||
"<info>Creating Thelia database, please wait</info>",
|
||||
""
|
||||
));
|
||||
$database->insertSql($connectionInfo["dbName"]);
|
||||
$this->manageSecret($database);
|
||||
|
||||
$output->writeln(array(
|
||||
"",
|
||||
"<info>Database created without errors</info>",
|
||||
"<info>Creating file configuration, please wait</info>",
|
||||
""
|
||||
));
|
||||
|
||||
$this->createConfigFile($connectionInfo);
|
||||
|
||||
$output->writeln(array(
|
||||
"",
|
||||
"<info>Config file created with success. Your thelia is installed</info>",
|
||||
""
|
||||
));
|
||||
}
|
||||
|
||||
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
|
||||
*
|
||||
* @param \Symfony\Component\Console\Output\OutputInterface $output
|
||||
*/
|
||||
protected function checkPermission(OutputInterface $output)
|
||||
{
|
||||
$output->writeln(array(
|
||||
"Checking some permissions"
|
||||
));
|
||||
|
||||
/** @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>"
|
||||
)
|
||||
)
|
||||
);
|
||||
} else {
|
||||
$output->writeln(array(
|
||||
sprintf(
|
||||
"<error>%s </error>%s",
|
||||
$data['text'],
|
||||
sprintf("<error>%s</error>", $data["hint"])
|
||||
)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if (false === $isValid) {
|
||||
throw new \RuntimeException('Please put correct permissions and reload install process');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* rename database config file and complete it
|
||||
*
|
||||
* @param array $connectionInfo
|
||||
*/
|
||||
protected function createConfigFile($connectionInfo)
|
||||
{
|
||||
$fs = new Filesystem();
|
||||
|
||||
$sampleConfigFile = THELIA_CONF_DIR . "database.yml.sample";
|
||||
$configFile = THELIA_CONF_DIR . "database.yml";
|
||||
|
||||
$fs->copy($sampleConfigFile, $configFile, true);
|
||||
|
||||
$configContent = file_get_contents($configFile);
|
||||
|
||||
$configContent = str_replace("%DRIVER%", "mysql", $configContent);
|
||||
$configContent = str_replace("%USERNAME%", $connectionInfo["username"], $configContent);
|
||||
$configContent = str_replace("%PASSWORD%", $connectionInfo["password"], $configContent);
|
||||
$configContent = str_replace(
|
||||
"%DSN%",
|
||||
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"));
|
||||
}
|
||||
|
||||
/**
|
||||
* test database access
|
||||
*
|
||||
* @param $connectionInfo
|
||||
* @param OutputInterface $output
|
||||
* @return bool|\PDO
|
||||
*/
|
||||
protected function tryConnection($connectionInfo, OutputInterface $output)
|
||||
{
|
||||
if (is_null($connectionInfo["dbName"])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$dsn = "mysql:host=%s;port=%s";
|
||||
|
||||
try {
|
||||
$connection = new \PDO(
|
||||
sprintf($dsn, $connectionInfo["host"], $connectionInfo["port"]),
|
||||
$connectionInfo["username"],
|
||||
$connectionInfo["password"]
|
||||
);
|
||||
$connection->query('SET NAMES \'UTF8\'');
|
||||
} catch (\PDOException $e) {
|
||||
$output->writeln(array(
|
||||
"<error>Wrong connection information</error>"
|
||||
));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return $connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ask to user all needed information
|
||||
*
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return array
|
||||
*/
|
||||
protected function getConnectionInfo(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
/** @var QuestionHelper $helper */
|
||||
$helper = $this->getHelper('question');
|
||||
|
||||
$connectionInfo = array();
|
||||
|
||||
$connectionInfo['host'] = $this->enterData(
|
||||
$helper,
|
||||
$input,
|
||||
$output,
|
||||
"Database host [default: localhost] : ",
|
||||
"You must specify a database host",
|
||||
false,
|
||||
"localhost"
|
||||
);
|
||||
|
||||
$connectionInfo['port'] = $this->enterData(
|
||||
$helper,
|
||||
$input,
|
||||
$output,
|
||||
"Database port [default: 3306] : ",
|
||||
"You must specify a database port",
|
||||
false,
|
||||
"3306"
|
||||
);
|
||||
|
||||
$connectionInfo['dbName'] = $this->enterData(
|
||||
$helper,
|
||||
$input,
|
||||
$output,
|
||||
"Database name (if database does not exist, Thelia will try to create it) : ",
|
||||
"You must specify a database name"
|
||||
);
|
||||
|
||||
$connectionInfo['username'] = $this->enterData(
|
||||
$helper,
|
||||
$input,
|
||||
$output,
|
||||
"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);
|
||||
}
|
||||
}
|
||||
93
core/lib/Thelia/Command/ModuleActivateCommand.php
Normal file
93
core/lib/Thelia/Command/ModuleActivateCommand.php
Normal file
@@ -0,0 +1,93 @@
|
||||
<?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\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
|
||||
*
|
||||
* Class ModuleActivateCommand
|
||||
* @package Thelia\Command
|
||||
* @author Etienne Roudeix <eroudeix@openstudio.fr>
|
||||
*
|
||||
*/
|
||||
class ModuleActivateCommand extends BaseModuleGenerate
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName("module:activate")
|
||||
->setDescription("Activates a module")
|
||||
->addOption(
|
||||
"with-dependencies",
|
||||
null,
|
||||
InputOption::VALUE_NONE,
|
||||
'activate module recursively'
|
||||
)
|
||||
->addArgument(
|
||||
"module",
|
||||
InputArgument::REQUIRED,
|
||||
"module to activate"
|
||||
);
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$moduleCode = $this->formatModuleName($input->getArgument("module"));
|
||||
|
||||
$module = ModuleQuery::create()->findOneByCode($moduleCode);
|
||||
|
||||
if (null === $module) {
|
||||
throw new \RuntimeException(sprintf("module %s not found", $moduleCode));
|
||||
}
|
||||
|
||||
if ($module->getActivate() == BaseModule::IS_ACTIVATED) {
|
||||
throw new \RuntimeException(sprintf("module %s is already actived", $moduleCode));
|
||||
}
|
||||
|
||||
|
||||
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()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
//impossible to change output class in CommandTester...
|
||||
if (method_exists($output, "renderBlock")) {
|
||||
$output->renderBlock(array(
|
||||
'',
|
||||
sprintf("Activation succeed for module %s", $moduleCode),
|
||||
''
|
||||
), "bg=green;fg=black");
|
||||
}
|
||||
}
|
||||
}
|
||||
87
core/lib/Thelia/Command/ModuleDeactivateCommand.php
Normal file
87
core/lib/Thelia/Command/ModuleDeactivateCommand.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\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;
|
||||
|
||||
/**
|
||||
* Deactivates a module
|
||||
*
|
||||
* Class ModuleDeactivateCommand
|
||||
* @package Thelia\Command
|
||||
* @author Nicolas Villa <nicolas@libre-shop.com>
|
||||
*
|
||||
*/
|
||||
class ModuleDeactivateCommand extends BaseModuleGenerate
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName("module:deactivate")
|
||||
->setDescription("Deactivate a module")
|
||||
->addOption(
|
||||
"with-dependencies",
|
||||
null,
|
||||
InputOption::VALUE_NONE,
|
||||
'activate module recursively'
|
||||
)
|
||||
->addArgument(
|
||||
"module",
|
||||
InputArgument::REQUIRED,
|
||||
"module to deactivate"
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$moduleCode = $this->formatModuleName($input->getArgument("module"));
|
||||
|
||||
$module = ModuleQuery::create()->findOneByCode($moduleCode);
|
||||
|
||||
if (null === $module) {
|
||||
throw new \RuntimeException(sprintf("module %s not found", $moduleCode));
|
||||
}
|
||||
|
||||
if ($module->getActivate() == BaseModule::IS_NOT_ACTIVATED) {
|
||||
throw new \RuntimeException(sprintf("module %s is already deactivated", $moduleCode));
|
||||
}
|
||||
|
||||
|
||||
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("Deactivation fail with Exception : [%d] %s", $e->getCode(), $e->getMessage()));
|
||||
}
|
||||
|
||||
//impossible to change output class in CommandTester...
|
||||
if (method_exists($output, "renderBlock")) {
|
||||
$output->renderBlock(array(
|
||||
'',
|
||||
sprintf("Deactivation succeed for module %s", $moduleCode),
|
||||
''
|
||||
), "bg=green;fg=black");
|
||||
}
|
||||
}
|
||||
}
|
||||
226
core/lib/Thelia/Command/ModuleGenerateCommand.php
Normal file
226
core/lib/Thelia/Command/ModuleGenerateCommand.php
Normal file
@@ -0,0 +1,226 @@
|
||||
<?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\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
|
||||
/**
|
||||
* generate a new Module
|
||||
*
|
||||
* Class ModuleGenerateCommand
|
||||
* @package Thelia\Command
|
||||
* @author Manuel Raynaud <manu@raynaud.io>
|
||||
*/
|
||||
class ModuleGenerateCommand extends BaseModuleGenerate
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName("module:generate")
|
||||
->setDescription("generate all needed files for creating a new Module")
|
||||
->addArgument(
|
||||
"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 . $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($output, "renderBlock")) {
|
||||
// impossible to change output class in CommandTester...
|
||||
$output->renderBlock(array(
|
||||
'',
|
||||
sprintf("module %s create with success", $this->module),
|
||||
"You can now configure your module and complete module.xml file",
|
||||
''
|
||||
), "bg=green;fg=black");
|
||||
}
|
||||
}
|
||||
|
||||
private function createDirectories()
|
||||
{
|
||||
$fs = new Filesystem();
|
||||
|
||||
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()
|
||||
{
|
||||
$fs = new Filesystem();
|
||||
|
||||
try {
|
||||
$skeletonDir = str_replace("/", DIRECTORY_SEPARATOR, __DIR__ . "/Skeleton/Module/");
|
||||
|
||||
// config.xml file
|
||||
$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);
|
||||
|
||||
// Readme.md file
|
||||
$filename = $this->moduleDirectory . DIRECTORY_SEPARATOR . "Readme.md";
|
||||
if (!$fs->exists($filename)) {
|
||||
$readmeContent = file_get_contents($skeletonDir . "Readme.md");
|
||||
|
||||
// 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]));
|
||||
|
||||
$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
|
||||
$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("%%DOMAINNAME%%", strtolower($this->module), $classContent);
|
||||
|
||||
file_put_contents($filename, $classContent);
|
||||
}
|
||||
|
||||
// schema.xml file
|
||||
$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(
|
||||
'%%XSD_LOCATION%%',
|
||||
$fs->makePathRelative(
|
||||
THELIA_VENDOR . 'propel/propel/resources/xsd/',
|
||||
$this->moduleDirectory
|
||||
) . 'database.xsd',
|
||||
$schemaContent
|
||||
);
|
||||
|
||||
file_put_contents($filename, $schemaContent);
|
||||
}
|
||||
|
||||
// routing.xml file
|
||||
$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);
|
||||
|
||||
file_put_contents($filename, $routingContent);
|
||||
}
|
||||
|
||||
// I18n sample files
|
||||
$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
|
||||
);
|
||||
}
|
||||
|
||||
$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;
|
||||
}
|
||||
}
|
||||
}
|
||||
122
core/lib/Thelia/Command/ModuleGenerateModelCommand.php
Normal file
122
core/lib/Thelia/Command/ModuleGenerateModelCommand.php
Normal file
@@ -0,0 +1,122 @@
|
||||
<?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\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;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
|
||||
/**
|
||||
* generate class model for a specific module
|
||||
*
|
||||
* Class ModuleGenerateModelCommand
|
||||
* @package Thelia\Command
|
||||
* @author Manuel Raynaud <manu@raynaud.io>
|
||||
*/
|
||||
class ModuleGenerateModelCommand extends BaseModuleGenerate
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName("module:generate:model")
|
||||
->setDescription("generate model for a specific module")
|
||||
->addArgument(
|
||||
"name",
|
||||
InputArgument::REQUIRED,
|
||||
"module name"
|
||||
)
|
||||
->addOption(
|
||||
"generate-sql",
|
||||
null,
|
||||
InputOption::VALUE_NONE,
|
||||
"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 . $this->module;
|
||||
|
||||
$fs = new Filesystem();
|
||||
|
||||
if ($fs->exists($this->moduleDirectory) === false) {
|
||||
throw new \RuntimeException(sprintf("%s module does not exists", $this->module));
|
||||
}
|
||||
|
||||
if ($fs->exists($this->moduleDirectory . DS . "Config" . DS . "schema.xml") === false) {
|
||||
throw new \RuntimeException("schema.xml not found in Config directory. Needed file for generating model");
|
||||
}
|
||||
|
||||
$this->generateModel($output);
|
||||
|
||||
/** @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(' ');
|
||||
$this->generateSql($output);
|
||||
}
|
||||
}
|
||||
|
||||
protected function generateSql(OutputInterface $output)
|
||||
{
|
||||
$command = $this->getApplication()->find("module:generate:sql");
|
||||
|
||||
$command->run(
|
||||
new ArrayInput(array(
|
||||
"command" => $command->getName(),
|
||||
"name" => $this->module
|
||||
)),
|
||||
$output
|
||||
);
|
||||
}
|
||||
|
||||
protected function generateModel(OutputInterface $output)
|
||||
{
|
||||
$fs = new Filesystem();
|
||||
$moduleBuildPropel = new ModelBuildCommand();
|
||||
$moduleBuildPropel->setApplication($this->getApplication());
|
||||
|
||||
$moduleBuildPropel->run(
|
||||
new ArrayInput(array(
|
||||
"command" => $moduleBuildPropel->getName(),
|
||||
"--output-dir" => THELIA_MODULE_DIR,
|
||||
"--input-dir" => $this->moduleDirectory . DS ."Config"
|
||||
)),
|
||||
$output
|
||||
);
|
||||
|
||||
$verifyDirectories = array(
|
||||
THELIA_MODULE_DIR . "Thelia",
|
||||
$this->moduleDirectory . DS . "Model" . DS . "Thelia"
|
||||
);
|
||||
|
||||
foreach ($verifyDirectories as $directory) {
|
||||
if ($fs->exists($directory)) {
|
||||
$fs->remove($directory);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
83
core/lib/Thelia/Command/ModuleGenerateSqlCommand.php
Normal file
83
core/lib/Thelia/Command/ModuleGenerateSqlCommand.php
Normal file
@@ -0,0 +1,83 @@
|
||||
<?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\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;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
|
||||
/**
|
||||
* generate sql for a specific module
|
||||
*
|
||||
* Class ModuleGenerateSqlCommand
|
||||
* @package Thelia\Command
|
||||
* @author Manuel Raynaud <manu@raynaud.io>
|
||||
*/
|
||||
class ModuleGenerateSqlCommand extends BaseModuleGenerate
|
||||
{
|
||||
public function configure()
|
||||
{
|
||||
$this
|
||||
->setName("module:generate:sql")
|
||||
->setDescription("Generate the sql from schema.xml file")
|
||||
->addArgument(
|
||||
"name",
|
||||
InputArgument::REQUIRED,
|
||||
"Module name"
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->module = $this->formatModuleName($input->getArgument("name"));
|
||||
$this->moduleDirectory = THELIA_MODULE_DIR . $this->module;
|
||||
|
||||
$fs = new Filesystem();
|
||||
|
||||
if ($fs->exists($this->moduleDirectory) === false) {
|
||||
throw new \RuntimeException(sprintf("%s module does not exists", $this->module));
|
||||
}
|
||||
|
||||
if ($fs->exists($this->moduleDirectory . DS . "Config" . DS . "schema.xml") === false) {
|
||||
throw new \RuntimeException("schema.xml not found in Config directory. Needed file for generating model");
|
||||
}
|
||||
|
||||
$sqlBuild = new SqlBuildCommand();
|
||||
$sqlBuild->setApplication($this->getApplication());
|
||||
|
||||
$sqlBuild->run(
|
||||
new ArrayInput(array(
|
||||
"command" => $sqlBuild->getName(),
|
||||
"--output-dir" => $this->moduleDirectory . DS ."Config",
|
||||
"--input-dir" => $this->moduleDirectory . DS ."Config"
|
||||
)),
|
||||
$output
|
||||
);
|
||||
|
||||
/** @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;
|
||||
}
|
||||
}
|
||||
62
core/lib/Thelia/Command/ModuleRefreshCommand.php
Normal file
62
core/lib/Thelia/Command/ModuleRefreshCommand.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<?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\Exception\InvalidModuleException;
|
||||
use Thelia\Module\ModuleManagement;
|
||||
|
||||
/**
|
||||
* Class ModuleRefreshCommand
|
||||
* Refresh modules list
|
||||
*
|
||||
* @package Thelia\Command
|
||||
* @author Jérôme Billiras <jbilliras@openstudio.fr>
|
||||
*/
|
||||
class ModuleRefreshCommand extends ContainerAwareCommand
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('module:refresh')
|
||||
->setDescription('Refresh modules list');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
try {
|
||||
$moduleManagement = new ModuleManagement;
|
||||
$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())
|
||||
);
|
||||
}
|
||||
|
||||
if (method_exists($output, 'renderBlock')) {
|
||||
$output->renderBlock(
|
||||
[
|
||||
'',
|
||||
'Modules list successfully refreshed',
|
||||
''
|
||||
],
|
||||
'bg=green;fg=black'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
43
core/lib/Thelia/Command/Output/TheliaConsoleOutput.php
Normal file
43
core/lib/Thelia/Command/Output/TheliaConsoleOutput.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?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\Output;
|
||||
|
||||
use Symfony\Component\Console\Output\ConsoleOutput;
|
||||
|
||||
class TheliaConsoleOutput extends ConsoleOutput
|
||||
{
|
||||
public function renderBlock(array $messages, $style = "info")
|
||||
{
|
||||
$strlen = function ($string) {
|
||||
if (!function_exists('mb_strlen')) {
|
||||
return strlen($string);
|
||||
}
|
||||
|
||||
if (false === $encoding = mb_detect_encoding($string)) {
|
||||
return strlen($string);
|
||||
}
|
||||
|
||||
return mb_strlen($string, $encoding);
|
||||
};
|
||||
$length = 0;
|
||||
foreach ($messages as $message) {
|
||||
$length = ($strlen($message) > $length) ? $strlen($message) : $length;
|
||||
}
|
||||
$output = array();
|
||||
foreach ($messages as $message) {
|
||||
$output[] = "<" . $style . ">" . " " . $message . str_repeat(' ', $length - $strlen($message)) . " </" . $style . ">";
|
||||
}
|
||||
|
||||
$this->writeln($output);
|
||||
}
|
||||
}
|
||||
68
core/lib/Thelia/Command/ReloadDatabaseCommand.php
Normal file
68
core/lib/Thelia/Command/ReloadDatabaseCommand.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?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\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 <manu@raynaud.io>
|
||||
*/
|
||||
class ReloadDatabaseCommand extends BaseModuleGenerate
|
||||
{
|
||||
public function configure()
|
||||
{
|
||||
$this
|
||||
->setName("thelia:dev:reloadDB")
|
||||
->setDescription("erase current database and create new one")
|
||||
/* ->addOption(
|
||||
"load-fixtures",
|
||||
null,
|
||||
InputOption::VALUE_NONE,
|
||||
"load fixtures in databases"
|
||||
)*/
|
||||
;
|
||||
}
|
||||
|
||||
public function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
/** @var ConnectionWrapper $connection */
|
||||
$connection = Propel::getConnection(ProductTableMap::DATABASE_NAME);
|
||||
$connection = $connection->getWrappedConnection();
|
||||
|
||||
$tables = $connection->query("SHOW TABLES");
|
||||
$connection->query("SET FOREIGN_KEY_CHECKS = 0");
|
||||
foreach ($tables as $table) {
|
||||
$connection->query(sprintf("DROP TABLE `%s`", $table[0]));
|
||||
}
|
||||
$connection->query("SET FOREIGN_KEY_CHECKS = 1");
|
||||
|
||||
$database = new Database($connection);
|
||||
$output->writeln(array(
|
||||
'',
|
||||
'<info>starting reloaded database, please wait</info>'
|
||||
));
|
||||
$database->insertSql();
|
||||
$output->writeln(array(
|
||||
'',
|
||||
'<info>Database reloaded with success</info>',
|
||||
''
|
||||
));
|
||||
}
|
||||
}
|
||||
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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
28
core/lib/Thelia/Command/Skeleton/Module/Class.php.template
Normal file
28
core/lib/Thelia/Command/Skeleton/Module/Class.php.template
Normal file
@@ -0,0 +1,28 @@
|
||||
<?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 %%NAMESPACE%%;
|
||||
|
||||
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
|
||||
*
|
||||
* Have fun !
|
||||
*/
|
||||
}
|
||||
4
core/lib/Thelia/Command/Skeleton/Module/I18n/en_US.php
Normal file
4
core/lib/Thelia/Command/Skeleton/Module/I18n/en_US.php
Normal file
@@ -0,0 +1,4 @@
|
||||
<?php
|
||||
return array(
|
||||
// 'an english string' => 'The displayed english string',
|
||||
);
|
||||
4
core/lib/Thelia/Command/Skeleton/Module/I18n/fr_FR.php
Normal file
4
core/lib/Thelia/Command/Skeleton/Module/I18n/fr_FR.php
Normal file
@@ -0,0 +1,4 @@
|
||||
<?php
|
||||
return array(
|
||||
// 'an english string' => 'La traduction française de la chaine',
|
||||
);
|
||||
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%%"
|
||||
}
|
||||
}
|
||||
50
core/lib/Thelia/Command/Skeleton/Module/config.xml
Normal file
50
core/lib/Thelia/Command/Skeleton/Module/config.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_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>
|
||||
41
core/lib/Thelia/Command/Skeleton/Module/module.xml
Normal file
41
core/lib/Thelia/Command/Skeleton/Module/module.xml
Normal file
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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é 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>
|
||||
<authors>
|
||||
<author>
|
||||
<name></name>
|
||||
<email></email>
|
||||
</author>
|
||||
</authors>
|
||||
<type>classic</type>
|
||||
<!--
|
||||
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>
|
||||
</module>
|
||||
31
core/lib/Thelia/Command/Skeleton/Module/routing.xml
Normal file
31
core/lib/Thelia/Command/Skeleton/Module/routing.xml
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<routes xmlns="http://symfony.com/schema/routing"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
|
||||
|
||||
<!--
|
||||
|
||||
if a /admin/module/%%CLASSNAME_LOWER%%/ route is provided, a "Configuration" button will be displayed
|
||||
for the module in the module list. Clicking this button will invoke this route.
|
||||
|
||||
<route id="my_route_id" path="/admin/module/%%CLASSNAME_LOWER%%">
|
||||
<default key="_controller">%%NAMESPACE%%\Full\Class\Name\Of\YourConfigurationController::methodName</default>
|
||||
</route>
|
||||
|
||||
<route id="my_route_id" path="/admin/module/%%CLASSNAME_LOWER%%/route-name">
|
||||
<default key="_controller">%%NAMESPACE%%\Full\Class\Name\Of\YourAdminController::methodName</default>
|
||||
</route>
|
||||
|
||||
<route id="my_route_id" path="/my/route/name">
|
||||
<default key="_controller">%%NAMESPACE%%\Full\Class\Name\Of\YourOtherController::methodName</default>
|
||||
</route>
|
||||
|
||||
...add as many routes as required.
|
||||
|
||||
<route>
|
||||
...
|
||||
</route>
|
||||
-->
|
||||
|
||||
</routes>
|
||||
30
core/lib/Thelia/Command/Skeleton/Module/schema.xml
Normal file
30
core/lib/Thelia/Command/Skeleton/Module/schema.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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>
|
||||
191
core/lib/Thelia/Condition/ConditionCollection.php
Normal file
191
core/lib/Thelia/Condition/ConditionCollection.php
Normal file
@@ -0,0 +1,191 @@
|
||||
<?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\Condition;
|
||||
|
||||
use ArrayAccess;
|
||||
use Countable;
|
||||
use Iterator;
|
||||
use Thelia\Condition\Implementation\ConditionInterface;
|
||||
|
||||
/**
|
||||
* Manage a set of ConditionInterface
|
||||
*
|
||||
* @package Condition
|
||||
* @author Guillaume MOREL <gmorel@openstudio.fr>
|
||||
*
|
||||
*/
|
||||
class ConditionCollection implements Iterator, Countable, ArrayAccess
|
||||
{
|
||||
/** @var ConditionInterface[] */
|
||||
protected $conditions = [];
|
||||
|
||||
/**
|
||||
* (PHP 5 >= 5.0.0)
|
||||
* Return the current element
|
||||
* @link http://php.net/manual/en/iterator.current.php
|
||||
*
|
||||
* @return mixed Can return any type.
|
||||
*/
|
||||
public function current()
|
||||
{
|
||||
$var = current($this->conditions);
|
||||
|
||||
return $var;
|
||||
}
|
||||
|
||||
/**
|
||||
* (PHP 5 >= 5.0.0)
|
||||
* Move forward to next element
|
||||
* @link http://php.net/manual/en/iterator.next.php
|
||||
*
|
||||
* @return void Any returned value is ignored.
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
next($this->conditions);
|
||||
}
|
||||
|
||||
/**
|
||||
* (PHP 5 >= 5.0.0)
|
||||
* Return the key of the current element
|
||||
* @link http://php.net/manual/en/iterator.key.php
|
||||
*
|
||||
* @return mixed scalar on success, or null on failure.
|
||||
*/
|
||||
public function key()
|
||||
{
|
||||
$var = key($this->conditions);
|
||||
|
||||
return $var;
|
||||
}
|
||||
|
||||
/**
|
||||
* (PHP 5 >= 5.0.0)
|
||||
* Checks if current position is valid
|
||||
* @link http://php.net/manual/en/iterator.valid.php
|
||||
*
|
||||
* @return boolean The return value will be casted to boolean and then evaluated.
|
||||
* Returns true on success or false on failure.
|
||||
*/
|
||||
public function valid()
|
||||
{
|
||||
$key = key($this->conditions);
|
||||
$var = ($key !== null && $key !== false);
|
||||
|
||||
return $var;
|
||||
}
|
||||
|
||||
/**
|
||||
* (PHP 5 >= 5.0.0)
|
||||
* Rewind the Iterator to the first element
|
||||
* @link http://php.net/manual/en/iterator.rewind.php
|
||||
*
|
||||
* @return void Any returned value is ignored.
|
||||
*/
|
||||
public function rewind()
|
||||
{
|
||||
reset($this->conditions);
|
||||
}
|
||||
|
||||
/**
|
||||
* (PHP 5 >= 5.1.0)
|
||||
* Count elements of an object
|
||||
* @link http://php.net/manual/en/countable.count.php
|
||||
*
|
||||
* @return int The custom count as an integer.
|
||||
* The return value is cast to an integer.
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
return count($this->conditions);
|
||||
}
|
||||
|
||||
/**
|
||||
* (PHP 5 >= 5.0.0)
|
||||
* Whether a offset exists
|
||||
* @link http://php.net/manual/en/arrayaccess.offsetexists.php
|
||||
* @param mixed $offset
|
||||
* An offset to check for.
|
||||
*
|
||||
* @return boolean true on success or false on failure.
|
||||
* The return value will be casted to boolean if non-boolean was returned.
|
||||
*/
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
return isset($this->conditions[$offset]);
|
||||
}
|
||||
|
||||
/**
|
||||
* (PHP 5 >= 5.0.0)
|
||||
* Offset to retrieve
|
||||
* @link http://php.net/manual/en/arrayaccess.offsetget.php
|
||||
* @param mixed $offset
|
||||
* The offset to retrieve.
|
||||
*
|
||||
* @return mixed Can return all value types.
|
||||
*/
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
return isset($this->conditions[$offset]) ? $this->conditions[$offset] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* (PHP 5 >= 5.0.0)
|
||||
* Offset to set
|
||||
* @link http://php.net/manual/en/arrayaccess.offsetset.php
|
||||
* @param mixed $offset
|
||||
* The offset to assign the value to.
|
||||
* @param mixed $value
|
||||
* The value to set.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function offsetSet($offset, $value)
|
||||
{
|
||||
if (is_null($offset)) {
|
||||
$this->conditions[] = $value;
|
||||
} else {
|
||||
$this->conditions[$offset] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* (PHP 5 >= 5.0.0)
|
||||
* Offset to unset
|
||||
* @link http://php.net/manual/en/arrayaccess.offsetunset.php
|
||||
* @param mixed $offset
|
||||
* The offset to unset.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function offsetUnset($offset)
|
||||
{
|
||||
unset($this->conditions[$offset]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow to compare 2 set of conditions
|
||||
*
|
||||
* @return string Jsoned data
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
$arrayToSerialize = [];
|
||||
/** @var ConditionInterface $condition */
|
||||
foreach ($this as $condition) {
|
||||
$arrayToSerialize[] = $condition->getSerializableCondition();
|
||||
}
|
||||
|
||||
return json_encode($arrayToSerialize);
|
||||
}
|
||||
}
|
||||
125
core/lib/Thelia/Condition/ConditionEvaluator.php
Normal file
125
core/lib/Thelia/Condition/ConditionEvaluator.php
Normal file
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Thelia\Condition;
|
||||
|
||||
use Thelia\Condition\Implementation\ConditionInterface;
|
||||
|
||||
/**
|
||||
* Validate Conditions
|
||||
*
|
||||
* @package Condition
|
||||
* @author Guillaume MOREL <gmorel@openstudio.fr>
|
||||
*
|
||||
*/
|
||||
class ConditionEvaluator
|
||||
{
|
||||
/**
|
||||
* Check if an Event matches SerializableCondition
|
||||
*
|
||||
* @param ConditionCollection $conditions Conditions to check against the Event
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isMatching(ConditionCollection $conditions)
|
||||
{
|
||||
$isMatching = true;
|
||||
/** @var ConditionInterface $condition */
|
||||
foreach ($conditions as $condition) {
|
||||
if (!$condition->isMatching()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return $isMatching;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do variable comparison
|
||||
*
|
||||
* @param mixed $v1 Variable 1
|
||||
* @param string $o Operator ex : Operators::DIFFERENT
|
||||
* @param mixed $v2 Variable 2
|
||||
*
|
||||
* @throws \Exception
|
||||
* @return bool
|
||||
*/
|
||||
public function variableOpComparison($v1, $o, $v2)
|
||||
{
|
||||
if ($o == Operators::DIFFERENT) {
|
||||
return ($v1 != $v2);
|
||||
}
|
||||
|
||||
switch ($o) {
|
||||
case Operators::SUPERIOR:
|
||||
// >
|
||||
if ($v1 > $v2) {
|
||||
return true;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case Operators::SUPERIOR_OR_EQUAL:
|
||||
// >=
|
||||
if ($v1 >= $v2) {
|
||||
return true;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case Operators::INFERIOR:
|
||||
// <
|
||||
if ($v1 < $v2) {
|
||||
return true;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case Operators::INFERIOR_OR_EQUAL:
|
||||
// <=
|
||||
if ($v1 <= $v2) {
|
||||
return true;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case Operators::EQUAL:
|
||||
// ==
|
||||
if ($v1 == $v2) {
|
||||
return true;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case Operators::IN:
|
||||
// in
|
||||
if (in_array($v1, $v2)) {
|
||||
return true;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case Operators::OUT:
|
||||
// not in
|
||||
if (!in_array($v1, $v2)) {
|
||||
return true;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new \Exception('Unrecognized operator ' . $o);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
157
core/lib/Thelia/Condition/ConditionFactory.php
Normal file
157
core/lib/Thelia/Condition/ConditionFactory.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\Condition;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Thelia\Condition\Implementation\ConditionInterface;
|
||||
use Thelia\Coupon\FacadeInterface;
|
||||
|
||||
/**
|
||||
* Manage how Condition could interact with the current application state (Thelia)
|
||||
*
|
||||
* @package Constraint
|
||||
* @author Guillaume MOREL <gmorel@openstudio.fr>
|
||||
*
|
||||
*/
|
||||
class ConditionFactory
|
||||
{
|
||||
/** @var ContainerInterface Service Container */
|
||||
protected $container = null;
|
||||
|
||||
/** @var FacadeInterface Provide necessary value from Thelia */
|
||||
protected $adapter;
|
||||
|
||||
/** @var array ConditionCollection to process*/
|
||||
protected $conditions = null;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param ContainerInterface $container Service container
|
||||
*/
|
||||
public function __construct(ContainerInterface $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
$this->adapter = $container->get('thelia.facade');
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize a collection of conditions
|
||||
*
|
||||
* @param ConditionCollection $collection A collection of conditions
|
||||
*
|
||||
* @return string A ready to be stored Condition collection
|
||||
*/
|
||||
public function serializeConditionCollection(ConditionCollection $collection)
|
||||
{
|
||||
if ($collection->count() == 0) {
|
||||
/** @var ConditionInterface $conditionNone */
|
||||
$conditionNone = $this->container->get(
|
||||
'thelia.condition.match_for_everyone'
|
||||
);
|
||||
$collection[] = $conditionNone;
|
||||
}
|
||||
$serializableConditions = [];
|
||||
/** @var $condition ConditionInterface */
|
||||
foreach ($collection as $condition) {
|
||||
$serializableConditions[] = $condition->getSerializableCondition();
|
||||
}
|
||||
|
||||
return base64_encode(json_encode($serializableConditions));
|
||||
}
|
||||
|
||||
/**
|
||||
* Unserialize a collection of conditions
|
||||
*
|
||||
* @param string $serializedConditions Serialized Conditions
|
||||
*
|
||||
* @return ConditionCollection Conditions ready to be processed
|
||||
*/
|
||||
public function unserializeConditionCollection($serializedConditions)
|
||||
{
|
||||
$unserializedConditions = json_decode(base64_decode($serializedConditions));
|
||||
|
||||
$collection = new ConditionCollection();
|
||||
|
||||
if (!empty($unserializedConditions)) {
|
||||
/** @var SerializableCondition $condition */
|
||||
foreach ($unserializedConditions as $condition) {
|
||||
if ($this->container->has($condition->conditionServiceId)) {
|
||||
/** @var ConditionInterface $conditionManager */
|
||||
$conditionManager = $this->build(
|
||||
$condition->conditionServiceId,
|
||||
(array) $condition->operators,
|
||||
(array) $condition->values
|
||||
);
|
||||
$collection[] = clone $conditionManager;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a Condition from form
|
||||
*
|
||||
* @param string $conditionServiceId Condition class name
|
||||
* @param array $operators Condition Operator (<, >, = )
|
||||
* @param array $values Values setting this Condition
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
* @return ConditionInterface Ready to use Condition or false
|
||||
*/
|
||||
public function build($conditionServiceId, array $operators, array $values)
|
||||
{
|
||||
if (!$this->container->has($conditionServiceId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @var ConditionInterface $condition */
|
||||
$condition = $this->container->get($conditionServiceId);
|
||||
$condition->setValidatorsFromForm($operators, $values);
|
||||
|
||||
return clone $condition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Condition inputs from serviceId
|
||||
*
|
||||
* @param string $conditionServiceId ConditionManager class name
|
||||
*
|
||||
* @return array Ready to be drawn condition inputs
|
||||
*/
|
||||
public function getInputsFromServiceId($conditionServiceId)
|
||||
{
|
||||
if (!$this->container->has($conditionServiceId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @var ConditionInterface $condition */
|
||||
$condition = $this->container->get($conditionServiceId);
|
||||
|
||||
return $this->getInputsFromConditionInterface($condition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Condition inputs from serviceId
|
||||
*
|
||||
* @param ConditionInterface $condition ConditionManager
|
||||
*
|
||||
* @return array Ready to be drawn condition inputs
|
||||
*/
|
||||
public function getInputsFromConditionInterface(ConditionInterface $condition)
|
||||
{
|
||||
return $condition->getValidators();
|
||||
}
|
||||
}
|
||||
35
core/lib/Thelia/Condition/ConditionOrganizer.php
Normal file
35
core/lib/Thelia/Condition/ConditionOrganizer.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?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\Condition;
|
||||
|
||||
/**
|
||||
* Manage how Condition could interact with each others
|
||||
*
|
||||
* @package Condition
|
||||
* @author Guillaume MOREL <gmorel@openstudio.fr>
|
||||
*
|
||||
*/
|
||||
class ConditionOrganizer implements ConditionOrganizerInterface
|
||||
{
|
||||
/**
|
||||
* Organize ConditionInterface
|
||||
*
|
||||
* @param array $conditions Array of ConditionInterface
|
||||
*
|
||||
* @return array Array of ConditionInterface sorted
|
||||
*/
|
||||
public function organize(array $conditions)
|
||||
{
|
||||
// @todo: Implement organize() method.
|
||||
}
|
||||
}
|
||||
32
core/lib/Thelia/Condition/ConditionOrganizerInterface.php
Normal file
32
core/lib/Thelia/Condition/ConditionOrganizerInterface.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?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\Condition;
|
||||
|
||||
/**
|
||||
* Manage how Condition could interact with each other
|
||||
*
|
||||
* @package Condition
|
||||
* @author Guillaume MOREL <gmorel@openstudio.fr>
|
||||
*
|
||||
*/
|
||||
interface ConditionOrganizerInterface
|
||||
{
|
||||
/**
|
||||
* Organize ConditionInterface
|
||||
*
|
||||
* @param array $conditions Array of ConditionInterface
|
||||
*
|
||||
* @return array Array of ConditionInterface sorted
|
||||
*/
|
||||
public function organize(array $conditions);
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Thelia\Condition\Implementation;
|
||||
|
||||
use Thelia\Condition\Operators;
|
||||
use Thelia\Coupon\FacadeInterface;
|
||||
use Thelia\Exception\InvalidConditionValueException;
|
||||
use Thelia\Model\Country;
|
||||
use Thelia\Model\CountryQuery;
|
||||
|
||||
/**
|
||||
* Check a Checkout against its Product number
|
||||
*
|
||||
* @package Condition
|
||||
* @author Franck Allimant <franck@cqfdev.fr>
|
||||
*
|
||||
*/
|
||||
abstract class AbstractMatchCountries extends ConditionAbstract
|
||||
{
|
||||
/** Condition 1st parameter : quantity */
|
||||
const COUNTRIES_LIST = 'countries';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function __construct(FacadeInterface $facade)
|
||||
{
|
||||
$this->availableOperators = [
|
||||
self::COUNTRIES_LIST => [
|
||||
Operators::IN,
|
||||
Operators::OUT
|
||||
]
|
||||
];
|
||||
|
||||
parent::__construct($facade);
|
||||
}
|
||||
|
||||
abstract protected function getSummaryLabel($cntryStrList, $i18nOperator);
|
||||
|
||||
abstract protected function getFormLabel();
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function setValidatorsFromForm(array $operators, array $values)
|
||||
{
|
||||
$this->checkComparisonOperatorValue($operators, self::COUNTRIES_LIST);
|
||||
|
||||
// Use default values if data is not defined.
|
||||
if (! isset($operators[self::COUNTRIES_LIST]) || ! isset($values[self::COUNTRIES_LIST])) {
|
||||
$operators[self::COUNTRIES_LIST] = Operators::IN;
|
||||
$values[self::COUNTRIES_LIST] = [];
|
||||
}
|
||||
|
||||
// Be sure that the value is an array, make one if required
|
||||
if (! is_array($values[self::COUNTRIES_LIST])) {
|
||||
$values[self::COUNTRIES_LIST] = array($values[self::COUNTRIES_LIST]);
|
||||
}
|
||||
|
||||
// Check that at least one category is selected
|
||||
if (empty($values[self::COUNTRIES_LIST])) {
|
||||
throw new InvalidConditionValueException(
|
||||
get_class(),
|
||||
self::COUNTRIES_LIST
|
||||
);
|
||||
}
|
||||
|
||||
$this->operators = [ self::COUNTRIES_LIST => $operators[self::COUNTRIES_LIST] ];
|
||||
$this->values = [ self::COUNTRIES_LIST => $values[self::COUNTRIES_LIST] ];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function isMatching()
|
||||
{
|
||||
// The delivery address should match one of the selected countries.
|
||||
|
||||
/* TODO !!!! */
|
||||
|
||||
return $this->conditionValidator->variableOpComparison(
|
||||
$this->facade->getNbArticlesInCart(),
|
||||
$this->operators[self::COUNTRIES_LIST],
|
||||
$this->values[self::COUNTRIES_LIST]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getSummary()
|
||||
{
|
||||
$i18nOperator = Operators::getI18n(
|
||||
$this->translator,
|
||||
$this->operators[self::COUNTRIES_LIST]
|
||||
);
|
||||
|
||||
$cntryStrList = '';
|
||||
|
||||
$cntryIds = $this->values[self::COUNTRIES_LIST];
|
||||
|
||||
if (null !== $cntryList = CountryQuery::create()->findPks($cntryIds)) {
|
||||
/** @var Country $cntry */
|
||||
foreach ($cntryList as $cntry) {
|
||||
$cntryStrList .= $cntry->setLocale($this->getCurrentLocale())->getTitle() . ', ';
|
||||
}
|
||||
|
||||
$cntryStrList = rtrim($cntryStrList, ', ');
|
||||
}
|
||||
|
||||
return $this->getSummaryLabel($cntryStrList, $i18nOperator);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function generateInputs()
|
||||
{
|
||||
return array(
|
||||
self::COUNTRIES_LIST => array(
|
||||
'availableOperators' => $this->availableOperators[self::COUNTRIES_LIST],
|
||||
'value' => '',
|
||||
'selectedOperator' => Operators::IN
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function drawBackOfficeInputs()
|
||||
{
|
||||
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(),
|
||||
'countryLabel' => $this->getFormLabel()
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user