Merge branch 'master' into loops
Conflicts: core/lib/Thelia/Core/Template/Loop/Category.php core/lib/Thelia/Core/Template/Loop/FeatureValue.php core/lib/Thelia/Core/Template/Loop/Folder.php core/lib/Thelia/Core/Template/Loop/Product.php core/lib/Thelia/Core/Template/Smarty/Plugins/TheliaLoop.php install/faker.php
This commit is contained in:
32
core/lib/Thelia/Action/BaseAction.php
Normal file → Executable file
32
core/lib/Thelia/Action/BaseAction.php
Normal file → Executable file
@@ -22,33 +22,30 @@
|
||||
/*************************************************************************************/
|
||||
namespace Thelia\Action;
|
||||
|
||||
|
||||
use Thelia\Form\BaseForm;
|
||||
use Thelia\Action\Exception\FormValidationException;
|
||||
use Thelia\Core\Event\ActionEvent;
|
||||
use Symfony\Component\Form\Form;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
|
||||
|
||||
class BaseAction
|
||||
{
|
||||
|
||||
/**
|
||||
* @var The container
|
||||
*/
|
||||
protected $container;
|
||||
|
||||
public function __construct(ContainerInterface $container) {
|
||||
public function __construct(ContainerInterface $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a BaseForm
|
||||
*
|
||||
* @param BaseForm $aBaseForm the form
|
||||
* @param string $expectedMethod the expected method, POST or GET, or null for any of them
|
||||
* @throws FormValidationException is the form contains error, or the method is not the right one
|
||||
* @param BaseForm $aBaseForm the form
|
||||
* @param string $expectedMethod the expected method, POST or GET, or null for any of them
|
||||
* @throws FormValidationException is the form contains error, or the method is not the right one
|
||||
* @return \Symfony\Component\Form\Form Form the symfony form object
|
||||
*/
|
||||
protected function validateForm(BaseForm $aBaseForm, $expectedMethod = null)
|
||||
@@ -60,14 +57,11 @@ class BaseAction
|
||||
$form->bind($aBaseForm->getRequest());
|
||||
|
||||
if ($form->isValid()) {
|
||||
|
||||
return $form;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
throw new FormValidationException("Missing or invalid data");
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
throw new FormValidationException(sprintf("Wrong form method, %s expected.", $expectedMethod));
|
||||
}
|
||||
}
|
||||
@@ -75,12 +69,12 @@ class BaseAction
|
||||
/**
|
||||
* Propagate a form error in the action event
|
||||
*
|
||||
* @param BaseForm $aBaseForm the form
|
||||
* @param string $error_message an error message that may be displayed to the customer
|
||||
* @param ActionEvent $event the action event
|
||||
* @param BaseForm $aBaseForm the form
|
||||
* @param string $error_message an error message that may be displayed to the customer
|
||||
* @param ActionEvent $event the action event
|
||||
*/
|
||||
protected function propagateFormError(BaseForm $aBaseForm, $error_message, ActionEvent $event) {
|
||||
|
||||
protected function propagateFormError(BaseForm $aBaseForm, $error_message, ActionEvent $event)
|
||||
{
|
||||
// The form has an error
|
||||
$aBaseForm->setError(true);
|
||||
$aBaseForm->setErrorMessage($error_message);
|
||||
@@ -102,4 +96,4 @@ class BaseAction
|
||||
return $this->container->get('event_dispatcher');
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,10 +25,8 @@ namespace Thelia\Action;
|
||||
|
||||
use Propel\Runtime\Exception\PropelException;
|
||||
use Symfony\Component\Config\Definition\Exception\Exception;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Core\Event\ActionEvent;
|
||||
use Thelia\Core\Event\CartEvent;
|
||||
use Thelia\Form\CartAdd;
|
||||
use Thelia\Model\ProductPrice;
|
||||
@@ -36,7 +34,6 @@ use Thelia\Model\ProductPriceQuery;
|
||||
use Thelia\Model\CartItem;
|
||||
use Thelia\Model\CartItemQuery;
|
||||
use Thelia\Model\ConfigQuery;
|
||||
use Thelia\Action\Exception\FormValidationException;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -52,74 +49,46 @@ class Cart extends BaseAction implements EventSubscriberInterface
|
||||
* add an article in the current cart
|
||||
* @param \Thelia\Core\Event\CartEvent $event
|
||||
*/
|
||||
public function addArticle(CartEvent $event)
|
||||
public function addItem(CartEvent $event)
|
||||
{
|
||||
$request = $event->getRequest();
|
||||
$message = null;
|
||||
|
||||
try {
|
||||
$cartAdd = $this->getAddCartForm($request);
|
||||
$cart = $event->getCart();
|
||||
$newness = $event->getNewness();
|
||||
$append = $event->getAppend();
|
||||
$quantity = $event->getQuantity();
|
||||
|
||||
$form = $this->validateForm($cartAdd);
|
||||
$productSaleElementsId = $event->getProductSaleElementsId();
|
||||
$productId = $event->getProduct();
|
||||
|
||||
$cart = $event->getCart();
|
||||
$newness = $form->get("newness")->getData();
|
||||
$append = $form->get("append")->getData();
|
||||
$quantity = $form->get("quantity")->getData();
|
||||
$cartItem = $this->findItem($cart->getId(), $productId, $productSaleElementsId);
|
||||
|
||||
$productSaleElementsId = $form->get("product_sale_elements_id")->getData();
|
||||
$productId = $form->get("product")->getData();
|
||||
if ($cartItem === null || $newness) {
|
||||
$productPrice = ProductPriceQuery::create()
|
||||
->filterByProductSaleElementsId($productSaleElementsId)
|
||||
->findOne();
|
||||
|
||||
$cartItem = $this->findItem($cart->getId(), $productId, $productSaleElementsId);
|
||||
|
||||
if ($cartItem === null || $newness) {
|
||||
$productPrice = ProductPriceQuery::create()
|
||||
->filterByProductSaleElementsId($productSaleElementsId)
|
||||
->findOne()
|
||||
;
|
||||
|
||||
$this->addItem($cart, $productId, $productSaleElementsId, $quantity, $productPrice);
|
||||
}
|
||||
|
||||
if ($append && $cartItem !== null) {
|
||||
$this->updateQuantity($cartItem, $quantity);
|
||||
}
|
||||
|
||||
} catch (PropelException $e) {
|
||||
\Thelia\Log\Tlog::getInstance()->error(sprintf("Failed to add item to cart with message : %s", $e->getMessage()));
|
||||
$message = "Failed to add this article to your cart, please try again";
|
||||
} catch (FormValidationException $e) {
|
||||
|
||||
$message = $e->getMessage();
|
||||
}
|
||||
if($message) {
|
||||
// The form has errors, propagate it.
|
||||
$this->propagateFormError($cartAdd, $message, $event);
|
||||
$this->doAddItem($cart, $productId, $productSaleElementsId, $quantity, $productPrice);
|
||||
}
|
||||
|
||||
if ($append && $cartItem !== null) {
|
||||
$this->updateQuantity($cartItem, $quantity);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Delete specify article present into cart
|
||||
*
|
||||
* @param \Thelia\Core\Event\CartEvent $event
|
||||
*/
|
||||
public function deleteArticle(CartEvent $event)
|
||||
public function deleteItem(CartEvent $event)
|
||||
{
|
||||
$request = $event->getRequest();
|
||||
|
||||
if (null !== $cartItemId = $request->get('cartItem')) {
|
||||
if (null !== $cartItemId = $event->getCartItem()) {
|
||||
$cart = $event->getCart();
|
||||
try {
|
||||
$cartItem = CartItemQuery::create()
|
||||
->filterByCartId($cart->getId())
|
||||
->filterById($cartItemId)
|
||||
->delete();
|
||||
} catch (PropelException $e) {
|
||||
\Thelia\Log\Tlog::getInstance()->error(sprintf("error during deleting cartItem with message : %s", $e->getMessage()));
|
||||
}
|
||||
$cartItem = CartItemQuery::create()
|
||||
->filterByCartId($cart->getId())
|
||||
->filterById($cartItemId)
|
||||
->delete();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -132,25 +101,18 @@ class Cart extends BaseAction implements EventSubscriberInterface
|
||||
*
|
||||
* @param \Thelia\Core\Event\CartEvent $event
|
||||
*/
|
||||
public function modifyArticle(CartEvent $event)
|
||||
public function changeItem(CartEvent $event)
|
||||
{
|
||||
$request = $event->getRequest();
|
||||
if ((null !== $cartItemId = $event->getCartItem()) && (null !== $quantity = $event->getQuantity())) {
|
||||
$cart = $event->getCart();
|
||||
|
||||
if (null !== $cartItemId = $request->get("cartItem") && null !== $quantity = $request->get("quantity")) {
|
||||
$cartItem = CartItemQuery::create()
|
||||
->filterByCartId($cart->getId())
|
||||
->filterById($cartItemId)
|
||||
->findOne();
|
||||
|
||||
try {
|
||||
$cart = $event->getCart($request);
|
||||
|
||||
$cartItem = CartItemQuery::create()
|
||||
->filterByCartId($cart->getId())
|
||||
->filterById($cartItemId)
|
||||
->findOne();
|
||||
|
||||
if ($cartItem) {
|
||||
$this->updateQuantity($cartItem, $quantity);
|
||||
}
|
||||
} catch (PropelException $e) {
|
||||
\Thelia\Log\Tlog::getInstance()->error(sprintf("error during updating cartItem with message : %s", $e->getMessage()));
|
||||
if ($cartItem) {
|
||||
$this->updateQuantity($cartItem, $quantity);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -178,24 +140,22 @@ class Cart extends BaseAction implements EventSubscriberInterface
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
"action.addArticle" => array("addArticle", 128),
|
||||
"action.deleteArticle" => array("deleteArticle", 128),
|
||||
"action.changeArticle" => array("modifyArticle", 128),
|
||||
"action.addArticle" => array("addItem", 128),
|
||||
"action.deleteArticle" => array("deleteItem", 128),
|
||||
"action.changeArticle" => array("changeItem", 128),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* increase the quantity for an existing cartItem
|
||||
*
|
||||
* @param CartItem $cartItem
|
||||
* @param float $quantity
|
||||
* @param float $quantity
|
||||
*/
|
||||
protected function updateQuantity(CartItem $cartItem, $quantity)
|
||||
{
|
||||
$cartItem->setDisptacher($this->getDispatcher());
|
||||
$cartItem->addQuantity($quantity)
|
||||
$cartItem->updateQuantity($quantity)
|
||||
->save();
|
||||
}
|
||||
|
||||
@@ -203,12 +163,12 @@ class Cart extends BaseAction implements EventSubscriberInterface
|
||||
* try to attach a new item to an existing cart
|
||||
*
|
||||
* @param \Thelia\Model\Cart $cart
|
||||
* @param int $productId
|
||||
* @param int $productSaleElementsId
|
||||
* @param float $quantity
|
||||
* @param ProductPrice $productPrice
|
||||
* @param int $productId
|
||||
* @param int $productSaleElementsId
|
||||
* @param float $quantity
|
||||
* @param ProductPrice $productPrice
|
||||
*/
|
||||
protected function addItem(\Thelia\Model\Cart $cart, $productId, $productSaleElementsId, $quantity, ProductPrice $productPrice)
|
||||
protected function doAddItem(\Thelia\Model\Cart $cart, $productId, $productSaleElementsId, $quantity, ProductPrice $productPrice)
|
||||
{
|
||||
$cartItem = new CartItem();
|
||||
$cartItem->setDisptacher($this->getDispatcher());
|
||||
@@ -227,9 +187,9 @@ class Cart extends BaseAction implements EventSubscriberInterface
|
||||
* find a specific record in CartItem table using the Cart id, the product id
|
||||
* and the product_sale_elements id
|
||||
*
|
||||
* @param int $cartId
|
||||
* @param int $productId
|
||||
* @param int $productSaleElementsId
|
||||
* @param int $cartId
|
||||
* @param int $productId
|
||||
* @param int $productSaleElementsId
|
||||
* @return ChildCartItem
|
||||
*/
|
||||
protected function findItem($cartId, $productId, $productSaleElementsId)
|
||||
@@ -241,28 +201,4 @@ class Cart extends BaseAction implements EventSubscriberInterface
|
||||
->findOne();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the good way to construct the cart form
|
||||
*
|
||||
* @param Request $request
|
||||
* @return CartAdd
|
||||
*/
|
||||
private function getAddCartForm(Request $request)
|
||||
{
|
||||
if ($request->isMethod("post")) {
|
||||
$cartAdd = new CartAdd($request);
|
||||
} else {
|
||||
$cartAdd = new CartAdd(
|
||||
$request,
|
||||
"form",
|
||||
array(),
|
||||
array(
|
||||
'csrf_protection' => false,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $cartAdd;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
176
core/lib/Thelia/Action/Category.php
Normal file → Executable file
176
core/lib/Thelia/Action/Category.php
Normal file → Executable file
@@ -40,15 +40,14 @@ use Propel\Runtime\Propel;
|
||||
use Thelia\Model\Map\CategoryTableMap;
|
||||
use Propel\Runtime\Exception\PropelException;
|
||||
|
||||
|
||||
class Category extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
public function create(ActionEvent $event)
|
||||
{
|
||||
|
||||
$this->checkAuth("ADMIN", "admin.category.create");
|
||||
$this->checkAuth("ADMIN", "admin.category.create");
|
||||
|
||||
$request = $event->getRequest();
|
||||
$request = $event->getRequest();
|
||||
|
||||
try {
|
||||
$categoryCreationForm = new CategoryCreationForm($request);
|
||||
@@ -92,7 +91,7 @@ class Category extends BaseAction implements EventSubscriberInterface
|
||||
public function modify(ActionEvent $event)
|
||||
{
|
||||
|
||||
$this->checkAuth("ADMIN", "admin.category.delete");
|
||||
$this->checkAuth("ADMIN", "admin.category.delete");
|
||||
|
||||
$request = $event->getRequest();
|
||||
|
||||
@@ -163,9 +162,9 @@ class Category extends BaseAction implements EventSubscriberInterface
|
||||
public function delete(ActionEvent $event)
|
||||
{
|
||||
|
||||
$this->checkAuth("ADMIN", "admin.category.delete");
|
||||
$this->checkAuth("ADMIN", "admin.category.delete");
|
||||
|
||||
$request = $event->getRequest();
|
||||
$request = $event->getRequest();
|
||||
|
||||
try {
|
||||
$categoryDeletionForm = new CategoryDeletionForm($request);
|
||||
@@ -214,11 +213,11 @@ class Category extends BaseAction implements EventSubscriberInterface
|
||||
public function toggleVisibility(ActionEvent $event)
|
||||
{
|
||||
|
||||
$this->checkAuth("ADMIN", "admin.category.edit");
|
||||
$this->checkAuth("ADMIN", "admin.category.edit");
|
||||
|
||||
$request = $event->getRequest();
|
||||
$request = $event->getRequest();
|
||||
|
||||
$category = CategoryQuery::create()->findPk($request->get('category_id', 0));
|
||||
$category = CategoryQuery::create()->findPk($request->get('category_id', 0));
|
||||
|
||||
if ($category !== null) {
|
||||
|
||||
@@ -237,8 +236,9 @@ class Category extends BaseAction implements EventSubscriberInterface
|
||||
*
|
||||
* @param ActionEvent $event
|
||||
*/
|
||||
public function changePositionUp(ActionEvent $event) {
|
||||
return $this->exchangePosition($event, 'up');
|
||||
public function changePositionUp(ActionEvent $event)
|
||||
{
|
||||
return $this->exchangePosition($event, 'up');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -246,67 +246,65 @@ class Category extends BaseAction implements EventSubscriberInterface
|
||||
*
|
||||
* @param ActionEvent $event
|
||||
*/
|
||||
public function changePositionDown(ActionEvent $event) {
|
||||
return $this->exchangePosition($event, 'down');
|
||||
public function changePositionDown(ActionEvent $event)
|
||||
{
|
||||
return $this->exchangePosition($event, 'down');
|
||||
}
|
||||
|
||||
/**
|
||||
* Move up or down a category
|
||||
*
|
||||
* @param ActionEvent $event
|
||||
* @param string $direction up to move up, down to move down
|
||||
* @param string $direction up to move up, down to move down
|
||||
*/
|
||||
protected function exchangePosition(ActionEvent $event, $direction) {
|
||||
protected function exchangePosition(ActionEvent $event, $direction)
|
||||
{
|
||||
$this->checkAuth("ADMIN", "admin.category.edit");
|
||||
|
||||
$this->checkAuth("ADMIN", "admin.category.edit");
|
||||
$request = $event->getRequest();
|
||||
|
||||
$request = $event->getRequest();
|
||||
$category = CategoryQuery::create()->findPk($request->get('category_id', 0));
|
||||
|
||||
$category = CategoryQuery::create()->findPk($request->get('category_id', 0));
|
||||
if ($category !== null) {
|
||||
|
||||
if ($category !== null) {
|
||||
// The current position of the category
|
||||
$my_position = $category->getPosition();
|
||||
|
||||
// The current position of the category
|
||||
$my_position = $category->getPosition();
|
||||
// Find category to exchange position with
|
||||
$search = CategoryQuery::create()
|
||||
->filterByParent($category->getParent());
|
||||
|
||||
// Find category to exchange position with
|
||||
$search = CategoryQuery::create()
|
||||
->filterByParent($category->getParent());
|
||||
// Up or down ?
|
||||
if ($direction == 'up') {
|
||||
// Find the category immediately before me
|
||||
$search->filterByPosition(array('max' => $my_position-1))->orderByPosition(Criteria::DESC);
|
||||
} elseif ($direction == 'down') {
|
||||
// Find the category immediately after me
|
||||
$search->filterByPosition(array('min' => $my_position+1))->orderByPosition(Criteria::ASC);
|
||||
} else
|
||||
|
||||
// Up or down ?
|
||||
if ($direction == 'up') {
|
||||
// Find the category immediately before me
|
||||
$search->filterByPosition(array('max' => $my_position-1))->orderByPosition(Criteria::DESC);
|
||||
}
|
||||
else if ($direction == 'down') {
|
||||
// Find the category immediately after me
|
||||
$search->filterByPosition(array('min' => $my_position+1))->orderByPosition(Criteria::ASC);
|
||||
}
|
||||
else
|
||||
return;
|
||||
return;
|
||||
|
||||
$result = $search->findOne();
|
||||
$result = $search->findOne();
|
||||
|
||||
// If we found the proper category, exchange their positions
|
||||
if ($result) {
|
||||
|
||||
// If we found the proper category, exchange their positions
|
||||
if ($result) {
|
||||
$cnx = Propel::getWriteConnection(CategoryTableMap::DATABASE_NAME);
|
||||
|
||||
$cnx = Propel::getWriteConnection(CategoryTableMap::DATABASE_NAME);
|
||||
$cnx->beginTransaction();
|
||||
|
||||
$cnx->beginTransaction();
|
||||
try {
|
||||
$category->setPosition($result->getPosition())->save();
|
||||
|
||||
try {
|
||||
$category->setPosition($result->getPosition())->save();
|
||||
$result->setPosition($my_position)->save();
|
||||
|
||||
$result->setPosition($my_position)->save();
|
||||
|
||||
$cnx->commit();
|
||||
}
|
||||
catch(Exception $e) {
|
||||
$cnx->rollback();
|
||||
}
|
||||
}
|
||||
}
|
||||
$cnx->commit();
|
||||
} catch (Exception $e) {
|
||||
$cnx->rollback();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -314,61 +312,59 @@ class Category extends BaseAction implements EventSubscriberInterface
|
||||
*
|
||||
* @param ActionEvent $event
|
||||
*/
|
||||
public function changePosition(ActionEvent $event) {
|
||||
public function changePosition(ActionEvent $event)
|
||||
{
|
||||
$this->checkAuth("ADMIN", "admin.category.edit");
|
||||
|
||||
$this->checkAuth("ADMIN", "admin.category.edit");
|
||||
$request = $event->getRequest();
|
||||
|
||||
$request = $event->getRequest();
|
||||
$category = CategoryQuery::create()->findPk($request->get('category_id', 0));
|
||||
|
||||
$category = CategoryQuery::create()->findPk($request->get('category_id', 0));
|
||||
if ($category !== null) {
|
||||
|
||||
if ($category !== null) {
|
||||
// The required position
|
||||
$new_position = $request->get('position', null);
|
||||
|
||||
// The required position
|
||||
$new_position = $request->get('position', null);
|
||||
// The current position
|
||||
$current_position = $category->getPosition();
|
||||
|
||||
// The current position
|
||||
$current_position = $category->getPosition();
|
||||
if ($new_position != null && $new_position > 0 && $new_position != $current_position) {
|
||||
|
||||
if ($new_position != null && $new_position > 0 && $new_position != $current_position) {
|
||||
// Find categories to offset
|
||||
$search = CategoryQuery::create()->filterByParent($category->getParent());
|
||||
|
||||
// Find categories to offset
|
||||
$search = CategoryQuery::create()->filterByParent($category->getParent());
|
||||
if ($new_position > $current_position) {
|
||||
// The new position is after the current position -> we will offset + 1 all categories located between us and the new position
|
||||
$search->filterByPosition(array('min' => 1+$current_position, 'max' => $new_position));
|
||||
|
||||
if ($new_position > $current_position) {
|
||||
// The new position is after the current position -> we will offset + 1 all categories located between us and the new position
|
||||
$search->filterByPosition(array('min' => 1+$current_position, 'max' => $new_position));
|
||||
$delta = -1;
|
||||
} else {
|
||||
// The new position is brefore the current position -> we will offset - 1 all categories located between us and the new position
|
||||
$search->filterByPosition(array('min' => $new_position, 'max' => $current_position - 1));
|
||||
|
||||
$delta = -1;
|
||||
}
|
||||
else {
|
||||
// The new position is brefore the current position -> we will offset - 1 all categories located between us and the new position
|
||||
$search->filterByPosition(array('min' => $new_position, 'max' => $current_position - 1));
|
||||
$delta = 1;
|
||||
}
|
||||
|
||||
$delta = 1;
|
||||
}
|
||||
$results = $search->find();
|
||||
|
||||
$results = $search->find();
|
||||
$cnx = Propel::getWriteConnection(CategoryTableMap::DATABASE_NAME);
|
||||
|
||||
$cnx = Propel::getWriteConnection(CategoryTableMap::DATABASE_NAME);
|
||||
$cnx->beginTransaction();
|
||||
|
||||
$cnx->beginTransaction();
|
||||
try {
|
||||
foreach ($results as $result) {
|
||||
$result->setPosition($result->getPosition() + $delta)->save($cnx);
|
||||
}
|
||||
|
||||
try {
|
||||
foreach($results as $result) {
|
||||
$result->setPosition($result->getPosition() + $delta)->save($cnx);
|
||||
}
|
||||
$category->setPosition($new_position)->save($cnx);
|
||||
|
||||
$category->setPosition($new_position)->save($cnx);
|
||||
|
||||
$cnx->commit();
|
||||
}
|
||||
catch(Exception $e) {
|
||||
$cnx->rollback();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$cnx->commit();
|
||||
} catch (Exception $e) {
|
||||
$cnx->rollback();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of event names this subscriber listens to.
|
||||
|
||||
@@ -25,8 +25,8 @@ namespace Thelia\Action;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Core\Event\ActionEvent;
|
||||
use Thelia\Core\Event\CustomerCreateOrUpdateEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Form\BaseForm;
|
||||
use Thelia\Form\CustomerCreation;
|
||||
use Thelia\Form\CustomerModification;
|
||||
use Thelia\Model\Customer as CustomerModel;
|
||||
@@ -34,105 +34,57 @@ use Thelia\Log\Tlog;
|
||||
use Thelia\Model\CustomerQuery;
|
||||
use Thelia\Form\CustomerLogin;
|
||||
use Thelia\Core\Security\Authentication\CustomerUsernamePasswordFormAuthenticator;
|
||||
use Thelia\Core\Security\SecurityContext;
|
||||
use Symfony\Component\Validator\Exception\ValidatorException;
|
||||
use Thelia\Core\Security\Exception\AuthenticationException;
|
||||
use Thelia\Core\Security\Exception\UsernameNotFoundException;
|
||||
use Propel\Runtime\Exception\PropelException;
|
||||
use Thelia\Action\Exception\FormValidationException;
|
||||
|
||||
class Customer extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
|
||||
public function create(ActionEvent $event)
|
||||
public function create(CustomerCreateOrUpdateEvent $event)
|
||||
{
|
||||
$request = $event->getRequest();
|
||||
|
||||
try {
|
||||
$customerCreationForm = new CustomerCreation($request);
|
||||
$customer = new CustomerModel();
|
||||
$customer->setDispatcher($this->getDispatcher());
|
||||
|
||||
$form = $this->validateForm($customerCreationForm, "POST");
|
||||
$this->createOrUpdateCustomer($customer, $event);
|
||||
|
||||
$data = $form->getData();
|
||||
$customer = new CustomerModel();
|
||||
$customer->setDispatcher($event->getDispatcher());
|
||||
|
||||
$customer->createOrUpdate(
|
||||
$data["title"],
|
||||
$data["firstname"],
|
||||
$data["lastname"],
|
||||
$data["address1"],
|
||||
$data["address2"],
|
||||
$data["address3"],
|
||||
$data["phone"],
|
||||
$data["cellphone"],
|
||||
$data["zipcode"],
|
||||
$data["country"],
|
||||
$data["email"],
|
||||
$data["password"],
|
||||
$request->getSession()->getLang()
|
||||
);
|
||||
|
||||
$event->customer = $customer;
|
||||
|
||||
} catch (PropelException $e) {
|
||||
|
||||
Tlog::getInstance()->error(sprintf('error during creating customer on action/createCustomer with message "%s"', $e->getMessage()));
|
||||
|
||||
$message = "Failed to create your account, please try again.";
|
||||
} catch (FormValidationException $e) {
|
||||
|
||||
$message = $e->getMessage();
|
||||
}
|
||||
|
||||
// The form has errors, propagate it.
|
||||
$this->propagateFormError($customerCreationForm, $message, $event);
|
||||
}
|
||||
|
||||
public function modify(ActionEvent $event)
|
||||
public function modify(CustomerCreateOrUpdateEvent $event)
|
||||
{
|
||||
$request = $event->getRequest();
|
||||
|
||||
try {
|
||||
$customerModification = new CustomerModification($request);
|
||||
$customer = $event->getCustomer();
|
||||
$customer->setDispatcher($this->getDispatcher());
|
||||
|
||||
$form = $this->validateForm($customerModification, "POST");
|
||||
$this->createOrUpdateCustomer($customer, $event);
|
||||
|
||||
$data = $form->getData();
|
||||
}
|
||||
|
||||
$customer = CustomerQuery::create()->findPk(1);
|
||||
private function createOrUpdateCustomer(CustomerModel $customer, CustomerCreateOrUpdateEvent $event)
|
||||
{
|
||||
$customer->createOrUpdate(
|
||||
$event->getTitle(),
|
||||
$event->getFirstname(),
|
||||
$event->getLastname(),
|
||||
$event->getAddress1(),
|
||||
$event->getAddress2(),
|
||||
$event->getAddress3(),
|
||||
$event->getPhone(),
|
||||
$event->getCellphone(),
|
||||
$event->getZipcode(),
|
||||
$event->getCity(),
|
||||
$event->getCountry(),
|
||||
$event->getEmail(),
|
||||
$event->getPassword(),
|
||||
$event->getLang(),
|
||||
$event->getReseller(),
|
||||
$event->getSponsor(),
|
||||
$event->getDiscount()
|
||||
);
|
||||
|
||||
$data = $form->getData();
|
||||
|
||||
$customer->createOrUpdate(
|
||||
$data["title"],
|
||||
$data["firstname"],
|
||||
$data["lastname"],
|
||||
$data["address1"],
|
||||
$data["address2"],
|
||||
$data["address3"],
|
||||
$data["phone"],
|
||||
$data["cellphone"],
|
||||
$data["zipcode"],
|
||||
$data["country"]
|
||||
);
|
||||
|
||||
// Update the logged-in user, and redirect to the success URL (exits)
|
||||
// We don-t send the login event, as the customer si already logged.
|
||||
$this->processSuccessfullLogin($event, $customer, $customerModification);
|
||||
} catch (PropelException $e) {
|
||||
|
||||
|
||||
Tlog::getInstance()->error(sprintf('error during modifying customer on action/modifyCustomer with message "%s"', $e->getMessage()));
|
||||
|
||||
$message = "Failed to change your account, please try again.";
|
||||
} catch (FormValidationException $e) {
|
||||
|
||||
$message = $e->getMessage();
|
||||
}
|
||||
|
||||
// The form has errors, propagate it.
|
||||
$this->propagateFormError($customerModification, $message, $event);
|
||||
$event->setCustomer($customer);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -144,49 +96,7 @@ class Customer extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
$event->getDispatcher()->dispatch(TheliaEvents::CUSTOMER_LOGOUT, $event);
|
||||
|
||||
|
||||
$this->getFrontSecurityContext()->clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform user login. On a successful login, the user is redirected to the URL
|
||||
* found in the success_url form parameter, or / if none was found.
|
||||
*
|
||||
* If login is not successfull, the same view is dispolyed again.
|
||||
*
|
||||
* @param ActionEvent $event
|
||||
*/
|
||||
public function login(ActionEvent $event)
|
||||
{
|
||||
$request = $event->getRequest();
|
||||
|
||||
$customerLoginForm = new CustomerLogin($request);
|
||||
|
||||
$authenticator = new CustomerUsernamePasswordFormAuthenticator($request, $customerLoginForm);
|
||||
|
||||
try {
|
||||
$user = $authenticator->getAuthentifiedUser();
|
||||
|
||||
$event->customer = $customer;
|
||||
|
||||
} catch (ValidatorException $ex) {
|
||||
$message = "Missing or invalid information. Please check your input.";
|
||||
} catch (UsernameNotFoundException $ex) {
|
||||
$message = "This email address was not found.";
|
||||
} catch (AuthenticationException $ex) {
|
||||
$message = "Login failed. Please check your username and password.";
|
||||
} catch (\Exception $ex) {
|
||||
$message = sprintf("Unable to process your request. Please try again (%s in %s).", $ex->getMessage(), $ex->getFile());
|
||||
}
|
||||
|
||||
// The for has an error
|
||||
$customerLoginForm->setError(true);
|
||||
$customerLoginForm->setErrorMessage($message);
|
||||
|
||||
// Dispatch the errored form
|
||||
$event->setErrorForm($customerLoginForm);
|
||||
|
||||
// A this point, the same view is displayed again.
|
||||
$this->getFrontSecurityContext()->clear();
|
||||
}
|
||||
|
||||
public function changePassword(ActionEvent $event)
|
||||
@@ -219,8 +129,6 @@ class Customer extends BaseAction implements EventSubscriberInterface
|
||||
return array(
|
||||
"action.createCustomer" => array("create", 128),
|
||||
"action.modifyCustomer" => array("modify", 128),
|
||||
"action.loginCustomer" => array("login", 128),
|
||||
"action.logoutCustomer" => array("logout", 128),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
<?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\Exception;
|
||||
|
||||
class ActionException extends \RuntimeException
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
<?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\Exception;
|
||||
|
||||
class FormValidationException extends ActionException
|
||||
{
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
<?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\Exception;
|
||||
|
||||
class ProductNotFoundException extends ActionException
|
||||
{
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
<?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\Exception;
|
||||
|
||||
class StockNotFoundException extends ActionException
|
||||
{
|
||||
|
||||
}
|
||||
497
core/lib/Thelia/Action/Image.php
Executable file
497
core/lib/Thelia/Action/Image.php
Executable file
@@ -0,0 +1,497 @@
|
||||
<?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\ActionEvent;
|
||||
use Thelia\Core\Event\ImageEvent;
|
||||
use Thelia\Model\ConfigQuery;
|
||||
use Thelia\Tools\URL;
|
||||
|
||||
use Imagine\Image\ImagineInterface;
|
||||
use Imagine\Image\ImageInterface;
|
||||
use Imagine\Image\Box;
|
||||
use Imagine\Image\Color;
|
||||
use Imagine\Image\Point;
|
||||
use Thelia\Exception\ImageException;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
|
||||
/**
|
||||
*
|
||||
* Image management actions. This class handles image processing an 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).
|
||||
*
|
||||
* In the images caches directory, a subdirectory for images categories (eg. product, category, folder, etc.) is
|
||||
* automatically created, and the cached image is created here. Plugin may use their own subdirectory as required.
|
||||
*
|
||||
* The cached image name contains a hash of the processing options, and the original (normalized) name of the image.
|
||||
*
|
||||
* A copy (or symbolic link, by default) of the original image is always created in the cache, so that the full
|
||||
* resolution image is always available.
|
||||
*
|
||||
* Various image processing options are available :
|
||||
*
|
||||
* - resizing, with border, crop, or by keeping image aspect ratio
|
||||
* - rotation, in degrees, positive or negative
|
||||
* - background color, applyed to empty background when creating borders or rotating
|
||||
* - effects. The effects are applied in the specified order. The following effects are available:
|
||||
* - gamma:value : change the image Gamma to the specified value. Example: gamma:0.7
|
||||
* - grayscale or greyscale: switch image to grayscale
|
||||
* - colorize:color : apply a color mask to the image. Exemple: colorize:#ff2244
|
||||
* - negative : transform the image in its negative equivalent
|
||||
* - vflip or vertical_flip : vertical flip
|
||||
* - hflip or horizontal_flip : horizontal flip
|
||||
*
|
||||
* If a problem occurs, an ImageException may be thrown.
|
||||
*
|
||||
* @package Thelia\Action
|
||||
* @author Franck Allimant <franck@cqfdev.fr>
|
||||
*
|
||||
*/
|
||||
class Image extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
// Resize mode constants
|
||||
const EXACT_RATIO_WITH_BORDERS = 1;
|
||||
const EXACT_RATIO_WITH_CROP = 2;
|
||||
const KEEP_IMAGE_RATIO = 3;
|
||||
|
||||
/**
|
||||
* Clear the image cache. Is a subdirectory is specified, only this directory is cleared.
|
||||
* If no directory is specified, the whole cache is cleared.
|
||||
* Only files are deleted, directories will remain.
|
||||
*
|
||||
* @param ImageEvent $event
|
||||
*/
|
||||
public function clearCache(ImageEvent $event) {
|
||||
|
||||
$path = $this->getCachePath($event->getCacheSubdirectory(), false);
|
||||
|
||||
$this->clearDirectory($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively clears the specified directory.
|
||||
*
|
||||
* @param string $path the directory path
|
||||
*/
|
||||
protected function clearDirectory($path) {
|
||||
|
||||
$iterator = new \DirectoryIterator($path);
|
||||
|
||||
foreach ($iterator as $fileinfo) {
|
||||
|
||||
if ($fileinfo->isDot()) continue;
|
||||
|
||||
if ($fileinfo->isFile() || $fileinfo->isLink()) {
|
||||
@unlink($fileinfo->getPathname());
|
||||
}
|
||||
else if ($fileinfo->isDir()) {
|
||||
$this->clearDirectory($fileinfo->getPathname());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process image and write the result in the image cache.
|
||||
*
|
||||
* If the image already exists in cache, the cache file is immediately returned, without any processing
|
||||
* If the original (full resolution) image is required, create either a symbolic link with the
|
||||
* original image in the cache dir, or copy it in the cache dir.
|
||||
*
|
||||
* This method updates the cache_file_path and file_url attributes of the event
|
||||
*
|
||||
* @param ImageEvent $event
|
||||
* @throws \InvalidArgumentException, ImageException
|
||||
*/
|
||||
public function processImage(ImageEvent $event)
|
||||
{
|
||||
|
||||
$subdir = $event->getCacheSubdirectory();
|
||||
$source_file = $event->getSourceFilepath();
|
||||
|
||||
if (null == $subdir || null == $source_file) {
|
||||
throw new \InvalidArgumentException("Cache sub-directory and source file path cannot be null");
|
||||
}
|
||||
|
||||
// echo basename($source_file).": ";
|
||||
|
||||
// Find cached file path
|
||||
$cacheFilePath = $this->getCacheFilePath($subdir, $source_file, $event);
|
||||
|
||||
$originalImagePathInCache = $this->getCacheFilePath($subdir, $source_file, $event, true);
|
||||
|
||||
if (! file_exists($cacheFilePath)) {
|
||||
|
||||
if (! file_exists($source_file)) {
|
||||
throw new ImageException(sprintf("Source image file %s does not exists.", $source_file));
|
||||
}
|
||||
|
||||
// Create a chached version of the original image in the web space, if not exists
|
||||
|
||||
if (! file_exists($originalImagePathInCache)) {
|
||||
|
||||
$mode = ConfigQuery::read('original_image_delivery_mode', 'symlink');
|
||||
|
||||
if ($mode == 'symlink') {
|
||||
if (false == symlink($source_file, $originalImagePathInCache)) {
|
||||
throw new ImageException(sprintf("Failed to create symbolic link for %s in %s image cache directory", basename($source_file), $subdir));
|
||||
}
|
||||
}
|
||||
else {// mode = 'copy'
|
||||
if (false == @copy($source_file, $originalImagePathInCache)) {
|
||||
throw new ImageException(sprintf("Failed to copy %s in %s image cache directory", basename($source_file), $subdir));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process image only if we have some transformations to do.
|
||||
if (! $event->isOriginalImage()) {
|
||||
|
||||
// We have to process the image.
|
||||
$imagine = $this->createImagineInstance();
|
||||
|
||||
$image = $imagine->open($source_file);
|
||||
|
||||
if ($image) {
|
||||
|
||||
$background_color = $event->getBackgroundColor();
|
||||
|
||||
if ($background_color != null) {
|
||||
$bg_color = new Color($background_color);
|
||||
}
|
||||
else
|
||||
$bg_color = null;
|
||||
|
||||
// Apply resize
|
||||
$image = $this->applyResize($imagine, $image, $event->getWidth(), $event->getHeight(), $event->getResizeMode(), $bg_color);
|
||||
|
||||
// Rotate if required
|
||||
$rotation = intval($event->getRotation());
|
||||
|
||||
if ($rotation != 0)
|
||||
$image->rotate($rotation, $bg_color);
|
||||
|
||||
// Flip
|
||||
// Process each effects
|
||||
foreach ($event->getEffects() as $effect) {
|
||||
|
||||
$effect = trim(strtolower($effect));
|
||||
|
||||
$params = explode(':', $effect);
|
||||
|
||||
switch ($params[0]) {
|
||||
|
||||
case 'greyscale':
|
||||
case 'grayscale':
|
||||
$image->effects()->grayscale();
|
||||
break;
|
||||
|
||||
case 'negative':
|
||||
$image->effects()->negative();
|
||||
break;
|
||||
|
||||
case 'horizontal_flip':
|
||||
case 'hflip':
|
||||
$image->flipHorizontally();
|
||||
break;
|
||||
|
||||
case 'vertical_flip':
|
||||
case 'vflip':
|
||||
$image-> flipVertically();
|
||||
break;
|
||||
|
||||
case 'gamma':
|
||||
// Syntax: gamma:value. Exemple: gamma:0.7
|
||||
if (isset($params[1])) {
|
||||
$gamma = floatval($params[1]);
|
||||
|
||||
$image->effects()->gamma($gamma);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'colorize':
|
||||
// Syntax: colorize:couleur. Exemple: colorize:#ff00cc
|
||||
if (isset($params[1])) {
|
||||
$the_color = new Color($params[1]);
|
||||
|
||||
$image->effects()->colorize($the_color);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$quality = $event->getQuality();
|
||||
|
||||
if (is_null($quality)) $quality = ConfigQuery::read('default_image_quality_percent', 75);
|
||||
|
||||
$image->save(
|
||||
$cacheFilePath,
|
||||
array('quality' => $quality)
|
||||
);
|
||||
}
|
||||
else {
|
||||
throw new ImageException(sprintf("Source file %s cannot be opened.", basename($source_file)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the image URL
|
||||
$processed_image_url = $this->getCacheFileURL($subdir, basename($cacheFilePath));
|
||||
|
||||
// compute the full resulution image path in cache
|
||||
$original_image_url = $this->getCacheFileURL($subdir, basename($originalImagePathInCache));
|
||||
|
||||
// Update the event with file path and file URL
|
||||
$event->setCacheFilepath($cacheFilePath);
|
||||
$event->setCacheOriginalFilepath($originalImagePathInCache);
|
||||
|
||||
$event->setFileUrl(URL::absoluteUrl($processed_image_url, null, URL::PATH_TO_FILE));
|
||||
$event->setOriginalFileUrl(URL::absoluteUrl($original_image_url, null, URL::PATH_TO_FILE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Process image resizing, with borders or cropping. If $dest_width and $dest_height
|
||||
* are both null, no resize is performed.
|
||||
*
|
||||
* @param ImagineInterface $imagine the Imagine instance
|
||||
* @param ImageInterface $image the image to process
|
||||
* @param int $dest_width the required width
|
||||
* @param int $dest_height the required height
|
||||
* @param int $resize_mode the resize mode (crop / bands / keep image ratio)p
|
||||
* @param string $bg_color the bg_color used for bands
|
||||
* @return ImageInterface the resized image.
|
||||
*/
|
||||
protected function applyResize(ImagineInterface $imagine, ImageInterface $image, $dest_width, $dest_height, $resize_mode, $bg_color)
|
||||
{
|
||||
if (! (is_null($dest_width) && is_null($dest_height))) {
|
||||
|
||||
$width_orig = $image->getSize()->getWidth();
|
||||
$height_orig = $image->getSize()->getHeight();
|
||||
|
||||
if (is_null($dest_width))
|
||||
$dest_width = $width_orig;
|
||||
|
||||
if (is_null($dest_height))
|
||||
$dest_height = $height_orig;
|
||||
|
||||
if (is_null($resize_mode))
|
||||
$resize_mode = self::KEEP_IMAGE_RATIO;
|
||||
|
||||
$width_diff = $dest_width / $width_orig;
|
||||
$height_diff = $dest_height / $height_orig;
|
||||
|
||||
$delta_x = $delta_y = $border_width = $border_height = 0;
|
||||
|
||||
if ($width_diff > 1 AND $height_diff > 1) {
|
||||
|
||||
$next_width = $width_orig;
|
||||
$next_height = $height_orig;
|
||||
|
||||
$dest_width = ($resize_mode == self::EXACT_RATIO_WITH_BORDERS ? $dest_width : $next_width);
|
||||
$dest_height = ($resize_mode == self::EXACT_RATIO_WITH_BORDERS ? $dest_height : $next_height);
|
||||
}
|
||||
else if ($width_diff > $height_diff) {
|
||||
// Image height > image width
|
||||
|
||||
$next_height = $dest_height;
|
||||
$next_width = intval(($width_orig * $next_height) / $height_orig);
|
||||
|
||||
if ($resize_mode == self::EXACT_RATIO_WITH_CROP) {
|
||||
$next_width = $dest_width;
|
||||
$next_height = intval($height_orig * $dest_width / $width_orig);
|
||||
$delta_y = ($next_height - $dest_height) / 2;
|
||||
}
|
||||
else if ($resize_mode != self::EXACT_RATIO_WITH_BORDERS) {
|
||||
$dest_width = $next_width;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Image width > image height
|
||||
$next_width = $dest_width;
|
||||
$next_height = intval($height_orig * $dest_width / $width_orig);
|
||||
|
||||
if ($resize_mode == self::EXACT_RATIO_WITH_CROP) {
|
||||
$next_height = $dest_height;
|
||||
$next_width = intval(($width_orig * $next_height) / $height_orig);
|
||||
$delta_x = ($next_width - $dest_width) / 2;
|
||||
}
|
||||
else if ($resize_mode != self::EXACT_RATIO_WITH_BORDERS) {
|
||||
$dest_height = $next_height;
|
||||
}
|
||||
}
|
||||
|
||||
$image->resize(new Box($next_width, $next_height));
|
||||
|
||||
// echo "w=$dest_width, h=$dest_height, nw=$next_width, nh=$next_height, dx=$delta_x, dy=$delta_y, bw=$border_width, bh=$border_height\n";
|
||||
|
||||
if ($resize_mode == self::EXACT_RATIO_WITH_BORDERS) {
|
||||
|
||||
$border_width = intval(($dest_width - $next_width) / 2);
|
||||
$border_height = intval(($dest_height - $next_height) / 2);
|
||||
|
||||
$canvas = new Box($dest_width, $dest_height);
|
||||
|
||||
return $imagine->create($canvas, $bg_color)
|
||||
->paste($image, new Point($border_width, $border_height));
|
||||
}
|
||||
|
||||
else if ($resize_mode == self::EXACT_RATIO_WITH_CROP) {
|
||||
$image->crop(
|
||||
new Point($delta_x, $delta_y),
|
||||
new Box($dest_width, $dest_height)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $image;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the absolute URL to the cached image
|
||||
*
|
||||
* @param string $subdir the subdirectory related to cache base
|
||||
* @param string $filename the safe filename, as returned by getCacheFilePath()
|
||||
* @return string the absolute URL to the cached image
|
||||
*/
|
||||
protected function getCacheFileURL($subdir, $safe_filename)
|
||||
{
|
||||
$path = $this->getCachePathFromWebRoot($subdir);
|
||||
|
||||
return URL::absoluteUrl(sprintf("%s/%s", $path, $safe_filename), null, URL::PATH_TO_FILE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the full path of the cached file
|
||||
*
|
||||
* @param string $subdir the subdirectory related to cache base
|
||||
* @param string $filename the filename
|
||||
* @param boolean $forceOriginalImage if true, the origiunal image path in the cache dir is returned.
|
||||
* @return string the cache directory path relative to Web Root
|
||||
*/
|
||||
protected function getCacheFilePath($subdir, $filename, ImageEvent $event, $forceOriginalImage = false)
|
||||
{
|
||||
$path = $this->getCachePath($subdir);
|
||||
|
||||
$safe_filename = preg_replace("[^:alnum:\-\._]", "-", strtolower(basename($filename)));
|
||||
|
||||
// Keep original safe name if no tranformations are applied
|
||||
if ($forceOriginalImage || $event->isOriginalImage())
|
||||
return sprintf("%s/%s", $path, $safe_filename);
|
||||
else
|
||||
return sprintf("%s/%s-%s", $path, $event->getOptionsHash(), $safe_filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the cache directory path relative to Web Root
|
||||
*
|
||||
* @param string $subdir the subdirectory related to cache base, or null to get the cache directory only.
|
||||
* @return string the cache directory path relative to Web Root
|
||||
*/
|
||||
protected function getCachePathFromWebRoot($subdir = null)
|
||||
{
|
||||
$cache_dir_from_web_root = ConfigQuery::read('image_cache_dir_from_web_root', 'cache');
|
||||
|
||||
if ($subdir != null) {
|
||||
$safe_subdir = basename($subdir);
|
||||
|
||||
$path = sprintf("%s/%s", $cache_dir_from_web_root, $safe_subdir);
|
||||
}
|
||||
else
|
||||
$path = $cache_dir_from_web_root;
|
||||
|
||||
// Check if path is valid, e.g. in the cache dir
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the absolute cache directory path
|
||||
*
|
||||
* @param string $subdir the subdirectory related to cache base, or null to get the cache base directory.
|
||||
* @throws \RuntimeException if cache directory cannot be created
|
||||
* @return string the absolute cache directory path
|
||||
*/
|
||||
protected function getCachePath($subdir = null, $create_if_not_exists = true)
|
||||
{
|
||||
$cache_base = $this->getCachePathFromWebRoot($subdir);
|
||||
|
||||
$web_root = rtrim(THELIA_WEB_DIR, '/');
|
||||
|
||||
$path = sprintf("%s/%s", $web_root, $cache_base);
|
||||
|
||||
// Create directory (recursively) if it does not exists.
|
||||
if ($create_if_not_exists && !is_dir($path)) {
|
||||
if (!@mkdir($path, 0777, true)) {
|
||||
throw new ImageException(sprintf("Failed to create %s/%s image cache directory", $cache_base));
|
||||
}
|
||||
}
|
||||
|
||||
// Check if path is valid, e.g. in the cache dir
|
||||
$cache_base = realpath(sprintf("%s/%s", $web_root, $this->getCachePathFromWebRoot()));
|
||||
|
||||
if (strpos(realpath($path), $cache_base) !== 0) {
|
||||
throw new \InvalidArgumentException(sprintf("Invalid cache path %s, with subdirectory %s", $path, $subdir));
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Imagine object using current driver configuration
|
||||
*
|
||||
* @return \Imagine\ImagineInterface
|
||||
*/
|
||||
protected function createImagineInstance()
|
||||
{
|
||||
$driver = ConfigQuery::read("imagine_graphic_driver", "gd");
|
||||
|
||||
switch ($driver) {
|
||||
case 'imagik':
|
||||
$image = new \Imagine\Imagick\Imagine();
|
||||
break;
|
||||
|
||||
case 'gmagick':
|
||||
$image = new \Imagine\Gmagick\Imagine();
|
||||
break;
|
||||
|
||||
case 'gd':
|
||||
default:
|
||||
$image = new \Imagine\Gd\Imagine();
|
||||
}
|
||||
|
||||
return $image;
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
TheliaEvents::IMAGE_PROCESS => array("processImage", 128),
|
||||
TheliaEvents::IMAGE_CLEAR_CACHE => array("clearCache", 128),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user