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

# By franck
# Via franck
* 'catalog' of https://github.com/thelia/thelia:
  Finished combination creation GUI
  Put curresncy selector in toolbar
  Started price tab
  Finished product multiple categories attachment
  Ajaxified product modification tabs
  Finished product features management
  Aded feature_template and category_template position management
  Finished product feature values
  Fixed product update process
  Added missing files
  Working catalog branch

Conflicts:
	core/lib/Thelia/Action/BaseAction.php
	install/insert.sql
	local/config/schema.xml
	templates/admin/default/folders.html
	templates/admin/default/product-edit.html
This commit is contained in:
gmorel
2013-09-23 12:27:36 +02:00
81 changed files with 5045 additions and 2297 deletions

View File

@@ -58,6 +58,7 @@ abstract class AbstractCrudController extends BaseAdminController
* @param string $objectName the lower case object name. Example. "message"
*
* @param string $defaultListOrder the default object list order, or null if list is not sortable. Example: manual
* @param string $orderRequestParameterName Name of the request parameter that set the list order (null if list is not sortable)
*
* @param string $viewPermissionIdentifier the 'view' permission identifier. Example: "admin.configuration.message.view"
* @param string $createPermissionIdentifier the 'create' permission identifier. Example: "admin.configuration.message.create"
@@ -445,6 +446,8 @@ abstract class AbstractCrudController extends BaseAdminController
/**
* Update object position (only for objects whichsupport that)
*
* FIXME: integrate with genericUpdatePositionAction
*/
public function updatePositionAction()
{
@@ -482,6 +485,38 @@ abstract class AbstractCrudController extends BaseAdminController
}
}
protected function genericUpdatePositionAction($object, $eventName, $doFinalRedirect = true) {
// Check current user authorization
if (null !== $response = $this->checkAuth($this->updatePermissionIdentifier)) return $response;
if ($object != null) {
try {
$mode = $this->getRequest()->get('mode', null);
if ($mode == 'up')
$mode = UpdatePositionEvent::POSITION_UP;
else if ($mode == 'down')
$mode = UpdatePositionEvent::POSITION_DOWN;
else
$mode = UpdatePositionEvent::POSITION_ABSOLUTE;
$position = $this->getRequest()->get('position', null);
$event = new UpdatePositionEvent($object->getId(), $mode, $position);
$this->dispatch($eventName, $event);
}
catch (\Exception $ex) {
// Any error
return $this->errorPage($ex);
}
}
if ($doFinalRedirect) $this->redirectToEditionTemplate();
}
/**
* Online status toggle (only for object which support it)
*/

View File

@@ -250,6 +250,23 @@ class BaseAdminController extends BaseController
$this->redirect(URL::getInstance()->absoluteUrl($this->getRoute($routeId), $urlParameters));
}
/**
* Get the current edition currency ID, checking if a change was requested in the current request.
*/
protected function getCurrentEditionCurrency()
{
// Return the new language if a change is required.
if (null !== $edit_currency_id = $this->getRequest()->get('edit_currency_id', null)) {
if (null !== $edit_currency = LangQuery::create()->findOneById($edit_currency_id)) {
return $edit_currency;
}
}
// Otherwise return the lang stored in session.
return $this->getSession()->getAdminEditionCurrency();
}
/**
* Get the current edition lang ID, checking if a change was requested in the current request.
*/
@@ -376,6 +393,9 @@ class BaseAdminController extends BaseController
// Find the current edit language ID
$edition_language = $this->getCurrentEditionLang();
// Find the current edit currency ID
$edition_currency = $this->getCurrentEditionCurrency();
// Prepare common template variables
$args = array_merge($args, array(
'locale' => $session->getLang()->getLocale(),
@@ -385,11 +405,16 @@ class BaseAdminController extends BaseController
'edit_language_id' => $edition_language->getId(),
'edit_language_locale' => $edition_language->getLocale(),
'edit_currency_id' => $edition_currency->getId(),
'current_url' => $this->getRequest()->getUri()
));
// Update the current edition language in session
$this->getSession()->setAdminEditionLang($edition_language);
// Update the current edition language & currency in session
$this->getSession()
->setAdminEditionLang($edition_language)
->setAdminEditionCurrency($edition_currency)
;
// Render the template.
try {

View File

@@ -43,6 +43,16 @@ use Thelia\Model\AccessoryQuery;
use Thelia\Model\CategoryQuery;
use Thelia\Core\Event\ProductAddAccessoryEvent;
use Thelia\Core\Event\ProductDeleteAccessoryEvent;
use Thelia\Core\Event\FeatureProductUpdateEvent;
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;
/**
* Manages products
@@ -72,6 +82,35 @@ class ProductController extends AbstractCrudController
);
}
/**
* Attributes ajax tab loading
*/
public function loadAttributesAjaxTabAction() {
return $this->render(
'ajax/product-attributes-tab',
array(
'product_id' => $this->getRequest()->get('product_id', 0),
)
);
}
/**
* Related information ajax tab loading
*/
public function loadRelatedAjaxTabAction() {
return $this->render(
'ajax/product-related-tab',
array(
'product_id' => $this->getRequest()->get('product_id', 0),
'folder_id' => $this->getRequest()->get('folder_id', 0),
'accessory_category_id' => $this->getRequest()->get('accessory_category_id', 0)
)
);
}
protected function getCreationForm()
{
return new ProductCreationForm($this->getRequest());
@@ -92,6 +131,10 @@ class ProductController extends AbstractCrudController
->setLocale($formData['locale'])
->setDefaultCategory($formData['default_category'])
->setVisible($formData['visible'])
->setBasePrice($formData['price'])
->setBaseWeight($formData['weight'])
->setCurrencyId($formData['currency'])
->setTaxRuleId($formData['tax_rule'])
;
return $createEvent;
@@ -110,8 +153,8 @@ class ProductController extends AbstractCrudController
->setPostscriptum($formData['postscriptum'])
->setVisible($formData['visible'])
->setUrl($formData['url'])
->setParent($formData['parent'])
;
->setDefaultCategory($formData['default_category'])
;
return $changeEvent;
}
@@ -137,9 +180,15 @@ class ProductController extends AbstractCrudController
protected function hydrateObjectForm($object)
{
// Get the default produc sales element
$salesElement = ProductSaleElementsQuery::create()->filterByProduct($object)->filterByIsDefault(true)->findOne();
// $prices = $salesElement->getProductPrices();
// Prepare the data that will hydrate the form
$data = array(
'id' => $object->getId(),
'ref' => $object->getRef(),
'locale' => $object->getLocale(),
'title' => $object->getTitle(),
'chapo' => $object->getChapo(),
@@ -148,6 +197,8 @@ class ProductController extends AbstractCrudController
'visible' => $object->getVisible(),
'url' => $object->getRewrittenUrl($this->getCurrentEditionLocale()),
'default_category' => $object->getDefaultCategoryId()
// A terminer pour les prix
);
// Setup the object form
@@ -179,10 +230,10 @@ class ProductController extends AbstractCrudController
protected function getEditionArguments()
{
return array(
'category_id' => $this->getCategoryId(),
'product_id' => $this->getRequest()->get('product_id', 0),
'folder_id' => $this->getRequest()->get('folder_id', 0),
'accessory_category_id'=> $this->getRequest()->get('accessory_category_id', 0),
'category_id' => $this->getCategoryId(),
'product_id' => $this->getRequest()->get('product_id', 0),
'folder_id' => $this->getRequest()->get('folder_id', 0),
'accessory_category_id' => $this->getRequest()->get('accessory_category_id', 0),
'current_tab' => $this->getRequest()->get('current_tab', 'general')
);
}
@@ -417,7 +468,6 @@ class ProductController extends AbstractCrudController
public function deleteAccessoryAction()
{
// Check current user authorization
if (null !== $response = $this->checkAuth("admin.products.update")) return $response;
@@ -443,35 +493,249 @@ class ProductController extends AbstractCrudController
}
/**
* Update accessory position (only for objects whichsupport that)
* Update accessory position
*/
public function updateAccessoryPositionAction()
{
$accessory = AccessoryQuery::create()->findPk($this->getRequest()->get('accessory_id', null));
return $this->genericUpdatePositionAction(
$accessory,
TheliaEvents::PRODUCT_UPDATE_ACCESSORY_POSITION
);
}
/**
* Update related content position
*/
public function updateContentPositionAction()
{
$content = ProductAssociatedContentQuery::create()->findPk($this->getRequest()->get('content_id', null));
return $this->genericUpdatePositionAction(
$content,
TheliaEvents::PRODUCT_UPDATE_CONTENT_POSITION
);
}
/**
* Change product template for a given product.
*
* @param unknown $productId
*/
public function setProductTemplateAction($productId) {
// Check current user authorization
if (null !== $response = $this->checkAuth('admin.products.update')) return $response;
try {
$mode = $this->getRequest()->get('mode', null);
$product = ProductQuery::create()->findPk($productId);
if ($mode == 'up')
$mode = UpdatePositionEvent::POSITION_UP;
else if ($mode == 'down')
$mode = UpdatePositionEvent::POSITION_DOWN;
else
$mode = UpdatePositionEvent::POSITION_ABSOLUTE;
if ($product != null) {
$position = $this->getRequest()->get('position', null);
$template_id = intval($this->getRequest()->get('template_id', 0));
$event = new UpdatePositionEvent($mode, $position);
$this->dispatch(TheliaEvents::PRODUCT_UPDATE_ACCESSORY_POSITION, $event);
}
catch (\Exception $ex) {
// Any error
return $this->errorPage($ex);
$this->dispatch(
TheliaEvents::PRODUCT_SET_TEMPLATE,
new ProductSetTemplateEvent($product, $template_id)
);
}
$this->redirectToEditionTemplate();
}
/**
* Update product attributes and features
*/
public function updateAttributesAndFeaturesAction($productId) {
$product = ProductQuery::create()->findPk($productId);
if ($product != null) {
$featureTemplate = FeatureTemplateQuery::create()->filterByTemplateId($product->getTemplateId())->find();
if ($featureTemplate !== null) {
// Get all features for the template attached to this product
$allFeatures = FeatureQuery::create()
->filterByFeatureTemplate($featureTemplate)
->find();
$updatedFeatures = array();
// Update all features values, starting with feature av. values
$featureValues = $this->getRequest()->get('feature_value', array());
foreach($featureValues as $featureId => $featureValueList) {
// Delete all features av. for this feature.
$event = new FeatureProductDeleteEvent($productId, $featureId);
$this->dispatch(TheliaEvents::PRODUCT_FEATURE_DELETE_VALUE, $event);
// Add then all selected values
foreach($featureValueList as $featureValue) {
$event = new FeatureProductUpdateEvent($productId, $featureId, $featureValue);
$this->dispatch(TheliaEvents::PRODUCT_FEATURE_UPDATE_VALUE, $event);
}
$updatedFeatures[] = $featureId;
}
// Update then features text values
$featureTextValues = $this->getRequest()->get('feature_text_value', array());
foreach($featureTextValues as $featureId => $featureValue) {
// considere empty text as empty feature value (e.g., we will delete it)
if (empty($featureValue)) continue;
$event = new FeatureProductUpdateEvent($productId, $featureId, $featureValue, true);
$this->dispatch(TheliaEvents::PRODUCT_FEATURE_UPDATE_VALUE, $event);
$updatedFeatures[] = $featureId;
}
// Delete features which don't have any values
foreach($allFeatures as $feature) {
if (! in_array($feature->getId(), $updatedFeatures)) {
$event = new FeatureProductDeleteEvent($productId, $feature->getId());
$this->dispatch(TheliaEvents::PRODUCT_FEATURE_DELETE_VALUE, $event);
}
}
}
}
// If we have to stay on the same page, do not redirect to the succesUrl,
// just redirect to the edit page again.
if ($this->getRequest()->get('save_mode') == 'stay') {
$this->redirectToEditionTemplate($this->getRequest());
}
// Redirect to the category/product list
$this->redirectToListTemplate();
}
public function addAdditionalCategoryAction() {
// Check current user authorization
if (null !== $response = $this->checkAuth("admin.products.update")) return $response;
$category_id = intval($this->getRequest()->get('additional_category_id'));
if ($category_id > 0) {
$event = new ProductAddCategoryEvent(
$this->getExistingObject(),
$category_id
);
try {
$this->dispatch(TheliaEvents::PRODUCT_ADD_CATEGORY, $event);
}
catch (\Exception $ex) {
// Any error
return $this->errorPage($ex);
}
}
$this->redirectToEditionTemplate();
}
public function deleteAdditionalCategoryAction() {
// Check current user authorization
if (null !== $response = $this->checkAuth("admin.products.update")) return $response;
$category_id = intval($this->getRequest()->get('additional_category_id'));
if ($category_id > 0) {
$event = new ProductDeleteCategoryEvent(
$this->getExistingObject(),
$category_id
);
try {
$this->dispatch(TheliaEvents::PRODUCT_REMOVE_CATEGORY, $event);
}
catch (\Exception $ex) {
// Any error
return $this->errorPage($ex);
}
}
$this->redirectToEditionTemplate();
}
// -- Product combination management ---------------------------------------
public function getAttributeValuesAction($productId, $attributeId) {
$result = array();
// Get attribute for this product
$attribute = AttributeQuery::create()->findPk($attributeId);
if ($attribute !== null) {
$values = AttributeAvQuery::create()
->joinWithI18n($this->getCurrentEditionLocale())
->filterByAttribute($attribute)
->find();
;
if ($values !== null) {
foreach($values as $value) {
$result[] = array('id' => $value->getId(), 'title' => $value->getTitle());
}
}
}
return $this->jsonResponse(json_encode($result));
}
public function addAttributeValueToCombinationAction($productId, $attributeAvId, $combination) {
$result = array();
// Get attribute for this product
$attributeAv = AttributeAvQuery::create()->joinWithI18n($this->getCurrentEditionLocale())->findPk($attributeAvId);
if ($attributeAv !== null) {
$addIt = true;
// Check if this attribute is not already present
$combinationArray = explode(',', $combination);
foreach ($combinationArray as $id) {
$attrAv = AttributeAvQuery::create()->joinWithI18n($this->getCurrentEditionLocale())->findPk($id);
if ($attrAv !== null) {
if ($attrAv->getAttributeId() == $attributeAv->getAttributeId()) {
$attribute = AttributeQuery::create()->joinWithI18n($this->getCurrentEditionLocale())->findPk($attributeAv->getAttributeId());
$result['error'] = $this->getTranslator()->trans(
'A value for attribute "%name" is already present in the combination',
array('%name' => $attribute->getTitle())
);
$addIt = false;
}
$result[] = array('id' => $attrAv->getId(), 'title' => $attrAv->getTitle());
}
}
if ($addIt) $result[] = array('id' => $attributeAv->getId(), 'title' => $attributeAv->getTitle());
}
return $this->jsonResponse(json_encode($result));
}
}

View File

@@ -39,6 +39,8 @@ use Thelia\Core\Event\TemplateDeleteAttributeEvent;
use Thelia\Core\Event\TemplateAddAttributeEvent;
use Thelia\Core\Event\TemplateAddFeatureEvent;
use Thelia\Core\Event\TemplateDeleteFeatureEvent;
use Thelia\Model\FeatureTemplateQuery;
use Thelia\Model\AttributeTemplateQuery;
/**
* Manages product templates
@@ -255,6 +257,21 @@ class TemplateController extends AbstractCrudController
$this->redirectToEditionTemplate();
}
public function updateAttributePositionAction() {
// Find attribute_template
$attributeTemplate = AttributeTemplateQuery::create()
->filterByTemplateId($this->getRequest()->get('template_id', null))
->filterByAttributeId($this->getRequest()->get('attribute_id', null))
->findOne()
;
return $this->genericUpdatePositionAction(
$attributeTemplate,
TheliaEvents::TEMPLATE_CHANGE_ATTRIBUTE_POSITION
);
}
public function addFeatureAction() {
// Check current user authorization
@@ -299,4 +316,18 @@ class TemplateController extends AbstractCrudController
$this->redirectToEditionTemplate();
}
public function updateFeaturePositionAction() {
// Find feature_template
$featureTemplate = FeatureTemplateQuery::create()
->filterByTemplateId($this->getRequest()->get('template_id', null))
->filterByFeatureId($this->getRequest()->get('feature_id', null))
->findOne()
;
return $this->genericUpdatePositionAction(
$featureTemplate,
TheliaEvents::TEMPLATE_CHANGE_FEATURE_POSITION
);
}
}