Merge branches 'catalog' and 'upload_management' of https://github.com/thelia/thelia into catalog

# By franck
# Via franck
* 'catalog' of https://github.com/thelia/thelia:
  Impemented combination creation

# By Manuel Raynaud (29) and others
# Via gmorel (6) and others
* 'upload_management' of https://github.com/thelia/thelia: (52 commits)
  Working : Upload image : Fix upload validation
  - Image format allowed - manual-reverse order on image loop
  Upload allow only for images
  Hide upload zone during upload
  Working : Upload image : Fix unit tests
  Working : Upload image : set product image form loaded via ajax, fix category, folder, content
  WIP : Upload image : set product image form loaded via ajax
  Setting tinymce
  Update uploader view Update image edit view
  Working : Upload management : on content
  Working : Upload management : on folder, category, product
  cache dataccessfunctions
  Working : Upload management : fix e.preventDefault in chrome and safari
  Working : Image management set on Category
  fire event on insert content in createmethod
  fix issue, default foler is set on content creation
  allow to create new content
  update default param of content model
  create content listener for crud management
  dispatch event in pre/post crud method for content model
  ...

Conflicts:
	templates/admin/default/product-edit.html
This commit is contained in:
gmorel
2013-09-23 17:10:03 +02:00
98 changed files with 8688 additions and 277 deletions

View File

@@ -35,10 +35,10 @@ Installation
------------
``` bash
$ git clone --recursive https://github.com/thelia/thelia.git
$ git clone https://github.com/thelia/thelia.git
$ cd thelia
$ curl -sS https://getcomposer.org/installer | php
$ php composer.phar install --optimize-autoloader
$ php composer.phar install --prefer-dist --optimize-autoloader
```
Finish the installation using cli tools :

View File

@@ -37,7 +37,8 @@
"imagine/imagine": "dev-master",
"symfony/icu": "1.0",
"swiftmailer/swiftmailer": "5.0.*"
"swiftmailer/swiftmailer": "5.0.*",
"symfony/serializer": "2.3.*"
},
"require-dev" : {
"phpunit/phpunit": "3.7.*",

67
composer.lock generated
View File

@@ -3,7 +3,7 @@
"This file locks the dependencies of your project to a known state",
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file"
],
"hash": "a40be01c82e68ba0c446dc204d2667da",
"hash": "097481390dc87b3482d895b3b6a65479",
"packages": [
{
"name": "imagine/imagine",
@@ -1456,6 +1456,53 @@
"homepage": "http://symfony.com",
"time": "2013-08-23 14:06:02"
},
{
"name": "symfony/serializer",
"version": "v2.3.4",
"target-dir": "Symfony/Component/Serializer",
"source": {
"type": "git",
"url": "https://github.com/symfony/Serializer.git",
"reference": "457ba76395955926a67ea692957b0872dead5278"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Serializer/zipball/457ba76395955926a67ea692957b0872dead5278",
"reference": "457ba76395955926a67ea692957b0872dead5278",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.3-dev"
}
},
"autoload": {
"psr-0": {
"Symfony\\Component\\Serializer\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "http://symfony.com/contributors"
}
],
"description": "Symfony Serializer Component",
"homepage": "http://symfony.com",
"time": "2013-07-21 12:12:18"
},
{
"name": "symfony/translation",
"version": "v2.2.6",
@@ -1722,12 +1769,12 @@
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "1.2.12"
"reference": "0e9958c459d675fb497d8dc5001c91d335734e48"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/1.2.12",
"reference": "1.2.12",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/0e9958c459d675fb497d8dc5001c91d335734e48",
"reference": "0e9958c459d675fb497d8dc5001c91d335734e48",
"shasum": ""
},
"require": {
@@ -1916,12 +1963,12 @@
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-token-stream.git",
"reference": "1.2.0"
"reference": "31babf400e5b5868573bf49a000a3519d3978233"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/1.2.0",
"reference": "1.2.0",
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/31babf400e5b5868573bf49a000a3519d3978233",
"reference": "31babf400e5b5868573bf49a000a3519d3978233",
"shasum": ""
},
"require": {
@@ -1966,12 +2013,12 @@
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "3.7.24"
"reference": "af7b77ccb5c64458bdfca95665d29558d1df7d08"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3.7.24",
"reference": "3.7.24",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/af7b77ccb5c64458bdfca95665d29558d1df7d08",
"reference": "af7b77ccb5c64458bdfca95665d29558d1df7d08",
"shasum": ""
},
"require": {

View File

@@ -23,6 +23,7 @@
namespace Thelia\Action;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Thelia\Model\AdminLog;
use Propel\Runtime\ActiveQuery\PropelQuery;
use Propel\Runtime\ActiveQuery\ModelCriteria;
use Thelia\Core\Event\UpdatePositionEvent;
@@ -72,4 +73,18 @@ class BaseAction
return $object->movePositionDown();
}
}
/**
* Helper to append a message to the admin log.
*
* @param string $message
*/
public function adminLogAppend($message)
{
AdminLog::append(
$message,
$this->container->get('request'),
$this->container->get('thelia.securityContext')->getAdminUser()
);
}
}

View File

@@ -0,0 +1,112 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Action;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Thelia\Core\Event\Content\ContentCreateEvent;
use Thelia\Core\Event\Content\ContentUpdateEvent;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Model\ContentQuery;
use Thelia\Model\Content as ContentModel;
use Thelia\Model\FolderQuery;
/**
* Class Content
* @package Thelia\Action
* @author manuel raynaud <mraynaud@openstudio.fr>
*/
class Content extends BaseAction implements EventSubscriberInterface
{
public function create(ContentCreateEvent $event)
{
$content = new ContentModel();
$content
->setVisible($event->getVisible())
->setLocale($event->getLocale())
->setTitle($event->getTitle())
->create($event->getDefaultFolder())
;
$event->setContent($content);
}
/**
* process update content
*
* @param ContentUpdateEvent $event
*/
public function update(ContentUpdateEvent $event)
{
if (null !== $content = ContentQuery::create()->findPk($event->getContentId())) {
$content->setDispatcher($this->getDispatcher());
$content
->setVisible($event->getVisible())
->setLocale($event->getLocale())
->setTitle($event->getTitle())
->setDescription($event->getDescription())
->setChapo($event->getChapo())
->setPostscriptum($event->getPostscriptum())
->save()
;
$event->setContent($content);
}
}
/**
* Returns an array of event names this subscriber wants to listen to.
*
* The array keys are event names and the value can be:
*
* * The method name to call (priority defaults to 0)
* * An array composed of the method name to call and the priority
* * An array of arrays composed of the method names to call and respective
* priorities, or 0 if unset
*
* For instance:
*
* * array('eventName' => 'methodName')
* * array('eventName' => array('methodName', $priority))
* * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
*
* @return array The event names to listen to
*
* @api
*/
public static function getSubscribedEvents()
{
return array(
TheliaEvents::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),
);
}
}

View File

@@ -0,0 +1,155 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Action;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Thelia\Core\Event\FolderCreateEvent;
use Thelia\Core\Event\FolderDeleteEvent;
use Thelia\Core\Event\FolderToggleVisibilityEvent;
use Thelia\Core\Event\FolderUpdateEvent;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Core\Event\UpdatePositionEvent;
use Thelia\Model\FolderQuery;
use Thelia\Model\Folder as FolderModel;
/**
* Class Folder
* @package Thelia\Action
* @author Manuel Raynaud <mraynaud@openstudio.fr>
*/
class Folder extends BaseAction implements EventSubscriberInterface {
public function update(FolderUpdateEvent $event)
{
if (null !== $folder = FolderQuery::create()->findPk($event->getFolderId())) {
$folder->setDispatcher($this->getDispatcher());
$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);
}
}
public function delete(FolderDeleteEvent $event)
{
if (null !== $folder = FolderQuery::create()->findPk($event->getFolderId())) {
$folder->setDispatcher($this->getDispatcher())
->delete();
$event->setFolder($folder);
}
}
/**
* @param FolderCreateEvent $event
*/
public function create(FolderCreateEvent $event)
{
$folder = new FolderModel();
$folder->setDispatcher($this->getDispatcher());
$folder
->setParent($event->getParent())
->setVisible($event->getVisible())
->setLocale($event->getLocale())
->setTitle($event->getTitle())
->save();
$event->setFolder($folder);
}
public function toggleVisibility(FolderToggleVisibilityEvent $event)
{
$folder = $event->getFolder();
$folder
->setDispatcher($this->getDispatcher())
->setVisible(!$folder->getVisible())
->save();
}
public function updatePosition(UpdatePositionEvent $event)
{
if(null !== $folder = FolderQuery::create()->findPk($event->getObjectId())) {
$folder->setDispatcher($this->getDispatcher());
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;
}
}
}
/**
* Returns an array of event names this subscriber wants to listen to.
*
* The array keys are event names and the value can be:
*
* * The method name to call (priority defaults to 0)
* * An array composed of the method name to call and the priority
* * An array of arrays composed of the method names to call and respective
* priorities, or 0 if unset
*
* For instance:
*
* * array('eventName' => 'methodName')
* * array('eventName' => array('methodName', $priority))
* * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
*
* @return array The event names to listen to
*
* @api
*/
public static function getSubscribedEvents()
{
return array(
TheliaEvents::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),
);
}
}

View File

@@ -23,10 +23,20 @@
namespace Thelia\Action;
use Propel\Runtime\ActiveRecord\ActiveRecordInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Thelia\Core\Event\ImageCreateOrUpdateEvent;
use Thelia\Core\Event\ImagesCreateOrUpdateEvent;
use Thelia\Core\Event\ImageDeleteEvent;
use Thelia\Core\Event\ImageEvent;
use Thelia\Model\CategoryImage;
use Thelia\Model\ConfigQuery;
use Thelia\Model\ContentImage;
use Thelia\Model\FolderImage;
use Thelia\Model\ProductImage;
use Thelia\Tools\FileManager;
use Thelia\Tools\URL;
use Imagine\Image\ImagineInterface;
@@ -39,10 +49,10 @@ use Thelia\Core\Event\TheliaEvents;
/**
*
* Image management actions. This class handles image processing an caching.
* Image management actions. This class handles image processing and caching.
*
* Basically, images are stored outside the web space (by default in local/media/images),
* and cached in the web space (by default in web/local/images).
* 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.
@@ -78,6 +88,8 @@ class Image extends BaseCachedFile implements EventSubscriberInterface
const EXACT_RATIO_WITH_CROP = 2;
const KEEP_IMAGE_RATIO = 3;
/**
* @return string root of the image cache directory in web space
*/
@@ -240,6 +252,132 @@ class Image extends BaseCachedFile implements EventSubscriberInterface
$event->setOriginalFileUrl(URL::getInstance()->absoluteUrl($original_image_url, null, URL::PATH_TO_FILE));
}
/**
* Take care of saving image in the database and file storage
*
* @param ImageCreateOrUpdateEvent $event Image event
*
* @throws \Thelia\Exception\ImageException
* @todo refactor make all pictures using propel inheritance and factorise image behaviour into one single clean action
*/
public function saveImage(ImageCreateOrUpdateEvent $event)
{
$this->adminLogAppend(
$this->container->get('thelia.translator')->trans(
'Saving images for %parentName% parent id %parentId% (%parentType%)',
array(
'%parentName%' => $event->getParentName(),
'%parentId%' => $event->getParentId(),
'%parentType%' => $event->getImageType()
),
'image'
)
);
$fileManager = new FileManager($this->container);
$model = $event->getModelImage();
$nbModifiedLines = $model->save();
$event->setModelImage($model);
if (!$nbModifiedLines) {
throw new ImageException(
sprintf(
'Image "%s" with parent id %s (%s) failed to be saved',
$event->getParentName(),
$event->getParentId(),
$event->getImageType()
)
);
}
$newUploadedFile = $fileManager->copyUploadedFile($event->getParentId(), $event->getImageType(), $event->getModelImage(), $event->getUploadedFile());
$event->setUploadedFile($newUploadedFile);
}
/**
* Take care of updating image in the database and file storage
*
* @param ImageCreateOrUpdateEvent $event Image event
*
* @throws \Thelia\Exception\ImageException
* @todo refactor make all pictures using propel inheritance and factorise image behaviour into one single clean action
*/
public function updateImage(ImageCreateOrUpdateEvent $event)
{
$this->adminLogAppend(
$this->container->get('thelia.translator')->trans(
'Updating images for %parentName% parent id %parentId% (%parentType%)',
array(
'%parentName%' => $event->getParentName(),
'%parentId%' => $event->getParentId(),
'%parentType%' => $event->getImageType()
),
'image'
)
);
$fileManager = new FileManager($this->container);
// Copy and save file
if ($event->getUploadedFile()) {
// Remove old picture file from file storage
$url = $fileManager->getUploadDir($event->getImageType()) . '/' . $event->getOldModelImage()->getFile();
unlink(str_replace('..', '', $url));
$newUploadedFile = $fileManager->copyUploadedFile(
$event->getModelImage()->getParentId(),
$event->getImageType(),
$event->getModelImage(), $event->getUploadedFile());
$event->setUploadedFile($newUploadedFile);
}
// Update image modifications
$event->getModelImage()->save();
$event->setModelImage($event->getModelImage());
}
/**
* Take care of deleting image in the database and file storage
*
* @param ImageDeleteEvent $event Image event
*
* @throws \Exception
* @todo refactor make all pictures using propel inheritance and factorise image behaviour into one single clean action
*/
public function deleteImage(ImageDeleteEvent $event)
{
$fileManager = new FileManager($this->container);
try {
$fileManager->deleteImage($event->getImageToDelete(), $event->getImageType());
$this->adminLogAppend(
$this->container->get('thelia.translator')->trans(
'Deleting image for %id% with parent id %parentId%',
array(
'%id%' => $event->getImageToDelete()->getId(),
'%parentId%' => $event->getImageToDelete()->getParentId(),
),
'image'
)
);
} catch(\Exception $e) {
$this->adminLogAppend(
$this->container->get('thelia.translator')->trans(
'Fail to delete image for %id% with parent id %parentId% (Exception : %e%)',
array(
'%id%' => $event->getImageToDelete()->getId(),
'%parentId%' => $event->getImageToDelete()->getParentId(),
'%e%' => $e->getMessage()
),
'image'
)
);
throw $e;
}
}
/**
* Process image resizing, with borders or cropping. If $dest_width and $dest_height
* are both null, no resize is performed.
@@ -362,6 +500,9 @@ class Image extends BaseCachedFile implements EventSubscriberInterface
return array(
TheliaEvents::IMAGE_PROCESS => array("processImage", 128),
TheliaEvents::IMAGE_CLEAR_CACHE => array("clearCache", 128),
TheliaEvents::IMAGE_DELETE => array("deleteImage", 128),
TheliaEvents::IMAGE_SAVE => array("saveImage", 128),
TheliaEvents::IMAGE_UPDATE => array("updateImage", 128),
);
}
}

View File

@@ -23,18 +23,23 @@
namespace Thelia\Action;
use Propel\Runtime\Exception\PropelException;
use Propel\Runtime\ActiveQuery\ModelCriteria;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Thelia\Core\Event\OrderEvent;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Model\Base\AddressQuery;
use Thelia\Exception\OrderException;
use Thelia\Exception\TheliaProcessException;
use Thelia\Model\AddressQuery;
use Thelia\Model\OrderProductAttributeCombination;
use Thelia\Model\ModuleQuery;
use Thelia\Model\OrderProduct;
use Thelia\Model\OrderStatus;
use Thelia\Model\Map\OrderTableMap;
use Thelia\Model\OrderAddress;
use Thelia\Model\OrderStatusQuery;
use Thelia\Model\ConfigQuery;
use Thelia\Tools\I18n;
/**
*
@@ -108,14 +113,18 @@ class Order extends BaseAction implements EventSubscriberInterface
/* use a copy to avoid errored reccord in session */
$placedOrder = $sessionOrder->copy();
$placedOrder->setDispatcher($this->getDispatcher());
$customer = $this->getSecurityContext()->getCustomerUser();
$currency = $this->getSession()->getCurrency();
$lang = $this->getSession()->getLang();
$deliveryAddress = AddressQuery::create()->findPk($sessionOrder->chosenDeliveryAddress);
$taxCountry = $deliveryAddress->getCountry();
$invoiceAddress = AddressQuery::create()->findPk($sessionOrder->chosenInvoiceAddress);
$cart = $this->getSession()->getCart();
$cartItems = $cart->getCartItems();
$paymentModule = ModuleQuery::findPk($placedOrder->getPaymentModuleId());
$paymentModule = ModuleQuery::create()->findPk($placedOrder->getPaymentModuleId());
/* fulfill order */
$placedOrder->setCustomerId($customer->getId());
@@ -163,24 +172,116 @@ class Order extends BaseAction implements EventSubscriberInterface
$placedOrder->save($con);
/* fulfill order_products and decrease stock // @todo dispatch event */
/* fulfill order_products and decrease stock */
foreach($cartItems as $cartItem) {
$product = $cartItem->getProduct();
/* get translation */
$productI18n = I18n::forceI18nRetrieving($this->getSession()->getLang()->getLocale(), 'Product', $product->getId());
$pse = $cartItem->getProductSaleElements();
/* check still in stock */
if($cartItem->getQuantity() > $pse->getQuantity()) {
throw new TheliaProcessException("Not enough stock", TheliaProcessException::CART_ITEM_NOT_ENOUGH_STOCK, $cartItem);
}
/* decrease stock */
$pse->setQuantity(
$pse->getQuantity() - $cartItem->getQuantity()
);
$pse->save($con);
/* get tax */
$taxRuleI18n = I18n::forceI18nRetrieving($this->getSession()->getLang()->getLocale(), 'TaxRule', $product->getTaxRuleId());
$taxDetail = $product->getTaxRule()->getTaxDetail(
$taxCountry,
$cartItem->getPromo() == 1 ? $cartItem->getPromoPrice() : $cartItem->getPrice(),
$this->getSession()->getLang()->getLocale()
);
$orderProduct = new OrderProduct();
$orderProduct
->setOrderId($placedOrder->getId())
->setProductRef($product->getRef())
->setProductSaleElementsRef($pse->getRef())
->setTitle($productI18n->getTitle())
->setChapo($productI18n->getChapo())
->setDescription($productI18n->getDescription())
->setPostscriptum($productI18n->getPostscriptum())
->setQuantity($cartItem->getQuantity())
->setPrice($cartItem->getPrice())
->setPromoPrice($cartItem->getPromoPrice())
->setWasNew($pse->getNewness())
->setWasInPromo($cartItem->getPromo())
->setWeight($pse->getWeight())
->setTaxRuleTitle($taxRuleI18n->getTitle())
->setTaxRuleDescription($taxRuleI18n->getDescription())
;
$orderProduct->setDispatcher($this->getDispatcher());
$orderProduct->save($con);
/* fulfill order_product_tax */
foreach($taxDetail as $tax) {
$tax->setOrderProductId($orderProduct->getId());
$tax->save($con);
}
/* fulfill order_attribute_combination and decrease stock */
foreach($pse->getAttributeCombinations() as $attributeCombination) {
$attribute = I18n::forceI18nRetrieving($this->getSession()->getLang()->getLocale(), 'Attribute', $attributeCombination->getAttributeId());
$attributeAv = I18n::forceI18nRetrieving($this->getSession()->getLang()->getLocale(), 'AttributeAv', $attributeCombination->getAttributeAvId());
$orderAttributeCombination = new OrderProductAttributeCombination();
$orderAttributeCombination
->setOrderProductId($orderProduct->getId())
->setAttributeTitle($attribute->getTitle())
->setAttributeChapo($attribute->getChapo())
->setAttributeDescription($attribute->getDescription())
->setAttributePostscriptumn($attribute->getPostscriptum())
->setAttributeAvTitle($attributeAv->getTitle())
->setAttributeAvChapo($attributeAv->getChapo())
->setAttributeAvDescription($attributeAv->getDescription())
->setAttributeAvPostscriptum($attributeAv->getPostscriptum())
;
$orderAttributeCombination->save($con);
}
}
/* discount @todo */
$con->commit();
/* T1style : dispatch mail event ? */
$this->getDispatcher()->dispatch(TheliaEvents::ORDER_BEFORE_PAYMENT, new OrderEvent($placedOrder));
/* clear session ? */
/* clear session */
/* but memorize placed order */
$sessionOrder = new \Thelia\Model\Order();
$event->setOrder($sessionOrder);
$event->setPlacedOrder($placedOrder);
$this->getSession()->setOrder($sessionOrder);
/* empty cart @todo */
/* call pay method */
$paymentModuleReflection = new \ReflectionClass($paymentModule->getFullNamespace());
$paymentModuleInstance = $paymentModuleReflection->newInstance();
$paymentModuleInstance->setRequest($this->request);
$paymentModuleInstance->setDispatcher($this->dispatcher);
$paymentModuleInstance->setRequest($this->getRequest());
$paymentModuleInstance->setDispatcher($this->getDispatcher());
$paymentModuleInstance->pay();
$paymentModuleInstance->pay($placedOrder);
}
/**
* @param \Thelia\Core\Event\OrderEvent $event
*/
public function sendOrderEmail(OrderEvent $event)
{
/* @todo */
}
/**
@@ -188,14 +289,13 @@ class Order extends BaseAction implements EventSubscriberInterface
*/
public function setReference(OrderEvent $event)
{
$x = true;
$this->setRef($this->generateRef());
$event->getOrder()->setRef($this->generateRef());
}
public function generateRef()
{
return sprintf('O', uniqid('', true), $this->getId());
/* order addresses are unique */
return uniqid('ORD', true);
}
/**
@@ -226,7 +326,8 @@ class Order extends BaseAction implements EventSubscriberInterface
TheliaEvents::ORDER_SET_INVOICE_ADDRESS => array("setInvoiceAddress", 128),
TheliaEvents::ORDER_SET_PAYMENT_MODULE => array("setPaymentModule", 128),
TheliaEvents::ORDER_PAY => array("create", 128),
TheliaEvents::ORDER_SET_REFERENCE => array("setReference", 128),
TheliaEvents::ORDER_BEFORE_CREATE => array("setReference", 128),
TheliaEvents::ORDER_BEFORE_PAYMENT => array("sendOrderEmail", 128),
);
}

View File

@@ -61,6 +61,11 @@ use Thelia\Model\ProductSaleElementsQuery;
use Propel\Runtime\ActiveQuery\PropelQuery;
use Thelia\Core\Event\ProductDeleteCategoryEvent;
use Thelia\Core\Event\ProductAddCategoryEvent;
use Thelia\Model\AttributeAvQuery;
use Thelia\Model\AttributeCombination;
use Thelia\Core\Event\ProductCreateCombinationEvent;
use Propel\Runtime\Propel;
use Thelia\Model\Map\ProductTableMap;
class Product extends BaseAction implements EventSubscriberInterface
{
@@ -331,7 +336,6 @@ class Product extends BaseAction implements EventSubscriberInterface
->setProductId($event->getProductId())
->setFeatureId($event->getFeatureId())
;
}
@@ -356,6 +360,58 @@ class Product extends BaseAction implements EventSubscriberInterface
;
}
public function createProductCombination(ProductCreateCombinationEvent $event) {
$con = Propel::getWriteConnection(ProductTableMap::DATABASE_NAME);
$con->beginTransaction();
try {
if ($event->getUseDefaultPricing()) {
// Get the default pricing
$salesElement = ProductSaleElementsQuery::create()->filterByIsDefault(true)->findOne();
}
else {
// We have to create a new ProductSaleElement
echo "no default !!!!";
exit;
}
if (null == $salesElement)
throw new \LogicException("Cannot create or get the product sales element for this new combination.");
$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();
}
}
}
// Store all the stuff !
$con->commit();
}
catch(\Exception $ex) {
$con->rollback();
throw $ex;
}
}
/**
* {@inheritDoc}
*/
@@ -374,6 +430,9 @@ class Product extends BaseAction implements EventSubscriberInterface
TheliaEvents::PRODUCT_UPDATE_ACCESSORY_POSITION => array("updateAccessoryPosition", 128),
TheliaEvents::PRODUCT_UPDATE_CONTENT_POSITION => array("updateContentPosition", 128),
TheliaEvents::PRODUCT_ADD_COMBINATION => array("createProductCombination", 128),
TheliaEvents::PRODUCT_DELETE_COMBINATION => array("deleteProductCombination", 128),
TheliaEvents::PRODUCT_ADD_ACCESSORY => array("addAccessory", 128),
TheliaEvents::PRODUCT_REMOVE_ACCESSORY => array("removeAccessory", 128),

View File

@@ -97,6 +97,16 @@
<tag name="kernel.event_subscriber"/>
</service>
<service id="thelia.action.folder" class="Thelia\Action\Folder">
<argument type="service" id="service_container"/>
<tag name="kernel.event_subscriber"/>
</service>
<service id="thelia.action.content" class="Thelia\Action\Content">
<argument type="service" id="service_container"/>
<tag name="kernel.event_subscriber"/>
</service>
</services>
</config>

View File

@@ -21,6 +21,7 @@
<loop class="Thelia\Core\Template\Loop\FeatureAvailability" name="feature-availability"/>
<loop class="Thelia\Core\Template\Loop\FeatureValue" name="feature_value"/>
<loop class="Thelia\Core\Template\Loop\Folder" name="folder"/>
<loop class="Thelia\Core\Template\Loop\Module" name="module"/>
<loop class="Thelia\Core\Template\Loop\Order" name="order"/>
<loop class="Thelia\Core\Template\Loop\OrderStatus" name="order-status"/>
<loop class="Thelia\Core\Template\Loop\CategoryPath" name="category-path"/>
@@ -57,6 +58,7 @@
<form name="thelia.admin.category.creation" class="Thelia\Form\CategoryCreationForm"/>
<form name="thelia.admin.category.modification" class="Thelia\Form\CategoryModificationForm"/>
<form name="thelia.admin.category.image.modification" class="Thelia\Form\CategoryImageModification"/>
<form name="thelia.admin.product.creation" class="Thelia\Form\ProductCreationForm"/>
<form name="thelia.admin.product.modification" class="Thelia\Form\ProductModificationForm"/>
@@ -239,6 +241,11 @@
<argument type="service" id="thelia.securityContext" />
</service>
<service id="smarty.plugin.flashMessage" class="Thelia\Core\Template\Smarty\Plugins\FlashMessage" scope="request">
<tag name="thelia.parser.register_plugin"/>
<argument type="service" id="request" />
</service>
<service id="http_kernel" class="Thelia\Core\TheliaHttpKernel">
<argument type="service" id="event_dispatcher" />

View File

@@ -37,6 +37,37 @@
<default key="_controller">Thelia\Controller\Admin\CategoryController::defaultAction</default>
</route>
<!-- Route to the file controller -->
<route id="admin.image.save-ajax" path="/admin/image/type/{parentType}/{parentId}/save-ajax">
<default key="_controller">Thelia\Controller\Admin\FileController::saveImageAjaxAction</default>
<requirement key="parentType">.*</requirement>
<requirement key="parentId">\d+</requirement>
</route>
<route id="admin.image.form-ajax" path="/admin/image/type/{parentType}/{parentId}/form-ajax">
<default key="_controller">Thelia\Controller\Admin\FileController::getImageFormAjaxAction</default>
<requirement key="parentType">.*</requirement>
<requirement key="parentId">\d+</requirement>
</route>
<route id="admin.image.list-ajax" path="/admin/image/type/{parentType}/{parentId}/list-ajax">
<default key="_controller">Thelia\Controller\Admin\FileController::getImageListAjaxAction</default>
<requirement key="parentType">.*</requirement>
<requirement key="parentId">\d+</requirement>
</route>
<route id="admin.image.update.view" path="/admin/image/type/{parentType}/{imageId}/update" methods="get">
<default key="_controller">Thelia\Controller\Admin\FileController::viewImageAction</default>
<requirement key="customer_id">\d+</requirement>
</route>
<route id="admin.image.update.process" path="/admin/image/type/{parentType}/{imageId}/update" methods="post">
<default key="_controller">Thelia\Controller\Admin\FileController::updateImageAction</default>
<requirement key="customer_id">\d+</requirement>
</route>
<route id="admin.image.delete" path="/admin/image/type/{parentType}/delete/{imageId}">
<default key="_controller">Thelia\Controller\Admin\FileController::deleteImagesAction</default>
<requirement key="parentType">.*</requirement>
<requirement key="parentId">\d+</requirement>
</route>
<!-- Customer rule management -->
<route id="admin.customers" path="/admin/customers">
@@ -106,6 +137,10 @@
<default key="_controller">Thelia\Controller\Admin\CategoryController::addRelatedContentAction</default>
</route>
<route id="admin.categories.related-content.add" path="/admin/categories/related-picture/add">
<default key="_controller">Thelia\Controller\Admin\CategoryController::addRelatedPictureAction</default>
</route>
<route id="admin.categories.related-content.delete" path="/admin/categories/related-content/delete">
<default key="_controller">Thelia\Controller\Admin\CategoryController::deleteRelatedContentAction</default>
</route>
@@ -230,28 +265,66 @@
<requirement key="_format">xml|json</requirement>
</route>
<route id="admin.product.add-attribute-value-to-combination" path="/admin/product/{productId}/add-attribute-value-to-combination/{attributeAvId}/{combination}.{_format}" methods="GET">
<default key="_controller">Thelia\Controller\Admin\ProductController::addAttributeValueToCombinationAction</default>
<requirement key="_format">xml|json</requirement>
</route>
<route id="admin.product.combination.add" path="/admin/product/combination/add">
<default key="_controller">Thelia\Controller\Admin\ProductController::addCombinationAction</default>
</route>
<route id="admin.product.combination.delete" path="/admin/product/combination/delete">
<default key="_controller">Thelia\Controller\Admin\ProductController::deleteCombinationAction</default>
</route>
<!-- Folder routes management -->
<route id="admin.folders.default" path="/admin/folders">
<default key="_controller">Thelia\Controller\Admin\FolderController::indexAction</default>
<default key="_controller">Thelia\Controller\Admin\FolderController::defaultAction</default>
</route>
<route id="admin.folders.create" path="/admin/folders/create">
<default key="_controller">Thelia\Controller\Admin\FolderController::createAction</default>
</route>
<route id="admin.folders.update" path="/admin/folders/update/{folder_id}" methods="get">
<route id="admin.folders.update" path="/admin/folders/update/{folder_id}">
<default key="_controller">Thelia\Controller\Admin\FolderController::updateAction</default>
<requirement key="folder_id">\d+</requirement>
</route>
<route id="admin.folders.toggle-online" path="/admin/folders/toggle-online">
<default key="_controller">Thelia\Controller\Admin\FolderController::setToggleVisibilityAction</default>
</route>
<route id="admin.folders.save" path="/admin/folders/save">
<default key="_controller">Thelia\Controller\Admin\FolderController::processUpdateAction</default>
</route>
<route id="admin.folders.delete" path="/admin/folders/delete">
<default key="_controller">Thelia\Controller\Admin\FolderController::deleteAction</default>
</route>
<route id="admin.folders.update-position" path="/admin/folders/update-position">
<default key="_controller">Thelia\Controller\Admin\FolderController::updatePositionAction</default>
</route>
<!-- content routes management -->
<route id="admin.folders.create" path="/admin/content/create">
<default key="_controller">Thelia\Controller\Admin\ContentController::createAction</default>
</route>
<route id="admin.content.update" path="admin/content/update/{content_id}">
<default key="_controller">Thelia\Controller\Admin\ContentController::updateAction</default>
<requirement key="content_id">\d+</requirement>
</route>
<route id="admin.content.save" path="/admin/content/save">
<default key="_controller">Thelia\Controller\Admin\ContentController::processUpdateAction</default>
</route>
<!-- Route to the Coupon controller (process Coupon browsing) -->
<route id="admin.coupon.list" path="/admin/coupon/">

View File

@@ -137,7 +137,11 @@
<route id="order.payment.process" path="/order/pay">
<default key="_controller">Thelia\Controller\Front\OrderController::pay</default>
<default key="_view">order_payment</default>
</route>
<route id="order.placed" path="/order/placed/{order_id}">
<default key="_controller">Thelia\Controller\Front\OrderController::orderPlaced</default>
<default key="_view">order_placed</default>
</route>
<!-- end order management process -->

View File

@@ -527,9 +527,6 @@ abstract class AbstractCrudController extends BaseAdminController
$changeEvent = $this->createToggleVisibilityEvent($this->getRequest());
// Create and dispatch the change event
$changeEvent->setIsDefault(true);
try {
$this->dispatch($this->visibilityToggleEventIdentifier, $changeEvent);
} catch (\Exception $ex) {
@@ -537,7 +534,7 @@ abstract class AbstractCrudController extends BaseAdminController
return $this->errorPage($ex);
}
$this->redirectToListTemplate();
return $this->nullResponse();
}
/**

View File

@@ -23,10 +23,13 @@
namespace Thelia\Controller\Admin;
use Symfony\Component\HttpFoundation\Response;
use Thelia\Core\Event\CategoryDeleteEvent;
use Thelia\Core\Event\ImageCreateOrUpdateEvent;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Core\Event\CategoryUpdateEvent;
use Thelia\Core\Event\CategoryCreateEvent;
use Thelia\Log\Tlog;
use Thelia\Model\CategoryQuery;
use Thelia\Form\CategoryModificationForm;
use Thelia\Form\CategoryCreationForm;
@@ -34,7 +37,6 @@ use Thelia\Core\Event\UpdatePositionEvent;
use Thelia\Core\Event\CategoryToggleVisibilityEvent;
use Thelia\Core\Event\CategoryDeleteContentEvent;
use Thelia\Core\Event\CategoryAddContentEvent;
use Thelia\Model\CategoryAssociatedContent;
use Thelia\Model\FolderQuery;
use Thelia\Model\ContentQuery;
use Propel\Runtime\ActiveQuery\Criteria;
@@ -306,6 +308,39 @@ class CategoryController extends AbstractCrudController
$this->redirectToEditionTemplate();
}
/**
* Add category pictures
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function addRelatedPictureAction()
{
// Check current user authorization
if (null !== $response = $this->checkAuth("admin.categories.update")) {
return $response;
}
// $content_id = intval($this->getRequest()->get('content_id'));
//
// if ($content_id > 0) {
//
// $event = new CategoryAddContentEvent(
// $this->getExistingObject(),
// $content_id
// );
//
// try {
// $this->dispatch(TheliaEvents::CATEGORY_ADD_CONTENT, $event);
// }
// catch (\Exception $ex) {
// // Any error
// return $this->errorPage($ex);
// }
// }
$this->redirectToEditionTemplate();
}
public function deleteRelatedContentAction() {
// Check current user authorization
@@ -331,4 +366,5 @@ class CategoryController extends AbstractCrudController
$this->redirectToEditionTemplate();
}
}

View File

@@ -0,0 +1,289 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Controller\Admin;
use Thelia\Core\Event\Content\ContentCreateEvent;
use Thelia\Core\Event\Content\ContentUpdateEvent;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Form\ContentCreationForm;
use Thelia\Form\ContentModificationForm;
use Thelia\Model\ContentQuery;
/**
* Class ContentController
* @package Thelia\Controller\Admin
* @author manuel raynaud <mraynaud@openstudio.fr>
*/
class ContentController extends AbstractCrudController
{
public function __construct()
{
parent::__construct(
'content',
'manual',
'content_order',
'admin.content.default',
'admin.content.create',
'admin.content.update',
'admin.content.delete',
TheliaEvents::CONTENT_CREATE,
TheliaEvents::CONTENT_UPDATE,
TheliaEvents::CONTENT_DELETE,
TheliaEvents::CONTENT_TOGGLE_VISIBILITY,
TheliaEvents::CONTENT_UPDATE_POSITION
);
}
/**
* Return the creation form for this object
*/
protected function getCreationForm()
{
return new ContentCreationForm($this->getRequest());
}
/**
* Return the update form for this object
*/
protected function getUpdateForm()
{
return new ContentModificationForm($this->getRequest());
}
/**
* Hydrate the update form for this object, before passing it to the update template
*
* @param \Thelia\Form\ContentModificationForm $object
*/
protected function hydrateObjectForm($object)
{
// Prepare the data that will hydrate the form
$data = array(
'id' => $object->getId(),
'locale' => $object->getLocale(),
'title' => $object->getTitle(),
'chapo' => $object->getChapo(),
'description' => $object->getDescription(),
'postscriptum' => $object->getPostscriptum(),
'visible' => $object->getVisible(),
'url' => $object->getRewrittenUrl($this->getCurrentEditionLocale()),
);
// Setup the object form
return new ContentModificationForm($this->getRequest(), "form", $data);
}
/**
* Creates the creation event with the provided form data
*
* @param unknown $formData
*/
protected function getCreationEvent($formData)
{
$contentCreateEvent = new ContentCreateEvent();
$contentCreateEvent
->setLocale($formData['locale'])
->setDefaultFolder($formData['default_folder'])
->setTitle($formData['title'])
->setVisible($formData['visible'])
;
return $contentCreateEvent;
}
/**
* Creates the update event with the provided form data
*
* @param unknown $formData
*/
protected function getUpdateEvent($formData)
{
$contentUpdateEvent = new ContentUpdateEvent($formData['id']);
$contentUpdateEvent
->setLocale($formData['locale'])
->setTitle($formData['title'])
->setChapo($formData['chapo'])
->setDescription($formData['description'])
->setPostscriptum($formData['postscriptum'])
->setVisible($formData['visible'])
->setUrl($formData['url'])
->setDefaultFolder($formData['default_folder']);
return $contentUpdateEvent;
}
/**
* Creates the delete event with the provided form data
*/
protected function getDeleteEvent()
{
// TODO: Implement getDeleteEvent() method.
}
/**
* Return true if the event contains the object, e.g. the action has updated the object in the event.
*
* @param \Thelia\Core\Event\Content\ContentEvent $event
*/
protected function eventContainsObject($event)
{
return $event->hasContent();
}
/**
* Get the created object from an event.
*
* @param $event \Thelia\Core\Event\Content\ContentEvent
*
* @return null|\Thelia\Model\Content
*/
protected function getObjectFromEvent($event)
{
return $event->getContent();
}
/**
* Load an existing object from the database
*
* @return \Thelia\Model\Content
*/
protected function getExistingObject()
{
return ContentQuery::create()
->joinWithI18n($this->getCurrentEditionLocale())
->findOneById($this->getRequest()->get('content_id', 0));
}
/**
* Returns the object label form the object event (name, title, etc.)
*
* @param $object \Thelia\Model\Content
*
* @return string content title
*
*/
protected function getObjectLabel($object)
{
return $object->getTitle();
}
/**
* Returns the object ID from the object
*
* @param $object \Thelia\Model\Content
*
* @return int content id
*/
protected function getObjectId($object)
{
return $object->getId();
}
protected function getFolderId()
{
$folderId = $this->getRequest()->get('folder_id', null);
if(null === $folderId) {
$content = $this->getExistingObject();
if($content) {
$folderId = $content->getDefaultFolderId();
}
}
return $folderId ?: 0;
}
/**
* Render the main list template
*
* @param unknown $currentOrder, if any, null otherwise.
*/
protected function renderListTemplate($currentOrder)
{
$this->getListOrderFromSession('content', 'content_order', 'manual');
return $this->render('folders',
array(
'content_order' => $currentOrder,
'parent' => $this->getFolderId()
));
}
protected function getEditionArguments()
{
return array(
'content_id' => $this->getRequest()->get('content_id', 0),
'current_tab' => $this->getRequest()->get('current_tab', 'general')
);
}
/**
* Render the edition template
*/
protected function renderEditionTemplate()
{
return $this->render('content-edit', $this->getEditionArguments());
}
/**
* Redirect to the edition template
*/
protected function redirectToEditionTemplate()
{
$this->redirect($this->getRoute('admin.content.update', $this->getEditionArguments()));
}
/**
* Redirect to the list template
*/
protected function redirectToListTemplate()
{
$this->redirectToRoute(
'admin.content.default',
array('parent' => $this->getFolderId())
);
}
/**
* @param \Thelia\Core\Event\Content\ContentUpdateEvent $updateEvent
* @return Response|void
*/
protected function performAdditionalUpdateAction($updateEvent)
{
if ($this->getRequest()->get('save_mode') != 'stay') {
// Redirect to parent category list
$this->redirectToRoute(
'admin.folders.default',
array('parent' => $this->getFolderId())
);
}
}
}

View File

@@ -0,0 +1,403 @@
<?php
/**********************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/**********************************************************************************/
namespace Thelia\Controller\Admin;
use Propel\Runtime\Exception\PropelException;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Router;
use Symfony\Component\Validator\Constraints\Image;
use Symfony\Component\Validator\Constraints\ImageValidator;
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
use Thelia\Core\Event\ImageCreateOrUpdateEvent;
use Thelia\Core\Event\ImagesCreateOrUpdateEvent;
use Thelia\Core\Event\ImageDeleteEvent;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Core\Translation\Translator;
use Thelia\Form\Exception\FormValidationException;
use Thelia\Log\Tlog;
use Thelia\Model\CategoryImage;
use Thelia\Model\ContentImage;
use Thelia\Model\FolderImage;
use Thelia\Model\ProductImage;
use Thelia\Tools\FileManager;
use Thelia\Tools\Rest\ResponseRest;
/**
* Created by JetBrains PhpStorm.
* Date: 8/19/13
* Time: 3:24 PM
*
* Control View and Action (Model) via Events
* Control Files and Images
*
* @package File
* @author Guillaume MOREL <gmorel@openstudio.fr>
*
*/
class FileController extends BaseAdminController
{
/**
* Manage how a file collection has to be saved
*
* @param int $parentId Parent id owning files being saved
* @param string $parentType Parent Type owning files being saved
*
* @return Response
*/
public function saveFilesAction($parentId, $parentType)
{
}
/**
* Manage how a image collection has to be saved
*
* @param int $parentId Parent id owning images being saved
* @param string $parentType Parent Type owning images being saved
*
* @return Response
*/
public function saveImageAjaxAction($parentId, $parentType)
{
$this->checkAuth('ADMIN', 'admin.image.save');
$this->checkXmlHttpRequest();
if ($this->isParentTypeValid($parentType)) {
if ($this->getRequest()->isMethod('POST')) {
/** @var UploadedFile $fileBeingUploaded */
$fileBeingUploaded = $this->getRequest()->files->get('file');
$fileManager = new FileManager($this->container);
// Validate if file is too big
if ($fileBeingUploaded->getError() == 1) {
$message = $this->getTranslator()
->trans(
'File is too heavy, please retry with a file having a size less than %size%.',
array('%size%' => ini_get('post_max_size')),
'image'
);
return new ResponseRest($message, 'text', 403);
}
// Validate if it is a image or file
if (!$fileManager->isImage($fileBeingUploaded->getMimeType())) {
$message = $this->getTranslator()
->trans(
'You can only upload images (.png, .jpg, .jpeg, .gif)',
array(),
'image'
);
return new ResponseRest($message, 'text', 415);
}
$parentModel = $fileManager->getParentImageModel($parentType, $parentId);
$imageModel = $fileManager->getImageModel($parentType);
if ($parentModel === null || $imageModel === null || $fileBeingUploaded === null) {
return new Response('', 404);
}
$defaultTitle = $parentModel->getTitle();
$imageModel->setParentId($parentId);
$imageModel->setTitle($defaultTitle);
$imageCreateOrUpdateEvent = new ImageCreateOrUpdateEvent(
$parentType,
$parentId
);
$imageCreateOrUpdateEvent->setModelImage($imageModel);
$imageCreateOrUpdateEvent->setUploadedFile($fileBeingUploaded);
$imageCreateOrUpdateEvent->setParentName($parentModel->getTitle());
// Dispatch Event to the Action
$this->dispatch(
TheliaEvents::IMAGE_SAVE,
$imageCreateOrUpdateEvent
);
return new ResponseRest(array('status' => true, 'message' => ''));
}
}
return new Response('', 404);
}
/**
* Manage how a image list will be displayed in AJAX
*
* @param int $parentId Parent id owning images being saved
* @param string $parentType Parent Type owning images being saved
*
* @return Response
*/
public function getImageListAjaxAction($parentId, $parentType)
{
$this->checkAuth('ADMIN', 'admin.image.save');
$this->checkXmlHttpRequest();
$args = array('imageType' => $parentType, 'parentId' => $parentId);
return $this->render('includes/image-upload-list-ajax', $args);
}
/**
* Manage how an image list will be uploaded in AJAX
*
* @param int $parentId Parent id owning images being saved
* @param string $parentType Parent Type owning images being saved
*
* @return Response
*/
public function getImageFormAjaxAction($parentId, $parentType)
{
$this->checkAuth('ADMIN', 'admin.image.save');
$this->checkXmlHttpRequest();
$args = array('imageType' => $parentType, 'parentId' => $parentId);
return $this->render('includes/image-upload-form', $args);
}
/**
* Manage how an image is viewed
*
* @param int $imageId Parent id owning images being saved
* @param string $parentType Parent Type owning images being saved
*
* @return Response
*/
public function viewImageAction($imageId, $parentType)
{
if (null !== $response = $this->checkAuth('admin.image.view')) {
return $response;
}
try {
$fileManager = new FileManager($this->container);
$image = $fileManager->getImageModelQuery($parentType)->findPk($imageId);
$redirectUrl = $fileManager->getRedirectionUrl($parentType, $image->getParentId());
return $this->render('image-edit', array(
'imageId' => $imageId,
'imageType' => $parentType,
'redirectUrl' => $redirectUrl
));
} catch (Exception $e) {
$this->pageNotFound();
}
}
/**
* Manage how an image is updated
*
* @param int $imageId Parent id owning images being saved
* @param string $parentType Parent Type owning images being saved
*
* @return Response
*/
public function updateImageAction($imageId, $parentType)
{
if (null !== $response = $this->checkAuth('admin.image.update')) {
return $response;
}
$message = false;
$fileManager = new FileManager($this->container);
$imageModification = $fileManager->getImageForm($parentType, $this->getRequest());
try {
$image = $fileManager->getImageModelQuery($parentType)->findPk($imageId);
$oldImage = clone $image;
if (null === $image) {
throw new \InvalidArgumentException(sprintf('%d image id does not exists', $imageId));
}
$form = $this->validateForm($imageModification);
$event = $this->createEventInstance($parentType, $image, $form->getData());
$event->setOldModelImage($oldImage);
$files = $this->getRequest()->files;
$fileForm = $files->get($imageModification->getName());
if (isset($fileForm['file'])) {
$event->setUploadedFile($fileForm['file']);
}
$this->dispatch(TheliaEvents::IMAGE_UPDATE, $event);
$imageUpdated = $event->getModelImage();
$this->adminLogAppend(sprintf('Image with Ref %s (ID %d) modified', $imageUpdated->getTitle(), $imageUpdated->getId()));
if ($this->getRequest()->get('save_mode') == 'close') {
$this->redirectToRoute('admin.images');
} else {
$this->redirectSuccess($imageModification);
}
} catch (FormValidationException $e) {
$message = sprintf('Please check your input: %s', $e->getMessage());
} catch (PropelException $e) {
$message = $e->getMessage();
} catch (\Exception $e) {
$message = sprintf('Sorry, an error occurred: %s', $e->getMessage().' '.$e->getFile());
}
if ($message !== false) {
Tlog::getInstance()->error(sprintf('Error during image editing : %s.', $message));
$imageModification->setErrorMessage($message);
$this->getParserContext()
->addForm($imageModification)
->setGeneralError($message);
}
return $this->render('image-edit', array(
'imageId' => $imageId,
'imageType' => $parentType
));
}
/**
* Manage how a image has to be deleted (AJAX)
*
* @param int $imageId Parent id owning images being saved
* @param string $parentType Parent Type owning images being saved
*
* @return Response
*/
public function deleteImagesAction($imageId, $parentType)
{
$this->checkAuth('ADMIN', 'admin.image.delete');
$this->checkXmlHttpRequest();
$fileManager = new FileManager($this->container);
$imageModelQuery = $fileManager->getImageModelQuery($parentType);
$model = $imageModelQuery->findPk($imageId);
if ($model == null) {
return $this->pageNotFound();
}
// Feed event
$imageDeleteEvent = new ImageDeleteEvent(
$model,
$parentType
);
// Dispatch Event to the Action
$this->dispatch(
TheliaEvents::IMAGE_DELETE,
$imageDeleteEvent
);
$message = $this->getTranslator()
->trans(
'Images deleted successfully',
array(),
'image'
);
return new Response($message);
}
/**
* Log error message
*
* @param string $parentType Parent type
* @param string $action Creation|Update|Delete
* @param string $message Message to log
* @param \Exception $e Exception to log
*
* @return $this
*/
protected function logError($parentType, $action, $message, $e)
{
Tlog::getInstance()->error(
sprintf(
'Error during ' . $parentType . ' ' . $action . ' process : %s. Exception was %s',
$message,
$e->getMessage()
)
);
return $this;
}
/**
* Check if parent type is valid or not
*
* @param string $parentType Parent type
*
* @return bool
*/
public function isParentTypeValid($parentType)
{
return (in_array($parentType, ImagesCreateOrUpdateEvent::getAvailableType()));
}
/**
* Create Event instance
*
* @param string $parentType Parent Type owning images being saved
* @param CategoryImage|ProductImage|ContentImage|FolderImage $model Image model
* @param array $data Post data
*
* @return ImageCreateOrUpdateEvent
*/
private function createEventInstance($parentType, $model, $data)
{
$imageCreateEvent = new ImageCreateOrUpdateEvent($parentType, null);
if (isset($data['title'])) {
$model->setTitle($data['title']);
}
if (isset($data['chapo'])) {
$model->setChapo($data['chapo']);
}
if (isset($data['description'])) {
$model->setDescription($data['description']);
}
if (isset($data['file'])) {
$model->setFile($data['file']);
}
if (isset($data['postscriptum'])) {
$model->setPostscriptum($data['postscriptum']);
}
$imageCreateEvent->setModelImage($model);
return $imageCreateEvent;
}
}

View File

@@ -22,25 +22,307 @@
/*************************************************************************************/
namespace Thelia\Controller\Admin;
use Thelia\Core\Event\FolderCreateEvent;
use Thelia\Core\Event\FolderDeleteEvent;
use Thelia\Core\Event\FolderToggleVisibilityEvent;
use Thelia\Core\Event\FolderUpdateEvent;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Core\Event\UpdatePositionEvent;
use Thelia\Form\FolderCreationForm;
use Thelia\Form\FolderModificationForm;
use Thelia\Model\FolderQuery;
/**
* Class FolderController
* @package Thelia\Controller\Admin
* @author Manuel Raynaud <mraynaud@openstudio.fr>
*/
class FolderController extends BaseAdminController
class FolderController extends AbstractCrudController
{
public function indexAction()
public function __construct()
{
if (null !== $response = $this->checkAuth("admin.folder.view")) return $response;
return $this->render("folders", array("display_folder" => 20));
parent::__construct(
'folder',
'manual',
'folder_order',
'admin.folder.default',
'admin.folder.create',
'admin.folder.update',
'admin.folder.delete',
TheliaEvents::FOLDER_CREATE,
TheliaEvents::FOLDER_UPDATE,
TheliaEvents::FOLDER_DELETE,
TheliaEvents::FOLDER_TOGGLE_VISIBILITY,
TheliaEvents::FOLDER_UPDATE_POSITION
);
}
public function updateAction($folder_id)
/**
* Return the creation form for this object
*/
protected function getCreationForm()
{
return new FolderCreationForm($this->getRequest());
}
/**
* Return the update form for this object
*/
protected function getUpdateForm()
{
return new FolderModificationForm($this->getRequest());
}
/**
* Hydrate the update form for this object, before passing it to the update template
*
* @param \Thelia\Model\Folder $object
*/
protected function hydrateObjectForm($object) {
// Prepare the data that will hydrate the form
$data = array(
'id' => $object->getId(),
'locale' => $object->getLocale(),
'title' => $object->getTitle(),
'chapo' => $object->getChapo(),
'description' => $object->getDescription(),
'postscriptum' => $object->getPostscriptum(),
'visible' => $object->getVisible(),
'url' => $object->getRewrittenUrl($this->getCurrentEditionLocale()),
'parent' => $object->getParent()
);
// Setup the object form
return new FolderModificationForm($this->getRequest(), "form", $data);
}
/**
* Creates the creation event with the provided form data
*
* @param unknown $formData
*/
protected function getCreationEvent($formData)
{
$creationEvent = new FolderCreateEvent();
$creationEvent
->setLocale($formData['locale'])
->setTitle($formData['title'])
->setVisible($formData['visible'])
->setParent($formData['parent']);
return $creationEvent;
}
/**
* Creates the update event with the provided form data
*
* @param unknown $formData
*/
protected function getUpdateEvent($formData)
{
$updateEvent = new FolderUpdateEvent($formData['id']);
$updateEvent
->setLocale($formData['locale'])
->setTitle($formData['title'])
->setChapo($formData['chapo'])
->setDescription($formData['description'])
->setPostscriptum($formData['postscriptum'])
->setVisible($formData['visible'])
->setUrl($formData['url'])
->setParent($formData['parent'])
;
return $updateEvent;
}
/**
* Creates the delete event with the provided form data
*/
protected function getDeleteEvent()
{
return new FolderDeleteEvent($this->getRequest()->get('folder_id'), 0);
}
/**
* @return FolderToggleVisibilityEvent|void
*/
protected function createToggleVisibilityEvent()
{
return new FolderToggleVisibilityEvent($this->getExistingObject());
}
/**
* @param $positionChangeMode
* @param $positionValue
* @return UpdatePositionEvent|void
*/
protected function createUpdatePositionEvent($positionChangeMode, $positionValue) {
return new UpdatePositionEvent(
$this->getRequest()->get('folder_id', null),
$positionChangeMode,
$positionValue
);
}
/**
* Return true if the event contains the object, e.g. the action has updated the object in the event.
*
* @param \Thelia\Core\Event\FolderEvent $event
*/
protected function eventContainsObject($event)
{
return $event->hasFolder();
}
/**
* Get the created object from an event.
*
* @param $event \Thelia\Core\Event\FolderEvent $event
*
* @return null|\Thelia\Model\Folder
*/
protected function getObjectFromEvent($event)
{
return $event->hasFolder() ? $event->getFolder() : null;
}
/**
* Load an existing object from the database
*/
protected function getExistingObject() {
return FolderQuery::create()
->joinWithI18n($this->getCurrentEditionLocale())
->findOneById($this->getRequest()->get('folder_id', 0));
}
/**
* Returns the object label form the object event (name, title, etc.)
*
* @param unknown $object
*/
protected function getObjectLabel($object) {
return $object->getTitle();
}
/**
* Returns the object ID from the object
*
* @param unknown $object
*/
protected function getObjectId($object)
{
return $object->getId();
}
/**
* Render the main list template
*
* @param unknown $currentOrder, if any, null otherwise.
*/
protected function renderListTemplate($currentOrder) {
// Get content order
$content_order = $this->getListOrderFromSession('content', 'content_order', 'manual');
return $this->render('folders',
array(
'folder_order' => $currentOrder,
'content_order' => $content_order,
'parent' => $this->getRequest()->get('parent', 0)
));
}
/**
* Render the edition template
*/
protected function renderEditionTemplate() {
return $this->render('folder-edit', $this->getEditionArguments());
}
protected function getEditionArguments()
{
return array(
'folder_id' => $this->getRequest()->get('folder_id', 0),
'current_tab' => $this->getRequest()->get('current_tab', 'general')
);
}
/**
* @param \Thelia\Core\Event\FolderUpdateEvent $updateEvent
* @return Response|void
*/
protected function performAdditionalUpdateAction($updateEvent)
{
if ($this->getRequest()->get('save_mode') != 'stay') {
// Redirect to parent category list
$this->redirectToRoute(
'admin.folders.default',
array('parent' => $updateEvent->getFolder()->getParent())
);
}
}
/**
* Put in this method post object delete processing if required.
*
* @param \Thelia\Core\Event\FolderDeleteEvent $deleteEvent the delete event
* @return Response a response, or null to continue normal processing
*/
protected function performAdditionalDeleteAction($deleteEvent)
{
// Redirect to parent category list
$this->redirectToRoute(
'admin.folders.default',
array('parent' => $deleteEvent->getFolder()->getParent())
);
}
/**
* @param $event \Thelia\Core\Event\UpdatePositionEvent
* @return null|Response
*/
protected function performAdditionalUpdatePositionAction($event)
{
return $this->render("folder-edit", array(
"folder_id" => $folder_id
));
$folder = FolderQuery::create()->findPk($event->getObjectId());
if ($folder != null) {
// Redirect to parent category list
$this->redirectToRoute(
'admin.folders.default',
array('parent' => $folder->getParent())
);
}
return null;
}
/**
* Redirect to the edition template
*/
protected function redirectToEditionTemplate()
{
$this->redirect($this->getRoute('admin.folders.update', $this->getEditionArguments()));
}
/**
* Redirect to the list template
*/
protected function redirectToListTemplate()
{
$this->redirectToRoute(
'admin.folders.default',
array('parent' => $this->getRequest()->get('parent', 0))
);
}
}

View File

@@ -48,11 +48,14 @@ use Thelia\Model\FeatureQuery;
use Thelia\Core\Event\FeatureProductDeleteEvent;
use Thelia\Model\FeatureTemplateQuery;
use Thelia\Core\Event\ProductSetTemplateEvent;
use Thelia\Model\Base\ProductSaleElementsQuery;
use Thelia\Core\Event\ProductAddCategoryEvent;
use Thelia\Core\Event\ProductDeleteCategoryEvent;
use Thelia\Model\AttributeQuery;
use Thelia\Model\AttributeAvQuery;
use Thelia\Model\ProductSaleElementsQuery;
use Thelia\Model\AttributeCombination;
use Thelia\Model\AttributeAv;
use Thelia\Core\Event\ProductCreateCombinationEvent;
/**
* Manages products
@@ -699,6 +702,7 @@ class ProductController extends AbstractCrudController
}
public function addAttributeValueToCombinationAction($productId, $attributeAvId, $combination) {
$result = array();
// Get attribute for this product
@@ -708,6 +712,8 @@ class ProductController extends AbstractCrudController
$addIt = true;
$attribute = $attributeAv->getAttribute();
// Check if this attribute is not already present
$combinationArray = explode(',', $combination);
@@ -717,9 +723,7 @@ class ProductController extends AbstractCrudController
if ($attrAv !== null) {
if ($attrAv->getAttributeId() == $attributeAv->getAttributeId()) {
$attribute = AttributeQuery::create()->joinWithI18n($this->getCurrentEditionLocale())->findPk($attributeAv->getAttributeId());
if ($attrAv->getAttributeId() == $attribute->getId()) {
$result['error'] = $this->getTranslator()->trans(
'A value for attribute "%name" is already present in the combination',
@@ -729,13 +733,39 @@ class ProductController extends AbstractCrudController
$addIt = false;
}
$result[] = array('id' => $attrAv->getId(), 'title' => $attrAv->getTitle());
$result[] = array('id' => $attrAv->getId(), 'title' => $attrAv->getAttribute()->getTitle() . " : " . $attrAv->getTitle());
}
}
if ($addIt) $result[] = array('id' => $attributeAv->getId(), 'title' => $attributeAv->getTitle());
if ($addIt) $result[] = array('id' => $attributeAv->getId(), 'title' => $attribute->getTitle() . " : " . $attributeAv->getTitle());
}
return $this->jsonResponse(json_encode($result));
}
/**
* A a new combination to a product
*/
public function addCombinationAction() {
// Check current user authorization
if (null !== $response = $this->checkAuth("admin.products.update")) return $response;
$event = new ProductCreateCombinationEvent(
$this->getExistingObject(),
$this->getRequest()->get('use_default_princing', 0),
$this->getRequest()->get('combination_attributes', array())
);
try {
$this->dispatch(TheliaEvents::PRODUCT_ADD_COMBINATION, $event);
}
catch (\Exception $ex) {
// Any error
return $this->errorPage($ex);
}
echo "done!";
exit;
$this->redirectToEditionTemplate();
}
}

View File

@@ -24,6 +24,8 @@ namespace Thelia\Controller\Front;
use Symfony\Component\Routing\Router;
use Thelia\Controller\BaseController;
use Thelia\Model\AddressQuery;
use Thelia\Model\ModuleQuery;
use Thelia\Tools\URL;
class BaseFrontController extends BaseController
@@ -69,7 +71,7 @@ class BaseFrontController extends BaseController
protected function checkValidDelivery()
{
$order = $this->getSession()->getOrder();
if(null === $order || null === $order->chosenDeliveryAddress || null === $order->getDeliveryModuleId()) {
if(null === $order || null === $order->chosenDeliveryAddress || null === $order->getDeliveryModuleId() || null === AddressQuery::create()->findPk($order->chosenDeliveryAddress) || null === ModuleQuery::create()->findPk($order->getDeliveryModuleId())) {
$this->redirectToRoute("order.delivery");
}
}
@@ -77,7 +79,7 @@ class BaseFrontController extends BaseController
protected function checkValidInvoice()
{
$order = $this->getSession()->getOrder();
if(null === $order || null === $order->chosenInvoiceAddress || null === $order->getPaymentModuleId()) {
if(null === $order || null === $order->chosenInvoiceAddress || null === $order->getPaymentModuleId() || null === AddressQuery::create()->findPk($order->chosenInvoiceAddress) || null === ModuleQuery::create()->findPk($order->getPaymentModuleId())) {
$this->redirectToRoute("order.invoice");
}
}

View File

@@ -23,6 +23,7 @@
namespace Thelia\Controller\Front;
use Propel\Runtime\Exception\PropelException;
use Thelia\Exception\TheliaProcessException;
use Thelia\Form\Exception\FormValidationException;
use Thelia\Core\Event\OrderEvent;
use Thelia\Core\Event\TheliaEvents;
@@ -32,9 +33,11 @@ use Thelia\Form\OrderPayment;
use Thelia\Log\Tlog;
use Thelia\Model\AddressQuery;
use Thelia\Model\AreaDeliveryModuleQuery;
use Thelia\Model\Base\OrderQuery;
use Thelia\Model\CountryQuery;
use Thelia\Model\ModuleQuery;
use Thelia\Model\Order;
use Thelia\Tools\URL;
/**
* Class OrderController
@@ -78,11 +81,8 @@ class OrderController extends BaseFrontController
throw new \Exception("Delivery module cannot be use with selected delivery address");
}
/* try to get postage amount */
/* get postage amount */
$moduleReflection = new \ReflectionClass($deliveryModule->getFullNamespace());
if ($moduleReflection->isSubclassOf("Thelia\Module\DeliveryModuleInterface") === false) {
throw new \RuntimeException(sprintf("delivery module %s is not a Thelia\Module\DeliveryModuleInterface", $deliveryModule->getCode()));
}
$moduleInstance = $moduleReflection->newInstance();
$postage = $moduleInstance->getPostage($deliveryAddress->getCountry());
@@ -190,6 +190,36 @@ class OrderController extends BaseFrontController
$orderEvent = $this->getOrderEvent();
$this->getDispatcher()->dispatch(TheliaEvents::ORDER_PAY, $orderEvent);
$placedOrder = $orderEvent->getPlacedOrder();
if(null !== $placedOrder && null !== $placedOrder->getId()) {
/* order has been placed */
$this->redirect(URL::getInstance()->absoluteUrl($this->getRoute('order.placed', array('order_id' => $orderEvent->getPlacedOrder()->getId()))));
} else {
/* order has not been placed */
$this->redirectToRoute("cart.view");
}
}
public function orderPlaced($order_id)
{
/* check if the placed order matched the customer */
$placedOrder = OrderQuery::create()->findPk(
$this->getRequest()->attributes->get('order_id')
);
if(null === $placedOrder) {
throw new TheliaProcessException("No placed order", TheliaProcessException::NO_PLACED_ORDER, $placedOrder);
}
$customer = $this->getSecurityContext()->getCustomerUser();
if(null === $customer || $placedOrder->getCustomerId() !== $customer->getId()) {
throw new TheliaProcessException("Received placed order id does not belong to the current customer", TheliaProcessException::PLACED_ORDER_ID_BAD_CURRENT_CUSTOMER, $placedOrder);
}
$this->getParserContext()->set("placed_order_id", $placedOrder->getId());
}
protected function getOrderEvent()

View File

@@ -0,0 +1,124 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Core\Event\Content;
/**
* Class ContentCreateEvent
* @package Thelia\Core\Event\Content
* @author manuel raynaud <mraynaud@openstudio.fr>
*/
class ContentCreateEvent extends ContentEvent
{
protected $title;
protected $default_folder;
protected $locale;
protected $visible;
/**
* @param mixed $locale
*
* @return $this
*/
public function setLocale($locale)
{
$this->locale = $locale;
return $this;
}
/**
* @return mixed
*/
public function getLocale()
{
return $this->locale;
}
/**
* @param mixed $default_folder
*
* @return $this
*/
public function setDefaultFolder($default_folder)
{
$this->default_folder = $default_folder;
return $this;
}
/**
* @return mixed
*/
public function getDefaultFolder()
{
return $this->default_folder;
}
/**
* @param mixed $visible
*
* @return $this
*/
public function setVisible($visible)
{
$this->visible = $visible;
return $this;
}
/**
* @return mixed
*/
public function getVisible()
{
return $this->visible;
}
/**
* @param mixed $title
*
* @return $this
*/
public function setTitle($title)
{
$this->title = $title;
return $this;
}
/**
* @return mixed
*/
public function getTitle()
{
return $this->title;
}
}

View File

@@ -0,0 +1,73 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Core\Event\Content;
use Thelia\Core\Event\ActionEvent;
use Thelia\Model\Content;
/**
* Class ContentEvent
* @package Thelia\Core\Event\Content
* @author manuel raynaud <mraynaud@openstudio.fr>
*/
class ContentEvent extends ActionEvent
{
/**
* @var \Thelia\Model\Content
*/
protected $content;
function __construct(Content $content = null)
{
$this->content = $content;
}
/**
* @param \Thelia\Model\Content $content
*/
public function setContent(Content $content)
{
$this->content = $content;
return $this;
}
/**
* @return \Thelia\Model\Content
*/
public function getContent()
{
return $this->content;
}
/**
* check if content exists
*
* @return bool
*/
public function hasContent()
{
return null !== $this->content;
}
}

View File

@@ -0,0 +1,150 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Core\Event\Content;
/**
* Class ContentUpdateEvent
* @package Thelia\Core\Event\Content
* @author manuel raynaud <mraynaud@openstudio.fr>
*/
class ContentUpdateEvent extends ContentCreateEvent
{
protected $content_id;
protected $chapo;
protected $description;
protected $postscriptum;
protected $url;
function __construct($content_id)
{
$this->content_id = $content_id;
}
/**
* @param mixed $chapo
*
* @return $this
*/
public function setChapo($chapo)
{
$this->chapo = $chapo;
return $this;
}
/**
* @return mixed
*/
public function getChapo()
{
return $this->chapo;
}
/**
* @param mixed $content_id
*
* @return $this
*/
public function setContentId($content_id)
{
$this->content_id = $content_id;
return $this;
}
/**
* @return mixed
*/
public function getContentId()
{
return $this->content_id;
}
/**
* @param mixed $description
*
* @return $this
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* @return mixed
*/
public function getDescription()
{
return $this->description;
}
/**
* @param mixed $postscriptum
*
* @return $this
*/
public function setPostscriptum($postscriptum)
{
$this->postscriptum = $postscriptum;
return $this;
}
/**
* @return mixed
*/
public function getPostscriptum()
{
return $this->postscriptum;
}
/**
* @param mixed $url
*
* @return $this
*/
public function setUrl($url)
{
$this->url = $url;
return $this;
}
/**
* @return mixed
*/
public function getUrl()
{
return $this->url;
}
}

View File

@@ -0,0 +1,120 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Core\Event;
/**
* Class FolderCreateEvent
* @package Thelia\Core\Event
* @author Manuel Raynaud <mraynaud@openstudio.fr>
*/
class FolderCreateEvent extends FolderEvent {
protected $title;
protected $parent;
protected $locale;
protected $visible;
/**
* @param mixed $locale
*
* @return $this
*/
public function setLocale($locale)
{
$this->locale = $locale;
return $this;
}
/**
* @return mixed
*/
public function getLocale()
{
return $this->locale;
}
/**
* @param mixed $parent
*
*
* @return $this
*/
public function setParent($parent)
{
$this->parent = $parent;
return $this;
}
/**
* @return mixed
*/
public function getParent()
{
return $this->parent;
}
/**
* @param mixed $title
*
* @return $this
*/
public function setTitle($title)
{
$this->title = $title;
return $this;
}
/**
* @return mixed
*/
public function getTitle()
{
return $this->title;
}
/**
* @param mixed $visible
*
* @return $this
*/
public function setVisible($visible)
{
$this->visible = $visible;
return $this;
}
/**
* @return mixed
*/
public function getVisible()
{
return $this->visible;
}
}

View File

@@ -0,0 +1,64 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Core\Event;
/**
* Class FolderDeleteEvent
* @package Thelia\Core\Event
* @author Manuel Raynaud <mraynaud@openstudio.fr>
*/
class FolderDeleteEvent extends FolderEvent{
/**
* @var int folder id
*/
protected $folder_id;
/**
* @param int $folder_id
*/
function __construct($folder_id)
{
$this->folder_id = $folder_id;
}
/**
* @param int $folder_id
*/
public function setFolderId($folder_id)
{
$this->folder_id = $folder_id;
}
/**
* @return int
*/
public function getFolderId()
{
return $this->folder_id;
}
}

View File

@@ -0,0 +1,73 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Core\Event;
use Thelia\Model\Folder;
/**
* Class FolderEvent
* @package Thelia\Core\Event
* @author Manuel Raynaud <mraynaud@openstudio.fr>
*/
class FolderEvent extends ActionEvent {
/**
* @var \Thelia\Model\Folder
*/
protected $folder;
function __construct(Folder $folder = null)
{
$this->folder = $folder;
}
/**
* @param \Thelia\Model\Folder $folder
*/
public function setFolder(Folder $folder)
{
$this->folder = $folder;
return $this;
}
/**
* @return \Thelia\Model\Folder
*/
public function getFolder()
{
return $this->folder;
}
/**
* test if a folder object exists
*
* @return bool
*/
public function hasFolder()
{
return null !== $this->folder;
}
}

View File

@@ -0,0 +1,34 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Core\Event;
/**
* Class FolderToggleVisibilityEvent
* @package Thelia\Core\Event
* @author Manuel Raynaud <mraynaud@openstudio.fr>
*/
class FolderToggleVisibilityEvent extends FolderEvent {
}

View File

@@ -0,0 +1,136 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Core\Event;
/**
* Class FolderUpdateEvent
* @package Thelia\Core\Event
* @author Manuel Raynaud <mraynaud@openstudio.fr>
*/
class FolderUpdateEvent extends FolderCreateEvent {
protected $folder_id;
protected $chapo;
protected $description;
protected $postscriptum;
protected $url;
function __construct($folder_id)
{
$this->folder_id = $folder_id;
}
/**
* @param mixed $chapo
*/
public function setChapo($chapo)
{
$this->chapo = $chapo;
return $this;
}
/**
* @return mixed
*/
public function getChapo()
{
return $this->chapo;
}
/**
* @param mixed $description
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* @return mixed
*/
public function getDescription()
{
return $this->description;
}
/**
* @param mixed $folder_id
*/
public function setFolderId($folder_id)
{
$this->folder_id = $folder_id;
return $this;
}
/**
* @return mixed
*/
public function getFolderId()
{
return $this->folder_id;
}
/**
* @param mixed $postscriptum
*/
public function setPostscriptum($postscriptum)
{
$this->postscriptum = $postscriptum;
return $this;
}
/**
* @return mixed
*/
public function getPostscriptum()
{
return $this->postscriptum;
}
/**
* @param mixed $url
*/
public function setUrl($url)
{
$this->url = $url;
return $this;
}
/**
* @return mixed
*/
public function getUrl()
{
return $this->url;
}
}

View File

@@ -0,0 +1,213 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Core\Event;
use Symfony\Component\HttpFoundation\File\UploadedFile;
/**
* Created by JetBrains PhpStorm.
* Date: 9/18/13
* Time: 3:56 PM
*
* Occurring when an Image is saved
*
* @package Image
* @author Guillaume MOREL <gmorel@openstudio.fr>
*
*/
class ImageCreateOrUpdateEvent extends ActionEvent
{
/** @var \Thelia\Model\CategoryImage|\Thelia\Model\ProductImage|\Thelia\Model\ContentImage|\Thelia\Model\FolderImage model to save */
protected $modelImage = array();
/** @var \Thelia\Model\CategoryImage|\Thelia\Model\ProductImage|\Thelia\Model\ContentImage|\Thelia\Model\FolderImage model to save */
protected $oldModelImage = array();
/** @var UploadedFile Image file to save */
protected $uploadedFile = null;
/** @var int Image parent id */
protected $parentId = null;
/** @var string Image type */
protected $imageType = null;
/** @var string Parent name */
protected $parentName = null;
/**
* Constructor
*
* @param string $imageType Image type
* ex : FileManager::TYPE_CATEGORY
* @param int $parentId Image parent id
*/
public function __construct($imageType, $parentId)
{
$this->imageType = $imageType;
$this->parentId = $parentId;
}
/**
* Set Image to save
*
* @param $image \Thelia\Model\CategoryImage|\Thelia\Model\ProductImage|\Thelia\Model\ContentImage|\Thelia\Model\FolderImage
*
* @return $this
*/
public function setModelImage($image)
{
$this->modelImage = $image;
return $this;
}
/**
* Get Image being saved
*
* @return \Thelia\Model\CategoryImage|\Thelia\Model\ProductImage|\Thelia\Model\ContentImage|\Thelia\Model\FolderImage
*/
public function getModelImage()
{
return $this->modelImage;
}
/**
* Set picture type
*
* @param string $imageType Image type
*
* @return $this
*/
public function setImageType($imageType)
{
$this->imageType = $imageType;
return $this;
}
/**
* Get picture type
*
* @return string
*/
public function getImageType()
{
return $this->imageType;
}
/**
* Set Image parent id
*
* @param int $parentId Image parent id
*
* @return $this
*/
public function setParentId($parentId)
{
$this->parentId = $parentId;
return $this;
}
/**
* Get Image parent id
*
* @return int
*/
public function getParentId()
{
return $this->parentId;
}
/**
* Set uploaded file
*
* @param UploadedFile $uploadedFile File being uploaded
*
* @return $this
*/
public function setUploadedFile($uploadedFile)
{
$this->uploadedFile = $uploadedFile;
return $this;
}
/**
* Get uploaded file
*
* @return UploadedFile
*/
public function getUploadedFile()
{
return $this->uploadedFile;
}
/**
* Set parent name
*
* @param string $parentName Parent name
*
* @return $this
*/
public function setParentName($parentName)
{
$this->parentName = $parentName;
return $this;
}
/**
* Get parent name
*
* @return string
*/
public function getParentName()
{
return $this->parentName;
}
/**
* Set old model value
*
* @param \Thelia\Model\CategoryImage|\Thelia\Model\ContentImage|\Thelia\Model\FolderImage|\Thelia\Model\ProductImage $oldModelImage
*/
public function setOldModelImage($oldModelImage)
{
$this->oldModelImage = $oldModelImage;
}
/**
* Get old model value
*
* @return \Thelia\Model\CategoryImage|\Thelia\Model\ContentImage|\Thelia\Model\FolderImage|\Thelia\Model\ProductImage
*/
public function getOldModelImage()
{
return $this->oldModelImage;
}
}

View File

@@ -0,0 +1,112 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Core\Event;
use Thelia\Model\CategoryImage;
use Thelia\Model\ContentImage;
use Thelia\Model\FolderImage;
use Thelia\Model\ProductImage;
/**
* Created by JetBrains PhpStorm.
* Date: 9/18/13
* Time: 3:56 PM
*
* Occurring when a Image is about to be deleted
*
* @package Image
* @author Guillaume MOREL <gmorel@openstudio.fr>
*
*/
class ImageDeleteEvent extends ActionEvent
{
/** @var string Image type */
protected $imageType = null;
/** @var CategoryImage|ProductImage|ContentImage|FolderImage Image about to be deleted */
protected $imageToDelete = null;
/**
* Constructor
*
* @param CategoryImage|ProductImage|ContentImage|FolderImage $imageToDelete Image about to be deleted
* @param string $imageType Image type
* ex : FileManager::TYPE_CATEGORY
*/
public function __construct($imageToDelete, $imageType)
{
$this->imageToDelete = $imageToDelete;
$this->imageType = $imageType;
}
/**
* Set picture type
*
* @param string $imageType Image type
*
* @return $this
*/
public function setImageType($imageType)
{
$this->imageType = $imageType;
return $this;
}
/**
* Get picture type
*
* @return string
*/
public function getImageType()
{
return $this->imageType;
}
/**
* Set Image about to be deleted
*
* @param CategoryImage|ProductImage|ContentImage|FolderImage $imageToDelete Image about to be deleted
*
* @return $this
*/
public function setImageToDelete($imageToDelete)
{
$this->imageToDelete = $imageToDelete;
return $this;
}
/**
* Get Image about to be deleted
*
* @return CategoryImage|ProductImage|ContentImage|FolderImage
*/
public function getImageToDelete()
{
return $this->imageToDelete;
}
}

View File

@@ -0,0 +1,184 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Core\Event;
/**
* Created by JetBrains PhpStorm.
* Date: 9/18/13
* Time: 3:56 PM
*
* Occurring when a Image list is saved
*
* @package Image
* @author Guillaume MOREL <gmorel@openstudio.fr>
*
*/
class ImagesCreateOrUpdateEvent extends ActionEvent
{
CONST TYPE_PRODUCT = 'product';
CONST TYPE_CATEGORY = 'category';
CONST TYPE_CONTENT = 'content';
CONST TYPE_FOLDER = 'folder';
/** @var array Images model to save */
protected $modelImages = array();
/** @var array Images file to save */
protected $uploadedFiles = array();
/** @var int Image parent id */
protected $parentId = null;
/** @var string Image type */
protected $imageType = null;
/** @var array Available image parent type */
protected static $availableType = array(
self::TYPE_PRODUCT,
self::TYPE_CATEGORY,
self::TYPE_CONTENT,
self::TYPE_FOLDER,
);
/**
* Constructor
*
* @param string $pictureType Picture type
* ex : ImageCreateOrUpdateEvent::TYPE_CATEGORY
* @param int $parentId Image parent id
*/
public function __construct($pictureType, $parentId)
{
$this->imageType = $pictureType;
$this->parentId = $parentId;
}
/**
* Set Images to save
*
* @param array $images Thelia\Model\CategoryImage Array
*
* @return $this
*/
public function setModelImages($images)
{
$this->modelImages = $images;
return $this;
}
/**
* Get Images being saved
*
* @return array Array of Thelia\Model\CategoryImage
*/
public function getModelImages()
{
return $this->modelImages;
}
/**
* Set Images to save
*
* @param array $images Thelia\Model\CategoryImage Array
*
* @return $this
*/
public function setUploadedFiles($images)
{
$this->uploadedFiles = $images;
return $this;
}
/**
* Get Images being saved
*
* @return array Array of Thelia\Model\CategoryImage
*/
public function getUploadedFiles()
{
return $this->uploadedFiles;
}
/**
* Set picture type
*
* @param string $pictureType Picture type
*
* @return $this
*/
public function setImageType($pictureType)
{
$this->imageType = $pictureType;
return $this;
}
/**
* Get picture type
*
* @return string
*/
public function getImageType()
{
return $this->imageType;
}
/**
* Get all image parent type available
*
* @return array
*/
public static function getAvailableType()
{
return self::$availableType;
}
/**
* Set Image parent id
*
* @param int $parentId Image parent id
*
* @return $this
*/
public function setParentId($parentId)
{
$this->parentId = $parentId;
return $this;
}
/**
* Get Image parent id
*
* @return int
*/
public function getParentId()
{
return $this->parentId;
}
}

View File

@@ -28,6 +28,7 @@ use Thelia\Model\Order;
class OrderEvent extends ActionEvent
{
protected $order = null;
protected $placedOrder = null;
protected $invoiceAddress = null;
protected $deliveryAddress = null;
protected $deliveryModule = null;
@@ -51,6 +52,14 @@ class OrderEvent extends ActionEvent
$this->order = $order;
}
/**
* @param Order $order
*/
public function setPlacedOrder(Order $order)
{
$this->placedOrder = $order;
}
/**
* @param $address
*/
@@ -107,6 +116,14 @@ class OrderEvent extends ActionEvent
return $this->order;
}
/**
* @return null|Order
*/
public function getPlacedOrder()
{
return $this->placedOrder;
}
/**
* @return null|int
*/

View File

@@ -0,0 +1,63 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Core\Event;
use Thelia\Model\Product;
class ProductCreateCombinationEvent extends ProductEvent
{
protected $use_default_pricing;
protected $attribute_av_list;
public function __construct(Product $product, $use_default_pricing, $attribute_av_list)
{
parent::__construct($product);
$this->use_default_pricing = $use_default_pricing;
$this->attribute_av_list = $attribute_av_list;
}
public function getUseDefaultPricing()
{
return $this->use_default_pricing;
}
public function setUseDefaultPricing($use_default_pricing)
{
$this->use_default_pricing = $use_default_pricing;
return $this;
}
public function getAttributeAvList()
{
return $this->attribute_av_list;
}
public function setAttributeAvList($attribute_av_list)
{
$this->attribute_av_list = $attribute_av_list;
return $this;
}
}

View File

@@ -165,6 +165,46 @@ final class TheliaEvents
const BEFORE_UPDATECATEGORY = "action.before_updateCategory";
const AFTER_UPDATECATEGORY = "action.after_updateCategory";
// -- folder management -----------------------------------------------
const FOLDER_CREATE = "action.createFolder";
const FOLDER_UPDATE = "action.updateFolder";
const FOLDER_DELETE = "action.deleteFolder";
const FOLDER_TOGGLE_VISIBILITY = "action.toggleFolderVisibility";
const FOLDER_UPDATE_POSITION = "action.updateFolderPosition";
// const FOLDER_ADD_CONTENT = "action.categoryAddContent";
// const FOLDER_REMOVE_CONTENT = "action.categoryRemoveContent";
const BEFORE_CREATEFOLDER = "action.before_createFolder";
const AFTER_CREATEFOLDER = "action.after_createFolder";
const BEFORE_DELETEFOLDER = "action.before_deleteFolder";
const AFTER_DELETEFOLDER = "action.after_deleteFolder";
const BEFORE_UPDATEFOLDER = "action.before_updateFolder";
const AFTER_UPDATEFOLDER = "action.after_updateFolder";
// -- content management -----------------------------------------------
const CONTENT_CREATE = "action.createContent";
const CONTENT_UPDATE = "action.updateContent";
const CONTENT_DELETE = "action.deleteContent";
const CONTENT_TOGGLE_VISIBILITY = "action.toggleContentVisibility";
const CONTENT_UPDATE_POSITION = "action.updateContentPosition";
// const FOLDER_ADD_CONTENT = "action.categoryAddContent";
// const FOLDER_REMOVE_CONTENT = "action.categoryRemoveContent";
const BEFORE_CREATECONTENT = "action.before_createContent";
const AFTER_CREATECONTENT = "action.after_createContent";
const BEFORE_DELETECONTENT = "action.before_deleteContent";
const AFTER_DELETECONTENT = "action.after_deleteContent";
const BEFORE_UPDATECONTENT = "action.before_updateContent";
const AFTER_UPDATECONTENT = "action.after_updateContent";
// -- Categories Associated Content ----------------------------------------
const BEFORE_CREATECATEGORY_ASSOCIATED_CONTENT = "action.before_createCategoryAssociatedContent";
@@ -188,7 +228,10 @@ final class TheliaEvents
const PRODUCT_REMOVE_CONTENT = "action.productRemoveContent";
const PRODUCT_UPDATE_CONTENT_POSITION = "action.updateProductContentPosition";
const PRODUCT_SET_TEMPLATE = "action.productSetTemplate";
const PRODUCT_ADD_COMBINATION = "action.productAddCombination";
const PRODUCT_DELETE_COMBINATION = "action.productDeleteCombination";
const PRODUCT_SET_TEMPLATE = "action.productSetTemplate";
const PRODUCT_ADD_ACCESSORY = "action.productAddProductAccessory";
const PRODUCT_REMOVE_ACCESSORY = "action.productRemoveProductAccessory";
@@ -277,7 +320,12 @@ final class TheliaEvents
const ORDER_SET_INVOICE_ADDRESS = "action.order.setInvoiceAddress";
const ORDER_SET_PAYMENT_MODULE = "action.order.setPaymentModule";
const ORDER_PAY = "action.order.pay";
const ORDER_SET_REFERENCE = "action.order.setReference";
const ORDER_BEFORE_CREATE = "action.order.beforeCreate";
const ORDER_AFTER_CREATE = "action.order.afterCreate";
const ORDER_BEFORE_PAYMENT = "action.order.beforePayment";
const ORDER_PRODUCT_BEFORE_CREATE = "action.orderProduct.beforeCreate";
const ORDER_PRODUCT_AFTER_CREATE = "action.orderProduct.afterCreate";
/**
* Sent on image processing
@@ -294,6 +342,21 @@ final class TheliaEvents
*/
const IMAGE_CLEAR_CACHE = "action.clearImageCache";
/**
* Save given images
*/
const IMAGE_SAVE = "action.saveImages";
/**
* Save given images
*/
const IMAGE_UPDATE = "action.updateImages";
/**
* Delete given image
*/
const IMAGE_DELETE = "action.deleteImage";
/**
* Sent when creating a Coupon
*/

View File

@@ -79,10 +79,20 @@ class ViewListener implements EventSubscriberInterface
$content = $parser->getContent();
if ($content instanceof Response) {
$event->setResponse($content);
$response = $content;$event->setResponse($content);
} else {
$event->setResponse(new Response($content, $parser->getStatus() ?: 200));
$response = new Response($content, $parser->getStatus() ?: 200);
}
$response->setCache(array(
'last_modified' => new \DateTime(),
'max_age' => 600,
's_maxage' => 600,
'private' => false,
'public' => true,
));
$event->setResponse($response);
} catch (ResourceNotFoundException $e) {
$event->setResponse(new Response($e->getMessage(), 404));
} catch (AuthenticationException $ex) {

View File

@@ -81,6 +81,8 @@ class Cart extends BaseLoop
return $result;
}
$taxCountry = CountryQuery::create()->findPk(64); // @TODO : make it magic;
foreach ($cartItems as $cartItem) {
$product = $cartItem->getProduct();
$productSaleElement = $cartItem->getProductSaleElements();
@@ -97,12 +99,8 @@ class Cart extends BaseLoop
->set("STOCK", $productSaleElement->getQuantity())
->set("PRICE", $cartItem->getPrice())
->set("PROMO_PRICE", $cartItem->getPromoPrice())
->set("TAXED_PRICE", $cartItem->getTaxedPrice(
CountryQuery::create()->findOneById(64) // @TODO : make it magic
))
->set("PROMO_TAXED_PRICE", $cartItem->getTaxedPromoPrice(
CountryQuery::create()->findOneById(64) // @TODO : make it magic
))
->set("TAXED_PRICE", $cartItem->getTaxedPrice($taxCountry))
->set("PROMO_TAXED_PRICE", $cartItem->getTaxedPromoPrice($taxCountry))
->set("IS_PROMO", $cartItem->getPromo() === 1 ? 1 : 0);
$result->addRow($loopResultRow);
}

View File

@@ -234,6 +234,7 @@ class Content extends BaseI18nLoop
->set("DESCRIPTION", $content->getVirtualColumn('i18n_DESCRIPTION'))
->set("POSTSCRIPTUM", $content->getVirtualColumn('i18n_POSTSCRIPTUM'))
->set("POSITION", $content->getPosition())
->set("DEFAULT_FOLDER", $content->getDefaultFolderId())
->set("URL", $content->getUrl($locale))
;

View File

@@ -0,0 +1,137 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Core\Template\Loop;
use Propel\Runtime\ActiveQuery\Criteria;
use Thelia\Core\Template\Element\BaseI18nLoop;
use Thelia\Core\Template\Element\LoopResult;
use Thelia\Core\Template\Element\LoopResultRow;
use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
use Thelia\Core\Template\Loop\Argument\Argument;
use Thelia\Model\ModuleQuery;
use Thelia\Module\BaseModule;
use Thelia\Type;
/**
*
* Module loop
*
*
* Class Module
* @package Thelia\Core\Template\Loop
* @author Etienne Roudeix <eroudeix@openstudio.fr>
*/
class Module extends BaseI18nLoop
{
public $timestampable = true;
/**
* @return ArgumentCollection
*/
protected function getArgDefinitions()
{
return new ArgumentCollection(
Argument::createIntListTypeArgument('id'),
new Argument(
'module_type',
new Type\TypeCollection(
new Type\EnumListType(array(
BaseModule::CLASSIC_MODULE_TYPE,
BaseModule::DELIVERY_MODULE_TYPE,
BaseModule::PAYMENT_MODULE_TYPE,
))
)
),
Argument::createIntListTypeArgument('exclude'),
Argument::createBooleanOrBothTypeArgument('active', Type\BooleanOrBothType::ANY)
);
}
/**
* @param $pagination
*
* @return \Thelia\Core\Template\Element\LoopResult
*/
public function exec(&$pagination)
{
$search = ModuleQuery::create();
/* manage translations */
$locale = $this->configureI18nProcessing($search);
$id = $this->getId();
if (null !== $id) {
$search->filterById($id, Criteria::IN);
}
$moduleType = $this->getModule_type();
if (null !== $moduleType) {
$search->filterByType($moduleType, Criteria::IN);
}
$exclude = $this->getExclude();
if (!is_null($exclude)) {
$search->filterById($exclude, Criteria::NOT_IN);
}
$active = $this->getActive();
if($active !== Type\BooleanOrBothType::ANY) {
$search->filterByActivate($active ? 1 : 0, Criteria::EQUAL);
}
$search->orderByPosition();
/* perform search */
$modules = $this->search($search, $pagination);
$loopResult = new LoopResult($modules);
foreach ($modules as $module) {
$loopResultRow = new LoopResultRow($loopResult, $module, $this->versionable, $this->timestampable, $this->countable);
$loopResultRow->set("ID", $module->getId())
->set("IS_TRANSLATED",$module->getVirtualColumn('IS_TRANSLATED'))
->set("LOCALE",$locale)
->set("TITLE",$module->getVirtualColumn('i18n_TITLE'))
->set("CHAPO", $module->getVirtualColumn('i18n_CHAPO'))
->set("DESCRIPTION", $module->getVirtualColumn('i18n_DESCRIPTION'))
->set("POSTSCRIPTUM", $module->getVirtualColumn('i18n_POSTSCRIPTUM'))
->set("CODE", $module->getCode())
->set("TYPE", $module->getType())
->set("ACTIVE", $module->getActivate())
->set("CLASS", $module->getFullNamespace())
->set("POSITION", $module->getPosition());
$loopResult->addRow($loopResultRow);
}
return $loopResult;
}
}

View File

@@ -23,12 +23,16 @@
namespace Thelia\Core\Template\Loop;
use Propel\Runtime\ActiveQuery\Criteria;
use Thelia\Core\Template\Element\BaseLoop;
use Thelia\Core\Template\Element\LoopResult;
use Thelia\Core\Template\Element\LoopResultRow;
use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
use Thelia\Core\Template\Loop\Argument\Argument;
use Thelia\Model\OrderQuery;
use Thelia\Type\TypeCollection;
use Thelia\Type;
/**
*
* @package Thelia\Core\Template\Loop
@@ -37,19 +41,94 @@ use Thelia\Core\Template\Loop\Argument\Argument;
*/
class Order extends BaseLoop
{
public $countable = true;
public $timestampable = true;
public $versionable = false;
public function getArgDefinitions()
{
return new ArgumentCollection();
return new ArgumentCollection(
Argument::createIntListTypeArgument('id'),
new Argument(
'customer',
new TypeCollection(
new Type\IntType(),
new Type\EnumType(array('current'))
),
'current'
),
Argument::createIntListTypeArgument('status')
);
}
/**
* @param $pagination
*
*
* @return \Thelia\Core\Template\Element\LoopResult
* @return LoopResult
*/
public function exec(&$pagination)
{
// TODO : a coder !
return new LoopResult();
$search = OrderQuery::create();
$id = $this->getId();
if (null !== $id) {
$search->filterById($id, Criteria::IN);
}
$customer = $this->getCustomer();
if ($customer === 'current') {
$currentCustomer = $this->securityContext->getCustomerUser();
if ($currentCustomer === null) {
return new LoopResult();
} else {
$search->filterByCustomerId($currentCustomer->getId(), Criteria::EQUAL);
}
} else {
$search->filterByCustomerId($customer, Criteria::EQUAL);
}
$status = $this->getStatus();
if (null !== $status) {
$search->filterByStatusId($status, Criteria::IN);
}
$orders = $this->search($search, $pagination);
$loopResult = new LoopResult($orders);
foreach ($orders as $order) {
$tax = 0;
$amount = $order->getTotalAmount($tax);
$loopResultRow = new LoopResultRow($loopResult, $order, $this->versionable, $this->timestampable, $this->countable);
$loopResultRow
->set("ID", $order->getId())
->set("REF", $order->getRef())
->set("CUSTOMER", $order->getCustomerId())
->set("DELIVERY_ADDRESS", $order->getDeliveryOrderAddressId())
->set("INVOICE_ADDRESS", $order->getInvoiceOrderAddressId())
->set("INVOICE_DATE", $order->getInvoiceDate())
->set("CURRENCY", $order->getCurrencyId())
->set("CURRENCY_RATE", $order->getCurrencyRate())
->set("TRANSACTION_REF", $order->getTransactionRef())
->set("DELIVERY_REF", $order->getDeliveryRef())
->set("INVOICE_REF", $order->getInvoiceRef())
->set("POSTAGE", $order->getPostage())
->set("PAYMENT_MODULE", $order->getPaymentModuleId())
->set("DELIVERY_MODULE", $order->getDeliveryModuleId())
->set("STATUS", $order->getStatusId())
->set("LANG", $order->getLangId())
->set("POSTAGE", $order->getPostage())
->set("TOTAL_TAX", $tax)
->set("TOTAL_AMOUNT", $amount - $tax)
->set("TOTAL_TAXED_AMOUNT", $amount)
;
$loopResult->addRow($loopResultRow);
}
return $loopResult;
}
}

View File

@@ -170,17 +170,18 @@ class ProductSaleElements extends BaseLoop
$taxedPromoPrice = null;
}
$loopResultRow->set("ID", $PSEValue->getId())
->set("QUANTITY", $PSEValue->getQuantity())
->set("IS_PROMO", $PSEValue->getPromo() === 1 ? 1 : 0)
->set("IS_NEW", $PSEValue->getNewness() === 1 ? 1 : 0)
->set("WEIGHT", $PSEValue->getWeight())
->set("PRICE", $price)
->set("PRICE_TAX", $taxedPrice - $price)
->set("TAXED_PRICE", $taxedPrice)
->set("PROMO_PRICE", $promoPrice)
->set("PROMO_PRICE_TAX", $taxedPromoPrice - $promoPrice)
->set("TAXED_PROMO_PRICE", $taxedPromoPrice);
$loopResultRow
->set("ID" , $PSEValue->getId())
->set("QUANTITY" , $PSEValue->getQuantity())
->set("IS_PROMO" , $PSEValue->getPromo() === 1 ? 1 : 0)
->set("IS_NEW" , $PSEValue->getNewness() === 1 ? 1 : 0)
->set("WEIGHT" , $PSEValue->getWeight())
->set("PRICE" , $price)
->set("PRICE_TAX" , $taxedPrice - $price)
->set("TAXED_PRICE" , $taxedPrice)
->set("PROMO_PRICE" , $promoPrice)
->set("PROMO_PRICE_TAX" , $taxedPromoPrice - $promoPrice)
->set("TAXED_PROMO_PRICE" , $taxedPromoPrice);
$loopResult->addRow($loopResultRow);
}

View File

@@ -56,6 +56,8 @@ class DataAccessFunctions extends AbstractSmartyPlugin
protected $request;
protected $dispatcher;
private static $dataAccessCache = array();
public function __construct(Request $request, SecurityContext $securityContext, ParserContext $parserContext, ContainerAwareEventDispatcher $dispatcher)
{
$this->securityContext = $securityContext;
@@ -160,7 +162,12 @@ class DataAccessFunctions extends AbstractSmartyPlugin
public function countryDataAccess($params, $smarty)
{
$defaultCountry = CountryQuery::create()->findOneByByDefault(1);
if(array_key_exists('defaultCountry', self::$dataAccessCache)) {
$defaultCountry = self::$dataAccessCache['defaultCountry'];
} else {
$defaultCountry = CountryQuery::create()->findOneByByDefault(1);
self::$dataAccessCache['defaultCountry'] = $defaultCountry;
}
switch($params["attr"]) {
case "default":
@@ -170,6 +177,13 @@ class DataAccessFunctions extends AbstractSmartyPlugin
public function cartDataAccess($params, $smarty)
{
if(array_key_exists('currentCountry', self::$dataAccessCache)) {
$currentCountry = self::$dataAccessCache['currentCountry'];
} else {
$currentCountry = CountryQuery::create()->findOneById(64); // @TODO : make it magic
self::$dataAccessCache['currentCountry'] = $currentCountry;
}
$cart = $this->getCart($this->request);
$result = "";
switch($params["attr"]) {
@@ -180,9 +194,7 @@ class DataAccessFunctions extends AbstractSmartyPlugin
$result = $cart->getTotalAmount();
break;
case "total_taxed_price":
$result = $cart->getTaxedAmount(
CountryQuery::create()->findOneById(64) // @TODO : make it magic
);
$result = $cart->getTaxedAmount($currentCountry);
break;
}
@@ -234,24 +246,30 @@ class DataAccessFunctions extends AbstractSmartyPlugin
*/
protected function dataAccessWithI18n($objectLabel, $params, ModelCriteria $search, $columns = array('TITLE', 'CHAPO', 'DESCRIPTION', 'POSTSCRIPTUM'), $foreignTable = null, $foreignKey = 'ID')
{
$lang = $this->getNormalizedParam($params, array('lang'));
if ($lang === null) {
$lang = $this->request->getSession()->getLang()->getId();
if(array_key_exists('data_' . $objectLabel, self::$dataAccessCache)) {
$data = self::$dataAccessCache['data_' . $objectLabel];
} else {
$lang = $this->getNormalizedParam($params, array('lang'));
if ($lang === null) {
$lang = $this->request->getSession()->getLang()->getId();
}
ModelCriteriaTools::getI18n(
false,
$lang,
$search,
$this->request->getSession()->getLang()->getLocale(),
$columns,
$foreignTable,
$foreignKey,
true
);
$data = $search->findOne();
self::$dataAccessCache['data_' . $objectLabel] = $data;
}
ModelCriteriaTools::getI18n(
false,
$lang,
$search,
$this->request->getSession()->getLang()->getLocale(),
$columns,
$foreignTable,
$foreignKey,
true
);
$data = $search->findOne();
$noGetterData = array();
foreach ($columns as $column) {
$noGetterData[$column] = $data->getVirtualColumn('i18n_' . $column);

View File

@@ -0,0 +1,103 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Core\Template\Smarty\Plugins;
use Symfony\Component\Form\FormView;
use Thelia\Form\BaseForm;
use Thelia\Core\Template\Element\Exception\ElementNotFoundException;
use Symfony\Component\HttpFoundation\Request;
use Thelia\Core\Template\Smarty\SmartyPluginDescriptor;
use Thelia\Core\Template\Smarty\AbstractSmartyPlugin;
use Thelia\Core\Template\ParserContext;
/**
* Created by JetBrains PhpStorm.
* Date: 9/18/13
* Time: 3:56 PM
*
* Plugin for smarty defining blocks allowing to get flash message
* A flash message is a variable, array, object stored in session under the flashMessage key
* ex $SESSION['flashMessage']['myKey']
*
* blocks :
* - {flashMessage key="myKey"} ... {/flashMessage}
*
* Class Form
*
* @package Thelia\Core\Template\Smarty\Plugins
* @author Guillaume MOREL <gmorel@openstudio.fr>
*/
class FlashMessage extends AbstractSmartyPlugin
{
/** @var Request Request service */
protected $request;
/**
* Constructor
*
* @param Request $request Request service
*/
public function __construct(Request $request)
{
$this->request = $request;
}
/**
* Get FlashMessage
* And clean session from this key
*
* @param array $params Block parameters
* @param mixed $content Block content
* @param \Smarty_Internal_Template $template Template
* @param bool $repeat Control how many times
* the block is displayed
*
* @return mixed
*/
public function getFlashMessage($params, $content, \Smarty_Internal_Template $template, &$repeat)
{
if ($repeat) {
$key = $params['key'];
$flashBag = $this->request->getSession()->get('flashMessage');
$template->assign('value', $flashBag[$key]);
// Reset flash message (can be read once)
unset($flashBag[$key]);
$this->request->getSession()->set('flashMessage', $flashBag);
} else {
return $content;
}
}
/**
* @return array an array of SmartyPluginDescriptor
*/
public function getPluginDescriptors()
{
return array(
new SmartyPluginDescriptor("block", "flashMessage", $this, "getFlashMessage")
);
}
}

View File

@@ -39,6 +39,7 @@ class TaxEngineException extends \RuntimeException
const UNDEFINED_TAX_RULES_COLLECTION = 503;
const UNDEFINED_REQUIREMENTS = 504;
const UNDEFINED_REQUIREMENT_VALUE = 505;
const UNDEFINED_TAX_RULE = 506;
const BAD_AMOUNT_FORMAT = 601;

View File

@@ -0,0 +1,54 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Exception;
/**
* these exception are non fatal exception, due to thelia process exception
* or customer random navigation
*
* they redirect the customer who trig them to a specific error page // @todo
*
* Class TheliaProcessException
* @package Thelia\Exception
*/
class TheliaProcessException extends \RuntimeException
{
public $data = null;
const UNKNOWN_EXCEPTION = 0;
const CART_ITEM_NOT_ENOUGH_STOCK = 100;
const NO_PLACED_ORDER = 101;
const PLACED_ORDER_ID_BAD_CURRENT_CUSTOMER = 102;
public function __construct($message, $code = null, $data = null, $previous = null)
{
$this->data = $data;
if ($code === null) {
$code = self::UNKNOWN_EXCEPTION;
}
parent::__construct($message, $code, $previous);
}
}

View File

@@ -0,0 +1,53 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Form;
use Thelia\Core\Translation\Translator;
use Thelia\Form\Image\ImageModification;
/**
* Created by JetBrains PhpStorm.
* Date: 9/18/13
* Time: 3:56 PM
*
* Form allowing to process an image collection
*
* @package Image
* @author Guillaume MOREL <gmorel@openstudio.fr>
*
*/
class CategoryImageModification extends ImageModification
{
/**
* Get form name
* This name must be unique
*
* @return string
*/
public function getName()
{
return 'thelia_category_image_modification';
}
}

View File

@@ -27,7 +27,7 @@ use Thelia\Core\Translation\Translator;
class ContentCreationForm extends BaseForm
{
protected function buildForm($change_mode = false)
protected function buildForm()
{
$this->formBuilder
->add("title", "text", array(
@@ -40,9 +40,11 @@ class ContentCreationForm extends BaseForm
)
))
->add("default_folder", "integer", array(
"label" => Translator::getInstance()->trans("Default folder *"),
"constraints" => array(
new NotBlank()
)
),
"label_attr" => array("for" => "default_folder")
))
->add("locale", "text", array(
"constraints" => array(

View File

@@ -0,0 +1,53 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Form;
use Thelia\Core\Translation\Translator;
use Thelia\Form\Image\ImageModification;
/**
* Created by JetBrains PhpStorm.
* Date: 9/18/13
* Time: 3:56 PM
*
* Form allowing to process an image collection
*
* @package Image
* @author Guillaume MOREL <gmorel@openstudio.fr>
*
*/
class ContentImageModification extends ImageModification
{
/**
* Get form name
* This name must be unique
*
* @return string
*/
public function getName()
{
return 'thelia_content_image_modification';
}
}

View File

@@ -0,0 +1,61 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Form;
use Symfony\Component\Validator\Constraints\GreaterThan;
use Symfony\Component\Validator\Constraints\NotBlank;
use Thelia\Core\Translation\Translator;
use Thelia\Form\StandardDescriptionFieldsTrait;
/**
* Class ContentModificationForm
* @package Thelia\Form
* @author manuel raynaud <mraynaud@openstudio.fr>
*/
class ContentModificationForm extends ContentCreationForm {
use StandardDescriptionFieldsTrait;
protected function buildForm()
{
parent::buildForm();
$this->formBuilder
->add("id", "hidden", array("constraints" => array(new GreaterThan(array('value' => 0)))))
->add("url", "text", array(
"label" => Translator::getInstance()->trans("Rewriten URL *"),
"constraints" => array(new NotBlank()),
"label_attr" => array("for" => "rewritten_url")
))
;
// Add standard description fields, excluding title and locale, which a re defined in parent class
$this->addStandardDescFields(array('title', 'locale'));
}
public function getName()
{
return "thelia_content_modification";
}
}

View File

@@ -0,0 +1,53 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Form;
use Thelia\Core\Translation\Translator;
use Thelia\Form\Image\ImageModification;
/**
* Created by JetBrains PhpStorm.
* Date: 9/18/13
* Time: 3:56 PM
*
* Form allowing to process an image collection
*
* @package Image
* @author Guillaume MOREL <gmorel@openstudio.fr>
*
*/
class FolderImageModification extends ImageModification
{
/**
* Get form name
* This name must be unique
*
* @return string
*/
public function getName()
{
return 'thelia_folder_image_modification';
}
}

View File

@@ -32,7 +32,7 @@ class FolderModificationForm extends FolderCreationForm
protected function buildForm()
{
parent::buildForm(true);
parent::buildForm();
$this->formBuilder
->add("id", "hidden", array("constraints" => array(new GreaterThan(array('value' => 0)))))

View File

@@ -0,0 +1,183 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Form\Image;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Validator\Constraints\Image;
use Symfony\Component\Validator\Constraints\NotBlank;
use Thelia\Core\Translation\Translator;
use Thelia\Form\BaseForm;
/**
* Created by JetBrains PhpStorm.
* Date: 9/18/13
* Time: 3:56 PM
*
* Form allowing to process an image
* @todo refactor make all pictures using propel inheritance and factorise image behaviour into one single clean action
*
* @package Image
* @author Guillaume MOREL <gmorel@openstudio.fr>
*
*/
abstract class ImageModification extends BaseForm
{
// public function __construct(Request $request, $type= "form", $data = array(), $options = array(), $isUpdate = false)
// {
// parent::__construct($request, $type, $data, $options);
// $this->setIsUpdate($isUpdate);
// }
// /** @var bool Flag for update/create mode */
// protected $isUpdate = false;
/**
*
* in this function you add all the fields you need for your Form.
* Form this you have to call add method on $this->form attribute :
*
* $this->form->add('name', 'text')
* ->add('email', 'email', array(
* 'attr' => array(
* 'class' => 'field'
* ),
* 'label' => 'email',
* 'constraints' => array(
* new NotBlank()
* )
* )
* )
* ->add('age', 'integer');
*
* @return null
*/
protected function buildForm()
{
// if (false === $this->isUpdate) {
$this->formBuilder->add(
'file',
'file',
array(
'constraints' => array(
// new NotBlank(),
new Image(
array(
'minWidth' => 200,
'minHeight' => 200
)
)
),
'label' => Translator::getInstance()->trans('File'),
'label_attr' => array(
'for' => 'file'
)
)
);
// }
$this->formBuilder
->add(
'title',
'text',
array(
'constraints' => array(
new NotBlank()
),
'label' => Translator::getInstance()->trans('Title'),
'label_attr' => array(
'for' => 'title'
)
)
)
->add(
'description',
'text',
array(
'constraints' => array(),
'label' => Translator::getInstance()->trans('Description'),
'label_attr' => array(
'for' => 'description'
)
)
)
->add(
'chapo',
'text',
array(
'constraints' => array(),
'label' => Translator::getInstance()->trans('Chapo'),
'label_attr' => array(
'for' => 'chapo'
)
)
)
->add(
'postscriptum',
'text',
array(
'constraints' => array(),
'label' => Translator::getInstance()->trans('Post Scriptum'),
'label_attr' => array(
'for' => 'postscriptum'
)
)
)
->add(
'postscriptum',
'text',
array(
'constraints' => array(),
'label' => Translator::getInstance()->trans('Post Scriptum'),
'label_attr' => array(
'for' => 'postscriptum'
)
)
);
}
// /**
// * Set form in update or create mode
// *
// * @param boolean $isUpdate
// */
// public function setIsUpdate($isUpdate)
// {
// $this->isUpdate = $isUpdate;
// }
//
// /**
// * Get for mode
// *
// * @return boolean
// */
// public function getIsUpdate()
// {
// return $this->isUpdate;
// }
}

View File

@@ -80,7 +80,7 @@ class OrderDelivery extends BaseForm
->filterByType(BaseModule::DELIVERY_MODULE_TYPE)
->filterByActivate(1)
->filterById($value)
->find();
->findOne();
if(null === $module) {
$context->addViolation("Delivery module ID not found");

View File

@@ -0,0 +1,53 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Form;
use Thelia\Core\Translation\Translator;
use Thelia\Form\Image\ImageModification;
/**
* Created by JetBrains PhpStorm.
* Date: 9/18/13
* Time: 3:56 PM
*
* Form allowing to process an image collection
*
* @package Image
* @author Guillaume MOREL <gmorel@openstudio.fr>
*
*/
class ProductImageModification extends ImageModification
{
/**
* Get form name
* This name must be unique
*
* @return string
*/
public function getName()
{
return 'thelia_product_image_modification';
}
}

View File

@@ -2,6 +2,8 @@
namespace Thelia\Model;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Thelia\Model\Base\CategoryImage as BaseCategoryImage;
use Propel\Runtime\Connection\ConnectionInterface;
@@ -25,4 +27,29 @@ class CategoryImage extends BaseCategoryImage
return true;
}
/**
* Set Image parent id
*
* @param int $parentId parent id
*
* @return $this
*/
public function setParentId($parentId)
{
$this->setCategoryId($parentId);
return $this;
}
/**
* Get Image parent id
*
* @return int parent id
*/
public function getParentId()
{
return $this->getCategoryId();
}
}

View File

@@ -2,7 +2,12 @@
namespace Thelia\Model;
use Propel\Runtime\Propel;
use Thelia\Core\Event\Content\ContentEvent;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Model\Base\Content as BaseContent;
use Thelia\Model\ContentFolderQuery;
use Thelia\Model\Map\ContentTableMap;
use Thelia\Tools\URL;
use Propel\Runtime\Connection\ConnectionInterface;
@@ -30,13 +35,78 @@ class Content extends BaseContent
// and generate the position relative to this folder
}
/**
* {@inheritDoc}
*/
public function preInsert(ConnectionInterface $con = null)
public function getDefaultFolderId()
{
$this->setPosition($this->getNextPosition());
// Find default folder
$default_folder = ContentFolderQuery::create()
->filterByContentId($this->getId())
->filterByDefaultFolder(true)
->findOne();
return $default_folder == null ? 0 : $default_folder->getFolderId();
}
public function setDefaultFolder($folderId)
{
/* ContentFolderQuery::create()
->filterByContentId($this->getId)
->update(array("DefaultFolder" => 0));*/
return $this;
}
public function create($defaultFolderId)
{
$con = Propel::getWriteConnection(ContentTableMap::DATABASE_NAME);
$con->beginTransaction();
$this->dispatchEvent(TheliaEvents::BEFORE_CREATECONTENT, new ContentEvent($this));
try {
$this->save($con);
$cf = new ContentFolder();
$cf->setContentId($this->getId())
->setFolderId($defaultFolderId)
->setDefaultFolder(1)
->save($con);
$this->setPosition($this->getNextPosition())->save($con);
$con->commit();
$this->dispatchEvent(TheliaEvents::AFTER_CREATECONTENT,new ContentEvent($this));
} catch(\Exception $ex) {
$con->rollback();
throw $ex;
}
}
public function preUpdate(ConnectionInterface $con = null)
{
$this->dispatchEvent(TheliaEvents::BEFORE_UPDATECONTENT, new ContentEvent($this));
return true;
}
public function postUpdate(ConnectionInterface $con = null)
{
$this->dispatchEvent(TheliaEvents::AFTER_UPDATECONTENT, new ContentEvent($this));
}
public function preDelete(ConnectionInterface $con = null)
{
$this->dispatchEvent(TheliaEvents::BEFORE_DELETECONTENT, new ContentEvent($this));
return true;
}
public function postDelete(ConnectionInterface $con = null)
{
$this->dispatchEvent(TheliaEvents::AFTER_DELETECONTENT, new ContentEvent($this));
}
}

View File

@@ -25,4 +25,28 @@ class ContentImage extends BaseContentImage
return true;
}
/**
* Set Image parent id
*
* @param int $parentId parent id
*
* @return $this
*/
public function setParentId($parentId)
{
$this->setContentId($parentId);
return $this;
}
/**
* Get Image parent id
*
* @return int parent id
*/
public function getParentId()
{
return $this->getContentId();
}
}

View File

@@ -2,6 +2,8 @@
namespace Thelia\Model;
use Thelia\Core\Event\FolderEvent;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Model\Base\Folder as BaseFolder;
use Thelia\Tools\URL;
use Propel\Runtime\Connection\ConnectionInterface;
@@ -67,6 +69,37 @@ class Folder extends BaseFolder
{
$this->setPosition($this->getNextPosition());
$this->dispatchEvent(TheliaEvents::BEFORE_CREATEFOLDER, new FolderEvent($this));
return true;
}
public function postInsert(ConnectionInterface $con = null)
{
$this->dispatchEvent(TheliaEvents::AFTER_CREATEFOLDER, new FolderEvent($this));
}
public function preUpdate(ConnectionInterface $con = null)
{
$this->dispatchEvent(TheliaEvents::BEFORE_UPDATEFOLDER, new FolderEvent($this));
return true;
}
public function postUpdate(ConnectionInterface $con = null)
{
$this->dispatchEvent(TheliaEvents::AFTER_UPDATEFOLDER, new FolderEvent($this));
}
public function preDelete(ConnectionInterface $con = null)
{
$this->dispatchEvent(TheliaEvents::BEFORE_DELETEFOLDER, new FolderEvent($this));
return true;
}
public function postDelete(ConnectionInterface $con = null)
{
$this->dispatchEvent(TheliaEvents::AFTER_DELETEFOLDER, new FolderEvent($this));
}
}

View File

@@ -25,4 +25,28 @@ class FolderImage extends BaseFolderImage
return true;
}
/**
* Set Image parent id
*
* @param int $parentId parent id
*
* @return $this
*/
public function setParentId($parentId)
{
$this->setFolderId($parentId);
return $this;
}
/**
* Get Image parent id
*
* @return int parent id
*/
public function getParentId()
{
return $this->getFolderId();
}
}

View File

@@ -2,10 +2,17 @@
namespace Thelia\Model;
use Propel\Runtime\ActiveQuery\Criteria;
use Propel\Runtime\Connection\ConnectionInterface;
use Propel\Runtime\Propel;
use Thelia\Core\Event\OrderEvent;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Model\Base\Order as BaseOrder;
use Thelia\Model\Base\OrderProductTaxQuery;
use Thelia\Model\Map\OrderProductTaxTableMap;
use Thelia\Model\OrderProductQuery;
use Thelia\Model\Map\OrderTableMap;
use \PDO;
class Order extends BaseOrder
{
@@ -19,20 +26,209 @@ class Order extends BaseOrder
*/
public function preInsert(ConnectionInterface $con = null)
{
$this->dispatchEvent(TheliaEvents::ORDER_SET_REFERENCE, new OrderEvent($this));
$this->dispatchEvent(TheliaEvents::ORDER_BEFORE_CREATE, new OrderEvent($this));
return true;
}
/**
* {@inheritDoc}
*/
public function postInsert(ConnectionInterface $con = null)
{
$this->dispatchEvent(TheliaEvents::ORDER_AFTER_CREATE, new OrderEvent($this));
}
/**
* calculate the total amount
*
* @TODO create body method
* @param int $tax
*
* @return int
* @return int|string|Base\double
*/
public function getTotalAmount()
public function getTotalAmount(&$tax = 0)
{
return 2;
$amount = 0;
$tax = 0;
/* browse all products */
$orderProductIds = array();
foreach($this->getOrderProducts() as $orderProduct) {
$taxAmount = OrderProductTaxQuery::create()
->withColumn('SUM(' . OrderProductTaxTableMap::AMOUNT . ')', 'total_tax')
->filterByOrderProductId($orderProduct->getId(), Criteria::EQUAL)
->findOne();
$amount += ($orderProduct->getWasInPromo() == 1 ? $orderProduct->getPromoPrice() : $orderProduct->getPrice()) * $orderProduct->getQuantity();
$tax += round($taxAmount->getVirtualColumn('total_tax'), 2) * $orderProduct->getQuantity();
}
return $amount + $tax + $this->getPostage(); // @todo : manage discount
}
/**
* PROPEL SHOULD FIX IT
*
* Insert the row in the database.
*
* @param ConnectionInterface $con
*
* @throws PropelException
* @see doSave()
*/
protected function doInsert(ConnectionInterface $con)
{
$modifiedColumns = array();
$index = 0;
$this->modifiedColumns[] = OrderTableMap::ID;
if (null !== $this->id) {
throw new PropelException('Cannot insert a value for auto-increment primary key (' . OrderTableMap::ID . ')');
}
// check the columns in natural order for more readable SQL queries
if ($this->isColumnModified(OrderTableMap::ID)) {
$modifiedColumns[':p' . $index++] = 'ID';
}
if ($this->isColumnModified(OrderTableMap::REF)) {
$modifiedColumns[':p' . $index++] = 'REF';
}
if ($this->isColumnModified(OrderTableMap::CUSTOMER_ID)) {
$modifiedColumns[':p' . $index++] = 'CUSTOMER_ID';
}
if ($this->isColumnModified(OrderTableMap::INVOICE_ORDER_ADDRESS_ID)) {
$modifiedColumns[':p' . $index++] = 'INVOICE_ORDER_ADDRESS_ID';
}
if ($this->isColumnModified(OrderTableMap::DELIVERY_ORDER_ADDRESS_ID)) {
$modifiedColumns[':p' . $index++] = 'DELIVERY_ORDER_ADDRESS_ID';
}
if ($this->isColumnModified(OrderTableMap::INVOICE_DATE)) {
$modifiedColumns[':p' . $index++] = 'INVOICE_DATE';
}
if ($this->isColumnModified(OrderTableMap::CURRENCY_ID)) {
$modifiedColumns[':p' . $index++] = 'CURRENCY_ID';
}
if ($this->isColumnModified(OrderTableMap::CURRENCY_RATE)) {
$modifiedColumns[':p' . $index++] = 'CURRENCY_RATE';
}
if ($this->isColumnModified(OrderTableMap::TRANSACTION_REF)) {
$modifiedColumns[':p' . $index++] = 'TRANSACTION_REF';
}
if ($this->isColumnModified(OrderTableMap::DELIVERY_REF)) {
$modifiedColumns[':p' . $index++] = 'DELIVERY_REF';
}
if ($this->isColumnModified(OrderTableMap::INVOICE_REF)) {
$modifiedColumns[':p' . $index++] = 'INVOICE_REF';
}
if ($this->isColumnModified(OrderTableMap::POSTAGE)) {
$modifiedColumns[':p' . $index++] = 'POSTAGE';
}
if ($this->isColumnModified(OrderTableMap::PAYMENT_MODULE_ID)) {
$modifiedColumns[':p' . $index++] = 'PAYMENT_MODULE_ID';
}
if ($this->isColumnModified(OrderTableMap::DELIVERY_MODULE_ID)) {
$modifiedColumns[':p' . $index++] = 'DELIVERY_MODULE_ID';
}
if ($this->isColumnModified(OrderTableMap::STATUS_ID)) {
$modifiedColumns[':p' . $index++] = 'STATUS_ID';
}
if ($this->isColumnModified(OrderTableMap::LANG_ID)) {
$modifiedColumns[':p' . $index++] = 'LANG_ID';
}
if ($this->isColumnModified(OrderTableMap::CREATED_AT)) {
$modifiedColumns[':p' . $index++] = 'CREATED_AT';
}
if ($this->isColumnModified(OrderTableMap::UPDATED_AT)) {
$modifiedColumns[':p' . $index++] = 'UPDATED_AT';
}
$db = Propel::getServiceContainer()->getAdapter(OrderTableMap::DATABASE_NAME);
if ($db->useQuoteIdentifier()) {
$tableName = $db->quoteIdentifierTable(OrderTableMap::TABLE_NAME);
} else {
$tableName = OrderTableMap::TABLE_NAME;
}
$sql = sprintf(
'INSERT INTO %s (%s) VALUES (%s)',
$tableName,
implode(', ', $modifiedColumns),
implode(', ', array_keys($modifiedColumns))
);
try {
$stmt = $con->prepare($sql);
foreach ($modifiedColumns as $identifier => $columnName) {
switch ($columnName) {
case 'ID':
$stmt->bindValue($identifier, $this->id, PDO::PARAM_INT);
break;
case 'REF':
$stmt->bindValue($identifier, $this->ref, PDO::PARAM_STR);
break;
case 'CUSTOMER_ID':
$stmt->bindValue($identifier, $this->customer_id, PDO::PARAM_INT);
break;
case 'INVOICE_ORDER_ADDRESS_ID':
$stmt->bindValue($identifier, $this->invoice_order_address_id, PDO::PARAM_INT);
break;
case 'DELIVERY_ORDER_ADDRESS_ID':
$stmt->bindValue($identifier, $this->delivery_order_address_id, PDO::PARAM_INT);
break;
case 'INVOICE_DATE':
$stmt->bindValue($identifier, $this->invoice_date ? $this->invoice_date->format("Y-m-d H:i:s") : null, PDO::PARAM_STR);
break;
case 'CURRENCY_ID':
$stmt->bindValue($identifier, $this->currency_id, PDO::PARAM_INT);
break;
case 'CURRENCY_RATE':
$stmt->bindValue($identifier, $this->currency_rate, PDO::PARAM_STR);
break;
case 'TRANSACTION_REF':
$stmt->bindValue($identifier, $this->transaction_ref, PDO::PARAM_STR);
break;
case 'DELIVERY_REF':
$stmt->bindValue($identifier, $this->delivery_ref, PDO::PARAM_STR);
break;
case 'INVOICE_REF':
$stmt->bindValue($identifier, $this->invoice_ref, PDO::PARAM_STR);
break;
case 'POSTAGE':
$stmt->bindValue($identifier, $this->postage, PDO::PARAM_STR);
break;
case 'PAYMENT_MODULE_ID':
$stmt->bindValue($identifier, $this->payment_module_id, PDO::PARAM_INT);
break;
case 'DELIVERY_MODULE_ID':
$stmt->bindValue($identifier, $this->delivery_module_id, PDO::PARAM_INT);
break;
case 'STATUS_ID':
$stmt->bindValue($identifier, $this->status_id, PDO::PARAM_INT);
break;
case 'LANG_ID':
$stmt->bindValue($identifier, $this->lang_id, PDO::PARAM_INT);
break;
case 'CREATED_AT':
$stmt->bindValue($identifier, $this->created_at ? $this->created_at->format("Y-m-d H:i:s") : null, PDO::PARAM_STR);
break;
case 'UPDATED_AT':
$stmt->bindValue($identifier, $this->updated_at ? $this->updated_at->format("Y-m-d H:i:s") : null, PDO::PARAM_STR);
break;
}
}
$stmt->execute();
} catch (Exception $e) {
Propel::log($e->getMessage(), Propel::LOG_ERR);
throw new PropelException(sprintf('Unable to execute INSERT statement [%s]', $sql), 0, $e);
}
try {
$pk = $con->lastInsertId();
} catch (Exception $e) {
throw new PropelException('Unable to get autoincrement id.', 0, $e);
}
$this->setId($pk);
$this->setNew(false);
}
}

24
core/lib/Thelia/Model/OrderProduct.php Executable file → Normal file
View File

@@ -2,8 +2,30 @@
namespace Thelia\Model;
use Propel\Runtime\Connection\ConnectionInterface;
use Thelia\Core\Event\OrderEvent;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Model\Base\OrderProduct as BaseOrderProduct;
class OrderProduct extends BaseOrderProduct {
class OrderProduct extends BaseOrderProduct
{
use \Thelia\Model\Tools\ModelEventDispatcherTrait;
/**
* {@inheritDoc}
*/
public function preInsert(ConnectionInterface $con = null)
{
$this->dispatchEvent(TheliaEvents::ORDER_PRODUCT_BEFORE_CREATE, new OrderEvent($this->getOrder()));
return true;
}
/**
* {@inheritDoc}
*/
public function postInsert(ConnectionInterface $con = null)
{
$this->dispatchEvent(TheliaEvents::ORDER_PRODUCT_AFTER_CREATE, new OrderEvent($this->getOrder()));
}
}

3
core/lib/Thelia/Model/OrderProductQuery.php Executable file → Normal file
View File

@@ -15,6 +15,7 @@ use Thelia\Model\Base\OrderProductQuery as BaseOrderProductQuery;
* long as it does not already exist in the output directory.
*
*/
class OrderProductQuery extends BaseOrderProductQuery {
class OrderProductQuery extends BaseOrderProductQuery
{
} // OrderProductQuery

View File

@@ -2,8 +2,11 @@
namespace Thelia\Model;
use Propel\Runtime\Exception\PropelException;
use Propel\Runtime\Propel;
use Thelia\Model\Base\OrderQuery as BaseOrderQuery;
use \PDO;
use Thelia\Model\Map\OrderTableMap;
/**
* Skeleton subclass for performing query and update operations on the 'order' table.
@@ -15,6 +18,38 @@ use Thelia\Model\Base\OrderQuery as BaseOrderQuery;
* long as it does not already exist in the output directory.
*
*/
class OrderQuery extends BaseOrderQuery {
class OrderQuery extends BaseOrderQuery
{
/**
* PROPEL SHOULD FIX IT
*
* Find object by primary key using raw SQL to go fast.
* Bypass doSelect() and the object formatter by using generated code.
*
* @param mixed $key Primary key to use for the query
* @param ConnectionInterface $con A connection object
*
* @return Order A model object, or null if the key is not found
*/
protected function findPkSimple($key, $con)
{
$sql = 'SELECT ID, REF, CUSTOMER_ID, INVOICE_ORDER_ADDRESS_ID, DELIVERY_ORDER_ADDRESS_ID, INVOICE_DATE, CURRENCY_ID, CURRENCY_RATE, TRANSACTION_REF, DELIVERY_REF, INVOICE_REF, POSTAGE, PAYMENT_MODULE_ID, DELIVERY_MODULE_ID, STATUS_ID, LANG_ID, CREATED_AT, UPDATED_AT FROM `order` WHERE ID = :p0';
try {
$stmt = $con->prepare($sql);
$stmt->bindValue(':p0', $key, PDO::PARAM_INT);
$stmt->execute();
} catch (\Exception $e) {
Propel::log($e->getMessage(), Propel::LOG_ERR);
throw new PropelException(sprintf('Unable to execute SELECT statement [%s]', $sql), 0, $e);
}
$obj = null;
if ($row = $stmt->fetch(\PDO::FETCH_NUM)) {
$obj = new Order();
$obj->hydrate($row);
OrderTableMap::addInstanceToPool($obj, (string) $key);
}
$stmt->closeCursor();
return $obj;
}
} // OrderQuery

View File

@@ -98,8 +98,6 @@ class Product extends BaseProduct
->filterByDefaultCategory(true)
->findOne()
;
echo "newcat= $defaultCategoryId ";
var_dump($productCategory);
if ($productCategory == null || $productCategory->getCategoryId() != $defaultCategoryId) {
exit;

View File

@@ -25,4 +25,28 @@ class ProductImage extends BaseProductImage
return true;
}
/**
* Set Image parent id
*
* @param int $parentId parent id
*
* @return $this
*/
public function setParentId($parentId)
{
$this->setProductId($parentId);
return $this;
}
/**
* Get Image parent id
*
* @return int parent id
*/
public function getParentId()
{
return $this->getProductId();
}
}

View File

@@ -3,7 +3,25 @@
namespace Thelia\Model;
use Thelia\Model\Base\TaxRule as BaseTaxRule;
use Thelia\TaxEngine\Calculator;
use Thelia\TaxEngine\OrderProductTaxCollection;
class TaxRule extends BaseTaxRule {
class TaxRule extends BaseTaxRule
{
/**
* @param Country $country
* @param $untaxedAmount
* @param null $askedLocale
*
* @return OrderProductTaxCollection
*/
public function getTaxDetail(Country $country, $untaxedAmount, $askedLocale = null)
{
$taxCalculator = new Calculator();
$taxCollection = new OrderProductTaxCollection();
$taxCalculator->loadTaxRule($this, $country)->getTaxedPrice($untaxedAmount, $taxCollection, $askedLocale);
return $taxCollection;
}
}

View File

@@ -21,13 +21,19 @@ class TaxRuleQuery extends BaseTaxRuleQuery
{
const ALIAS_FOR_TAX_RULE_COUNTRY_POSITION = 'taxRuleCountryPosition';
public function getTaxCalculatorCollection(Product $product, Country $country)
/**
* @param TaxRule $taxRule
* @param Country $country
*
* @return array|mixed|\Propel\Runtime\Collection\ObjectCollection
*/
public function getTaxCalculatorCollection(TaxRule $taxRule, Country $country)
{
$search = TaxQuery::create()
->filterByTaxRuleCountry(
TaxRuleCountryQuery::create()
->filterByCountry($country, Criteria::EQUAL)
->filterByTaxRuleId($product->getTaxRuleId())
->filterByTaxRuleId($taxRule->getId())
->orderByPosition()
->find()
)

View File

@@ -25,7 +25,9 @@
namespace Thelia\Module;
use Symfony\Component\DependencyInjection\ContainerAware;
use Thelia\Model\ModuleI18nQuery;
use Thelia\Model\Map\ModuleImageTableMap;
use Thelia\Model\ModuleI18n;
use Thelia\Tools\Image;
use Thelia\Exception\ModuleException;
use Thelia\Model\Module;
@@ -76,6 +78,27 @@ abstract class BaseModule extends ContainerAware
return $this->container;
}
public function setTitle(Module $module, $titles)
{
if(is_array($titles)) {
foreach($titles as $locale => $title) {
$moduleI18n = ModuleI18nQuery::create()->filterById($module->getId())->filterByLocale($locale)->findOne();
if(null === $moduleI18n) {
$moduleI18n = new ModuleI18n();
$moduleI18n
->setId($module->getId())
->setLocale($locale)
->setTitle($title)
;
$moduleI18n->save();
} else {
$moduleI18n->setTitle($title);
$moduleI18n->save();
}
}
}
}
public function deployImageFolder(Module $module, $folderPath)
{
try {

View File

@@ -24,8 +24,11 @@ namespace Thelia\TaxEngine;
use Thelia\Exception\TaxEngineException;
use Thelia\Model\Country;
use Thelia\Model\OrderProductTax;
use Thelia\Model\Product;
use Thelia\Model\TaxRule;
use Thelia\Model\TaxRuleQuery;
use Thelia\Tools\I18n;
/**
* Class Calculator
@@ -68,14 +71,34 @@ class Calculator
$this->product = $product;
$this->country = $country;
$this->taxRulesCollection = $this->taxRuleQuery->getTaxCalculatorCollection($product, $country);
$this->taxRulesCollection = $this->taxRuleQuery->getTaxCalculatorCollection($product->getTaxRule(), $country);
return $this;
}
public function getTaxAmountFromUntaxedPrice($untaxedPrice)
public function loadTaxRule(TaxRule $taxRule, Country $country)
{
return $this->getTaxedPrice($untaxedPrice) - $untaxedPrice;
$this->product = null;
$this->country = null;
$this->taxRulesCollection = null;
if($taxRule->getId() === null) {
throw new TaxEngineException('TaxRule id is empty in Calculator::loadTaxRule', TaxEngineException::UNDEFINED_TAX_RULE);
}
if($country->getId() === null) {
throw new TaxEngineException('Country id is empty in Calculator::loadTaxRule', TaxEngineException::UNDEFINED_COUNTRY);
}
$this->country = $country;
$this->taxRulesCollection = $this->taxRuleQuery->getTaxCalculatorCollection($taxRule, $country);
return $this;
}
public function getTaxAmountFromUntaxedPrice($untaxedPrice, &$taxCollection = null)
{
return $this->getTaxedPrice($untaxedPrice, $taxCollection) - $untaxedPrice;
}
public function getTaxAmountFromTaxedPrice($taxedPrice)
@@ -83,7 +106,15 @@ class Calculator
return $taxedPrice - $this->getUntaxedPrice($taxedPrice);
}
public function getTaxedPrice($untaxedPrice)
/**
* @param $untaxedPrice
* @param null $taxCollection returns OrderProductTaxCollection
* @param null $askedLocale
*
* @return int
* @throws \Thelia\Exception\TaxEngineException
*/
public function getTaxedPrice($untaxedPrice, &$taxCollection = null, $askedLocale = null)
{
if(null === $this->taxRulesCollection) {
throw new TaxEngineException('Tax rules collection is empty in Calculator::getTaxAmount', TaxEngineException::UNDEFINED_TAX_RULES_COLLECTION);
@@ -97,6 +128,9 @@ class Calculator
$currentPosition = 1;
$currentTax = 0;
if(null !== $taxCollection) {
$taxCollection = new OrderProductTaxCollection();
}
foreach($this->taxRulesCollection as $taxRule) {
$position = (int)$taxRule->getTaxRuleCountryPosition();
@@ -109,7 +143,17 @@ class Calculator
$currentPosition = $position;
}
$currentTax += $taxType->calculate($taxedPrice);
$taxAmount = round($taxType->calculate($taxedPrice), 2);
$currentTax += $taxAmount;
if(null !== $taxCollection) {
$taxI18n = I18n::forceI18nRetrieving($askedLocale, 'Tax', $taxRule->getId());
$orderProductTax = new OrderProductTax();
$orderProductTax->setTitle($taxI18n->getTitle());
$orderProductTax->setDescription($taxI18n->getDescription());
$orderProductTax->setAmount($taxAmount);
$taxCollection->addTax($orderProductTax);
}
}
$taxedPrice += $currentTax;

View File

@@ -0,0 +1,126 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\TaxEngine;
use Thelia\Model\OrderProductTax;
/**
*
* @author Etienne Roudeix <eroudeix@openstudio.fr>
*
*/
class OrderProductTaxCollection implements \Iterator
{
private $position;
protected $taxes = array();
public function __construct()
{
foreach (func_get_args() as $tax) {
$this->addTax($tax);
}
}
public function isEmpty()
{
return count($this->taxes) == 0;
}
/**
* @param OrderProductTax $tax
*
* @return OrderProductTaxCollection
*/
public function addTax(OrderProductTax $tax)
{
$this->taxes[] = $tax;
return $this;
}
public function getCount()
{
return count($this->taxes);
}
/**
* (PHP 5 &gt;= 5.0.0)<br/>
* Return the current element
* @link http://php.net/manual/en/iterator.current.php
* @return OrderProductTax
*/
public function current()
{
return $this->taxes[$this->position];
}
/**
* (PHP 5 &gt;= 5.0.0)<br/>
* Move forward to next element
* @link http://php.net/manual/en/iterator.next.php
* @return void Any returned value is ignored.
*/
public function next()
{
$this->position++;
}
/**
* (PHP 5 &gt;= 5.0.0)<br/>
* 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()
{
return $this->position;
}
/**
* (PHP 5 &gt;= 5.0.0)<br/>
* 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()
{
return isset($this->taxes[$this->position]);
}
/**
* (PHP 5 &gt;= 5.0.0)<br/>
* 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()
{
$this->position = 0;
}
public function getKey($key)
{
return isset($this->taxes[$key]) ? $this->taxes[$key] : null;
}
}

View File

@@ -86,7 +86,7 @@ class CalculatorTest extends \PHPUnit_Framework_TestCase
$taxRuleQuery = $this->getMock('\Thelia\Model\TaxRuleQuery', array('getTaxCalculatorCollection'));
$taxRuleQuery->expects($this->once())
->method('getTaxCalculatorCollection')
->with($productQuery, $countryQuery)
->with($productQuery->getTaxRule(), $countryQuery)
->will($this->returnValue('foo'));
$rewritingUrlQuery = $this->getProperty('taxRuleQuery');

View File

@@ -0,0 +1,377 @@
<?php
/**
* Created by JetBrains PhpStorm.
* Date: 9/18/13
* Time: 8:47 PM
*
* @author Guillaume MOREL <gmorel@openstudio.fr>
*/
namespace Thelia\Tests\Type;
use Thelia\Core\Event\ImagesCreateOrUpdateEvent;
use Thelia\Exception\ImageException;
use Thelia\Model\Admin;
use Thelia\Tools\FileManager;
class FileManagerTest extends \PHPUnit_Framework_TestCase {
/**
* @covers Thelia\Tools\FileManager::copyUploadedFile
*/
public function testCopyUploadedFile()
{
$this->markTestIncomplete(
'Mock issue'
);
$stubTranslator = $this->getMockBuilder('\Thelia\Core\Translation\Translator')
->disableOriginalConstructor()
->getMock();
$stubTranslator->expects($this->any())
->method('trans')
->will($this->returnValue('translated'));
$stubRequest = $this->getMockBuilder('\Thelia\Core\HttpFoundation\Request')
->disableOriginalConstructor()
->getMock();
$stubSecurity = $this->getMockBuilder('\Thelia\Core\Security\SecurityContext')
->disableOriginalConstructor()
->getMock();
$stubSecurity->expects($this->any())
->method('getAdminUser')
->will($this->returnValue(new Admin()));
// Create a map of arguments to return values.
$map = array(
array('thelia.translator', $stubTranslator),
array('request', $stubRequest),
array('thelia.securityContext', $stubSecurity)
);
$stubContainer = $this->getMockBuilder('\Symfony\Component\DependencyInjection\ContainerInterface')
->disableOriginalConstructor()
->getMock();
$stubContainer->expects($this->any())
->method('get')
->will($this->returnValueMap($map));
$stubProductImage = $this->getMockBuilder('\Thelia\Model\ProductImage')
->disableOriginalConstructor()
->getMock();
$stubProductImage->expects($this->any())
->method('getUploadDir')
->will($this->returnValue(THELIA_LOCAL_DIR . 'media/images/product'));
$stubProductImage->expects($this->any())
->method('getId')
->will($this->returnValue(42));
$stubProductImage->expects($this->any())
->method('setFile')
->will($this->returnValue(true));
$stubProductImage->expects($this->any())
->method('save')
->will($this->returnValue(0));
$stubUploadedFile = $this->getMockBuilder('\Symfony\Component\HttpFoundation\File\UploadedFile')
->disableOriginalConstructor()
->getMock();
$stubUploadedFile->expects($this->any())
->method('getClientOriginalName')
->will($this->returnValue('goodName'));
$stubUploadedFile->expects($this->any())
->method('getClientOriginalExtension')
->will($this->returnValue('png'));
$stubUploadedFile->expects($this->any())
->method('move')
->will($this->returnValue($stubUploadedFile));
$fileManager = new FileManager($stubContainer);
$newUploadedFiles = array();
$actual = $fileManager->copyUploadedFile(24, ImagesCreateOrUpdateEvent::TYPE_PRODUCT, $stubProductImage, $stubUploadedFile, $newUploadedFiles);
$this->assertCount(1, $actual);
}
/**
* @covers Thelia\Tools\FileManager::copyUploadedFile
* @expectedException \Thelia\Exception\ImageException
*/
public function testCopyUploadedFileExceptionImageException()
{
$this->markTestIncomplete(
'Mock issue'
);
$stubTranslator = $this->getMockBuilder('\Thelia\Core\Translation\Translator')
->disableOriginalConstructor()
->getMock();
$stubTranslator->expects($this->any())
->method('trans')
->will($this->returnValue('translated'));
$stubRequest = $this->getMockBuilder('\Thelia\Core\HttpFoundation\Request')
->disableOriginalConstructor()
->getMock();
$stubSecurity = $this->getMockBuilder('\Thelia\Core\Security\SecurityContext')
->disableOriginalConstructor()
->getMock();
$stubSecurity->expects($this->any())
->method('getAdminUser')
->will($this->returnValue(new Admin()));
// Create a map of arguments to return values.
$map = array(
array('thelia.translator', $stubTranslator),
array('request', $stubRequest),
array('thelia.securityContext', $stubSecurity)
);
$stubContainer = $this->getMockBuilder('\Symfony\Component\DependencyInjection\ContainerInterface')
->disableOriginalConstructor()
->getMock();
$stubContainer->expects($this->any())
->method('get')
->will($this->returnValueMap($map));
$stubProductImage = $this->getMockBuilder('\Thelia\Model\ProductImage')
->disableOriginalConstructor()
->getMock();
$stubProductImage->expects($this->any())
->method('getUploadDir')
->will($this->returnValue(THELIA_LOCAL_DIR . 'media/images/product'));
$stubProductImage->expects($this->any())
->method('getId')
->will($this->returnValue(42));
$stubProductImage->expects($this->any())
->method('setFile')
->will($this->returnValue(true));
$stubProductImage->expects($this->any())
->method('save')
->will($this->returnValue(0));
$stubUploadedFile = $this->getMockBuilder('\Symfony\Component\HttpFoundation\File\UploadedFile')
->disableOriginalConstructor()
->getMock();
$stubUploadedFile->expects($this->any())
->method('getClientOriginalName')
->will($this->returnValue('goodName'));
$stubUploadedFile->expects($this->any())
->method('getClientOriginalExtension')
->will($this->returnValue('png'));
$stubUploadedFile->expects($this->any())
->method('move')
->will($this->returnValue($stubUploadedFile));
$fileManager = new FileManager($stubContainer);
$newUploadedFiles = array();
$actual = $fileManager->copyUploadedFile(24, ImagesCreateOrUpdateEvent::TYPE_PRODUCT, $stubProductImage, $stubUploadedFile, $newUploadedFiles);
}
/**
* @covers Thelia\Tools\FileManager::saveImage
*/
public function testSaveImageProductImage()
{
$stubContainer = $this->getMockBuilder('\Symfony\Component\DependencyInjection\ContainerInterface')
->disableOriginalConstructor()
->getMock();
$stubProductImage = $this->getMockBuilder('\Thelia\Model\ProductImage')
->disableOriginalConstructor()
->getMock();
$stubProductImage->expects($this->any())
->method('save')
->will($this->returnValue(10));
$stubProductImage->expects($this->any())
->method('getFile')
->will($this->returnValue('file'));
$fileManager = new FileManager($stubContainer);
$event = new ImagesCreateOrUpdateEvent(ImagesCreateOrUpdateEvent::TYPE_PRODUCT, 24);
$expected = 10;
$actual = $fileManager->saveImage($event, $stubProductImage);
$this->assertEquals($expected, $actual);
}
/**
* @covers Thelia\Tools\FileManager::saveImage
*/
public function testSaveImageCategoryImage()
{
$stubContainer = $this->getMockBuilder('\Symfony\Component\DependencyInjection\ContainerInterface')
->disableOriginalConstructor()
->getMock();
$stubCategoryImage = $this->getMockBuilder('\Thelia\Model\CategoryImage')
->disableOriginalConstructor()
->getMock();
$stubCategoryImage->expects($this->any())
->method('save')
->will($this->returnValue(10));
$stubCategoryImage->expects($this->any())
->method('getFile')
->will($this->returnValue('file'));
$fileManager = new FileManager($stubContainer);
$event = new ImagesCreateOrUpdateEvent(ImagesCreateOrUpdateEvent::TYPE_CATEGORY, 24);
$expected = 10;
$actual = $fileManager->saveImage($event, $stubCategoryImage);
$this->assertEquals($expected, $actual);
}
/**
* @covers Thelia\Tools\FileManager::saveImage
*/
public function testSaveImageFolderImage()
{
$stubContainer = $this->getMockBuilder('\Symfony\Component\DependencyInjection\ContainerInterface')
->disableOriginalConstructor()
->getMock();
$stubFolderImage = $this->getMockBuilder('\Thelia\Model\FolderImage')
->disableOriginalConstructor()
->getMock();
$stubFolderImage->expects($this->any())
->method('save')
->will($this->returnValue(10));
$stubFolderImage->expects($this->any())
->method('getFile')
->will($this->returnValue('file'));
$fileManager = new FileManager($stubContainer);
$event = new ImagesCreateOrUpdateEvent(ImagesCreateOrUpdateEvent::TYPE_FOLDER, 24);
$expected = 10;
$actual = $fileManager->saveImage($event, $stubFolderImage);
$this->assertEquals($expected, $actual);
}
/**
* @covers Thelia\Tools\FileManager::saveImage
*/
public function testSaveImageContentImage()
{
$stubContainer = $this->getMockBuilder('\Symfony\Component\DependencyInjection\ContainerInterface')
->disableOriginalConstructor()
->getMock();
$stubContentImage = $this->getMockBuilder('\Thelia\Model\ContentImage')
->disableOriginalConstructor()
->getMock();
$stubContentImage->expects($this->any())
->method('save')
->will($this->returnValue(10));
$stubContentImage->expects($this->any())
->method('getFile')
->will($this->returnValue('file'));
$fileManager = new FileManager($stubContainer);
$event = new ImagesCreateOrUpdateEvent(ImagesCreateOrUpdateEvent::TYPE_CONTENT, 24);
$expected = 10;
$actual = $fileManager->saveImage($event, $stubContentImage);
$this->assertEquals($expected, $actual);
}
/**
* @covers Thelia\Tools\FileManager::saveImage
* @expectedException \Thelia\Exception\ImageException
*/
public function testSaveImageExceptionImageException()
{
$stubContainer = $this->getMockBuilder('\Symfony\Component\DependencyInjection\ContainerInterface')
->disableOriginalConstructor()
->getMock();
$fileManager = new FileManager($stubContainer);
$stubProductImage = $this->getMockBuilder('\Thelia\Model\ProductImage')
->disableOriginalConstructor()
->getMock();
$stubProductImage->expects($this->any())
->method('save')
->will($this->returnValue(10));
$stubProductImage->expects($this->any())
->method('getFile')
->will($this->returnValue('file'));
$event = new ImagesCreateOrUpdateEvent('bad', 24);
$fileManager->saveImage($event, $stubProductImage);
}
/**
* @covers Thelia\Tools\FileManager::saveImage
* @expectedException \Thelia\Exception\ImageException
*/
public function testSaveImageExceptionImageException2()
{
$stubContainer = $this->getMockBuilder('\Symfony\Component\DependencyInjection\ContainerInterface')
->disableOriginalConstructor()
->getMock();
$fileManager = new FileManager($stubContainer);
$stubProductImage = $this->getMockBuilder('\Thelia\Model\ProductImage')
->disableOriginalConstructor()
->getMock();
$stubProductImage->expects($this->any())
->method('save')
->will($this->returnValue(0));
$stubProductImage->expects($this->any())
->method('getFile')
->will($this->returnValue('file'));
$event = new ImagesCreateOrUpdateEvent(ImagesCreateOrUpdateEvent::TYPE_PRODUCT, 24);
$fileManager->saveImage($event, $stubProductImage);
}
/**
* @covers Thelia\Tools\FileManager::sanitizeFileName
*/
public function testSanitizeFileName()
{
$stubContainer = $this->getMockBuilder('\Symfony\Component\DependencyInjection\ContainerInterface')
->disableOriginalConstructor()
->getMock();
$fileManager = new FileManager($stubContainer);
$badFileName = 'azeéràçè§^"$*+-_°)(&é<>@#ty';
$expected = 'azeyryZyy-_yty';
$actual = $fileManager->sanitizeFileName($badFileName);
$this->assertEquals($expected, $actual);
}
/**
* @covers Thelia\Tools\FileManager::adminLogAppend
*/
public function testAdminLogAppend()
{
$this->markTestIncomplete(
'This test has not been implemented yet.'
);
}
}

View File

@@ -0,0 +1,473 @@
<?php
/**********************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/**********************************************************************************/
namespace Thelia\Tools;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Thelia\Core\Event\ImagesCreateOrUpdateEvent;
use Thelia\Core\HttpFoundation\Request;
use Thelia\Core\Translation\Translator;
use Thelia\Exception\ImageException;
use Thelia\Form\CategoryImageModification;
use Thelia\Form\ContentImageModification;
use Thelia\Form\FolderImageModification;
use Thelia\Form\ProductImageModification;
use Thelia\Model\AdminLog;
use Thelia\Model\CategoryImage;
use Thelia\Model\CategoryImageQuery;
use Thelia\Model\CategoryQuery;
use Thelia\Model\ContentImage;
use Thelia\Model\ContentImageQuery;
use Thelia\Model\ContentQuery;
use Thelia\Model\FolderImage;
use Thelia\Model\FolderImageQuery;
use Thelia\Model\FolderQuery;
use Thelia\Model\ProductImage;
use Thelia\Model\ProductImageQuery;
use Thelia\Model\ProductQuery;
/**
* Created by JetBrains PhpStorm.
* Date: 9/19/13
* Time: 3:24 PM
*
* File Manager
*
* @package File
* @author Guillaume MOREL <gmorel@openstudio.fr>
*
*/
class FileManager
{
CONST TYPE_PRODUCT = 'product';
CONST TYPE_CATEGORY = 'category';
CONST TYPE_CONTENT = 'content';
CONST TYPE_FOLDER = 'folder';
CONST TYPE_MODULE = 'module';
/** @var ContainerInterface Service Container */
protected $container = null;
/** @var Translator Service Translator */
protected $translator = null;
/**
* Constructor
*
* @param ContainerInterface $container Service container
*/
public function __construct(ContainerInterface $container)
{
$this->container = $container;
$this->translator = $this->container->get('thelia.translator');
}
/**
* Copy UploadedFile into the server storage directory
*
* @param int $parentId Parent id
* @param string $imageType Image type
* @param FolderImage|ContentImage|CategoryImage|ProductImage $modelImage Image saved
* @param UploadedFile $uploadedFile Ready to be uploaded file
*
* @throws \Thelia\Exception\ImageException
* @return UploadedFile
*/
public function copyUploadedFile($parentId, $imageType, $modelImage, $uploadedFile)
{
if ($uploadedFile !== null) {
$directory = $this->getUploadDir($imageType);
$fileName = $this->renameFile($modelImage->getId(), $uploadedFile);
$this->adminLogAppend(
$this->translator->trans(
'Uploading picture %pictureName% to %directory% for parent_id %parentId% (%parentType%)',
array(
'%pictureName%' => $uploadedFile->getClientOriginalName(),
'%directory%' => $directory . '/' . $fileName,
'%parentId%' => $parentId,
'%parentType%' => $imageType
),
'image'
)
);
$newUploadedFile = $uploadedFile->move($directory, $fileName);
$modelImage->setFile($fileName);
if (!$modelImage->save()) {
throw new ImageException(
sprintf(
'Image %s (%s) failed to be saved (image file)',
$modelImage->getFile(),
$imageType
)
);
}
}
return $newUploadedFile;
}
/**
* Save image into the database
*
* @param ImagesCreateOrUpdateEvent $event Image event
* @param FolderImage|ContentImage|CategoryImage|ProductImage $modelImage Image to save
*
* @return int Nb lines modified
* @throws \Thelia\Exception\ImageException
* @todo refactor make all pictures using propel inheritance and factorise image behaviour into one single clean action
*/
public function saveImage(ImagesCreateOrUpdateEvent $event, $modelImage)
{
$nbModifiedLines = 0;
if ($modelImage->getFile() !== null) {
switch ($event->getImageType()) {
case ImagesCreateOrUpdateEvent::TYPE_PRODUCT:
/** @var ProductImage $modelImage */
$modelImage->setProductId($event->getParentId());
break;
case ImagesCreateOrUpdateEvent::TYPE_CATEGORY:
/** @var CategoryImage $modelImage */
$modelImage->setCategoryId($event->getParentId());
break;
case ImagesCreateOrUpdateEvent::TYPE_CONTENT:
/** @var ContentImage $modelImage */
$modelImage->setContentId($event->getParentId());
break;
case ImagesCreateOrUpdateEvent::TYPE_FOLDER:
/** @var FolderImage $modelImage */
$modelImage->setFolderId($event->getParentId());
break;
default:
throw new ImageException(
sprintf(
'Picture parent type is unknown (available types : %s)',
implode(
',',
$event->getAvailableType()
)
)
);
}
$nbModifiedLines = $modelImage->save();
if (!$nbModifiedLines) {
throw new ImageException(
sprintf(
'Image %s failed to be saved (image content)',
$modelImage->getFile()
)
);
}
}
return $nbModifiedLines;
}
/**
* Sanitizes a filename replacing whitespace with dashes
*
* Removes special characters that are illegal in filenames on certain
* operating systems and special characters requiring special escaping
* to manipulate at the command line.
*
* @param string $string The filename to be sanitized
*
* @return string The sanitized filename
*/
public function sanitizeFileName($string)
{
$cleanName = strtr($string, 'ŠŽšžŸÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÑÒÓÔÕÖØÙÚÛÜÝàáâãäåçèéêëìíîïñòóôõöøùúûüýÿ', 'SZszYAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy');
$cleanName = strtr($cleanName, array('Þ' => 'TH', 'þ' => 'th', 'Ð' => 'DH', 'ð' => 'dh', 'ß' => 'ss', 'Œ' => 'OE', 'œ' => 'oe', 'Æ' => 'AE', 'æ' => 'ae', 'µ' => 'u'));
$cleanName = preg_replace(array('/\s/', '/\.[\.]+/', '/[^\w_\.\-]/'), array('_', '.', ''), $cleanName);
return $cleanName;
}
/**
* Helper to append a message to the admin log.
*
* @param string $message
*/
public function adminLogAppend($message)
{
AdminLog::append(
$message,
$this->container->get('request'),
$this->container->get('thelia.securityContext')->getAdminUser()
);
}
/**
* Delete image from file storage and database
*
* @param CategoryImage|ProductImage|ContentImage|FolderImage $imageModel Image being deleted
* @param string $parentType Parent type
*/
public function deleteImage($imageModel, $parentType)
{
$url = $this->getUploadDir($parentType) . '/' . $imageModel->getFile();
unlink(str_replace('..', '', $url));
$imageModel->delete();
}
/**
* Get image model from type
*
* @param string $parentType Parent type
*
* @return null|\Thelia\Model\CategoryImage|\Thelia\Model\ContentImage|\Thelia\Model\FolderImage|\Thelia\Model\ProductImage
*
* @todo refactor make all pictures using propel inheritance and factorise image behaviour into one single clean action
*/
public function getImageModel($parentType)
{
switch ($parentType) {
case ImagesCreateOrUpdateEvent::TYPE_PRODUCT:
$model = new ProductImage();
break;
case ImagesCreateOrUpdateEvent::TYPE_CATEGORY:
$model = new CategoryImage();
break;
case ImagesCreateOrUpdateEvent::TYPE_CONTENT:
$model = new ContentImage();
break;
case ImagesCreateOrUpdateEvent::TYPE_FOLDER:
$model = new FolderImage();
break;
default:
$model = null;
}
return $model;
}
/**
* Get image model query from type
*
* @param string $parentType
*
* @return null|\Thelia\Model\CategoryImageQuery|\Thelia\Model\ContentImageQuery|\Thelia\Model\FolderImageQuery|\Thelia\Model\ProductImageQuery
*
* @todo refactor make all pictures using propel inheritance and factorise image behaviour into one single clean action
*/
public function getImageModelQuery($parentType)
{
switch ($parentType) {
case ImagesCreateOrUpdateEvent::TYPE_PRODUCT:
$model = new ProductImageQuery();
break;
case ImagesCreateOrUpdateEvent::TYPE_CATEGORY:
$model = new CategoryImageQuery();
break;
case ImagesCreateOrUpdateEvent::TYPE_CONTENT:
$model = new ContentImageQuery();
break;
case ImagesCreateOrUpdateEvent::TYPE_FOLDER:
$model = new FolderImageQuery();
break;
default:
$model = null;
}
return $model;
}
/**
* Get image parent model from type
*
* @param string $parentType
* @param int $parentId
*
* @return null|\Thelia\Model\Category|\Thelia\Model\Content|\Thelia\Model\Folder|\Thelia\Model\Product
*
* @todo refactor make all pictures using propel inheritance and factorise image behaviour into one single clean action
*/
public function getParentImageModel($parentType, $parentId)
{
switch ($parentType) {
case ImagesCreateOrUpdateEvent::TYPE_PRODUCT:
$model = ProductQuery::create()->findPk($parentId);
break;
case ImagesCreateOrUpdateEvent::TYPE_CATEGORY:
$model = CategoryQuery::create()->findPk($parentId);
break;
case ImagesCreateOrUpdateEvent::TYPE_CONTENT:
$model = ContentQuery::create()->findPk($parentId);
break;
case ImagesCreateOrUpdateEvent::TYPE_FOLDER:
$model = FolderQuery::create()->findPk($parentId);
break;
default:
$model = null;
}
return $model;
}
/**
* Get image parent model from type
*
* @param string $parentType Parent type
* @param Request $request Request service
*
* @todo refactor make all pictures using propel inheritance and factorise image behaviour into one single clean action
* @return ProductImageModification|CategoryImageModification|ContentImageModification|FolderImageModification
*/
public function getImageForm($parentType, Request $request)
{
switch ($parentType) {
case ImagesCreateOrUpdateEvent::TYPE_PRODUCT:
$form = new ProductImageModification($request);
break;
case ImagesCreateOrUpdateEvent::TYPE_CATEGORY:
$form = new CategoryImageModification($request);
break;
case ImagesCreateOrUpdateEvent::TYPE_CONTENT:
$form = new ContentImageModification($request);
break;
case ImagesCreateOrUpdateEvent::TYPE_FOLDER:
$form = new FolderImageModification($request);
break;
default:
$model = null;
}
return $form;
}
/**
* Get image upload dir
*
* @param string $parentType Parent type
*
* @return string Uri
*/
public function getUploadDir($parentType)
{
switch ($parentType) {
case ImagesCreateOrUpdateEvent::TYPE_PRODUCT:
$uri = THELIA_LOCAL_DIR . 'media/images/' . ImagesCreateOrUpdateEvent::TYPE_PRODUCT;
break;
case ImagesCreateOrUpdateEvent::TYPE_CATEGORY:
$uri = THELIA_LOCAL_DIR . 'media/images/' . ImagesCreateOrUpdateEvent::TYPE_CATEGORY;
break;
case ImagesCreateOrUpdateEvent::TYPE_CONTENT:
$uri = THELIA_LOCAL_DIR . 'media/images/' . ImagesCreateOrUpdateEvent::TYPE_CONTENT;
break;
case ImagesCreateOrUpdateEvent::TYPE_FOLDER:
$uri = THELIA_LOCAL_DIR . 'media/images/' . ImagesCreateOrUpdateEvent::TYPE_FOLDER;
break;
default:
$uri = null;
}
return $uri;
}
/**
* Deduce image redirecting URL from parent type
*
* @param string $parentType Parent type
* @param int $parentId Parent id
* @return string
*/
public function getRedirectionUrl($parentType, $parentId)
{
switch ($parentType) {
case ImagesCreateOrUpdateEvent::TYPE_PRODUCT:
$uri = '/admin/products/update?product_id=' . $parentId;
break;
case ImagesCreateOrUpdateEvent::TYPE_CATEGORY:
$uri = '/admin/categories/update?category_id=' . $parentId;
break;
case ImagesCreateOrUpdateEvent::TYPE_CONTENT:
$uri = '/admin/content/update/' . $parentId;
break;
case ImagesCreateOrUpdateEvent::TYPE_FOLDER:
$uri = '/admin/folders/update/' . $parentId;
break;
default:
$uri = false;
}
return $uri;
}
/** @var array Available image parent type */
public static $availableType = array(
self::TYPE_PRODUCT,
self::TYPE_CATEGORY,
self::TYPE_CONTENT,
self::TYPE_FOLDER,
self::TYPE_MODULE
);
/**
* Rename file with image model id
*
* @param int $modelId Model id
* @param UploadedFile $uploadedFile File being saved
*
* @return string
*/
public function renameFile($modelId, $uploadedFile)
{
$extension = $uploadedFile->getClientOriginalExtension();
$fileName = $this->sanitizeFileName(
str_replace('.' . $extension, '', $uploadedFile->getClientOriginalName()) . "-" . $modelId . "." . strtolower(
$extension
)
);
return $fileName;
}
/**
* Check if a file is an image
* Check based on mime type
*
* @param string $mimeType File mime type
*
* @return bool
*/
public function isImage($mimeType)
{
$isValid = false;
$allowedType = array('image/jpeg' , 'image/png' ,'image/gif');
if (in_array($mimeType, $allowedType)) {
$isValid = true;
}
return $isValid;
}
}

View File

@@ -23,6 +23,8 @@
namespace Thelia\Tools;
use Propel\Runtime\ActiveQuery\ModelCriteria;
use Propel\Runtime\ActiveRecord\ActiveRecordInterface;
use Thelia\Model\Lang;
/**
@@ -54,4 +56,39 @@ class I18n
return \DateTime::createFromFormat($currentDateFormat, $date);
}
public static function forceI18nRetrieving($askedLocale, $modelName, $id, $needed = array('Title'))
{
$i18nQueryClass = sprintf("\\Thelia\\Model\\%sI18nQuery", $modelName);
$i18nClass = sprintf("\\Thelia\\Model\\%sI18n", $modelName);
/* get customer language translation */
$i18n = $i18nQueryClass::create()
->filterById($id)
->filterByLocale(
$askedLocale
)->findOne();
/* or default translation */
if(null === $i18n) {
$i18n = $i18nQueryClass::create()
->filterById($id)
->filterByLocale(
Lang::getDefaultLanguage()->getLocale()
)->findOne();
}
if(null === $i18n) { // @todo something else ?
$i18n = new $i18nClass();;
$i18n->setId($id);
foreach($needed as $need) {
$method = sprintf('set%s', $need);
if(method_exists($i18n, $method)) {
$i18n->$method('DEFAULT ' . strtoupper($need));
} else {
// @todo throw sg ?
}
}
}
return $i18n;
}
}

View File

@@ -26,7 +26,7 @@ class ResponseRest extends Response
* Constructor.
*
* @param array $data Array to be serialized
* @param string $format serialization format, xml or json available
* @param string $format serialization format, text, xml or json available
* @param integer $status The response status code
* @param array $headers An array of response headers
*
@@ -38,14 +38,22 @@ class ResponseRest extends Response
{
parent::__construct('', $status, $headers);
$this->format = $format;
$serializer = $this->getSerializer();
if ($format == 'text') {
if (isset($data)) {
$this->setContent($data);
}
if (isset($data)) {
$this->setContent($serializer->serialize($data, $this->format));
$this->headers->set('Content-Type', 'text/plain');
} else {
$this->format = $format;
$serializer = $this->getSerializer();
if (isset($data)) {
$this->setContent($serializer->serialize($data, $this->format));
}
$this->headers->set('Content-Type', 'application/' . $this->format);
}
$this->headers->set('Content-Type', 'application/' . $this->format);
}
/**

View File

@@ -71,6 +71,15 @@ class Cheque extends BaseModule implements PaymentModuleInterface
if(ModuleImageQuery::create()->filterByModule($module)->count() == 0) {
$this->deployImageFolder($module, sprintf('%s/images', __DIR__));
}
/* set module title */
$this->setTitle(
$module,
array(
"en_US" => "Cheque",
"fr_FR" => "Cheque",
)
);
}
public function destroy()

0
local/modules/Cheque/images/cheque.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@@ -71,6 +71,15 @@ class FakeCB extends BaseModule implements PaymentModuleInterface
if(ModuleImageQuery::create()->filterByModule($module)->count() == 0) {
$this->deployImageFolder($module, sprintf('%s/images', __DIR__));
}
/* set module title */
$this->setTitle(
$module,
array(
"en_US" => "Credit Card",
"fr_FR" => "Carte de crédit",
)
);
}
public function destroy()

0
local/modules/FakeCB/images/mastercard.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

0
local/modules/FakeCB/images/visa.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -85,7 +85,7 @@ $(function($){
couponManager.createOrUpdateRuleAjax();
}
}
return false;
});
};
couponManager.onClickSaveRule();
@@ -96,6 +96,7 @@ $(function($){
e.preventDefault();
var $this = $(this);
couponManager.removeRuleAjax($this.attr('data-int'));
return false;
});
};
couponManager.onClickDeleteRule();
@@ -109,6 +110,7 @@ $(function($){
// Hide row being updated
$this.parent().parent().remove();
return false;
});
};
couponManager.onClickUpdateRule();

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,99 @@
$(function($){
// Manage picture upload
$.imageUploadManager = {};
Dropzone.autoDiscover = false;
// Remove image on click
$.imageUploadManager.initImageDropZone = function() {
var imageDropzone = new Dropzone("#images-dropzone", {
dictDefaultMessage : $('.btn-browse').html(),
uploadMultiple: false,
maxFilesize: 8,
acceptedFiles: 'image/png, image/gif, image/jpeg'
});
var totalFiles = 0,
completedFiles = 0;
imageDropzone.on("addedfile", function(file){
totalFiles += 1;
if(totalFiles == 1){
$('.dz-message').hide();
}
});
imageDropzone.on("complete", function(file){
completedFiles += 1;
if (completedFiles === totalFiles){
$('.dz-message').slideDown();
}
});
imageDropzone.on("success", function(file) {
imageDropzone.removeFile(file);
$.imageUploadManager.updateImageListAjax();
$.imageUploadManager.onClickDeleteImage();
});
};
// Update picture list via AJAX call
$.imageUploadManager.updateImageListAjax = function() {
var $imageListArea = $(".image-manager .existing-image");
$imageListArea.html('<div class="loading" ></div>');
$.ajax({
type: "POST",
url: imageListUrl,
statusCode: {
404: function() {
$imageListArea.html(
imageListErrorMessage
);
}
}
}).done(function(data) {
$imageListArea.html(
data
);
});
};
// Remove image on click
$.imageUploadManager.onClickDeleteImage = function() {
$('.image-manager .image-delete-btn').on('click', function (e) {
e.preventDefault();
var $this = $(this);
var $parent = $this.parent();
$parent.find('a').remove();
$parent.append('<div class="loading" ></div>');
var $url = $this.attr("href");
var errorMessage = $this.attr("data-error-message");
$.ajax({
type: "POST",
url: $url,
statusCode: {
404: function() {
$(".image-manager .message").html(
errorMessage
);
}
}
}).done(function(data) {
$parent.parents('tr').remove();
$(".image-manager .message").html(
data
);
});
return false;
});
};
$.imageUploadManager.onClickDeleteImage();
});

View File

@@ -0,0 +1,160 @@
.dropzone{
cursor: pointer;
border: 4px dashed @gray-lighter;
padding: 70px;
margin: 20px 0;
&.dz-drag-hover{
border-color: @brand-primary;
}
.dz-message {
text-align: center;
span{
font-size: @font-size-large;
display: block;
color: @gray;
span{
display: block;
font-weight: bold;
margin: 10px 0;
font-size: @font-size-small;
}
button{
span{
display: inline-block;
font-size: @font-size-base;
margin: 0;
color: inherit;
}
}
}
}
.dz-error{
.alert();
.alert-danger();
margin: 10px 0;
}
.dz-preview,
.dropzone-previews .dz-preview {
background: rgba(255,255,255,0.8);
position: relative;
display: inline-block;
margin: 17px;
vertical-align: top;
border: 1px solid #acacac;
padding: 6px 6px 6px 6px;
}
.dz-preview.dz-file-preview [data-dz-thumbnail],
.dropzone-previews .dz-preview.dz-file-preview [data-dz-thumbnail] {
display: none;
}
.dz-preview .dz-details,
.dropzone-previews .dz-preview .dz-details {
width: 100px;
height: 100px;
position: relative;
background: #ebebeb;
padding: 5px;
margin-bottom: 22px;
}
.dz-preview .dz-details .dz-filename,
.dropzone-previews .dz-preview .dz-details .dz-filename {
overflow: hidden;
height: 100%;
}
.dz-preview .dz-details img,
.dropzone-previews .dz-preview .dz-details img {
position: absolute;
top: 0;
left: 0;
width: 100px;
height: 100px;
}
.dz-preview .dz-details .dz-size,
.dropzone-previews .dz-preview .dz-details .dz-size {
position: absolute;
bottom: -28px;
left: 3px;
height: 28px;
line-height: 28px;
}
.dz-preview.dz-error .dz-error-mark,
.dropzone-previews .dz-preview.dz-error .dz-error-mark {
display: block;
}
.dz-preview.dz-success .dz-success-mark,
.dropzone-previews .dz-preview.dz-success .dz-success-mark {
display: block;
}
.dz-preview:hover .dz-details img,
.dropzone-previews .dz-preview:hover .dz-details img {
display: none;
}
.dz-preview .dz-success-mark,
.dropzone-previews .dz-preview .dz-success-mark,
.dz-preview .dz-error-mark,
.dropzone-previews .dz-preview .dz-error-mark {
display: none;
position: absolute;
width: 40px;
height: 40px;
font-size: 30px;
text-align: center;
right: -10px;
top: -10px;
}
.dz-preview .dz-success-mark,
.dropzone-previews .dz-preview .dz-success-mark {
color: #8cc657;
}
.dz-preview .dz-error-mark,
.dropzone-previews .dz-preview .dz-error-mark {
color: #ee162d;
}
.dz-preview .dz-progress,
.dropzone-previews .dz-preview .dz-progress {
position: absolute;
top: 100px;
left: 6px;
right: 6px;
height: 6px;
background: #d7d7d7;
display: none;
}
.dz-preview .dz-progress .dz-upload,
.dropzone-previews .dz-preview .dz-progress .dz-upload {
position: absolute;
top: 0;
bottom: 0;
left: 0;
width: 0%;
background-color: #8cc657;
}
.dz-preview.dz-processing .dz-progress,
.dropzone-previews .dz-preview.dz-processing .dz-progress {
display: block;
}
.dz-preview .dz-error-message,
.dropzone-previews .dz-preview .dz-error-message {
display: none;
position: absolute;
top: -5px;
left: -20px;
background: rgba(245,245,245,0.8);
padding: 8px 10px;
color: #800;
min-width: 140px;
max-width: 500px;
z-index: 500;
}
.dz-preview:hover.dz-error .dz-error-message,
.dropzone-previews .dz-preview:hover.dz-error .dz-error-message {
display: block;
}
}

View File

@@ -14,6 +14,7 @@
@import "bootstrap-switch.less";
@import "bootstrap-select.less";
@import "jqplot.less";
@import "dropzone.less";
// -- Base styling ------------------------------------------------------------

View File

@@ -256,7 +256,8 @@
</div>
<div class="tab-pane fade {if $current_tab == 'images'}active in{/if}" id="images">
</div>
{include file='includes/image-upload-form.html' imageType='category' parentId=$category_id}
</div>
<div class="tab-pane fade {if $current_tab == 'documents'}active in{/if}" id="documents">
</div>
@@ -296,6 +297,14 @@
{/block}
{block name="javascript-initialization"}
{javascripts file='assets/js/dropzone.js'}
<script src="{$asset_url}"></script>
{/javascripts}
{javascripts file='assets/js/image-upload.js'}
<script src="{$asset_url}"></script>
{/javascripts}
<script src="{url file='/tinymce/tinymce.min.js'}"></script>
<script>
@@ -315,11 +324,9 @@
filemanager_title:"{intl l='Files manager'}" ,
external_plugins: { "filemanager" : "{url file='/tinymce/plugins/filemanager/plugin.min.js'}"}
});
</script>
<script>
$(function() {
$.imageUploadManager.initImageDropZone();
$('.use_default_rewriten_url').click(function(ev) {
alert("Not functionnal");

View File

@@ -0,0 +1,352 @@
{extends file="admin-layout.tpl"}
{block name="check-permissions"}admin.content.view{/block}
{block name="page-title"}{intl l='Edit content'}{/block}
{block name="main-content"}
<div class="folder edit-folder">
<div id="wrapper" class="container">
{* include file="includes/folder-breadcrumb.html" editing_category="true" *}
<div class="row">
{loop name="content_edit" type="content" visible="*" id="{$content_id}" backend_context="1" lang="$edit_language_id"}
<div class="col-md-12 general-block-decorator">
<div class="row">
<div class="col-md-7 title">
{intl l='Edit content %title' title=$TITLE}
</div>
<div class="col-md-5 actions">
{if $HAS_PREVIOUS != 0}
<a href="{url path="/admin/content/update/$PREVIOUS"}" class="btn btn-default" title="{intl l='Edit previous content'}"><span class="glyphicon glyphicon-arrow-left"></span></a>
{else}
<a href="#" disabled="disabled" class="btn btn-default"><span class="glyphicon glyphicon-arrow-left"></span></a>
{/if}
<a href="{$URL}" target="_blank" class="btn btn-default" title="{intl l='Preview folder page'}"><span class="glyphicon glyphicon-eye-open"></span></a>
{if $HAS_NEXT != 0}
<a href="{url path="/admin/content/update/$NEXT"}" class="btn btn-default" title="{intl l='Edit next content'}"><span class="glyphicon glyphicon-arrow-right"></span></a>
{else}
<a href="#" disabled="disabled" class="btn btn-default"><span class="glyphicon glyphicon-arrow-right"></span></a>
{/if}
</div>
</div>
<div class="row">
<div class="col-md-12">
<ul class="nav nav-tabs" id="tabbed-menu">
<li class="active"><a href="#general" data-toggle="tab">{intl l="General description"}</a></li>
<li><a href="#details" data-toggle="tab">{intl l="Details"}</a></li>
<li><a href="#images" data-toggle="tab">{intl l="Images"}</a></li>
<li><a href="#documents" data-toggle="tab">{intl l="Documents"}</a></li>
<li><a href="#modules" data-toggle="tab">{intl l="Modules"}</a></li>
</ul>
<div class="tab-content">
<div class="tab-pane fade active in" id="general">
<div class="form-container">
{form name="thelia.admin.content.modification"}
<form method="POST" action="{url path='/admin/content/save'}" {form_enctype form=$form} class="clearfix">
{include file="includes/inner-form-toolbar.html" close_url="{url path='/admin/folders' parent=0}"}
{* Be sure to get the folder ID, even if the form could not be validated *}
<input type="hidden" name="content_id" value="{$content_id}" />
<input type="hidden" name="current_tab" value="general" />
{form_hidden_fields form=$form}
{form_field form=$form field='success_url'}
<input type="hidden" name="{$name}" value="{url path="/admin/content/update{$ID}"}" />
{/form_field}
{form_field form=$form field='locale'}
<input type="hidden" name="{$name}" value="{$edit_language_locale}" />
{/form_field}
{if $form_error}<div class="alert alert-danger">{$form_error_message}</div>{/if}
{include file="includes/standard-description-form-fields.html"}
{form_field form=$form field='url'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">
{intl l="{$label}"} :
</label>
<input type="text" id="{$label_attr.for}" required="required" name="{$name}" value="{$value}" title="{intl l='Rewritten URL'}" placeholder="{intl l='Rewriten URL'}" class="form-control">
</div>
{/form_field}
<div class="row">
<div class="col-md-6">
{form_field form=$form field='default_folder'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">
{intl l="{$label}"} :
</label>
<select id="{$label_attr.for}" required="required" name="{$name}" class="form-control">
<option value="0">{intl l="Top level"}</option>
{$myparent=$DEFAULT_FOLDER}
{loop name="fold-parent" type="folder-tree" visible="*" folder="0"}
<option value="{$ID}" style="padding-left: {3 + $LEVEL * 20}px" {if $myparent == $ID}selected="selected"{/if} {if $folder_id == $ID}disabled="disabled"{/if}>{$TITLE}</option>
{/loop }
</select>
</div>
{/form_field}
</div>
<div class="col-md-6">
{form_field form=$form field='visible'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{intl l='Visibility'}</label>
<div class="checkbox">
<label>
<input type="checkbox" id="{$label_attr.for}" name="{$name}" value="1" {if $value != 0}checked="checked"{/if}>
{$label}
</label>
</div>
</div>
{/form_field}
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="control-group">
<lablel>&nbsp;</lablel>
<div class="controls">
<p>{intl l='Colder created on %date_create. Last modification: %date_change' date_create="{format_date date=$CREATE_DATE}" date_change="{format_date date=$UPDATE_DATE}"}</p>
</div>
</div>
</div>
</div>
</form>
{/form}
</div>
</div>
<div class="tab-pane fade" id="details">
<div class="form-container">
<div class="form-group">
<form action="{url path='/admin/folders/related-content/add'}" id="related_content_form">
{include
file="includes/inner-form-toolbar.html"
hide_submit_buttons=true
close_url="{url path='/admin/folders' folder_id=$folder_id}"
}
<input type="hidden" name="folder_id" value="{$folder_id}" />
<input type="hidden" name="current_tab" value="details" />
{ifloop rel="folders"}
<div class="row">
<div class="col-md-6">
<div class="form-group">
<select name="folder_id" id="folder_id" class="form-control">
<option value="">Select a folder...</option>
{loop name="folders" type="folder" backend_context="1" lang="$edit_language_id"}
<option value="{$ID}">{$TITLE}</option>
{/loop}
</select>
</div>
<span class="help-block">{intl l='Select a folder to get its content'}</span>
</div>
<div class="col-md-6">
<div id="content_selector" class="hide">
<div class="input-group">
<select required="required" name="content_id" id="content_id" class="form-control">
<option value="">Select a folder content...</option>
</select>
<span class="input-group-btn" id="content_add_button">
<button class="btn btn-default btn-primary action-btn" type="submit"><span class="glyphicon glyphicon-plus-sign"></span></button>
</span>
</div>
<span class="help-block">{intl l='Select a content and click (+) to add it to this category'}</span>
</div>
</div>
</div>
{/ifloop}
{elseloop rel="folders"}
<div class="alert alert-info">{intl l="No folders found"}</div>
{/elseloop}
</form>
</div>
<table class="table table-striped table-condensed table-left-aligned">
<thead>
<tr>
<th>{intl l='ID'}</th>
<th>{intl l='Attribute title'}</th>
{module_include location='folder_contents_table_header'}
<th class="actions">{intl l="Actions"}</th>
</tr>
</thead>
<tbody>
{*loop name="assigned_contents" type="associated_content" folder="$folder_id" backend_context="1" lang="$edit_language_id"}
<tr>
<td>{$ID}</td>
<td>
{$TITLE}
</td>
{module_include location='folder_contents_table_row'}
<td class="actions">
<div class="btn-group">
{loop type="auth" name="can_create" roles="ADMIN" permissions="admin.configuration.folder.content.delete"}
<a class="btn btn-default btn-xs delete-content" title="{intl l='Delete this content'}" href="#delete_content_dialog" data-id="{$ID}" data-toggle="modal">
<span class="glyphicon glyphicon-trash"></span>
</a>
{/loop}
</div>
</td>
</tr>
{/loop}
{elseloop rel="assigned_contents"}
<tr>
<td colspan="3">
<div class="alert alert-info">
{intl l="This folder contains no contents"}
</div>
</td>
</tr>
{/elseloop*}
</tbody>
</table>
</div>
</div>
<div class="tab-pane fade" id="images">
{include file='includes/image-upload-form.html' imageType='content' parentId=$content_id}
</div>
<div class="tab-pane fade" id="documents">
</div>
<div class="tab-pane fade" id="modules">
</div>
</div>
</div>
</div>
</div>
{/loop}
</div>
</div>
</div>
{* Delete related content confirmation dialog *}
{capture "delete_content_dialog"}
<!-- <input type="hidden" name="category_id" value="{$category_id}" /> -->
<input type="hidden" name="content_id" id="content_delete_id" value="" />
<input type="hidden" name="folder_id" id="folder_delete_id" value="" />
<input type="hidden" name="current_tab" value="details" />
{/capture}
{include
file = "includes/generic-confirm-dialog.html"
dialog_id = "delete_content_dialog"
dialog_title = {intl l="Remove related content"}
dialog_message = {intl l="Do you really want to remove this related content ?"}
form_action = {url path='/admin/folders/related-content/delete'}
form_content = {$smarty.capture.delete_content_dialog nofilter}
}
{/block}
{block name="javascript-initialization"}
{javascripts file='assets/js/dropzone.js'}
<script src="{$asset_url}"></script>
{/javascripts}
{javascripts file='assets/js/image-upload.js'}
<script src="{$asset_url}"></script>
{/javascripts}
<script>
$(function() {
$.imageUploadManager.initImageDropZone();
$('.use_default_rewriten_url').click(function(ev) {
alert("Not functionnal");
ev.preventDefault();
});
// Show proper tab, if defined
{if ! empty($current_tab)}
$('#tabbed-menu a[href="#{$current_tab}"]').tab('show')
{/if}
// Set proper content ID in delete content from
$('a.delete-content').click(function(ev) {
$('#content_delete_id').val($(this).data('id'));
$('#folder_delete_id').val($('#folder_id').val());
});
// Load content on folder selection
$('#folder_id').change(function(event) {
$.ajax({
url : '{url path="/admin/folder/$folder_id/available-related-content/"}' + $(this).val() + '.xml',
type : 'get',
dataType : 'json',
success : function(json) {
$('#content_id :not(:first-child)').remove();
var have_content = false;
$.each(json, function(idx, value) {
$('#content_id').append($('<option>').text(value.title).attr('value', value.id));
have_content = true; // Lame...
});
if (have_content)
$('#content_selector').removeClass('hide');
else
$('#content_selector').addClass('hide');
}
});
});
// Initialize folder (id={$folder_id}) select value
{if $folder_id != 0}
$('#folder_id').val("{$folder_id}").change();
{/if}
});
</script>
{/block}

View File

@@ -21,7 +21,7 @@
<div class="col-md-5 actions">
{if $HAS_PREVIOUS != 0}
<a href="{url path='/admin/folders/update' folder_id=$PREVIOUS}" class="btn btn-default" title="{intl l='Edit previous folder'}"><span class="glyphicon glyphicon-arrow-left"></span></a>
<a href="{url path="/admin/folders/update/$PREVIOUS"}" class="btn btn-default" title="{intl l='Edit previous folder'}"><span class="glyphicon glyphicon-arrow-left"></span></a>
{else}
<a href="#" disabled="disabled" class="btn btn-default"><span class="glyphicon glyphicon-arrow-left"></span></a>
{/if}
@@ -29,7 +29,7 @@
<a href="{$URL}" target="_blank" class="btn btn-default" title="{intl l='Preview folder page'}"><span class="glyphicon glyphicon-eye-open"></span></a>
{if $HAS_NEXT != 0}
<a href="{url path='/admin/folders/update' folder_id=$NEXT}" class="btn btn-default" title="{intl l='Edit next folder'}"><span class="glyphicon glyphicon-arrow-right"></span></a>
<a href="{url path="/admin/folders/update/$NEXT"}" class="btn btn-default" title="{intl l='Edit next folder'}"><span class="glyphicon glyphicon-arrow-right"></span></a>
{else}
<a href="#" disabled="disabled" class="btn btn-default"><span class="glyphicon glyphicon-arrow-right"></span></a>
{/if}
@@ -67,7 +67,7 @@
{form_hidden_fields form=$form}
{form_field form=$form field='success_url'}
<input type="hidden" name="{$name}" value="{url path='/admin/folder' folder_id={$folder_id}}" />
<input type="hidden" name="{$name}" value="{url path="/admin/folders/update{$ID}"}" />
{/form_field}
{form_field form=$form field='locale'}
@@ -101,9 +101,9 @@
<option value="0">{intl l="Top level"}</option>
{$myparent=$PARENT}
{loop name="fold-parent" type="folder-tree" visible="*" folder="0"}
{* loop name="fold-parent" type="folder-tree" visible="*" folder="0"}
<option value="{$ID}" style="padding-left: {3 + $LEVEL * 20}px" {if $myparent == $ID}selected="selected"{/if} {if $folder_id == $ID}disabled="disabled"{/if}>{$TITLE}</option>
{/loop}
{/loop *}
</select>
</div>
@@ -209,7 +209,7 @@
</thead>
<tbody>
{loop name="assigned_contents" type="associated_content" folder="$folder_id" backend_context="1" lang="$edit_language_id"}
{*loop name="assigned_contents" type="associated_content" folder="$folder_id" backend_context="1" lang="$edit_language_id"}
<tr>
<td>{$ID}</td>
@@ -239,13 +239,14 @@
</div>
</td>
</tr>
{/elseloop}
{/elseloop*}
</tbody>
</table>
</div>
</div>
<div class="tab-pane fade" id="images">
{include file='includes/image-upload-form.html' imageType='folder' parentId=$folder_id}
</div>
<div class="tab-pane fade" id="documents">
@@ -286,59 +287,65 @@
{/block}
{block name="javascript-initialization"}
<script>
{javascripts file='assets/js/dropzone.js'}
<script src="{$asset_url}"></script>
{/javascripts}
{javascripts file='assets/js/image-upload.js'}
<script src="{$asset_url}"></script>
{/javascripts}
<script>
$(function() {
$.imageUploadManager.initImageDropZone();
$(function() {
$('.use_default_rewriten_url').click(function(ev) {
alert("Not functionnal");
$('.use_default_rewriten_url').click(function(ev) {
alert("Not functionnal");
ev.preventDefault();
});
ev.preventDefault();
});
// Show proper tab, if defined
{if ! empty($current_tab)}
$('#tabbed-menu a[href="#{$current_tab}"]').tab('show')
{/if}
// Show proper tab, if defined
{if ! empty($current_tab)}
$('#tabbed-menu a[href="#{$current_tab}"]').tab('show')
{/if}
// Set proper content ID in delete content from
$('a.delete-content').click(function(ev) {
$('#content_delete_id').val($(this).data('id'));
$('#folder_delete_id').val($('#folder_id').val());
});
// Set proper content ID in delete content from
$('a.delete-content').click(function(ev) {
$('#content_delete_id').val($(this).data('id'));
$('#folder_delete_id').val($('#folder_id').val());
});
// Load content on folder selection
$('#folder_id').change(function(event) {
$.ajax({
url : '{url path="/admin/folder/$folder_id/available-related-content/"}' + $(this).val() + '.xml',
type : 'get',
dataType : 'json',
success : function(json) {
$('#content_id :not(:first-child)').remove();
// Load content on folder selection
$('#folder_id').change(function(event) {
$.ajax({
url : '{url path="/admin/folder/$folder_id/available-related-content/"}' + $(this).val() + '.xml',
type : 'get',
dataType : 'json',
success : function(json) {
$('#content_id :not(:first-child)').remove();
var have_content = false;
var have_content = false;
$.each(json, function(idx, value) {
$('#content_id').append($('<option>').text(value.title).attr('value', value.id));
$.each(json, function(idx, value) {
$('#content_id').append($('<option>').text(value.title).attr('value', value.id));
have_content = true; // Lame...
});
have_content = true; // Lame...
});
if (have_content)
$('#content_selector').removeClass('hide');
else
$('#content_selector').addClass('hide');
if (have_content)
$('#content_selector').removeClass('hide');
else
$('#content_selector').addClass('hide');
}
});
});
// Initialize folder (id={$folder_id}) select value
{if $folder_id != 0}
$('#folder_id').val("{$folder_id}").change();
{/if}
}
});
});
// Initialize folder (id={$folder_id}) select value
{if $folder_id != 0}
$('#folder_id').val("{$folder_id}").change();
{/if}
});
</script>
</script>
{/block}

View File

@@ -0,0 +1,149 @@
{extends file="admin-layout.tpl"}
{block name="page-title"}{intl l='Edit an image'}{/block}
{block name="check-permissions"}admin.image.edit{/block}
{block name="main-content"}
<div class="customers edit-image">
<div id="wrapper" class="container">
{loop type="image" name="image_edit" source="{$imageType}" id="{$imageId}" width="580" backend_context="1" lang="$edit_language_id"}
<ul class="breadcrumb">
<li><a href="{url path='/admin/home'}">{intl l="Home"}</a></li>
<li><a href="{url path="{$redirectUrl}"}">{intl l="Image"}</a></li>
<li>{intl l='Editing image "%name"' name="{$TITLE}"}</li>
</ul>
<div class="row">
<div class="col-md-12 general-block-decorator">
<div class="row">
<div class="col-md-12 title title-without-tabs">
{intl l="Edit image $TITLE"}
</div>
<div class="form-container">
<div class="col-md-12">
{form name="thelia.admin.category.image.modification"}
<form method="POST" action="{url path="/admin/image/type/{$imageType}/{$ID}/update"}" enctype="multipart/form-data" class="clearfix">
<div class="row inner-toolbar clearfix">
<div class="col-md-6 inner-actions pull-right">
<button type="submit" name="save_mode" value="stay" class="btn btn-default btn-primary" title="{intl l='Save'}">{intl l='Save'} <span class="glyphicon glyphicon-ok"></span></button>
<a href="{url path="{$redirectUrl}"}" class="btn btn-default btn-info">{intl l='Close'} <span class="glyphicon glyphicon-remove"></span></a>
</div>
</div>
{form_hidden_fields form=$form}
{form_field form=$form field='success_url'}
<input type="hidden" name="{$name}" value="{url path="/admin/image/type/{$imageType}/{$ID}/update"}" />
{/form_field}
{if $form_error}<div class="alert alert-danger">{$form_error_message}</div>{/if}
<p class="title title-without-tabs">{intl l="Image informations"}</p>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label class="control-label">{intl l="Preview"} : </label>
<p><img src="{$IMAGE_URL}" alt="{$TITLE}" class="img-thumbnail"></p>
</div>
</div>
<div class="col-md-6">
{form_field form=$form field='file'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
<input type="file" id="{$label_attr.for}" name="{$name}" class="form-control" value="" title="{intl l="{$label}"}" placeholder="{intl l='File'}">
</div>
{/form_field}
{form_field form=$form field='title'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
<input type="text" id="{$label_attr.for}" name="{$name}" class="form-control" value="{$TITLE}" title="{intl l="{$label}"}" placeholder="{intl l='Title'}">
</div>
{/form_field}
{form_field form=$form field='chapo'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
<textarea id="{$label_attr.for}" name="{$name}" class="form-control" title="{intl l="{$label}"}" placeholder="{intl l='Chapo'}">{$CHAPO}</textarea>
</div>
{/form_field}
{form_field form=$form field='postscriptum'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
<textarea id="{$label_attr.for}" name="{$name}" class="form-control" title="{intl l="{$label}"}" placeholder="{intl l='Post Scriptum'}">{$POSTSCRIPTUM}</textarea>
</div>
{/form_field}
</div>
</div>
<div class="row">
<div class="col-md-12">
{form_field form=$form field='description'}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{intl l="{$label}"} : </label>
<textarea id="{$label_attr.for}" name="{$name}" class="form-control wysiwyg" title="{intl l="{$label}"}" placeholder="{intl l='Description'}">{$DESCRIPTION}</textarea>
</div>
{/form_field}
</div>
</div>
</form>
{/form}
</div>
</div>
</div>
</div>
</div>
{/loop}
{elseloop rel="image_edit"}
<div class="row">
<div class="col-md-12">
<div class="alert alert-error">
{intl l="Sorry, image ID=$imageId was not found."}
</div>
</div>
</div>
{/elseloop}
</div>
</div>
{/block}
{block name="javascript-initialization"}
{javascripts file='assets/js/main.js'}
<script src="{$asset_url}"></script>
{/javascripts}
<script src="{url file='/tinymce/tinymce.min.js'}"></script>
<script>
tinymce.init({
selector: ".wysiwyg",
theme: "modern",
menubar : false,
language: "",
plugins: [
"advlist autolink link image lists charmap print preview hr anchor pagebreak",
"searchreplace wordcount visualblocks visualchars insertdatetime media nonbreaking",
"table contextmenu directionality emoticons paste textcolor filemanager"
],
toolbar1: "undo redo | bold italic underline | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | styleselect | filemanager | link unlink anchor | image media | forecolor backcolor | print preview code ",
image_advtab: true ,
external_filemanager_path:"{url file='/tinymce/plugins/filemanager/'}'",
filemanager_title:"{intl l='Files manager'}" ,
external_plugins: { "filemanager" : "{url file='/tinymce/plugins/filemanager/plugin.min.js'}"}
});
</script>
{/block}

View File

@@ -12,6 +12,8 @@ A generic modal creation dialog template. Parameters
form_action = The form action URL. Form is submitted when OK button is clicked
form_enctype = The form encoding
form_error_message = The form error message (optional)
ok_button_id (optionnal) = the id of the OK button
*}
<div class="modal fade" id="{$dialog_id}" tabindex="-1" role="dialog" aria-hidden="true">
@@ -33,7 +35,7 @@ A generic modal creation dialog template. Parameters
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal" aria-hidden="true"><span class="glyphicon glyphicon-remove"></span> {$dialog_cancel_label|default:{intl l='Cancel'}}</button>
<button type="submit" class="btn btn-default btn-primary"><span class="glyphicon glyphicon-check"></span> {$dialog_ok_label|default:{intl l='OK'}}</button>
<button {if ! empty($ok_button_id)}id="{$ok_button_id}"{/if} type="submit" class="btn btn-default btn-primary"><span class="glyphicon glyphicon-check"></span> {$dialog_ok_label|default:{intl l='OK'}}</button>
</div>
</form>

View File

@@ -0,0 +1,33 @@
{*
A generic image upload form
Parameters:
imageType = Image type (category, product, folder, content, module)
parentId = Image parent id, ex: category id
*}
<div class="image-manager" >
<form action="{url path="/admin/image/type/$imageType/$parentId/save-ajax"}" class="dropzone" id="images-dropzone" enctype="multipart/form-data">
<div class="fallback">
<input name="file" type="file" multiple />
</div>
<div class="btn-browse hide">
{intl l="Drop files to upload"}
<span>Or</span>
<button type="button" class="btn btn-info btn-upload"><span class="glyphicon glyphicon-upload"></span> {intl l="Browse files"}</button>
</div>
</form>
<div class="existing-image">
{include file='includes/image-upload-list-ajax.html'}
</div>
</div>
<script>
var imageDropZoneUrl = "{url path="/admin/image/type/$imageType/$parentId/save-ajax"}";
var imageListUrl = "{url path="/admin/image/type/$imageType/$parentId/list-ajax"}";
var imageListErrorMessage = "{intl l='Can\'t load images, please refresh this page.'}";
</script>

View File

@@ -0,0 +1,31 @@
{*
A generic image upload form
Parameters:
imageType = Image type (category, product, folder, content, module)
parentId = Image parent id, ex: category id
*}
{ifloop rel="image"}
<table class="table table-striped table-condensed table-left-aligned">
{loop type="image" name="image" source="{$imageType}" order="manual-reverse" source_id="{$parentId}" width="200" height="100" resize_mode="borders"}
<tr>
<td>
<img src="{$IMAGE_URL}" alt="{$TITLE}" class="img-thumbnail">
</td>
<td>
<div class="btn-group">
<a class="image-update-btn btn btn-default btn-xs" href="{url path="/admin/image/type/$imageType/$ID/update"}" data-error-message="{intl l='Please retry'}">
<span class="glyphicon glyphicon-edit"></span>
</a>
<a class="image-delete-btn btn btn-default btn-xs" href="{url path="/admin/image/type/$imageType/delete/$ID"}" data-error-message="{intl l='Please retry'}">
<span class="glyphicon glyphicon-trash"></span>
</a>
</div>
<td>
</tr>
{/loop}
</table>
{/ifloop}

View File

@@ -37,6 +37,10 @@
{/form_field}
{/loop}
<p class="title title-without-tabs">{intl l='Default pricing'}</p>
<p>{intl l="The default pricing is used with product that do not have any combinations. It is also used for product with combinations which share the same pricing information"}</p>
<div class="row">
{* -- Pricing ------------------------------------------------------- *}
@@ -173,81 +177,193 @@
{* -- Attribute combinations -------------------------------------------- *}
<div class="row">
<div class="col-md-12">
{module_include location='product_before_combinations'}
<p class="title title-without-tabs">{intl l='Attribute Combinations'}</p>
<div class="row">
<div class="col-md-12">
<div class="well well-sm">
{module_include location='product_before_combinations'}
<table class="table table-striped table-condensed" id="category_list">
<caption>
{intl l='Attribute Combinations'}
{ifloop rel="product-attributes"}
<form method="POST" action="{url path='/admin/products/combinations/save'}" {form_enctype form=$form} class="clearfix">
<div class="well well-sm">
<p class="title title-without-tabs">{intl l='Create a new combination'}</p>
{module_include location='product_combinations_list_caption'}
<div class="form-group">
<label class="control-label">{intl l="Attribute"} : </label>
<select required="required" name="attribute_id" id="attribute_id" class="form-control">
<option value="">{intl l='Select an attribute...'}</option>
{loop name="product-attributes" type="attribute" product=$product_id backend_context="1" lang=$edit_language_id}
<option value="{$ID}">{$TITLE}</option>
{/loop}
</select>
<span class="help-block">{intl l='Select an attribute and click (+) to view available values'}</span>
</div>
{loop type="auth" name="can_create" roles="ADMIN" permissions="admin.products.update"}
<a class="btn btn-default btn-primary action-btn" title="{intl l='Add a new combination'}" href="#combination_creation_dialog" data-toggle="modal">
<span class="glyphicon glyphicon-plus-sign"></span>
</a>
{/loop}
</caption>
<thead>
<tr>
<th>{intl l='Attributes'}</th>
<th class="text-center">{intl l='Quantity'}</th>
<th class="text-center">{intl l='Price<br />w/o taxes (%currency)' currency=$currency_symbol}</th>
<th class="text-center">{intl l='Price<br />w/ taxes (%currency)' currency=$currency_symbol}</th>
<th class="text-center">{intl l='Weight (Kg)'}</th>
<th class="text-center">{intl l='Is new'}</th>
<th class="text-center">{intl l='On sale'}</th>
<th class="text-center">{intl l='Sale price<br />w/o taxes (%currency)' currency=$currency_symbol}</th>
<th class="text-center">{intl l='Sale price<br />w/ taxes (%currency)' currency=$currency_symbol}</th>
<th class="actions">{intl l='Actions'}</th>
</tr>
</thead>
<tbody>
{loop name="product.sales.elements" type="product_sale_elements" product=$product_id currency=$edit_currency_id}
<tr>
<td>
{loop name="product.sales.elements.combinations" type="attribute_combination" product_sale_elements=$ID}
{$ATTRIBUTE_TITLE}&nbsp;
{/loop}
</td>
<td><input class="form-control text-right" type="text" name="quantity[{$ID}]" value="{format_number number=$QUANTITY}" /></td>
<td><input class="form-control text-right" type="text" name="price_wo_taxes[{$ID}]" value="{format_number number=$PRICE_TAX}" /></td>
<td><input class="form-control text-right" type="text" name="price_w_taxes[{$ID}]" value="{format_number number=$TAXED_PRICE}" /></td>
<td><input class="form-control text-right" type="text" name="weight[{$ID}]" value="{format_number number=$WEIGHT}" /></td>
<td>
<div class="make-switch switch-small" data-on="success" data-off="danger" data-on-label="<i class='glyphicon glyphicon-ok'></i>" data-off-label="<i class='glyphicon glyphicon-remove'></i>">
<input class="change-default" type="radio" name="on_sale[{$ID}]" value="{$ID}" {if $IS_PROMO}checked="checked"{/if}/>
</div>
</td>
<td>
<div class="make-switch switch-small" data-on="success" data-off="danger" data-on-label="<i class='glyphicon glyphicon-ok'></i>" data-off-label="<i class='glyphicon glyphicon-remove'></i>">
<input class="change-default" type="radio" name="is_new[{$ID}]" value="{$ID}" {if $IS_NEW}checked="checked"{/if}/>
</div>
</td>
<td><input class="form-control text-right" type="text" name="sale_price_wo_taxes[{$ID}]" value="{format_number number=$PROMO_PRICE_TAX}" /></td>
<td><input class="form-control text-right" type="text" name="sale_price_w_taxes[{$ID}]" value="{format_number number=$TAXED_PROMO_PRICE}" /></td>
<td class="actions">
<a class="btn btn-default btn-xs combination-delete" title="{intl l='Delete this combination'}" href="#combination_delete_dialog" data-id="{$ID}" data-toggle="modal"><i class="glyphicon glyphicon-trash"></i></a>
</td>
</tr>
{/loop}
</tbody>
</table>
</div>
</div>
</div>
{module_include location='product_after_combinations'}
</div>
{* -- Adding a new combination ------------------------------------------------- *}
{* Capture the dialog body, to pass it to the generic dialog *}
{capture "combination_creation_dialog"}
<input type="hidden" name="product_id" value="{$product_id}" />
<input type="hidden" name="current_tab" value="details" />
<div class="form-group">
<label class="control-label">{intl l="Attribute"} : </label>
<select name="attribute_id" id="attribute_id" class="form-control">
<option value="">{intl l='Select an attribute...'}</option>
{loop name="product-attributes" type="attribute" product=$product_id backend_context="1" lang=$edit_language_id}
<option value="{$ID}">{$TITLE}</option>
{/loop}
</select>
<span class="help-block">{intl l='Select an attribute and click (+) to view available values'}</span>
</div>
<div id="attribute_value_selector" class="hide">
<div class="input-group">
{* <label class="control-label">{intl l="Attribute values"} : </label> *}
<div id="attribute_value_selector" class="hide">
<div class="input-group">
{* <label class="control-label">{intl l="Attribute values"} : </label> *}
<select required="required" name="attribute_value_id" id="attribute_value_id" class="form-control">
<option value="">{intl l='Select an attribute value...'}</option>
</select>
<select rname="attribute_value_id" id="attribute_value_id" class="form-control">
<option value="">{intl l='Select an attribute value...'}</option>
</select>
<span class="input-group-btn" id="add_attr_value_button">
<button class="btn btn-default btn-primary action-btn add-value-to-combination" type="button"><span class="glyphicon glyphicon-plus-sign"></span></button>
</span>
</div>
<span class="input-group-btn" id="add_attr_value_button">
<button class="btn btn-default btn-primary action-btn add-value-to-combination" type="button"><span class="glyphicon glyphicon-plus-sign"></span></button>
</span>
</div>
<span class="help-block">{intl l='Select a value click (+) to add it to the combination'}</span>
</div>
<span class="help-block">{intl l='Select a value click (+) to add it to the combination'}</span>
</div>
<div id="attribute_value_selector_empty" class="hide">
<div class="alert alert-info">
{intl l="No available value for this attribute"}
</div>
</div>
<div id="attribute_value_selector_empty" class="hide">
<div class="alert alert-info">
{intl l="No available value for this attribute"}
</div>
</div>
<div class="form-group">
<div class="alert alert-danger hide" id="combination_attributes_error"></div>
<div class="form-group">
<div class="alert alert-danger hide" id="combination_attributes_error"></div>
<select multiple="multiple" size="5" name="combination_attributes" id="combination_attributes" class="form-control">
</select>
<select required="required" multiple="multiple" size="5" name="combination_attributes[]" id="combination_attributes" class="form-control">
</select>
<div class="help-block">
{intl l='To remove a value from the combination, select it and click "remove"'}
<div class="help-block">
{intl l='To remove a value from the combination, select it and click "remove"'}
<div class="pull-right">
<button class="btn btn-info btn-xs remove-value-from-combination" type="button">
{intl l="Remove selected value"} <span class="glyphicon glyphicon-minus-sign"></span>
</button>
</div>
</div>
</div>
<div class="pull-right">
<button class="btn btn-info btn-xs remove-value-from-combination" type="button">
{intl l="Remove selected values"} <span class="glyphicon glyphicon-minus-sign"></span>
</button>
</div>
</div>
</div>
</div>
</form>
{/ifloop}
{form_field form=$form field='isnew'}
<div class="form-group {if $error}has-error{/if}">
<div class="checkbox">
<label>
<input type="checkbox" id="use_default_princing" name="use_default_princing" value="1">
{intl l="Use default princing for this combination (you can change this later)"}
</label>
</div>
</div>
{/form_field}
{elseloop rel="product-attributes"}
<div class="alert alert-info">
{intl l="No attributes are attached to this product."}
</div>
{/elseloop}
{/capture}
{module_include location='product_after_combinations'}
{include
file = "includes/generic-create-dialog.html"
</div> {* com *}
</div> {* row *}
</div>
dialog_id = "combination_creation_dialog"
dialog_title = {intl l="Create a new combination"}
dialog_body = {$smarty.capture.combination_creation_dialog nofilter}
dialog_ok_label = {intl l="Create this combination"}
form_action = {url path='/admin/product/combination/add'}
form_enctype = ''
form_error_message = ''
ok_button_id = "combination_creation_dialog_ok"
}
{* -- Delete combination confirmation dialog ----------------------------------- *}
{capture "combination_delete_dialog"}
<input type="hidden" name="product_id" value="{$product_id}" />
<input type="hidden" name="current_tab" value="details" />
<input type="hidden" name="combination_id" id="combination_delete_id" value="" />
{module_include location='category_delete_form'}
{/capture}
{include
file = "includes/generic-confirm-dialog.html"
dialog_id = "combination_delete_dialog"
dialog_title = {intl l="Delete a combunation"}
dialog_message = {intl l="Do you really want to delete this combination ?"}
form_action = {url path='/admin/product/combination/delete'}
form_content = {$smarty.capture.combination_delete_dialog nofilter}
}

View File

@@ -62,7 +62,14 @@
data-toggle="tab">{intl l="Associations"}</a>
</li>
<li><a href="#images" data-toggle="tab">{intl l="Images"}</a></li>
<li>
<a href="#images"
data-toggle="tab"
data-href="{url path="/admin/image/type/product/{$product_id}/form-ajax"}"
data-callback="$.imageUploadManager.initImageDropZone">
{intl l="Images"}
</a>
</li>
<li><a href="#documents" data-toggle="tab">{intl l="Documents"}</a></li>
<li><a href="#modules" data-toggle="tab">{intl l="Modules"}</a></li>
</ul>
@@ -109,9 +116,15 @@
{block name="javascript-initialization"}
{javascripts file='assets/js/bootstrap-editable/bootstrap-editable.js'}
<script src="{$asset_url}"></script>
{/javascripts}
{javascripts file='assets/js/dropzone.js'}
<script src="{$asset_url}"></script>
{/javascripts}
{javascripts file='assets/js/image-upload.js'}
<script src="{$asset_url}"></script>
{/javascripts}
{javascripts file='assets/js/bootstrap-editable/bootstrap-editable.js'}
<script src="{$asset_url}"></script>
{/javascripts}
<script src="{url file='/tinymce/tinymce.min.js'}"></script>
<script>
@@ -138,8 +151,10 @@ $(function() {
// Atomatic ajax tab load, if data-href is defined.
$('.nav-tabs a[data-href]').on('shown.bs.tab', function(ev) {
var zis = $(this);
$(zis.attr('href')).load(zis.data('href'));
var $this = $(this);
$($this.attr('href')).load($this.data('href'), function(ev) {
eval($this.data('callback') + '();');
});
});
// Load active tab
@@ -229,6 +244,17 @@ $(function() {
event.preventDefault();
});
// Set proper category ID in combination delete from
$('a.combination-delete').click(function(ev) {
$('#combination_delete_id').val($(this).data('id'));
});
// In create combination dialog, select all element of conbination list
$('#combination_creation_dialog_ok').click(function() {
$('#combination_attributes option').prop('selected', 'selected');
});
});
</script>

View File

@@ -1,10 +1,10 @@
<div class="toolbar toolbar-{$toolbar}" role="toolbar">
{if $toolbar == "top" }
<div class="sorter-container">
<span class="amount">9 Item(s)</span>
{*<span class="amount">9 {intl l="Item(s)"}</span>*}
<span class="limiter">
<label for="limit-top">Show</label>
<label for="limit-top">{intl l="Show"}</label>
<select id="limit-top" name="limit">
<option value="{url path="{category attr="url"}" limit="4"}" {if $limit==4}selected{/if}>4</option>
<option value="{url path="{category attr="url"}" limit="8"}" {if $limit==8}selected{/if}>8</option>
@@ -12,7 +12,7 @@
<option value="{url path="{category attr="url"}" limit="50"}"{if $limit==50}selected{/if}>50</option>
<option value="{url path="{category attr="url"}" limit="9999999999"}" {if $limit==9999999999}selected{/if}>All</option>
</select>
<span class="per-page"> per page</span>
<span class="per-page">{intl l="per page"}</span>
</span><!-- /.limiter -->
<span class="sort-by">

View File

@@ -62,7 +62,7 @@ URL: http://www.thelia.net
<nav class="navbar-collapse collapse nav-main" role="navigation" aria-label="Main Navigation">
<ul class="nav navbar-nav navbar-categories">
<li class="active"><a href="{url path="/"}" class="home" tabindex="-1">Home</a></li>
<li class="dropdown">
{* <li class="dropdown">
<a href="" data-toggle="dropdown" class="dropdown-toggle">Pages</a>
<ul class="dropdown-menu list-subnav" role="menu">
<li class="active"><a href="index.html" tabindex="-1">Index</a></li>
@@ -79,8 +79,8 @@ URL: http://www.thelia.net
<li><a href="product-details.html">Product details</a></li>
<li><a href="address.html">New address</a></li>
</ul>
</li>
{loop type="category" name="category.navigation" parent="0" limit="3"}
</li>*}
{loop type="category" name="category.navigation" parent="0"}
<li><a href="{$URL}">{$TITLE}</a></li>
{/loop}
</ul>

View File

@@ -24,26 +24,30 @@
<a href="cart-step4.php" role="button" class="btn btn-step active"><span class="step-nb">4</span> <span class="step-label">Secure payment</span></a>
</div>
{loop type="order" name="placed-order" id=$placed_order_id}
<div id="payment-success" class="panel">
<div class="panel-heading">
<h3 class="panel-title">You chose to pay by : <span class="payment-method">Cheque</span></h3>
<h3 class="panel-title">You chose to pay by : <span class="payment-method">{loop name="payment-module" type="module" id=$PAYMENT_MODULE}{$TITLE}{/loop}</span></h3>
</div>
<div class="panel-body">
<h3>Thank you for the trust you place in us.</h3>
<p>A summary of your order email has been sent to the following address: email@toto.com</p>
<p>A summary of your order email has been sent to the following address: {customer attr="email"}</p>
<p>Your order will be confirmed by us upon receipt of your payment.</p>
<dl class="dl-horizontal">
<dt>Order number : </dt>
<dd>PRO123456788978979</dd>
<dd>{$REF}</dd>
<dt>Date : </dt>
<dd>02/12/2013</dd>
<dd>{format_date date=$CREATE_DATE output="date"}</dd>
<dt>Total : </dt>
<dd>$216.25</dd>
<dd>{loop type="currency" name="order-currency" id=$CURRENCY}{$SYMBOL}{/loop} {$TOTAL_TAXED_AMOUNT}</dd>
</dl>
</div>
</div>
{/loop}
<a href="{navigate to="index"}" role="button" class="btn btn-checkout-home"><span>Go home</span></a>
</article>

0
web/test_to_remove/admin-stats.json Normal file → Executable file
View File