diff --git a/core/bootstrap.php b/core/bootstrap.php index 8b53e72e5..a75190704 100755 --- a/core/bootstrap.php +++ b/core/bootstrap.php @@ -6,11 +6,11 @@ * Functions needed for Thelia bootstrap */ define('THELIA_ROOT' , rtrim(realpath(__DIR__ .'/../'),'/') . "/"); -define('THELIA_LOCAL_DIR' , THELIA_ROOT . '/local/'); +define('THELIA_LOCAL_DIR' , THELIA_ROOT . 'local/'); define('THELIA_CONF_DIR' , THELIA_LOCAL_DIR . 'config/'); define('THELIA_MODULE_DIR' , THELIA_LOCAL_DIR . 'modules/'); -define('THELIA_WEB_DIR' , THELIA_ROOT . '/web/'); -define('THELIA_TEMPLATE_DIR' , THELIA_ROOT . '/templates/'); +define('THELIA_WEB_DIR' , THELIA_ROOT . 'web/'); +define('THELIA_TEMPLATE_DIR' , THELIA_ROOT . 'templates/'); define('DS', DIRECTORY_SEPARATOR); $loader = require __DIR__ . "/vendor/autoload.php"; diff --git a/core/lib/Thelia/Action/Customer.php b/core/lib/Thelia/Action/Customer.php index 3a39a4bf2..6ed4b480d 100755 --- a/core/lib/Thelia/Action/Customer.php +++ b/core/lib/Thelia/Action/Customer.php @@ -25,6 +25,7 @@ namespace Thelia\Action; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Thelia\Core\Event\ActionEvent; +use Thelia\Core\Event\CustomerEvent; use Thelia\Core\Event\TheliaEvents; use Thelia\Form\BaseForm; use Thelia\Form\CustomerCreation; @@ -88,8 +89,8 @@ class Customer implements EventSubscriberInterface $data["password"], $request->getSession()->getLang() ); - - $event->getDispatcher()->dispatch(TheliaEvents::AFTER_CREATECUSTOMER, $event); + $customerEvent = new CustomerEvent($customer); + $event->getDispatcher()->dispatch(TheliaEvents::AFTER_CREATECUSTOMER, $customerEvent); // Connect the newly created user,and redirect to the success URL $this->processSuccessfulLogin($event, $customer, $customerCreationForm, true); @@ -136,7 +137,8 @@ class Customer implements EventSubscriberInterface $customer = CustomerQuery::create()->findPk(1); try { - $event->getDispatcher()->dispatch(TheliaEvents::BEFORE_CHANGECUSTOMER, $event); + $customerEvent = new CustomerEvent($customer); + $event->getDispatcher()->dispatch(TheliaEvents::BEFORE_CHANGECUSTOMER, $customerEvent); $data = $form->getData(); @@ -153,7 +155,8 @@ class Customer implements EventSubscriberInterface $data["country"] ); - $event->getDispatcher()->dispatch(TheliaEvents::AFTER_CHANGECUSTOMER, $event); + $customerEvent->customer = $customer; + $event->getDispatcher()->dispatch(TheliaEvents::AFTER_CHANGECUSTOMER, $customerEvent); // 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. diff --git a/core/lib/Thelia/Admin/Controller/AdminController.php b/core/lib/Thelia/Admin/Controller/AdminController.php index 57421825e..41be586d7 100755 --- a/core/lib/Thelia/Admin/Controller/AdminController.php +++ b/core/lib/Thelia/Admin/Controller/AdminController.php @@ -27,6 +27,12 @@ class AdminController extends BaseAdminController { public function indexAction() { - return $this->render("home.html"); + return $this->render("home"); + } + + public function processAction() + { + echo "not yet coded !"; + exit(); } } \ No newline at end of file diff --git a/core/lib/Thelia/Admin/Controller/BaseAdminController.php b/core/lib/Thelia/Admin/Controller/BaseAdminController.php index 742db4304..17010a69e 100755 --- a/core/lib/Thelia/Admin/Controller/BaseAdminController.php +++ b/core/lib/Thelia/Admin/Controller/BaseAdminController.php @@ -50,10 +50,23 @@ use Thelia\Core\Event\ActionEvent; class BaseAdminController extends ContainerAware { - const TEMPLATE_404 = "404.html"; + const TEMPLATE_404 = "404"; - protected function undefinedAction() + public function processTemplateAction($template) { + try { + if (! empty($template)) { + // If we have a view in the URL, render this view + return $this->render($template); + } + else if (null != $view = $this->getRequest()->get('view')) { + return $this->render($view); + } + } + catch (\Exception $ex) { + // Nothing special + } + return new Response($this->renderRaw(self::TEMPLATE_404), 404); } @@ -81,6 +94,9 @@ class BaseAdminController extends ContainerAware */ protected function renderRaw($templateName, $args = array()) { + // Add the template standard extension + $templateName .= '.html'; + $session = $this->getSession(); $args = array_merge($args, array( @@ -158,7 +174,7 @@ class BaseAdminController extends ContainerAware } /** - * @return a ParserInterface instance parser + * @return a ParserInterfac instance parser */ protected function getParser() { diff --git a/core/lib/Thelia/Admin/Controller/SessionController.php b/core/lib/Thelia/Admin/Controller/SessionController.php index 9928a5a01..7d1b6365d 100755 --- a/core/lib/Thelia/Admin/Controller/SessionController.php +++ b/core/lib/Thelia/Admin/Controller/SessionController.php @@ -37,7 +37,7 @@ class SessionController extends BaseAdminController { public function showLoginAction() { - return $this->render("login.html"); + return $this->render("login"); } public function checkLogoutAction() @@ -100,6 +100,6 @@ class SessionController extends BaseAdminController { $this->getParserContext()->setErrorForm($adminLoginForm); // Display the login form again - return $this->render("login.html"); + return $this->render("login"); } } \ No newline at end of file diff --git a/core/lib/Thelia/Config/Resources/config.xml b/core/lib/Thelia/Config/Resources/config.xml index cde8350a6..58c0c8579 100755 --- a/core/lib/Thelia/Config/Resources/config.xml +++ b/core/lib/Thelia/Config/Resources/config.xml @@ -16,6 +16,7 @@ + diff --git a/core/lib/Thelia/Config/Resources/routing/admin.xml b/core/lib/Thelia/Config/Resources/routing/admin.xml index fe5a0a283..4f053b76e 100755 --- a/core/lib/Thelia/Config/Resources/routing/admin.xml +++ b/core/lib/Thelia/Config/Resources/routing/admin.xml @@ -24,8 +24,22 @@ Thelia\Admin\Controller\SessionController::checkLoginAction - - Thelia\Admin\Controller\AdminController::undefinedAction - .* + + + + + Thelia\Admin\Controller\CategoryController::indexAction + + + + Thelia\Admin\Controller\CategoryController::processAction + .* + + + + + + Thelia\Admin\Controller\AdminController::processTemplateAction + .* \ No newline at end of file diff --git a/core/lib/Thelia/Core/Event/CustomerEvent.php b/core/lib/Thelia/Core/Event/CustomerEvent.php new file mode 100644 index 000000000..f9f00278d --- /dev/null +++ b/core/lib/Thelia/Core/Event/CustomerEvent.php @@ -0,0 +1,38 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Core\Event; + + +use Thelia\Model\Customer; + +class CustomerEvent extends InternalEvent { + + public $customer; + + public function __construct(Customer $customer) + { + $this->customer = $customer; + } + +} \ No newline at end of file diff --git a/core/lib/Thelia/Core/Template/Element/BaseLoop.php b/core/lib/Thelia/Core/Template/Element/BaseLoop.php index debc022b6..7c9740ee0 100755 --- a/core/lib/Thelia/Core/Template/Element/BaseLoop.php +++ b/core/lib/Thelia/Core/Template/Element/BaseLoop.php @@ -117,6 +117,9 @@ abstract class BaseLoop $faultActor = array(); $faultDetails = array(); + $loopType = isset($nameValuePairs['type']) ? $nameValuePairs['type'] : "undefined"; + $loopName = isset($nameValuePairs['name']) ? $nameValuePairs['name'] : "undefined"; + while (($argument = $this->args->current()) !== false) { $this->args->next(); @@ -125,17 +128,17 @@ abstract class BaseLoop /* check if mandatory */ if($value === null && $argument->mandatory) { $faultActor[] = $argument->name; - $faultDetails[] = sprintf('"%s" parameter is missing', $argument->name); + $faultDetails[] = sprintf('"%s" parameter is missing in loop type: %s, name: %s', $argument->name, $loopType, $loopName); } else if($value === '' && !$argument->empty) { /* check if empty */ $faultActor[] = $argument->name; - $faultDetails[] = sprintf('"%s" parameter cannot be empty', $argument->name); + $faultDetails[] = sprintf('"%s" parameter cannot be empty in loop type: %s, name: %s', $argument->name, $loopType, $loopName); } else if($value !== null && !$argument->type->isValid($value)) { /* check type */ $faultActor[] = $argument->name; - $faultDetails[] = sprintf('Invalid value for "%s" argument', $argument->name); + $faultDetails[] = sprintf('Invalid value for "%s" argument in loop type: %s, name: %s', $argument->name, $loopType, $loopName); } else { /* set default */ diff --git a/core/lib/Thelia/Core/Template/Element/LoopResultRow.php b/core/lib/Thelia/Core/Template/Element/LoopResultRow.php index 24fa67c7e..cb847b557 100755 --- a/core/lib/Thelia/Core/Template/Element/LoopResultRow.php +++ b/core/lib/Thelia/Core/Template/Element/LoopResultRow.php @@ -30,6 +30,8 @@ class LoopResultRow public function set($key, $value) { $this->substitution[$key] = $value === null ? '' : $value; + + return $this; } public function get($key) diff --git a/core/lib/Thelia/Core/Template/Loop/Category.php b/core/lib/Thelia/Core/Template/Loop/Category.php index 55e627d8f..87ea0ec08 100755 --- a/core/lib/Thelia/Core/Template/Loop/Category.php +++ b/core/lib/Thelia/Core/Template/Loop/Category.php @@ -168,14 +168,25 @@ class Category extends BaseLoop if ($this->not_empty && $category->countAllProducts() == 0) continue; $loopResultRow = new LoopResultRow(); - $loopResultRow->set("TITLE",$category->getTitle()); - $loopResultRow->set("CHAPO", $category->getChapo()); - $loopResultRow->set("DESCRIPTION", $category->getDescription()); - $loopResultRow->set("POSTSCRIPTUM", $category->getPostscriptum()); - $loopResultRow->set("PARENT", $category->getParent()); - $loopResultRow->set("ID", $category->getId()); - $loopResultRow->set("URL", $category->getUrl()); - $loopResultRow->set("PRODUCT_COUNT", $category->countChild()); + + $loopResultRow + ->set("ID", $category->getId()) + ->set("TITLE",$category->getTitle()) + ->set("CHAPO", $category->getChapo()) + ->set("DESCRIPTION", $category->getDescription()) + ->set("POSTSCRIPTUM", $category->getPostscriptum()) + ->set("PARENT", $category->getParent()) + ->set("URL", $category->getUrl()) + ->set("PRODUCT_COUNT", $category->countChild()) + ->set("VISIBLE", $category->getVisible() ? "1" : "0") + ->set("POSITION", $category->getPosition()) + + ->set("CREATE_DATE", $category->getCreatedAt()) + ->set("UPDATE_DATE", $category->getUpdatedAt()) + ->set("VERSION", $category->getVersion()) + ->set("VERSION_DATE", $category->getVersionCreatedAt()) + ->set("VERSION_AUTHOR", $category->getVersionCreatedBy()) + ; $loopResult->addRow($loopResultRow); } diff --git a/core/lib/Thelia/Core/Template/Loop/FeatureValue.php b/core/lib/Thelia/Core/Template/Loop/FeatureValue.php index 67aa7b402..403baf37a 100755 --- a/core/lib/Thelia/Core/Template/Loop/FeatureValue.php +++ b/core/lib/Thelia/Core/Template/Loop/FeatureValue.php @@ -87,7 +87,7 @@ class FeatureValue extends BaseLoop $search->filterByProductId($product, Criteria::EQUAL); - $featureAvailable = $this->geFeature_available(); + $featureAvailable = $this->getFeature_available(); if (null !== $featureAvailable) { $search->filterByFeatureAvId($featureAvailable, Criteria::IN); diff --git a/core/lib/Thelia/Core/Template/Loop/Product.php b/core/lib/Thelia/Core/Template/Loop/Product.php index e9c1f689a..817419ff4 100755 --- a/core/lib/Thelia/Core/Template/Loop/Product.php +++ b/core/lib/Thelia/Core/Template/Loop/Product.php @@ -86,7 +86,7 @@ class Product extends BaseLoop new TypeCollection( new Type\EnumListType(array('alpha', 'alpha_reverse', /*'min_price', 'max_price',*/ 'manual', 'manual_reverse', 'ref', /*'promo', 'new',*/ 'random', 'given_id')) ), - 'manual' + 'alpha' ), Argument::createIntListTypeArgument('exclude'), Argument::createIntListTypeArgument('exclude_category'), @@ -271,12 +271,12 @@ class Product extends BaseLoop $search->orderBy('real_price', Criteria::DESC); break;*/ case "manual": - if(null === $this->category || count($this->category) != 1) + if(null === $category || count($category) != 1) throw new \InvalidArgumentException('Manual order cannot be set without single category argument'); $search->orderByPosition(Criteria::ASC); break; case "manual_reverse": - if(null === $this->category || count($this->category) != 1) + if(null === $category || count($category) != 1) throw new \InvalidArgumentException('Manual order cannot be set without single category argument'); $search->orderByPosition(Criteria::DESC); break; @@ -395,17 +395,20 @@ class Product extends BaseLoop foreach ($products as $product) { $loopResultRow = new LoopResultRow(); - $loopResultRow->set("ID", $product->getId()); - $loopResultRow->set("REF",$product->getRef()); - $loopResultRow->set("TITLE",$product->getTitle()); - $loopResultRow->set("CHAPO", $product->getChapo()); - $loopResultRow->set("DESCRIPTION", $product->getDescription()); - $loopResultRow->set("POSTSCRIPTUM", $product->getPostscriptum()); - //$loopResultRow->set("PRICE", $product->getPrice()); - //$loopResultRow->set("PROMO_PRICE", $product->getPrice2()); - //$loopResultRow->set("WEIGHT", $product->getWeight()); - //$loopResultRow->set("PROMO", $product->getPromo()); - //$loopResultRow->set("NEW", $product->getNewness()); + + $loopResultRow->set("ID", $product->getId()) + ->set("REF",$product->getRef()) + ->set("TITLE",$product->getTitle()) + ->set("CHAPO", $product->getChapo()) + ->set("DESCRIPTION", $product->getDescription()) + ->set("POSTSCRIPTUM", $product->getPostscriptum()) + ->set("PRICE", $product->getPrice()) + ->set("PROMO_PRICE", $product->getPrice2()) + ->set("WEIGHT", $product->getWeight()) + ->set("PROMO", $product->getPromo()) + ->set("NEW", $product->getNewness()) + ->set("POSITION", $product->getPosition()) + ; $loopResult->addRow($loopResultRow); } diff --git a/core/lib/Thelia/Core/Template/Smarty/AbstractSmartyPlugin.php b/core/lib/Thelia/Core/Template/Smarty/AbstractSmartyPlugin.php index 0015dbb0b..8c1a83a71 100755 --- a/core/lib/Thelia/Core/Template/Smarty/AbstractSmartyPlugin.php +++ b/core/lib/Thelia/Core/Template/Smarty/AbstractSmartyPlugin.php @@ -51,6 +51,48 @@ abstract class AbstractSmartyPlugin return array(); } + /** + * Get a function or block parameter value, and normalize it, trimming balnks and + * making it lowercase + * + * @param array $params the parameters array + * @param mixed $name as single parameter name, or an array of names. In this case, the first defined parameter is returned. Use this for aliases (context, ctx, c) + * @param mixed $default the defaut value if parameter is missing (default to null) + * @return mixed the parameter value, or the default value if it is not found. + */ + public function getNormalizedParam($params, $name, $default = null) + { + $value = $this->getParam($params, $name, $default); + + if (is_string($value)) $value = strtolower(trim($value)); + + return $value; + } + + /** + * Get a function or block parameter value + * + * @param array $params the parameters array + * @param mixed $name as single parameter name, or an array of names. In this case, the first defined parameter is returned. Use this for aliases (context, ctx, c) + * @param mixed $default the defaut value if parameter is missing (default to null) + * @return mixed the parameter value, or the default value if it is not found. + */ + public function getParam($params, $name, $default = null) + { + if (is_array($name)) { + foreach($name as $test) { + if (isset($params[$test])) { + return $params[$test]; + } + } + } + else if (isset($params[$name])) { + return $params[$name]; + } + + return $default; + } + /** * @return an array of SmartyPluginDescriptor */ diff --git a/core/lib/Thelia/Core/Template/Smarty/Plugins/DataAccessFunctions.php b/core/lib/Thelia/Core/Template/Smarty/Plugins/DataAccessFunctions.php index 7fcbdfbc7..93ef84e58 100644 --- a/core/lib/Thelia/Core/Template/Smarty/Plugins/DataAccessFunctions.php +++ b/core/lib/Thelia/Core/Template/Smarty/Plugins/DataAccessFunctions.php @@ -78,13 +78,13 @@ class DataAccessFunctions extends AbstractSmartyPlugin */ protected function userDataAccess($objectLabel, $context, $params) { - $attribute = $params['attr']; + $attribute = $this->getNormalizedParam($params, array('attribute', 'attrib', 'attr')); if (! empty($attribute)) { $user = $this->securityContext->setContext($context)->getUser(); if (null != $user) { - $getter = sprintf("get%s", ucfirst(strtolower($attribute))); + $getter = sprintf("get%s", ucfirst($attribute)); if (method_exists($user, $getter)) { return $user->$getter(); diff --git a/core/lib/Thelia/Core/Template/Smarty/Plugins/Form.php b/core/lib/Thelia/Core/Template/Smarty/Plugins/Form.php index 7ddb96104..afb164604 100755 --- a/core/lib/Thelia/Core/Template/Smarty/Plugins/Form.php +++ b/core/lib/Thelia/Core/Template/Smarty/Plugins/Form.php @@ -85,11 +85,13 @@ class Form extends AbstractSmartyPlugin { if ($repeat) { - if (empty($params['name'])) { + $name = $this->getParam($params, 'name'); + + if (null == $name) { throw new \InvalidArgumentException("Missing 'name' parameter in form arguments"); } - $instance = $this->createInstance($params['name']); + $instance = $this->createInstance($name); // Check if parser context contains our form $errorForm = $this->parserContext->getErrorForm(); @@ -212,10 +214,11 @@ class Form extends AbstractSmartyPlugin protected function getFormFieldView($params) { $instance = $this->getInstanceFromParams($params); - if (! isset($params['field'])) + $fieldName = $this->getParam($params, 'field'); + + if (null == $fieldName) throw new \InvalidArgumentException("'field' parameter is missing"); - $fieldName = $params['field']; if (empty($instance->getView()[$fieldName])) throw new \InvalidArgumentException(sprintf("Field name '%s' not found in form %s", $fieldName, $instance->getName())); @@ -225,12 +228,12 @@ class Form extends AbstractSmartyPlugin protected function getInstanceFromParams($params) { - if (empty($params['form'])) { + $instance = $this->getParam($params, 'form'); + + if (null == $instance) { throw new \InvalidArgumentException("Missing 'form' parameter in form arguments"); } - $instance = $params["form"]; - if (! $instance instanceof \Thelia\Form\BaseForm) { throw new \InvalidArgumentException(sprintf("form parameter in form_field block must be an instance of \Thelia\Form\BaseForm, instance of %s found", get_class($instance))); diff --git a/core/lib/Thelia/Core/Template/Smarty/Plugins/Security.php b/core/lib/Thelia/Core/Template/Smarty/Plugins/Security.php index 51bb0d1ef..c1d12feb1 100755 --- a/core/lib/Thelia/Core/Template/Smarty/Plugins/Security.php +++ b/core/lib/Thelia/Core/Template/Smarty/Plugins/Security.php @@ -48,22 +48,25 @@ class Security extends AbstractSmartyPlugin public function checkAuthFunction($params, &$smarty) { // Context: 'front' or 'admin' - $context = strtolower(trim($params['context'])); + $context = $this->getNormalizedParam($params, 'context'); $this->securityContext->setContext($context); - $roles = $this->_explode($params['roles']); - $permissions = $this->_explode($params['permissions']); + $roles = $this->_explode($this->getParam($params, 'roles')); + $permissions = $this->_explode($this->getParam($params, 'permissions')); if (! $this->securityContext->isGranted($roles, $permissions)) { + $ex = new AuthenticationException( sprintf("User not granted for roles '%s', permissions '%s' in context '%s'.", implode(',', $roles), implode(',', $permissions), $context ) ); - if (! empty($params['login_tpl'])) { - $ex->setLoginTemplate($params['login_tpl']); + $loginTpl = $this->getParam($params, 'login_tpl'); + + if (null != $loginTpl) { + $ex->setLoginTemplate($loginTpl); } throw $ex; @@ -73,7 +76,7 @@ class Security extends AbstractSmartyPlugin } /** - * Define the various smarty plugins hendled by this class + * Define the various smarty plugins handled by this class * * @return an array of smarty plugin descriptors */ diff --git a/core/lib/Thelia/Core/Template/Smarty/Plugins/TheliaLoop.php b/core/lib/Thelia/Core/Template/Smarty/Plugins/TheliaLoop.php index ddb0eca4a..e1eefedb0 100755 --- a/core/lib/Thelia/Core/Template/Smarty/Plugins/TheliaLoop.php +++ b/core/lib/Thelia/Core/Template/Smarty/Plugins/TheliaLoop.php @@ -71,9 +71,11 @@ class TheliaLoop extends AbstractSmartyPlugin /** * Process the count function: executes a loop and return the number of items found */ - public function theliaCount($params, $template) { + public function theliaCount($params, $template) + { + $type = $this->getParam($params, 'type'); - if (empty($params['type'])) + if (null == $type) throw new \InvalidArgumentException("Missing 'type' parameter in count arguments"); $loop = $this->createLoopInstance($params); @@ -97,13 +99,15 @@ class TheliaLoop extends AbstractSmartyPlugin */ public function theliaLoop($params, $content, $template, &$repeat) { - if (empty($params['name'])) + $name = $this->getParam($params, 'name'); + + if (null == $name) throw new \InvalidArgumentException("Missing 'name' parameter in loop arguments"); - if (empty($params['type'])) - throw new \InvalidArgumentException("Missing 'type' parameter in loop arguments"); + $type = $this->getParam($params, 'type'); - $name = $params['name']; + if (null == $type) + throw new \InvalidArgumentException("Missing 'type' parameter in loop arguments"); if ($content === null) { // Check if a loop with the same name exists in the current scope, and abort if it's the case. @@ -116,8 +120,12 @@ class TheliaLoop extends AbstractSmartyPlugin self::$pagination[$name] = null; $loopResults = $loop->exec(self::$pagination[$name]); + $this->loopstack[$name] = $loopResults; + // Pas de résultat ? la boucle est terminée, ne pas évaluer le contenu. + if ($loopResults->isEmpty()) $repeat = false; + } else { $loopResults = $this->loopstack[$name]; @@ -223,10 +231,10 @@ class TheliaLoop extends AbstractSmartyPlugin */ public function theliaPageLoop($params, $content, $template, &$repeat) { - if (empty($params['rel'])) - throw new \InvalidArgumentException("Missing 'rel' parameter in page loop"); + $loopName = $this->getParam($params, 'rel'); - $loopName = $params['rel']; + if (null == $loopName) + throw new \InvalidArgumentException("Missing 'rel' parameter in page loop"); // Find loop results in the current template vars /* $loopResults = $template->getTemplateVars($loopName); @@ -274,11 +282,10 @@ class TheliaLoop extends AbstractSmartyPlugin */ protected function checkEmptyLoop($params, $template) { + $loopName = $this->getParam($params, 'rel'); - if (empty($params['rel'])) - throw new \InvalidArgumentException("Missing 'rel' parameter in ifloop/elseloop arguments"); - - $loopName = $params['rel']; + if (null == $loopName) + throw new \InvalidArgumentException("Missing 'rel' parameter in ifloop/elseloop arguments"); if (! isset($this->loopstack[$loopName])) { throw new \InvalidArgumentException("Loop $loopName is not defined."); diff --git a/core/lib/Thelia/Core/Template/Smarty/Plugins/Translation.php b/core/lib/Thelia/Core/Template/Smarty/Plugins/Translation.php index 6015ca618..43118b218 100755 --- a/core/lib/Thelia/Core/Template/Smarty/Plugins/Translation.php +++ b/core/lib/Thelia/Core/Template/Smarty/Plugins/Translation.php @@ -49,10 +49,10 @@ class Translation extends AbstractSmartyPlugin $vars = array(); foreach($params as $name => $value) { - $vars["%$name"] = $value; + if ($name != 'l') $vars["%$name"] = $value; } - return $this->translator->trans($params['l'], $vars); + return $this->translator->trans($this->getParam($params, 'l'), $vars); } /** diff --git a/core/lib/Thelia/Core/Template/Smarty/Plugins/UrlGenerator.php b/core/lib/Thelia/Core/Template/Smarty/Plugins/UrlGenerator.php index 9d63080be..8bc0ad991 100644 --- a/core/lib/Thelia/Core/Template/Smarty/Plugins/UrlGenerator.php +++ b/core/lib/Thelia/Core/Template/Smarty/Plugins/UrlGenerator.php @@ -47,7 +47,7 @@ class UrlGenerator extends AbstractSmartyPlugin public function generateUrlFunction($params, &$smarty) { // the path to process - $path = trim($params['path']); + $path = $this->getParam($params, 'path'); return URL::absoluteUrl($path, $this->getArgsFromParam($params)); } @@ -59,19 +59,36 @@ class UrlGenerator extends AbstractSmartyPlugin * @param unknown $smarty * @return string no text is returned. */ - public function generateViewUrlFunction($params, &$smarty) + public function generateFrontViewUrlFunction($params, &$smarty) + { + return $this->generateViewUrlFunction($params, false); + } + + /** + * Process administration view url generator function + * + * @param array $params + * @param unknown $smarty + * @return string no text is returned. + */ + public function generateAdminViewUrlFunction($params, &$smarty) + { + return $this->generateViewUrlFunction($params, true); + } + + protected function generateViewUrlFunction($params, $forAdmin) { // the view name (without .html) - $view = trim($params['view']); + $view = $this->getParam($params,'view'); // the related action (optionale) - $action = trim($params['action']); + $action = $this->getParam($params, 'action'); $args = $this->getArgsFromParam($params); if (! empty($action)) $args['action'] = $action; - return URL::viewUrl($view, $args); + return $forAdmin ? URL::adminViewUrl($view, $args) : URL::viewUrl($view, $args); } /** @@ -83,14 +100,13 @@ class UrlGenerator extends AbstractSmartyPlugin */ private function getArgsFromParam($params) { - if (isset($params['args'])) - return explode($params['args'], ','); + $args = $this->getParam($params, array('arguments', 'args')); - return array(); + return $args !== null ? explode($args, ',') : array(); } /** - * Define the various smarty plugins hendled by this class + * Define the various smarty plugins handled by this class * * @return an array of smarty plugin descriptors */ @@ -98,7 +114,8 @@ class UrlGenerator extends AbstractSmartyPlugin { return array( new SmartyPluginDescriptor('function', 'url', $this, 'generateUrlFunction'), - new SmartyPluginDescriptor('function', 'viewurl', $this, 'generateViewUrlFunction') + new SmartyPluginDescriptor('function', 'viewurl', $this, 'generateFrontViewUrlFunction'), + new SmartyPluginDescriptor('function', 'admin_viewurl', $this, 'generateAdminViewUrlFunction') ); } } diff --git a/core/lib/Thelia/Tests/Core/Template/Element/BaseLoopTestor.php b/core/lib/Thelia/Tests/Core/Template/Element/BaseLoopTestor.php new file mode 100755 index 000000000..bad6dc428 --- /dev/null +++ b/core/lib/Thelia/Tests/Core/Template/Element/BaseLoopTestor.php @@ -0,0 +1,86 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Tests\Core\Template\Element; + +use Symfony\Component\EventDispatcher\EventDispatcher; +use Thelia\Core\HttpFoundation\Request; +use Thelia\Core\Security\SecurityContext; +use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage; +use Thelia\Core\HttpFoundation\Session\Session; + +/** + * + * @author Etienne Roudeix + * + */ +abstract class BaseLoopTestor extends \PHPUnit_Framework_TestCase +{ + protected $request; + protected $dispatcher; + protected $securityContext; + + protected $instance; + + abstract public function getTestedClassName(); + abstract public function getTestedInstance(); + abstract public function getMandatoryArguments(); + + protected function getMethod($name) { + $class = new \ReflectionClass($this->getTestedClassName()); + $method = $class->getMethod($name); + $method->setAccessible(true); + return $method; + } + + public function setUp() + { + $this->request = new Request(); + $this->request->setSession(new Session(new MockArraySessionStorage())); + + $this->dispatcher = new EventDispatcher(); + + $this->securityContext = new SecurityContext($this->request); + + $this->instance = $this->getTestedInstance(); + $this->instance->initializeArgs($this->getMandatoryArguments()); + } + + public function testGetArgDefinitions() + { + $method = $this->getMethod('getArgDefinitions'); + + $methodReturn = $method->invoke($this->instance); + + $this->assertInstanceOf('Thelia\Core\Template\Loop\Argument\ArgumentCollection', $methodReturn); + } + + public function testExec() + { + $method = $this->getMethod('exec'); + + $methodReturn = $method->invokeArgs($this->instance, array(null)); + + $this->assertInstanceOf('\Thelia\Core\Template\Element\LoopResult', $methodReturn); + } +} diff --git a/core/lib/Thelia/Tests/Core/Template/Loop/AccessoryTest.php b/core/lib/Thelia/Tests/Core/Template/Loop/AccessoryTest.php new file mode 100755 index 000000000..99f5a0310 --- /dev/null +++ b/core/lib/Thelia/Tests/Core/Template/Loop/AccessoryTest.php @@ -0,0 +1,51 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Tests\Core\Template\Loop; + +use Thelia\Tests\Core\Template\Element\BaseLoopTestor; + +use Thelia\Core\Template\Loop\Accessory; + +/** + * + * @author Etienne Roudeix + * + */ +class AccessoryTest extends BaseLoopTestor +{ + public function getTestedClassName() + { + return 'Thelia\Core\Template\Loop\Accessory'; + } + + public function getTestedInstance() + { + return new Accessory($this->request, $this->dispatcher, $this->securityContext); + } + + public function getMandatoryArguments() + { + return array('product' => 1); + } +} diff --git a/core/lib/Thelia/Tests/Core/Template/Loop/AddressTest.php b/core/lib/Thelia/Tests/Core/Template/Loop/AddressTest.php new file mode 100755 index 000000000..7ca5c094b --- /dev/null +++ b/core/lib/Thelia/Tests/Core/Template/Loop/AddressTest.php @@ -0,0 +1,51 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Tests\Core\Template\Loop; + +use Thelia\Tests\Core\Template\Element\BaseLoopTestor; + +use Thelia\Core\Template\Loop\Address; + +/** + * + * @author Etienne Roudeix + * + */ +class AddressTest extends BaseLoopTestor +{ + public function getTestedClassName() + { + return 'Thelia\Core\Template\Loop\Address'; + } + + public function getTestedInstance() + { + return new Address($this->request, $this->dispatcher, $this->securityContext); + } + + public function getMandatoryArguments() + { + return array(); + } +} diff --git a/core/lib/Thelia/Tests/Core/Template/Loop/CategoryTest.php b/core/lib/Thelia/Tests/Core/Template/Loop/CategoryTest.php new file mode 100755 index 000000000..f33d07868 --- /dev/null +++ b/core/lib/Thelia/Tests/Core/Template/Loop/CategoryTest.php @@ -0,0 +1,51 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Tests\Core\Template\Loop; + +use Thelia\Tests\Core\Template\Element\BaseLoopTestor; + +use Thelia\Core\Template\Loop\Category; + +/** + * + * @author Etienne Roudeix + * + */ +class CategoryTest extends BaseLoopTestor +{ + public function getTestedClassName() + { + return 'Thelia\Core\Template\Loop\Category'; + } + + public function getTestedInstance() + { + return new Category($this->request, $this->dispatcher, $this->securityContext); + } + + public function getMandatoryArguments() + { + return array(); + } +} diff --git a/core/lib/Thelia/Tests/Core/Template/Loop/CountryTest.php b/core/lib/Thelia/Tests/Core/Template/Loop/CountryTest.php new file mode 100755 index 000000000..389d0bc5d --- /dev/null +++ b/core/lib/Thelia/Tests/Core/Template/Loop/CountryTest.php @@ -0,0 +1,51 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Tests\Core\Template\Loop; + +use Thelia\Tests\Core\Template\Element\BaseLoopTestor; + +use Thelia\Core\Template\Loop\Country; + +/** + * + * @author Etienne Roudeix + * + */ +class CountryTest extends BaseLoopTestor +{ + public function getTestedClassName() + { + return 'Thelia\Core\Template\Loop\Country'; + } + + public function getTestedInstance() + { + return new Country($this->request, $this->dispatcher, $this->securityContext); + } + + public function getMandatoryArguments() + { + return array(); + } +} diff --git a/core/lib/Thelia/Tests/Core/Template/Loop/CustomerTest.php b/core/lib/Thelia/Tests/Core/Template/Loop/CustomerTest.php new file mode 100755 index 000000000..62bcaa3be --- /dev/null +++ b/core/lib/Thelia/Tests/Core/Template/Loop/CustomerTest.php @@ -0,0 +1,51 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Tests\Core\Template\Loop; + +use Thelia\Tests\Core\Template\Element\BaseLoopTestor; + +use Thelia\Core\Template\Loop\Customer; + +/** + * + * @author Etienne Roudeix + * + */ +class CustomerTest extends BaseLoopTestor +{ + public function getTestedClassName() + { + return 'Thelia\Core\Template\Loop\Customer'; + } + + public function getTestedInstance() + { + return new Customer($this->request, $this->dispatcher, $this->securityContext); + } + + public function getMandatoryArguments() + { + return array(); + } +} diff --git a/core/lib/Thelia/Tests/Core/Template/Loop/FeatureAvailableTest.php b/core/lib/Thelia/Tests/Core/Template/Loop/FeatureAvailableTest.php new file mode 100755 index 000000000..e93b05a69 --- /dev/null +++ b/core/lib/Thelia/Tests/Core/Template/Loop/FeatureAvailableTest.php @@ -0,0 +1,51 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Tests\Core\Template\Loop; + +use Thelia\Tests\Core\Template\Element\BaseLoopTestor; + +use Thelia\Core\Template\Loop\FeatureAvailable; + +/** + * + * @author Etienne Roudeix + * + */ +class FeatureAvailableTest extends BaseLoopTestor +{ + public function getTestedClassName() + { + return 'Thelia\Core\Template\Loop\FeatureAvailable'; + } + + public function getTestedInstance() + { + return new FeatureAvailable($this->request, $this->dispatcher, $this->securityContext); + } + + public function getMandatoryArguments() + { + return array(); + } +} diff --git a/core/lib/Thelia/Tests/Core/Template/Loop/FeatureTest.php b/core/lib/Thelia/Tests/Core/Template/Loop/FeatureTest.php new file mode 100755 index 000000000..155088173 --- /dev/null +++ b/core/lib/Thelia/Tests/Core/Template/Loop/FeatureTest.php @@ -0,0 +1,51 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Tests\Core\Template\Loop; + +use Thelia\Tests\Core\Template\Element\BaseLoopTestor; + +use Thelia\Core\Template\Loop\Feature; + +/** + * + * @author Etienne Roudeix + * + */ +class FeatureTest extends BaseLoopTestor +{ + public function getTestedClassName() + { + return 'Thelia\Core\Template\Loop\Feature'; + } + + public function getTestedInstance() + { + return new Feature($this->request, $this->dispatcher, $this->securityContext); + } + + public function getMandatoryArguments() + { + return array(); + } +} diff --git a/core/lib/Thelia/Tests/Core/Template/Loop/FeatureValueTest.php b/core/lib/Thelia/Tests/Core/Template/Loop/FeatureValueTest.php new file mode 100755 index 000000000..3f6a14a16 --- /dev/null +++ b/core/lib/Thelia/Tests/Core/Template/Loop/FeatureValueTest.php @@ -0,0 +1,51 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Tests\Core\Template\Loop; + +use Thelia\Tests\Core\Template\Element\BaseLoopTestor; + +use Thelia\Core\Template\Loop\FeatureValue; + +/** + * + * @author Etienne Roudeix + * + */ +class FeatureValueTest extends BaseLoopTestor +{ + public function getTestedClassName() + { + return 'Thelia\Core\Template\Loop\FeatureValue'; + } + + public function getTestedInstance() + { + return new FeatureValue($this->request, $this->dispatcher, $this->securityContext); + } + + public function getMandatoryArguments() + { + return array('product' => 1, 'feature' => 1); + } +} diff --git a/core/lib/Thelia/Tests/Core/Template/Loop/ProductTest.php b/core/lib/Thelia/Tests/Core/Template/Loop/ProductTest.php new file mode 100755 index 000000000..58eaf55fd --- /dev/null +++ b/core/lib/Thelia/Tests/Core/Template/Loop/ProductTest.php @@ -0,0 +1,51 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Tests\Core\Template\Loop; + +use Thelia\Tests\Core\Template\Element\BaseLoopTestor; + +use Thelia\Core\Template\Loop\Product; + +/** + * + * @author Etienne Roudeix + * + */ +class ProductTest extends BaseLoopTestor +{ + public function getTestedClassName() + { + return 'Thelia\Core\Template\Loop\Product'; + } + + public function getTestedInstance() + { + return new Product($this->request, $this->dispatcher, $this->securityContext); + } + + public function getMandatoryArguments() + { + return array(); + } +} diff --git a/core/lib/Thelia/Tests/Core/Template/Loop/TitleTest.php b/core/lib/Thelia/Tests/Core/Template/Loop/TitleTest.php new file mode 100755 index 000000000..392e97930 --- /dev/null +++ b/core/lib/Thelia/Tests/Core/Template/Loop/TitleTest.php @@ -0,0 +1,51 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Tests\Core\Template\Loop; + +use Thelia\Tests\Core\Template\Element\BaseLoopTestor; + +use Thelia\Core\Template\Loop\Title; + +/** + * + * @author Etienne Roudeix + * + */ +class TitleTest extends BaseLoopTestor +{ + public function getTestedClassName() + { + return 'Thelia\Core\Template\Loop\Title'; + } + + public function getTestedInstance() + { + return new Title($this->request, $this->dispatcher, $this->securityContext); + } + + public function getMandatoryArguments() + { + return array(); + } +} diff --git a/core/lib/Thelia/Tools/URL.php b/core/lib/Thelia/Tools/URL.php index 4f8480eab..460703199 100644 --- a/core/lib/Thelia/Tools/URL.php +++ b/core/lib/Thelia/Tools/URL.php @@ -49,7 +49,7 @@ class URL $root = $path_only ? ConfigQuery::read('base_url', '/') : self::getIndexPage(); - $base = $root . $path; + $base = $root . '/' . ltrim($path, '/'); } else $base = $path; @@ -67,11 +67,26 @@ class URL return $base . $queryString; } + /** + * Returns the Absolute URL to a administration view + * + * @param string $viewName the view name (e.g. login for login.html) + * @param mixed $parameters An array of parameters + * + * @return string The generated URL + */ + public static function adminViewUrl($viewName, array $parameters = array()) { + + $path = sprintf("%s/admin/%s", self::getIndexPage(), $viewName); // FIXME ! view= should not be necessaray, check routing parameters + + return self::absoluteUrl($path, $parameters); + } + /** * Returns the Absolute URL to a view * - * @param string $viewName the view name (e.g. login for login.html) - * @param mixed $parameters An array of parameters + * @param string $viewName the view name (e.g. login for login.html) + * @param mixed $parameters An array of parameters * * @return string The generated URL */ diff --git a/templates/admin/default/404.html b/templates/admin/default/404.html index 5704c8125..48caf7a12 100755 --- a/templates/admin/default/404.html +++ b/templates/admin/default/404.html @@ -1,14 +1,11 @@ -{$page_title={intl l='Thelia'}} +{$page_title={intl l='Page not found'}} + {include file='includes/header.inc.html'} - -
-

Oops! An Error Occurred

-

The server returned a "404 Not Found".

+

{intl l="Oops! An Error Occurred"}

+

{intl l='The server returned a "404 Not Found"'}

+

{intl l='The page you\'ve requested was not found. Please check the page address, and try again.'}

- {include file='includes/footer.inc.html'} \ No newline at end of file diff --git a/templates/admin/default/assets/css/admin.less b/templates/admin/default/assets/css/admin.less index 0489c9348..f93a1cdd6 100755 --- a/templates/admin/default/assets/css/admin.less +++ b/templates/admin/default/assets/css/admin.less @@ -1,9 +1,31 @@ // -- Tools -------------------------------------------------------------------- -.border-radius(@radius: 5px) { - -webkit-border-radius: @radius; - -moz-border-radius: @radius; - border-radius: @radius; +.rounded(@radius: 2px) { + -webkit-border-radius: @radius; + -moz-border-radius: @radius; + border-radius: @radius; +} + +.border-radius(@topright: 0, @bottomright: 0, @bottomleft: 0, @topleft: 0) { + -webkit-border-top-right-radius: @topright; + -webkit-border-bottom-right-radius: @bottomright; + -webkit-border-bottom-left-radius: @bottomleft; + -webkit-border-top-left-radius: @topleft; + -moz-border-radius-topright: @topright; + -moz-border-radius-bottomright: @bottomright; + -moz-border-radius-bottomleft: @bottomleft; + -moz-border-radius-topleft: @topleft; + border-top-right-radius: @topright; + border-bottom-right-radius: @bottomright; + border-bottom-left-radius: @bottomleft; + border-top-left-radius: @topleft; + .background-clip(padding-box); +} + +.background-clip(@argument: padding-box) { + -moz-background-clip: @argument; + -webkit-background-clip: @argument; + background-clip: @argument; } .box-shadow(@shadow: 0 1px 2px rgba(0,0,0,.05)) { @@ -130,6 +152,10 @@ hr { float: right; margin: 0px; + .control-group { + margin-bottom: 0px; + } + input.search-query { background: url("img/search.png") no-repeat; width: 212px; @@ -137,7 +163,7 @@ hr { outline: none; border: none; padding: 5px 20px 5px 20px; - border-radius: 0px; + .rounded(0px); font-size: 12px; color: #eee; @@ -160,7 +186,7 @@ hr { border: none; top: 17px; box-shadow: none; - border-radius: 0px; + .rounded(0px); z-index: 1337; } } @@ -196,6 +222,7 @@ hr { // -- Brandbar ---------------------------------------------------------------- .loginpage { + .brandbar { width: 100%; } @@ -231,7 +258,7 @@ hr { } .breadcrumb { - border-radius: 0px; + .rounded(0px); padding: 25px 0px 25px 30px; background: url("img/logo-light.png") left center no-repeat; float: left; @@ -279,6 +306,38 @@ hr { } } +// -- Navigation bar ---------------------------------------------------------- + +.navbar { + margin-bottom: 0px; +} + +.navbar-inner { + border-top: none; + .border-radius(0, 4px, 4px, 0); + + .container{ + width: 1170px; + } +} + +// -- Breadcrumb -------------------------------------------------------------- + +.breadcrumb { + margin-top: 0; + background-color: transparent; + padding: 0 15px; + + + > li > .divider { + color: inherit; + } + + > .active { + color: inherit; + } +} + // -- Feed list on home page -------------------------------------------------- .feed-list { @@ -314,10 +373,15 @@ hr { margin: 0 auto 20px; background-color: #fff; border: 1px solid #e5e5e5; - .border-radius; + .rounded(5px); .box-shadow; } +textarea:focus, input[type="text"]:focus, input[type="password"]:focus, input[type="datetime"]:focus, input[type="datetime-local"]:focus, input[type="date"]:focus, input[type="month"]:focus, input[type="time"]:focus, input[type="week"]:focus, input[type="number"]:focus, input[type="email"]:focus, input[type="url"]:focus, input[type="search"]:focus, input[type="tel"]:focus, input[type="color"]:focus, .uneditable-input:focus { + border: 1px solid #E9730F; + box-shadow: 0px 0px 8px #FFA65A; +} + // -- Allow inline forms validation states ------------------------------------ .form-inline .warning .control-label, @@ -474,4 +538,51 @@ hr { color: #3a87ad; background-color: #d9edf7; border-color: #3a87ad; +} + +// -- Catalog Tables ---------------------------------------------------------- + +.table-striped { + + background: white; + + caption { + text-align: left; + color: #5A6876; + text-transform: uppercase; + font-weight: bold; + background-color: #fff; + padding: 0.5em 0.5em 0.5em 1em; + border-bottom: 2px solid #A5CED8; + + line-height: 30px; + + .btn-add-item { + display: block; + float: right; + } + } + + td, th { + text-align: center; + } + + td.object-title, th.object-title { + text-align: left; + } + + td.message { + // Center the alert box (20px bottom margin) in the table cell + padding: 20px 20px 0 20px; + + // No border, nor background in alert blocks + .alert { + border: none; + background-color: transparent; + + &-info { + background-color: transparent; + } + } + } } \ No newline at end of file diff --git a/templates/admin/default/home.html b/templates/admin/default/home.html index 83ae4fc68..6b429ae29 100755 --- a/templates/admin/default/home.html +++ b/templates/admin/default/home.html @@ -7,7 +7,9 @@ {module_include location='home_top'} -welcome home ! +
+ This is the administration home page. Put some interesting statistics here, and display useful information :) +
{module_include location='home_bottom'} diff --git a/templates/admin/default/includes/footer.inc.html b/templates/admin/default/includes/footer.inc.html index aca554da2..9611586b0 100755 --- a/templates/admin/default/includes/footer.inc.html +++ b/templates/admin/default/includes/footer.inc.html @@ -1,3 +1,5 @@ + {module_include location='before_footer'} +
- {* Include required JS files *} - - {javascripts file='../assets/js/jquery.min.js'} - - {/javascripts} - - {javascripts file='../assets/bootstrap/js/bootstrap.min.js'} - - {/javascripts} - - {* TODO allow modules to include JS here *} + {module_include location='after_footer'} \ No newline at end of file diff --git a/templates/admin/default/includes/header.inc.html b/templates/admin/default/includes/header.inc.html index e0dd1997c..e0a6d983e 100755 --- a/templates/admin/default/includes/header.inc.html +++ b/templates/admin/default/includes/header.inc.html @@ -19,6 +19,16 @@ {/stylesheets} + {* Include here page specifc CSS file, if any *} + + {if ! empty($thelia_page_css_file)} + {stylesheets file='../assets/css/$thelia_page_css_file' filters='less,cssembed'} + + {/stylesheets} + {/if} + + {* Modules css are included here *} + {module_include location='head_css'} @@ -59,12 +69,6 @@