Merge branch 'master' into rewrite

Conflicts:
	core/lib/Thelia/Core/Template/Loop/Attribute.php
	core/lib/Thelia/Core/Template/Loop/AttributeAvailability.php
	core/lib/Thelia/Core/Template/Loop/AttributeCombination.php
	core/lib/Thelia/Core/Template/Loop/Category.php
	core/lib/Thelia/Core/Template/Loop/Content.php
	core/lib/Thelia/Core/Template/Loop/Country.php
	core/lib/Thelia/Core/Template/Loop/Currency.php
	core/lib/Thelia/Core/Template/Loop/Feature.php
	core/lib/Thelia/Core/Template/Loop/FeatureAvailability.php
	core/lib/Thelia/Core/Template/Loop/FeatureValue.php
	core/lib/Thelia/Core/Template/Loop/Folder.php
	core/lib/Thelia/Core/Template/Loop/Image.php
	core/lib/Thelia/Core/Template/Loop/Product.php
	core/lib/Thelia/Core/Template/Loop/Title.php
	core/lib/Thelia/Model/Tools/ModelCriteriaTools.php
This commit is contained in:
Etienne Roudeix
2013-08-30 15:02:48 +02:00
49 changed files with 780 additions and 802 deletions

235
composer.lock generated
View File

@@ -11,12 +11,12 @@
"source": {
"type": "git",
"url": "https://github.com/ezyang/htmlpurifier.git",
"reference": "19eee1489965d9bc6eded80f847ced2382127261"
"reference": "fac747bdbdba6aeaba4bed91ef49b2378c1798e4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/19eee1489965d9bc6eded80f847ced2382127261",
"reference": "19eee1489965d9bc6eded80f847ced2382127261",
"url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/fac747bdbdba6aeaba4bed91ef49b2378c1798e4",
"reference": "fac747bdbdba6aeaba4bed91ef49b2378c1798e4",
"shasum": ""
},
"require": {
@@ -47,7 +47,7 @@
"keywords": [
"html"
],
"time": "2013-07-27 04:54:53"
"time": "2013-08-18 02:27:26"
},
{
"name": "imagine/imagine",
@@ -55,12 +55,12 @@
"source": {
"type": "git",
"url": "https://github.com/avalanche123/Imagine.git",
"reference": "v0.5.0"
"reference": "f64ec666baaa800edcbf237db41121a569230709"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/avalanche123/Imagine/zipball/v0.5.0",
"reference": "v0.5.0",
"url": "https://api.github.com/repos/avalanche123/Imagine/zipball/f64ec666baaa800edcbf237db41121a569230709",
"reference": "f64ec666baaa800edcbf237db41121a569230709",
"shasum": ""
},
"require": {
@@ -217,12 +217,12 @@
"source": {
"type": "git",
"url": "https://github.com/leafo/lessphp.git",
"reference": "v0.4.0"
"reference": "51f3f06f0fe78a722dabfd14578444bdd078d9de"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/leafo/lessphp/zipball/v0.4.0",
"reference": "v0.4.0",
"url": "https://api.github.com/repos/leafo/lessphp/zipball/51f3f06f0fe78a722dabfd14578444bdd078d9de",
"reference": "51f3f06f0fe78a722dabfd14578444bdd078d9de",
"shasum": ""
},
"type": "library",
@@ -258,26 +258,26 @@
"source": {
"type": "git",
"url": "https://github.com/propelorm/Propel2.git",
"reference": "2.0.0-alpha1"
"reference": "3b9ea45a6e1b9fb3903cb910a31fbbac4a66c184"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/propelorm/Propel2/zipball/2.0.0-alpha1",
"reference": "2.0.0-alpha1",
"url": "https://api.github.com/repos/propelorm/Propel2/zipball/3b9ea45a6e1b9fb3903cb910a31fbbac4a66c184",
"reference": "3b9ea45a6e1b9fb3903cb910a31fbbac4a66c184",
"shasum": ""
},
"require": {
"php": ">=5.4",
"psr/log": ">=1.0,<2.0",
"symfony/console": ">=2.2,<3.0",
"symfony/filesystem": ">=2.2,<3.0",
"symfony/finder": ">=2.2,<3.0",
"symfony/validator": ">=2.2,<3.0",
"symfony/yaml": ">=2.2,<3.0"
"psr/log": "~1.0",
"symfony/console": "~2.2",
"symfony/filesystem": "~2.2",
"symfony/finder": "~2.2",
"symfony/validator": "~2.2",
"symfony/yaml": "~2.2"
},
"require-dev": {
"behat/behat": ">=2.4,<3.0",
"monolog/monolog": ">=1.3,<2.0",
"behat/behat": "~2.4",
"monolog/monolog": "~1.3",
"phpunit/phpunit": "3.7.*"
},
"suggest": {
@@ -356,12 +356,12 @@
"source": {
"type": "git",
"url": "https://github.com/krichprollsch/phpCssEmbed.git",
"reference": "v1.0.2"
"reference": "406c6d5b846cafa9186f9944a6210d0e6fed154b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/krichprollsch/phpCssEmbed/zipball/v1.0.2",
"reference": "v1.0.2",
"url": "https://api.github.com/repos/krichprollsch/phpCssEmbed/zipball/406c6d5b846cafa9186f9944a6210d0e6fed154b",
"reference": "406c6d5b846cafa9186f9944a6210d0e6fed154b",
"shasum": ""
},
"require": {
@@ -540,17 +540,17 @@
},
{
"name": "symfony/class-loader",
"version": "v2.2.5",
"version": "v2.2.6",
"target-dir": "Symfony/Component/ClassLoader",
"source": {
"type": "git",
"url": "https://github.com/symfony/ClassLoader.git",
"reference": "v2.2.5"
"reference": "827c54ee9827f6de5afe53324cdbe47f017c0cba"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/ClassLoader/zipball/v2.2.5",
"reference": "v2.2.5",
"url": "https://api.github.com/repos/symfony/ClassLoader/zipball/827c54ee9827f6de5afe53324cdbe47f017c0cba",
"reference": "827c54ee9827f6de5afe53324cdbe47f017c0cba",
"shasum": ""
},
"require": {
@@ -586,21 +586,21 @@
],
"description": "Symfony ClassLoader Component",
"homepage": "http://symfony.com",
"time": "2013-05-06 20:02:13"
"time": "2013-08-09 07:16:43"
},
{
"name": "symfony/config",
"version": "v2.2.5",
"version": "v2.2.6",
"target-dir": "Symfony/Component/Config",
"source": {
"type": "git",
"url": "https://github.com/symfony/Config.git",
"reference": "v2.2.5"
"reference": "4ab8ad0c0f4bb52b0e7fb12d63b81892fb7f697a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Config/zipball/v2.2.5",
"reference": "v2.2.5",
"url": "https://api.github.com/repos/symfony/Config/zipball/4ab8ad0c0f4bb52b0e7fb12d63b81892fb7f697a",
"reference": "4ab8ad0c0f4bb52b0e7fb12d63b81892fb7f697a",
"shasum": ""
},
"require": {
@@ -637,17 +637,17 @@
},
{
"name": "symfony/console",
"version": "v2.2.5",
"version": "v2.2.6",
"target-dir": "Symfony/Component/Console",
"source": {
"type": "git",
"url": "https://github.com/symfony/Console.git",
"reference": "v2.2.5"
"reference": "b9ed9d61ff84296c9ace5ac333c15e6f35062eeb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Console/zipball/v2.2.5",
"reference": "v2.2.5",
"url": "https://api.github.com/repos/symfony/Console/zipball/b9ed9d61ff84296c9ace5ac333c15e6f35062eeb",
"reference": "b9ed9d61ff84296c9ace5ac333c15e6f35062eeb",
"shasum": ""
},
"require": {
@@ -680,21 +680,21 @@
],
"description": "Symfony Console Component",
"homepage": "http://symfony.com",
"time": "2013-07-08 14:34:53"
"time": "2013-08-17 16:29:09"
},
{
"name": "symfony/dependency-injection",
"version": "v2.2.5",
"version": "v2.2.6",
"target-dir": "Symfony/Component/DependencyInjection",
"source": {
"type": "git",
"url": "https://github.com/symfony/DependencyInjection.git",
"reference": "v2.2.5"
"reference": "434b31fe8548e0354d5f93b455d8927481ddfc6f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/DependencyInjection/zipball/v2.2.5",
"reference": "v2.2.5",
"url": "https://api.github.com/repos/symfony/DependencyInjection/zipball/434b31fe8548e0354d5f93b455d8927481ddfc6f",
"reference": "434b31fe8548e0354d5f93b455d8927481ddfc6f",
"shasum": ""
},
"require": {
@@ -739,17 +739,17 @@
},
{
"name": "symfony/event-dispatcher",
"version": "v2.2.5",
"version": "v2.2.6",
"target-dir": "Symfony/Component/EventDispatcher",
"source": {
"type": "git",
"url": "https://github.com/symfony/EventDispatcher.git",
"reference": "v2.2.5"
"reference": "45c43ffa186a0473c71a947981e43e025cd93c87"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/v2.2.5",
"reference": "v2.2.5",
"url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/45c43ffa186a0473c71a947981e43e025cd93c87",
"reference": "45c43ffa186a0473c71a947981e43e025cd93c87",
"shasum": ""
},
"require": {
@@ -793,17 +793,17 @@
},
{
"name": "symfony/filesystem",
"version": "v2.2.5",
"version": "v2.2.6",
"target-dir": "Symfony/Component/Filesystem",
"source": {
"type": "git",
"url": "https://github.com/symfony/Filesystem.git",
"reference": "v2.2.5"
"reference": "fa16b9ab446b84371a63ab391133ff58134edff1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Filesystem/zipball/v2.2.5",
"reference": "v2.2.5",
"url": "https://api.github.com/repos/symfony/Filesystem/zipball/fa16b9ab446b84371a63ab391133ff58134edff1",
"reference": "fa16b9ab446b84371a63ab391133ff58134edff1",
"shasum": ""
},
"require": {
@@ -840,17 +840,17 @@
},
{
"name": "symfony/finder",
"version": "v2.3.3",
"version": "v2.3.4",
"target-dir": "Symfony/Component/Finder",
"source": {
"type": "git",
"url": "https://github.com/symfony/Finder.git",
"reference": "v2.3.3"
"reference": "4a0fee5b86f5bbd9dfdc11ec124eba2915737ce1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Finder/zipball/v2.3.3",
"reference": "v2.3.3",
"url": "https://api.github.com/repos/symfony/Finder/zipball/4a0fee5b86f5bbd9dfdc11ec124eba2915737ce1",
"reference": "4a0fee5b86f5bbd9dfdc11ec124eba2915737ce1",
"shasum": ""
},
"require": {
@@ -883,21 +883,21 @@
],
"description": "Symfony Finder Component",
"homepage": "http://symfony.com",
"time": "2013-07-21 12:12:18"
"time": "2013-08-13 20:18:00"
},
{
"name": "symfony/form",
"version": "v2.2.5",
"version": "v2.2.6",
"target-dir": "Symfony/Component/Form",
"source": {
"type": "git",
"url": "https://github.com/symfony/Form.git",
"reference": "v2.2.5"
"reference": "33e3fcb6ca3cefe43ab22dcb8bee5ea039033a88"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Form/zipball/v2.2.5",
"reference": "v2.2.5",
"url": "https://api.github.com/repos/symfony/Form/zipball/33e3fcb6ca3cefe43ab22dcb8bee5ea039033a88",
"reference": "33e3fcb6ca3cefe43ab22dcb8bee5ea039033a88",
"shasum": ""
},
"require": {
@@ -942,21 +942,21 @@
],
"description": "Symfony Form Component",
"homepage": "http://symfony.com",
"time": "2013-08-02 13:12:51"
"time": "2013-08-25 11:59:08"
},
{
"name": "symfony/http-foundation",
"version": "v2.2.5",
"version": "v2.2.6",
"target-dir": "Symfony/Component/HttpFoundation",
"source": {
"type": "git",
"url": "https://github.com/symfony/HttpFoundation.git",
"reference": "v2.2.5"
"reference": "9402ff009d4f1ee63e83e8f2262993a7c2a3beea"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/HttpFoundation/zipball/v2.2.5",
"reference": "v2.2.5",
"url": "https://api.github.com/repos/symfony/HttpFoundation/zipball/9402ff009d4f1ee63e83e8f2262993a7c2a3beea",
"reference": "9402ff009d4f1ee63e83e8f2262993a7c2a3beea",
"shasum": ""
},
"require": {
@@ -992,21 +992,21 @@
],
"description": "Symfony HttpFoundation Component",
"homepage": "http://symfony.com",
"time": "2013-08-07 14:00:53"
"time": "2013-08-25 18:21:55"
},
{
"name": "symfony/http-kernel",
"version": "v2.2.5",
"version": "v2.2.6",
"target-dir": "Symfony/Component/HttpKernel",
"source": {
"type": "git",
"url": "https://github.com/symfony/HttpKernel.git",
"reference": "v2.2.5"
"reference": "080dea28df16aed1fbc7aeb08a1dcb10d7ab5299"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/HttpKernel/zipball/v2.2.5",
"reference": "v2.2.5",
"url": "https://api.github.com/repos/symfony/HttpKernel/zipball/080dea28df16aed1fbc7aeb08a1dcb10d7ab5299",
"reference": "080dea28df16aed1fbc7aeb08a1dcb10d7ab5299",
"shasum": ""
},
"require": {
@@ -1062,25 +1062,24 @@
],
"description": "Symfony HttpKernel Component",
"homepage": "http://symfony.com",
"time": "2013-08-07 15:57:43"
"time": "2013-08-26 19:27:24"
},
{
"name": "symfony/icu",
"version": "v1.2.0",
"version": "v1.0.0",
"target-dir": "Symfony/Component/Icu",
"source": {
"type": "git",
"url": "https://github.com/symfony/Icu.git",
"reference": "v1.2.0"
"reference": "v1.0.0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Icu/zipball/v1.2.0",
"reference": "v1.2.0",
"url": "https://api.github.com/repos/symfony/Icu/zipball/v1.0.0",
"reference": "v1.0.0",
"shasum": ""
},
"require": {
"lib-icu": ">=4.4",
"php": ">=5.3.3",
"symfony/intl": ">=2.3,<3.0"
},
@@ -1110,21 +1109,21 @@
"icu",
"intl"
],
"time": "2013-06-03 18:32:58"
"time": "2013-06-03 18:32:07"
},
{
"name": "symfony/intl",
"version": "v2.3.3",
"version": "v2.3.4",
"target-dir": "Symfony/Component/Intl",
"source": {
"type": "git",
"url": "https://github.com/symfony/Intl.git",
"reference": "v2.3.3"
"reference": "ebbcf7e3dab5185b4b24c961431e302a0ffb66ec"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Intl/zipball/v2.3.3",
"reference": "v2.3.3",
"url": "https://api.github.com/repos/symfony/Intl/zipball/ebbcf7e3dab5185b4b24c961431e302a0ffb66ec",
"reference": "ebbcf7e3dab5185b4b24c961431e302a0ffb66ec",
"shasum": ""
},
"require": {
@@ -1187,21 +1186,21 @@
"l10n",
"localization"
],
"time": "2013-08-01 12:40:45"
"time": "2013-08-24 14:32:55"
},
{
"name": "symfony/locale",
"version": "v2.3.3",
"version": "v2.3.4",
"target-dir": "Symfony/Component/Locale",
"source": {
"type": "git",
"url": "https://github.com/symfony/Locale.git",
"reference": "v2.3.3"
"reference": "490825116712881a351b9a13ad6dddd4a39b8bb0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Locale/zipball/v2.3.3",
"reference": "v2.3.3",
"url": "https://api.github.com/repos/symfony/Locale/zipball/490825116712881a351b9a13ad6dddd4a39b8bb0",
"reference": "490825116712881a351b9a13ad6dddd4a39b8bb0",
"shasum": ""
},
"require": {
@@ -1239,17 +1238,17 @@
},
{
"name": "symfony/options-resolver",
"version": "v2.2.5",
"version": "v2.2.6",
"target-dir": "Symfony/Component/OptionsResolver",
"source": {
"type": "git",
"url": "https://github.com/symfony/OptionsResolver.git",
"reference": "v2.2.5"
"reference": "b36671093db40feacce2d489298f0782a0a61cfd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/OptionsResolver/zipball/v2.2.5",
"reference": "v2.2.5",
"url": "https://api.github.com/repos/symfony/OptionsResolver/zipball/b36671093db40feacce2d489298f0782a0a61cfd",
"reference": "b36671093db40feacce2d489298f0782a0a61cfd",
"shasum": ""
},
"require": {
@@ -1291,17 +1290,17 @@
},
{
"name": "symfony/process",
"version": "v2.3.3",
"version": "v2.3.4",
"target-dir": "Symfony/Component/Process",
"source": {
"type": "git",
"url": "https://github.com/symfony/Process.git",
"reference": "v2.3.3"
"reference": "1e91553e1cedd0b8fb1da6ea4f89b02e21713d5b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Process/zipball/v2.3.3",
"reference": "v2.3.3",
"url": "https://api.github.com/repos/symfony/Process/zipball/1e91553e1cedd0b8fb1da6ea4f89b02e21713d5b",
"reference": "1e91553e1cedd0b8fb1da6ea4f89b02e21713d5b",
"shasum": ""
},
"require": {
@@ -1334,21 +1333,21 @@
],
"description": "Symfony Process Component",
"homepage": "http://symfony.com",
"time": "2013-08-02 21:51:01"
"time": "2013-08-22 06:42:25"
},
{
"name": "symfony/property-access",
"version": "v2.2.5",
"version": "v2.2.6",
"target-dir": "Symfony/Component/PropertyAccess",
"source": {
"type": "git",
"url": "https://github.com/symfony/PropertyAccess.git",
"reference": "v2.2.5"
"reference": "2452dd5d49c1602876d9eeb4de15425d5f9a6342"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/PropertyAccess/zipball/v2.2.5",
"reference": "v2.2.5",
"url": "https://api.github.com/repos/symfony/PropertyAccess/zipball/2452dd5d49c1602876d9eeb4de15425d5f9a6342",
"reference": "2452dd5d49c1602876d9eeb4de15425d5f9a6342",
"shasum": ""
},
"require": {
@@ -1392,21 +1391,21 @@
"property path",
"reflection"
],
"time": "2013-07-28 18:26:16"
"time": "2013-08-22 04:15:06"
},
{
"name": "symfony/routing",
"version": "v2.2.5",
"version": "v2.2.6",
"target-dir": "Symfony/Component/Routing",
"source": {
"type": "git",
"url": "https://github.com/symfony/Routing.git",
"reference": "v2.2.5"
"reference": "2704242137edc19cc61e71027a7a04eef28f42c6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Routing/zipball/v2.2.5",
"reference": "v2.2.5",
"url": "https://api.github.com/repos/symfony/Routing/zipball/2704242137edc19cc61e71027a7a04eef28f42c6",
"reference": "2704242137edc19cc61e71027a7a04eef28f42c6",
"shasum": ""
},
"require": {
@@ -1450,21 +1449,21 @@
],
"description": "Symfony Routing Component",
"homepage": "http://symfony.com",
"time": "2013-07-30 11:22:46"
"time": "2013-08-23 14:06:02"
},
{
"name": "symfony/translation",
"version": "v2.2.5",
"version": "v2.2.6",
"target-dir": "Symfony/Component/Translation",
"source": {
"type": "git",
"url": "https://github.com/symfony/Translation.git",
"reference": "v2.2.5"
"reference": "37a11fe823c28f9235548d253b215f07cec9a0de"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Translation/zipball/v2.2.5",
"reference": "v2.2.5",
"url": "https://api.github.com/repos/symfony/Translation/zipball/37a11fe823c28f9235548d253b215f07cec9a0de",
"reference": "37a11fe823c28f9235548d253b215f07cec9a0de",
"shasum": ""
},
"require": {
@@ -1505,7 +1504,7 @@
],
"description": "Symfony Translation Component",
"homepage": "http://symfony.com",
"time": "2013-07-28 18:26:16"
"time": "2013-08-24 12:29:44"
},
{
"name": "symfony/validator",
@@ -1514,12 +1513,12 @@
"source": {
"type": "git",
"url": "https://github.com/symfony/Validator.git",
"reference": "55808a75bf373a8edb6400239268d315f0a326c7"
"reference": "8f6f6be47fb8e1179cd225b1f949630e26221e42"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Validator/zipball/55808a75bf373a8edb6400239268d315f0a326c7",
"reference": "55808a75bf373a8edb6400239268d315f0a326c7",
"url": "https://api.github.com/repos/symfony/Validator/zipball/8f6f6be47fb8e1179cd225b1f949630e26221e42",
"reference": "8f6f6be47fb8e1179cd225b1f949630e26221e42",
"shasum": ""
},
"require": {
@@ -1566,21 +1565,21 @@
],
"description": "Symfony Validator Component",
"homepage": "http://symfony.com",
"time": "2013-08-13 20:18:00"
"time": "2013-08-24 15:26:22"
},
{
"name": "symfony/yaml",
"version": "v2.2.5",
"version": "v2.2.6",
"target-dir": "Symfony/Component/Yaml",
"source": {
"type": "git",
"url": "https://github.com/symfony/Yaml.git",
"reference": "v2.2.5"
"reference": "d135717c1a42cb566cc09433658e7e8dbbe30b0a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Yaml/zipball/v2.2.5",
"reference": "v2.2.5",
"url": "https://api.github.com/repos/symfony/Yaml/zipball/d135717c1a42cb566cc09433658e7e8dbbe30b0a",
"reference": "d135717c1a42cb566cc09433658e7e8dbbe30b0a",
"shasum": ""
},
"require": {
@@ -1613,7 +1612,7 @@
],
"description": "Symfony Yaml Component",
"homepage": "http://symfony.com",
"time": "2013-07-11 09:28:01"
"time": "2013-08-24 06:36:00"
}
],
"packages-dev": [

View File

@@ -40,52 +40,6 @@ class BaseAction
$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
* @return \Symfony\Component\Form\Form Form the symfony form object
*/
protected function validateForm(BaseForm $aBaseForm, $expectedMethod = null)
{
$form = $aBaseForm->getForm();
if ($expectedMethod == null || $aBaseForm->getRequest()->isMethod($expectedMethod)) {
$form->bind($aBaseForm->getRequest());
if ($form->isValid()) {
return $form;
} else {
throw new FormValidationException("Missing or invalid data");
}
} else {
throw new FormValidationException(sprintf("Wrong form method, %s expected.", $expectedMethod));
}
}
/**
* 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
*/
protected function propagateFormError(BaseForm $aBaseForm, $error_message, ActionEvent $event)
{
// The form has an error
$aBaseForm->setError(true);
$aBaseForm->setErrorMessage($error_message);
// Store the form in the parser context
$event->setErrorForm($aBaseForm);
// Stop event propagation
$event->stopPropagation();
}
/**
* Return the event dispatcher,
*
@@ -96,4 +50,33 @@ class BaseAction
return $this->container->get('event_dispatcher');
}
}
/**
* Check current user authorisations.
*
* @param mixed $roles a single role or an array of roles.
* @param mixed $permissions a single permission or an array of permissions.
*
* @throws AuthenticationException if permissions are not granted to the current user.
*/
protected function checkAuth($roles, $permissions) {
if (! $this->getSecurityContext()->isGranted(
is_array($roles) ? $roles : array($roles),
is_array($permissions) ? $permissions : array($permissions)) ) {
Tlog::getInstance()->addAlert("Authorization roles:", $roles, " permissions:", $permissions, " refused.");
throw new AuthorizationException("Sorry, you're not allowed to perform this action");
}
}
/**
* Return the security context
*
* @return Thelia\Core\Security\SecurityContext
*/
protected function getSecurityContext()
{
return $this->container->get('thelia.securityContext');
}
}

View File

@@ -24,134 +24,46 @@
namespace Thelia\Action;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Thelia\Core\Event\ActionEvent;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Model\Category as CategoryModel;
use Thelia\Form\CategoryCreationForm;
use Thelia\Core\Event\CategoryEvent;
use Thelia\Tools\Redirect;
use Thelia\Model\CategoryQuery;
use Thelia\Model\AdminLog;
use Thelia\Form\CategoryDeletionForm;
use Thelia\Action\Exception\FormValidationException;
use Propel\Runtime\ActiveQuery\Criteria;
use Propel\Runtime\Propel;
use Thelia\Model\Map\CategoryTableMap;
use Propel\Runtime\Exception\PropelException;
use Thelia\Core\Event\CategoryCreateEvent;
use Thelia\Core\Event\CategoryDeleteEvent;
use Thelia\Core\Event\CategoryToggleVisibilityEvent;
use Thelia\Core\Event\CategoryChangePositionEvent;
class Category extends BaseAction implements EventSubscriberInterface
{
public function create(ActionEvent $event)
public function create(CategoryCreateEvent $event)
{
$this->checkAuth("ADMIN", "admin.category.create");
$request = $event->getRequest();
$category = new CategoryModel();
try {
$categoryCreationForm = new CategoryCreationForm($request);
$event->getDispatcher()->dispatch(TheliaEvents::BEFORE_CREATECATEGORY, $event);
$form = $this->validateForm($categoryCreationForm, "POST");
$category->create(
$event->getTitle(),
$event->getParent(),
$event->getLocale()
);
$data = $form->getData();
$event->setCreatedCategory($category);
$category = new CategoryModel();
$event->getDispatcher()->dispatch(TheliaEvents::BEFORE_CREATECATEGORY, $event);
$category->create(
$data["title"],
$data["parent"],
$data["locale"]
);
AdminLog::append(sprintf("Category %s (ID %s) created", $category->getTitle(), $category->getId()), $request, $request->getSession()->getAdminUser());
$categoryEvent = new CategoryEvent($category);
$event->getDispatcher()->dispatch(TheliaEvents::AFTER_CREATECATEGORY, $categoryEvent);
// Substitute _ID_ in the URL with the ID of the created category
$successUrl = str_replace('_ID_', $category->getId(), $categoryCreationForm->getSuccessUrl());
// Redirect to the success URL
$this->redirect($successUrl);
} catch (PropelException $e) {
Tlog::getInstance()->error(sprintf('error during creating category with message "%s"', $e->getMessage()));
$message = "Failed to create this category, please try again.";
}
// The form has errors, propagate it.
$this->propagateFormError($categoryCreationForm, $message, $event);
$event->getDispatcher()->dispatch(TheliaEvents::AFTER_CREATECATEGORY, $event);
}
public function modify(ActionEvent $event)
public function modify(CategoryChangeEvent $event)
{
$this->checkAuth("ADMIN", "admin.category.change");
$this->checkAuth("ADMIN", "admin.category.delete");
$request = $event->getRequest();
$customerModification = new CustomerModification($request);
$form = $customerModification->getForm();
if ($request->isMethod("post")) {
$form->bind($request);
if ($form->isValid()) {
$data = $form->getData();
$customer = CustomerQuery::create()->findPk(1);
try {
$customerEvent = new CustomerEvent($customer);
$event->getDispatcher()->dispatch(TheliaEvents::BEFORE_CHANGECUSTOMER, $customerEvent);
$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"]
);
$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.
$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.";
}
} else {
$message = "Missing or invalid data";
}
} else {
$message = "Wrong form method !";
}
// The form has an error
$customerModification->setError(true);
$customerModification->setErrorMessage($message);
// Dispatch the errored form
$event->setErrorForm($customerModification);
// TODO !!
}
/**
@@ -159,50 +71,22 @@ class Category extends BaseAction implements EventSubscriberInterface
*
* @param ActionEvent $event
*/
public function delete(ActionEvent $event)
public function delete(CategoryDeleteEvent $event)
{
$this->checkAuth("ADMIN", "admin.category.delete");
$request = $event->getRequest();
$category = CategoryQuery::create()->findPk($event->getId());
try {
$categoryDeletionForm = new CategoryDeletionForm($request);
if ($category !== null) {
$form = $this->validateForm($categoryDeletionForm, "POST");
$event->setDeletedCategory($category);
$data = $form->getData();
$category = CategoryQuery::create()->findPk($data['id']);
$categoryEvent = new CategoryEvent($category);
$event->getDispatcher()->dispatch(TheliaEvents::BEFORE_DELETECATEGORY, $categoryEvent);
$event->getDispatcher()->dispatch(TheliaEvents::BEFORE_DELETECATEGORY, $event);
$category->delete();
AdminLog::append(sprintf("Category %s (ID %s) deleted", $category->getTitle(), $category->getId()), $request, $request->getSession()->getAdminUser());
$categoryEvent->category = $category;
$event->getDispatcher()->dispatch(TheliaEvents::AFTER_DELETECATEGORY, $categoryEvent);
// Substitute _ID_ in the URL with the ID of the created category
$successUrl = str_replace('_ID_', $category->getParent(), $categoryDeletionForm->getSuccessUrl());
// Redirect to the success URL
Redirect::exec($successUrl);
} catch (PropelException $e) {
\Thelia\Log\Tlog::getInstance()->error(sprintf('error during deleting category ID=%s on action/modifyCustomer with message "%s"', $data['id'], $e->getMessage()));
$message = "Failed to change your account, please try again.";
} catch (FormValidationException $e) {
$message = $e->getMessage();
$event->getDispatcher()->dispatch(TheliaEvents::AFTER_DELETECATEGORY, $event);
}
$this->propagateFormError($categoryDeletionForm, $message, $event);
}
/**
@@ -210,63 +94,55 @@ class Category extends BaseAction implements EventSubscriberInterface
*
* @param ActionEvent $event
*/
public function toggleVisibility(ActionEvent $event)
public function toggleVisibility(CategoryToggleVisibilityEvent $event)
{
$this->checkAuth("ADMIN", "admin.category.edit");
$request = $event->getRequest();
$category = CategoryQuery::create()->findPk($request->get('category_id', 0));
$category = CategoryQuery::create()->findPk($event->getId());
if ($category !== null) {
$event->setCategory($category);
$event->getDispatcher()->dispatch(TheliaEvents::BEFORE_CHANGECATEGORY, $event);
$category->setVisible($category->getVisible() ? false : true);
$category->save();
$categoryEvent = new CategoryEvent($category);
$event->getDispatcher()->dispatch(TheliaEvents::AFTER_CHANGECATEGORY, $categoryEvent);
$event->setCategory($category);
$event->getDispatcher()->dispatch(TheliaEvents::AFTER_CHANGECATEGORY, $event);
}
}
/**
* Move category up
* Changes category position, selecting absolute ou relative change.
*
* @param ActionEvent $event
* @param CategoryChangePositionEvent $event
*/
public function changePositionUp(ActionEvent $event)
public function changePosition(CategoryChangePositionEvent $event)
{
return $this->exchangePosition($event, 'up');
}
$this->checkAuth("ADMIN", "admin.category.edit");
/**
* Move category down
*
* @param ActionEvent $event
*/
public function changePositionDown(ActionEvent $event)
{
return $this->exchangePosition($event, 'down');
if ($event->getMode() == CategoryChangePositionEvent::POSITION_ABSOLUTE)
return $this->changeAbsolutePosition($event);
else
return $this->exchangePosition($event);
}
/**
* Move up or down a category
*
* @param ActionEvent $event
* @param string $direction up to move up, down to move down
* @param CategoryChangePositionEvent $event
*/
protected function exchangePosition(ActionEvent $event, $direction)
protected function exchangePosition(CategoryChangePositionEvent $event)
{
$this->checkAuth("ADMIN", "admin.category.edit");
$request = $event->getRequest();
$category = CategoryQuery::create()->findPk($request->get('category_id', 0));
$category = CategoryQuery::create()->findPk($event->getId());
if ($category !== null) {
$event->setCategory($category);
$event->getDispatcher()->dispatch(TheliaEvents::BEFORE_CHANGECATEGORY, $event);
// The current position of the category
$my_position = $category->getPosition();
@@ -275,10 +151,10 @@ class Category extends BaseAction implements EventSubscriberInterface
->filterByParent($category->getParent());
// Up or down ?
if ($direction == 'up') {
if ($event->getMode() == CategoryChangePositionEvent::POSITION_UP) {
// Find the category immediately before me
$search->filterByPosition(array('max' => $my_position-1))->orderByPosition(Criteria::DESC);
} elseif ($direction == 'down') {
} elseif ($event->getMode() == CategoryChangePositionEvent::POSITION_DOWN) {
// Find the category immediately after me
$search->filterByPosition(array('min' => $my_position+1))->orderByPosition(Criteria::ASC);
} else
@@ -304,26 +180,30 @@ class Category extends BaseAction implements EventSubscriberInterface
$cnx->rollback();
}
}
$event->setCategory($category);
$event->getDispatcher()->dispatch(TheliaEvents::AFTER_CHANGECATEGORY, $event);
}
}
/**
* Changes category position
*
* @param ActionEvent $event
* @param CategoryChangePositionEvent $event
*/
public function changePosition(ActionEvent $event)
protected function changeAbsolutePosition(CategoryChangePositionEvent $event)
{
$this->checkAuth("ADMIN", "admin.category.edit");
$request = $event->getRequest();
$category = CategoryQuery::create()->findPk($request->get('category_id', 0));
$category = CategoryQuery::create()->findPk($event->getId());
if ($category !== null) {
$event->setCategory($category);
$event->getDispatcher()->dispatch(TheliaEvents::BEFORE_CHANGECATEGORY, $event);
// The required position
$new_position = $request->get('position', null);
$new_position = $event->getPosition();
// The current position
$current_position = $category->getPosition();
@@ -363,6 +243,9 @@ class Category extends BaseAction implements EventSubscriberInterface
$cnx->rollback();
}
}
$event->setCategory($category);
$event->getDispatcher()->dispatch(TheliaEvents::AFTER_CHANGECATEGORY, $event);
}
}
@@ -389,12 +272,14 @@ class Category extends BaseAction implements EventSubscriberInterface
public static function getSubscribedEvents()
{
return array(
"action.createCategory" => array("create", 128),
"action.modifyCategory" => array("modify", 128),
"action.deleteCategory" => array("delete", 128),
TheliaEvents::CATEGORY_CREATE => array("create", 128),
TheliaEvents::CATEGORY_MODIFY => array("modify", 128),
TheliaEvents::CATEGORY_DELETE => array("delete", 128),
"action.toggleCategoryVisibility" => array("toggleVisibility", 128),
"action.changeCategoryPositionUp" => array("changePositionUp", 128),
TheliaEvents::CATEGORY_TOGGLE_VISIBILITY => array("toggleVisibility", 128),
TheliaEvents::CATEGORY_CHANGE_POSITION => array("changePosition", 128),
"action.changeCategoryPositionU" => array("changePositionUp", 128),
"action.changeCategoryPositionDown" => array("changePositionDown", 128),
"action.changeCategoryPosition" => array("changePosition", 128),
);

View File

@@ -96,7 +96,7 @@ class Customer extends BaseAction implements EventSubscriberInterface
{
$event->getDispatcher()->dispatch(TheliaEvents::CUSTOMER_LOGOUT, $event);
$this->getFrontSecurityContext()->clear();
$this->getSecurityContext()->clearCustomerUser();
}
public function changePassword(ActionEvent $event)
@@ -127,8 +127,8 @@ class Customer extends BaseAction implements EventSubscriberInterface
public static function getSubscribedEvents()
{
return array(
"action.createCustomer" => array("create", 128),
"action.modifyCustomer" => array("modify", 128),
TheliaEvents::CUSTOMER_CREATEACCOUNT => array("create", 128),
TheliaEvents::CUSTOMER_UPDATEACCOUNT => array("modify", 128),
);
}
}

View File

@@ -28,8 +28,8 @@ use Thelia\Model\ConfigQuery;
use Thelia\Model\Customer;
use Symfony\Component\HttpFoundation\Request;
use Thelia\Core\HttpFoundation\Session\Session;
use Thelia\Core\Event\Internal\CartEvent;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Core\Event\CartEvent;
trait CartTrait
{
@@ -42,8 +42,9 @@ trait CartTrait
*/
public function getCart(Request $request)
{
$session = $request->getSession();
if (null !== $cart = $request->getSession()->getCart()) {
if (null !== $cart = $session->getCart()) {
return $cart;
}
@@ -55,26 +56,26 @@ trait CartTrait
if ($cart) {
//le panier existe en base
$customer = $request->getSession()->getCustomerUser();
$customer = $session->getCustomerUser();
if ($customer) {
if ($cart->getCustomerId() != $customer->getId()) {
//le customer du panier n'est pas le mm que celui connecté, il faut cloner le panier sans le customer_id
$cart = $this->duplicateCart($cart, $request->getSession(), $customer);
$cart = $this->duplicateCart($cart, $session, $customer);
}
} else {
if ($cart->getCustomerId() != null) {
//il faut dupliquer le panier sans le customer_id
$cart = $this->duplicateCart($cart, $request->getSession());
$cart = $this->duplicateCart($cart, $session);
}
}
} else {
$cart = $this->createCart($request->getSession());
$cart = $this->createCart($session);
}
} else {
//le cookie de panier n'existe pas, il va falloir le créer et faire un enregistrement en base.
$cart = $this->createCart($request->getSession());
$cart = $this->createCart($session);
}
return $cart;
@@ -116,7 +117,7 @@ trait CartTrait
$cartEvent = new CartEvent($newCart);
$this->getDispatcher()->dispatch(TheliaEvents::CART_DUPLICATE, $cartEvent);
return $cartEvent->cart;
return $cartEvent->getCart();
}
protected function generateCookie()
@@ -131,4 +132,4 @@ trait CartTrait
return $id;
}
}
}

View File

@@ -22,16 +22,16 @@
<tag name="kernel.event_subscriber"/>
</service>
<service id="thelia.action.category" class="Thelia\Action\Category">
<argument type="service" id="service_container"/>
<tag name="kernel.event_subscriber"/>
</service>
<service id="thelia.action.category" class="Thelia\Action\Image">
<argument type="service" id="service_container"/>
<tag name="kernel.event_subscriber"/>
</service>
<service id="thelia.action.customer" class="Thelia\Action\Category">
<argument type="service" id="service_container"/>
<tag name="kernel.event_subscriber"/>
</service>
</services>
</config>

View File

@@ -85,8 +85,6 @@
<argument type="service" id="request" />
</service>
<service id="thelia.envContext" class="Thelia\Core\Context"/>
<!-- Parser context -->
<service id="thelia.parser.context" class="Thelia\Core\Template\ParserContext" scope="request">

View File

@@ -30,11 +30,22 @@ use Symfony\Component\HttpKernel\HttpKernelInterface;
use Thelia\Core\Security\Exception\AuthenticationException;
use Thelia\Tools\URL;
use Thelia\Tools\Redirect;
use Thelia\Core\Security\SecurityContext;
use Thelia\Model\AdminLog;
class BaseAdminController extends BaseController
{
const TEMPLATE_404 = "404";
/**
* Helper to append a message to the admin log.
*
* @param unknown $message
*/
public function adminLogAppend($message) {
AdminLog::append($message, $this->getRequest(), $this->getSecurityContext()->getAdminUser());
}
public function processTemplateAction($template)
{
try {

View File

@@ -25,12 +25,52 @@ namespace Thelia\Controller\Admin;
use Thelia\Core\Security\Exception\AuthenticationException;
use Thelia\Core\Security\Exception\AuthorizationException;
use Thelia\Log\Tlog;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Core\Event\CategoryCreateEvent;
use Thelia\Form\CategoryCreationForm;
use Thelia\Core\Event\CategoryDeleteEvent;
use Thelia\Core\Event\CategoryToggleVisibilityEvent;
use Thelia\Core\Event\CategoryChangePositionEvent;
use Thelia\Form\CategoryDeletionForm;
class CategoryController extends BaseAdminController
{
protected function createNewCategory($args)
{
$this->dispatchEvent("createCategory");
try {
$categoryCreationForm = new CategoryCreationForm($this->getRequest());
$form = $this->validateForm($categoryCreationForm, "POST");
$data = $form->getData();
$categoryCreateEvent = new CategoryCreateEvent(
$data["title"],
$data["parent"],
$data["locale"]
);
$this->dispatch(TheliaEvents::CATEGORY_CREATE, $categoryCreateEvent);
$category = $categoryCreateEvent->getCreatedCategory();
$this->adminLogAppend(sprintf("Category %s (ID %s) created", $category->getTitle(), $category->getId()));
// Substitute _ID_ in the URL with the ID of the created category
$successUrl = str_replace('_ID_', $category->getId(), $categoryCreationForm->getSuccessUrl());
// Redirect to the success URL
$this->redirect($successUrl);
}
catch (FormValidationException $e) {
$categoryCreationForm->setErrorMessage($e->getMessage());
$this->getParserContext()->setErrorForm($categoryCreationForm);
}
catch (Exception $e) {
Tlog::getInstance()->error(sprintf("Failed to create category: %s", $e->getMessage()));
$this->getParserContext()->setGeneralError($e->getMessage());
}
// At this point, the form has error, and should be redisplayed.
return $this->render('categories', $args);
@@ -45,9 +85,35 @@ class CategoryController extends BaseAdminController
protected function deleteCategory($args)
{
$this->dispatchEvent("deleteCategory");
try {
$categoryDeletionForm = new CategoryDeletionForm($this->getRequest());
// Something was wrong, category was not deleted. Display parent category list
$data = $this->validateForm($categoryDeletionForm, "POST")->getData();
$categoryDeleteEvent = new CategoryDeleteEvent($data['category_id']);
$this->dispatch(TheliaEvents::CATEGORY_DELETE, $categoryDeleteEvent);
$category = $categoryDeleteEvent->getDeletedCategory();
$this->adminLogAppend(sprintf("Category %s (ID %s) deleted", $category->getTitle(), $category->getId()));
// Substitute _ID_ in the URL with the ID of the created category
$successUrl = str_replace('_ID_', $categoryDeleteEvent->getDeletedCategory()->getId(), $categoryDeletionForm->getSuccessUrl());
// Redirect to the success URL
$this->redirect($successUrl);
}
catch (FormValidationException $e) {
$categoryDeletionForm->setErrorMessage($e->getMessage());
$this->getParserContext()->setErrorForm($categoryDeletionForm);
}
catch (Exception $e) {
Tlog::getInstance()->error(sprintf("Failed to delete category: %s", $e->getMessage()));
$this->getParserContext()->setGeneralError($e->getMessage());
}
// At this point, something was wrong, category was not deleted. Display parent category list
return $this->render('categories', $args);
}
@@ -60,28 +126,48 @@ class CategoryController extends BaseAdminController
protected function visibilityToggle($args)
{
$this->dispatchEvent("toggleCategoryVisibility");
$event = new CategoryToggleVisibilityEvent($this->getRequest()->get('category_id', 0));
$this->dispatch(TheliaEvents::CATEGORY_TOGGLE_VISIBILITY, $event);
return $this->nullResponse();
}
protected function changePosition($args)
{
$this->dispatchEvent("changeCategoryPosition");
$request = $this->getRequest();
$event = new CategoryChangePositionEvent(
$request->get('category_id', 0),
CategoryChangePositionEvent::POSITION_ABSOLUTE,
$request->get('position', null)
);
$this->dispatch(TheliaEvents::CATEGORY_CHANGE_POSITION, $event);
return $this->render('categories', $args);
}
protected function positionDown($args)
{
$this->dispatchEvent("changeCategoryPositionDown");
$event = new CategoryChangePositionEvent(
$this->getRequest()->get('category_id', 0),
CategoryChangePositionEvent::POSITION_DOWN
);
$this->dispatch(TheliaEvents::CATEGORY_CHANGE_POSITION, $event);
return $this->render('categories', $args);
}
protected function positionUp($args)
{
$this->dispatchEvent("changeCategoryPositionUp");
$event = new CategoryChangePositionEvent(
$this->getRequest()->get('category_id', 0),
CategoryChangePositionEvent::POSITION_UP
);
$this->dispatch(TheliaEvents::CATEGORY_CHANGE_POSITION, $event);
return $this->render('categories', $args);
}
@@ -138,9 +224,11 @@ class CategoryController extends BaseAdminController
return $this->positionDown($args);
}
} catch (AuthorizationException $ex) {
}
catch (AuthorizationException $ex) {
return $this->errorPage($ex->getMessage());
} catch (AuthenticationException $ex) {
}
catch (AuthenticationException $ex) {
return $this->errorPage($ex->getMessage());
}

View File

@@ -43,7 +43,7 @@ class SessionController extends BaseAdminController
{
$this->dispatch(TheliaEvents::ADMIN_LOGOUT);
$this->getSecurityContext()->clear();
$this->getSecurityContext()->clearAdminUser();
// Go back to login page.
return Redirect::exec(URL::absoluteUrl('/admin/login')); // FIXME - should be a parameter
@@ -61,7 +61,7 @@ class SessionController extends BaseAdminController
$user = $authenticator->getAuthentifiedUser();
// Success -> store user in security context
$this->getSecurityContext()->setUser($user);
$this->getSecurityContext()->setAdminUser($user);
// Log authentication success
AdminLog::append("Authentication successful", $request, $user);

View File

@@ -34,6 +34,7 @@ use Symfony\Component\EventDispatcher\EventDispatcher;
use Thelia\Core\Factory\ActionEventFactory;
use Thelia\Form\BaseForm;
use Thelia\Form\Exception\FormValidationException;
use Symfony\Component\EventDispatcher\Event;
/**
*
@@ -56,34 +57,12 @@ class BaseController extends ContainerAware
}
/**
* Create an action event
* Dispatch a Thelia event
*
* @param string $action
* @return EventDispatcher
* @param string $eventName a TheliaEvent name, as defined in TheliaEvents class
* @param Event $event the event
*/
protected function dispatchEvent($action)
{
// Create the
$eventFactory = new ActionEventFactory($this->getRequest(), $action, $this->container->getParameter("thelia.actionEvent"));
$actionEvent = $eventFactory->createActionEvent();
$this->dispatch("action.$action", $actionEvent);
if ($actionEvent->hasErrorForm()) {
$this->getParserContext()->setErrorForm($actionEvent->getErrorForm());
}
return $actionEvent;
}
/**
* Dispatch a Thelia event to modules
*
* @param string $eventName a TheliaEvent name, as defined in TheliaEvents class
* @param ActionEvent $event the event
*/
protected function dispatch($eventName, ActionEvent $event = null)
protected function dispatch($eventName, Event $event = null)
{
$this->getDispatcher()->dispatch($eventName, $event);
}
@@ -113,13 +92,9 @@ class BaseController extends ContainerAware
*
* @return \Thelia\Core\Security\SecurityContext
*/
protected function getSecurityContext($context = false)
protected function getSecurityContext()
{
$securityContext = $this->container->get('thelia.securityContext');
$securityContext->setContext($context === false ? SecurityContext::CONTEXT_BACK_OFFICE : $context);
return $securityContext;
return $this->container->get('thelia.securityContext');
}
/**

View File

@@ -36,6 +36,7 @@ use Thelia\Form\CustomerModification;
use Thelia\Form\Exception\FormValidationException;
use Thelia\Model\Customer;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Core\Event\CustomerEvent;
class CustomerController extends BaseFrontController
{
@@ -76,7 +77,7 @@ class CustomerController extends BaseFrontController
try {
$customer = $this->getSecurityContext(SecurityContext::CONTEXT_FRONT_OFFICE)->getUser();
$customer = $this->getSecurityContext()->getCustomerUser();
$form = $this->validateForm($customerModification, "post");
@@ -116,9 +117,7 @@ class CustomerController extends BaseFrontController
try {
$customer = $authenticator->getAuthentifiedUser();
$customerLoginEvent = new CustomerLoginEvent($customer);
$this->processLogin($customer, $customerLoginEvent);
$this->processLogin($customer);
$this->redirectSuccess();
} catch (ValidatorException $e) {
@@ -132,11 +131,11 @@ class CustomerController extends BaseFrontController
}
}
public function processLogin(Customer $customer,$event = null)
public function processLogin(Customer $customer)
{
$this->getSecurityContext(SecurityContext::CONTEXT_FRONT_OFFICE)->setUser($customer);
$this->getSecurityContext()->setCustomerUser($customer);
if($event) $this->dispatch(TheliaEvents::CUSTOMER_LOGIN, $event);
if($event) $this->dispatch(TheliaEvents::CUSTOMER_LOGIN, new CustomerLoginEvent($customer));
}
/**

View File

@@ -35,27 +35,8 @@ use Thelia\Form\BaseForm;
*/
abstract class ActionEvent extends Event
{
/**
*
* @var Symfony\Component\HttpFoundation\Request
*/
protected $request;
protected $errorForm = null;
protected $parameters = array();
/**
*
* @param \Symfony\Component\HttpFoundation\Request $request
* @param string $action
*/
public function __construct(Request $request)
{
$this->request = $request;
}
public function __set($name, $value)
{
$this->parameters[$name] = $value;
@@ -69,30 +50,4 @@ abstract class ActionEvent extends Event
return null;
}
/**
*
* @return \Symfony\Component\HttpFoundation\Request
*/
public function getRequest()
{
return $this->request;
}
public function setErrorForm(BaseForm $form)
{
$this->errorForm = $form;
if ($form != null) $this->stopPropagation();
}
public function getErrorForm()
{
return $this->errorForm;
}
public function hasErrorForm()
{
return $this->errorForm != null ? true : false;
}
}
}

View File

@@ -25,7 +25,7 @@ namespace Thelia\Core\Event;
use Thelia\Model\CartItem;
class CartItemEvent extends InternalEvent
class CartItemEvent extends ActionEvent
{
protected $cartItem;

View File

@@ -21,34 +21,64 @@
/* */
/*************************************************************************************/
namespace Thelia\Core;
namespace Thelia\Core\Event;
use Thelia\Model\Category;
class Context
class CategoryChangePositionEvent extends ActionEvent
{
const CONTEXT_FRONT_OFFICE = 'front';
const CONTEXT_BACK_OFFICE = 'admin';
const POSITION_UP = 1;
const POSITION_DOWN = 2;
const POSITION_ABSOLUTE = 3;
protected $defineContext = array(
self::CONTEXT_BACK_OFFICE,
self::CONTEXT_FRONT_OFFICE
);
protected $id;
protected $mode;
protected $position;
protected $category;
protected $currentContext = self::CONTEXT_FRONT_OFFICE;
public function isValidContext($context)
public function __construct($id, $mode, $position = null)
{
return in_array($context, $this->defineContext);
$this->id = $id;
$this->mode = $mode;
$this->position = $position;
}
public function setContext($context)
public function getId()
{
if ($this->isValidContext($context)) {
$this->currentContext = $context;
}
return $this->id;
}
public function getContext()
public function setId($id)
{
return $this->currentContext;
$this->id = $id;
}
}
public function getMode()
{
return $this->mode;
}
public function setMode($mode)
{
$this->mode = $mode;
}
public function getPosition()
{
return $this->position;
}
public function setPosition($position)
{
$this->position = $position;
}
public function getCategory()
{
return $this->category;
}
public function setCategory($category)
{
$this->category = $category;
}
}

View File

@@ -21,16 +21,62 @@
/* */
/*************************************************************************************/
namespace Thelia\Core\Event\Internal;
namespace Thelia\Core\Event;
use Symfony\Component\EventDispatcher\Event;
use Thelia\Model\Category;
/**
* Base class used for internal event like creating new Customer, adding item to cart, etc
*
* Class InternalEvent
* @package Thelia\Core\Event
*/
abstract class InternalEvent extends Event
class CategoryCreateEvent extends ActionEvent
{
protected $title;
protected $parent;
protected $locale;
protected $created_category;
public function __construct($title, $parent, $locale)
{
$this->title = $title;
$this->parent = $parent;
$this->locale = $locale;
}
public function getTitle()
{
return $this->title;
}
public function setTitle($title)
{
$this->title = $title;
}
public function getParent()
{
return $this->parent;
}
public function setParent($parent)
{
$this->parent = $parent;
}
public function getLocale()
{
return $this->locale;
}
public function setLocale($locale)
{
$this->locale = $locale;
}
public function getCreatedCategory()
{
return $this->created_category;
}
public function setCreatedCategory(Category $created_category)
{
$this->created_category = $created_category;
var_dump($this->created_category);
}
}

View File

@@ -21,17 +21,36 @@
/* */
/*************************************************************************************/
namespace Thelia\Core\Event\Internal;
namespace Thelia\Core\Event;
use Thelia\Model\Category;
use Thelia\Model\Cart;
class CartEvent extends InternalEvent
class CategoryDeleteEvent extends ActionEvent
{
public $cart;
protected $id;
protected $deleted_category;
public function __construct(Cart $cart)
public function __construct($id)
{
$this->cart = $cart;
$this->id = $id;
}
public function getId()
{
return $this->id;
}
public function setId($id)
{
$this->id = $id;
}
public function getDeletedCategory()
{
return $this->deleted_category;
}
public function setDeletedCategory(Category $deleted_category)
{
$this->deleted_category = $deleted_category;
}
}

View File

@@ -22,15 +22,35 @@
/*************************************************************************************/
namespace Thelia\Core\Event;
use Thelia\Model\Category;
class CategoryEvent extends InternalEvent
class CategoryToggleVisibilityEvent extends ActionEvent
{
public $category;
protected $id;
protected $category;
public function __construct(Category $category)
public function __construct($id)
{
$this->id = $id;
}
public function getId()
{
return $this->id;
}
public function setId($id)
{
$this->id = $id;
}
public function getCategory()
{
return $this->category;
}
public function setCategory(Category $category)
{
$this->category = $category;
}
}
}

View File

@@ -21,11 +21,12 @@
/* */
/*************************************************************************************/
namespace Thelia\Core\Event\Internal;
namespace Thelia\Core\Event;
use Thelia\Model\Customer;
use Thelia\Core\Event\ActionEvent;
class CustomerEvent extends InternalEvent
class CustomerEvent extends ActionEvent
{
public $customer;

View File

@@ -94,11 +94,29 @@ final class TheliaEvents
*/
const AFTER_CHANGECUSTOMER = "action.after_changecustomer";
/**
* Sent once the category creation form has been successfully validated, and before category insertion in the database.
*/
const BEFORE_CREATECATEGORY = "action.before_createcategory";
/**
* Create, change or delete a category
*/
const CATEGORY_CREATE = "action.createCategory";
const CATEGORY_MODIFY = "action.modifyCategory";
const CATEGORY_DELETE = "action.deleteCategory";
/**
* Toggle category visibility
*/
const CATEGORY_TOGGLE_VISIBILITY = "action.toggleCategoryVisibility";
/**
* Change category position
*/
const CATEGORY_CHANGE_POSITION = "action.changeCategoryPosition";
/**
* Sent just after a successful insert of a new category in the database.
*/
@@ -113,6 +131,11 @@ final class TheliaEvents
*/
const AFTER_DELETECATEGORY = "action.after_deletecategory";
/**
* Sent just before a successful change of a category in the database.
*/
const BEFORE_CHANGECATEGORY = "action.before_changecategory";
/**
* Sent just after a successful change of a category in the database.
*/
@@ -154,5 +177,4 @@ final class TheliaEvents
* Sent on cimage cache clear request
*/
const IMAGE_CLEAR_CACHE = "action.clearImageCache";
}

View File

@@ -33,36 +33,11 @@ use Thelia\Core\HttpFoundation\Request;
*/
class SecurityContext
{
const CONTEXT_FRONT_OFFICE = 'front';
const CONTEXT_BACK_OFFICE = 'admin';
private $request;
private $context;
public function __construct(Request $request)
{
$this->request = $request;
$this->context = null;
}
public function setContext($context)
{
if ($context !== self::CONTEXT_FRONT_OFFICE && $context !== self::CONTEXT_BACK_OFFICE) {
throw new \InvalidArgumentException(sprintf("Invalid or empty context identifier '%s'", $context));
}
$this->context = $context;
return $this;
}
public function getContext($exception_if_context_undefined = false)
{
if (null === $this->context && $exception_if_context_undefined === true)
throw new \LogicException("No context defined. Please use setContext() first.");
return $this->context;
}
private function getSession()
@@ -76,28 +51,47 @@ class SecurityContext
}
/**
* Gets the currently authenticated user in the current context, or null if none is defined
* Gets the currently authenticated user in the admin, or null if none is defined
*
* @return UserInterface|null A UserInterface instance or null if no user is available
*/
public function getUser()
public function getAdminUser()
{
$context = $this->getContext(true);
if ($context === self::CONTEXT_FRONT_OFFICE)
$user = $this->getSession()->getCustomerUser();
else if ($context == self::CONTEXT_BACK_OFFICE)
$user = $this->getSession()->getAdminUser();
else
$user = null;
return $user;
return $this->getSession()->getAdminUser();
}
final public function isAuthenticated()
/**
* Gets the currently authenticated customer, or null if none is defined
*
* @return UserInterface|null A UserInterface instance or null if no user is available
*/
public function getCustomerUser()
{
if (null !== $this->getUser()) {
return true;
return $this->getSession()->getCustomerUser();
}
/**
* Check if a user has at least one of the required roles
*
* @param UserInterface $user the user
* @param array $roles the roles
* @return boolean true if the user has the required role, false otherwise
*/
final public function hasRequiredRole($user, array $roles) {
if ($user != null) {
// Check if user's roles matches required roles
$userRoles = $user->getRoles();
$roleFound = false;
foreach ($userRoles as $role) {
if (in_array($role, $roles)) {
$roleFound = true;
return true;
}
}
}
return false;
@@ -110,85 +104,88 @@ class SecurityContext
*/
final public function isGranted(array $roles, array $permissions)
{
if ($this->isAuthenticated() === true) {
// Find a user which matches the required roles.
$user = $this->getCustomerUser();
$user = $this->getUser();
if (! $this->hasRequiredRole($user, $roles)) {
$user = $this->getAdminUser();
// Check if user's roles matches required roles
$userRoles = $user->getRoles();
if (! $this->hasRequiredRole($user, $roles)) {
$user = null;
}
}
$roleFound = false;
if ($user != null) {
foreach ($userRoles as $role) {
if (in_array($role, $roles)) {
$roleFound = true;
break;
}
if (empty($permissions)) {
return true;
}
if ($roleFound) {
// Get permissions from profile
// $userPermissions = $user->getPermissions(); FIXME
if (empty($permissions)) {
return true;
}
// TODO: Finalize permissions system !;
// Get permissions from profile
// $userPermissions = $user->getPermissions(); FIXME
$userPermissions = array('*'); // FIXME !
// TODO: Finalize permissions system !;
$permissionsFound = true;
$userPermissions = array('*'); // FIXME !
// User have all permissions ?
if (in_array('*', $userPermissions))
return true;
$permissionsFound = true;
// Check that user's permissions matches required permissions
foreach ($permissions as $permission) {
if (! in_array($permission, $userPermissions)) {
$permissionsFound = false;
// User have all permissions ?
if (in_array('*', $userPermissions))
return true;
// Check that user's permissions matches required permissions
foreach ($permissions as $permission) {
if (! in_array($permission, $userPermissions)) {
$permissionsFound = false;
break;
}
}
return $permissionsFound;
break;
}
}
return $permissionsFound;
}
return false;
}
/**
* Sets the authenticated user.
* Sets the authenticated admin user.
*
* @param UserInterface $user A UserInterface, or null if no further user should be stored
*/
public function setUser(UserInterface $user)
public function setAdminUser(UserInterface $user)
{
$context = $this->getContext(true);
$user->eraseCredentials();
if ($context === self::CONTEXT_FRONT_OFFICE)
$this->getSession()->setCustomerUser($user);
else if ($context == self::CONTEXT_BACK_OFFICE)
$this->getSession()->setAdminUser($user);
$this->getSession()->setAdminUser($user);
}
/**
* Clear the user from the security context
* Sets the authenticated customer user.
*
* @param UserInterface $user A UserInterface, or null if no further user should be stored
*/
public function clear()
public function setCustomerUser(UserInterface $user)
{
$context = $this->getContext(true);
$user->eraseCredentials();
if ($context === self::CONTEXT_FRONT_OFFICE)
$this->getSession()->clearCustomerUser();
else if ($context == self::CONTEXT_BACK_OFFICE)
$this->getSession()->clearAdminUser();
$this->getSession()->setCustomerUser($user);
}
}
/**
* Clear the customer from the security context
*/
public function clearCustomerUser()
{
$this->getSession()->clearCustomerUser();
}
/**
* Clear the admin from the security context
*/
public function clearAdminUser()
{
$this->getSession()->clearAdminUser();
}
}

View File

@@ -28,6 +28,7 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Thelia\Core\Template\Loop\Argument\Argument;
use Propel\Runtime\ActiveQuery\ModelCriteria;
use Thelia\Core\Security\SecurityContext;
use Thelia\Model\Tools\ModelCriteriaTools;
/**
*
@@ -234,6 +235,31 @@ abstract class BaseLoop
}
}
/**
* Setup ModelCriteria for proper i18n processing
*
* @param ModelCriteria $search the Propel Criteria to configure
* @param array $columns the i18n columns
* @param string $foreignTable the specified table (default to criteria table)
* @param string $foreignKey the foreign key in this table (default to criteria table)
*
* @return mixed the locale
*/
protected function configureI18nProcessing(ModelCriteria $search, $columns = array('TITLE', 'CHAPO', 'DESCRIPTION', 'POSTSCRIPTUM'), $foreignTable = null, $foreignKey = 'ID', $forceReturn = false) {
/* manage translations */
return ModelCriteriaTools::getI18n(
$this->getBackend_context(),
$this->getLang(),
$search,
$this->request->getSession()->getLocale(),
$columns,
$foreignTable,
$foreignKey,
$forceReturn
);
}
/**
*
* this function have to be implement in your own loop class.

View File

@@ -34,7 +34,6 @@ use Thelia\Core\Template\Loop\Argument\Argument;
use Thelia\Log\Tlog;
use Thelia\Model\Base\LangQuery;
use Thelia\Model\Tools\ModelCriteriaTools;
use Thelia\Model\Base\CategoryQuery;
use Thelia\Model\Base\ProductCategoryQuery;
@@ -92,7 +91,7 @@ class Attribute extends BaseLoop
$lang = $this->getLang();
/* manage translations */
ModelCriteriaTools::getI18n($backendContext, $lang, $search, ConfigQuery::getDefaultLangWhenNoTranslationAvailable(), $this->request->getSession()->getLocale());
$this->configureI18nProcessing($search);
$id = $this->getId();

View File

@@ -33,8 +33,6 @@ use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
use Thelia\Core\Template\Loop\Argument\Argument;
use Thelia\Log\Tlog;
use Thelia\Model\Tools\ModelCriteriaTools;
use Thelia\Model\Base\AttributeAvQuery;
use Thelia\Model\ConfigQuery;
use Thelia\Type\TypeCollection;
@@ -79,12 +77,8 @@ class AttributeAvailability extends BaseLoop
{
$search = AttributeAvQuery::create();
$backendContext = $this->getBackend_context();
$lang = $this->getLang();
/* manage translations */
ModelCriteriaTools::getI18n($backendContext, $lang, $search, ConfigQuery::getDefaultLangWhenNoTranslationAvailable(), $this->request->getSession()->getLocale());
$this->configureI18nProcessing($search);
$id = $this->getId();

View File

@@ -33,8 +33,6 @@ use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
use Thelia\Core\Template\Loop\Argument\Argument;
use Thelia\Log\Tlog;
use Thelia\Model\Tools\ModelCriteriaTools;
use Thelia\Model\Base\AttributeCombinationQuery;
use Thelia\Model\Map\AttributeAvTableMap;
use Thelia\Model\Map\AttributeTableMap;
@@ -59,6 +57,7 @@ class AttributeCombination extends BaseLoop
{
return new ArgumentCollection(
Argument::createIntTypeArgument('product_sale_elements', null, true),
Argument::createIntTypeArgument('lang'),
new Argument(
'order',
new TypeCollection(
@@ -79,20 +78,16 @@ class AttributeCombination extends BaseLoop
$search = AttributeCombinationQuery::create();
/* manage attribute translations */
ModelCriteriaTools::getFrontEndI18n(
$this->configureI18nProcessing(
$search,
ConfigQuery::getDefaultLangWhenNoTranslationAvailable(),
$this->request->getSession()->getLocale(),
array('TITLE', 'CHAPO', 'DESCRIPTION', 'POSTSCRIPTUM'),
AttributeTableMap::TABLE_NAME,
'ATTRIBUTE_ID'
);
/* manage attributeAv translations */
ModelCriteriaTools::getFrontEndI18n(
$this->configureI18nProcessing(
$search,
ConfigQuery::getDefaultLangWhenNoTranslationAvailable(),
$this->request->getSession()->getLocale(),
array('TITLE', 'CHAPO', 'DESCRIPTION', 'POSTSCRIPTUM'),
AttributeAvTableMap::TABLE_NAME,
'ATTRIBUTE_AV_ID'

View File

@@ -68,15 +68,12 @@ class Auth extends BaseLoop
*/
public function exec(&$pagination)
{
$context = $this->getContext();
$roles = $this->_explode($this->getRoles());
$permissions = $this->_explode($this->getPermissions());
$loopResult = new LoopResult();
try {
$this->securityContext->setContext($context);
if (true === $this->securityContext->isGranted($roles, $permissions == null ? array() : $permissions)) {
// Create an empty row: loop is no longer empty :)

View File

@@ -32,8 +32,6 @@ use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
use Thelia\Core\Template\Loop\Argument\Argument;
use Thelia\Log\Tlog;
use Thelia\Model\Tools\ModelCriteriaTools;
use Thelia\Model\CategoryQuery;
use Thelia\Model\ConfigQuery;
use Thelia\Type\TypeCollection;
@@ -98,12 +96,8 @@ class Category extends BaseLoop
{
$search = CategoryQuery::create();
$backendContext = $this->getBackend_context();
$lang = $this->getLang();
/* manage translations */
$locale = ModelCriteriaTools::getI18n($backendContext, $lang, $search, ConfigQuery::getDefaultLangWhenNoTranslationAvailable(), $this->request->getSession()->getLocale());
$locale = $this->configureI18nProcessing($search);
$id = $this->getId();
@@ -169,7 +163,6 @@ class Category extends BaseLoop
$loopResult = new LoopResult();
foreach ($categories as $category) {
/*
* no cause pagination lost :
* if ($this->getNotEmpty() && $category->countAllProducts() == 0) continue;

View File

@@ -65,7 +65,8 @@ class CategoryPath extends BaseLoop
Argument::createIntTypeArgument('category', null, true),
Argument::createIntTypeArgument('depth'),
Argument::createIntTypeArgument('level'),
Argument::createBooleanOrBothTypeArgument('visible', true, false)
Argument::createBooleanOrBothTypeArgument('visible', true, false),
Argument::createIntTypeArgument('lang')
);
}
@@ -80,6 +81,9 @@ class CategoryPath extends BaseLoop
$visible = $this->getVisible();
$search = CategoryQuery::create();
$this->configureI18nProcessing($search, array('TITLE'));
$search->filterById($id);
if ($visible != BooleanOrBothType::ANY) $search->filterByVisible($visible);
@@ -95,7 +99,7 @@ class CategoryPath extends BaseLoop
$loopResultRow = new LoopResultRow();
$loopResultRow
->set("TITLE",$category->getTitle())
->set("TITLE",$category->getVirtualColumn('i18n_TITLE'))
->set("URL", $category->getUrl())
->set("ID", $category->getId())
;
@@ -114,8 +118,11 @@ class CategoryPath extends BaseLoop
$ids[] = $parent;
$search = CategoryQuery::create();
$this->configureI18nProcessing($search, array('TITLE'));
$search->filterById($parent);
if ($visible == true) $search->filterByVisible($visible);
if ($visible != BooleanOrBothType::ANY) $search->filterByVisible($visible);
}
}
} while ($category != null && $parent > 0);

View File

@@ -31,8 +31,6 @@ use Thelia\Core\Template\Element\LoopResultRow;
use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
use Thelia\Core\Template\Loop\Argument\Argument;
use Thelia\Model\Tools\ModelCriteriaTools;
use Thelia\Model\FolderQuery;
use Thelia\Model\Map\ContentTableMap;
use Thelia\Model\ContentFolderQuery;
@@ -88,12 +86,8 @@ class Content extends BaseLoop
{
$search = ContentQuery::create();
$backendContext = $this->getBackend_context();
$lang = $this->getLang();
/* manage translations */
$locale = ModelCriteriaTools::getI18n($backendContext, $lang, $search, ConfigQuery::getDefaultLangWhenNoTranslationAvailable(), $this->request->getSession()->getLocale());
$locale = $this->configureI18nProcessing($search);
$id = $this->getId();

View File

@@ -31,8 +31,6 @@ use Thelia\Core\Template\Element\LoopResultRow;
use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
use Thelia\Core\Template\Loop\Argument\Argument;
use Thelia\Model\Tools\ModelCriteriaTools;
use Thelia\Model\CountryQuery;
use Thelia\Model\ConfigQuery;
@@ -70,12 +68,8 @@ class Country extends BaseLoop
{
$search = CountryQuery::create();
$backendContext = $this->getBackend_context();
$lang = $this->getLang();
/* manage translations */
ModelCriteriaTools::getI18n($backendContext, $lang, $search, ConfigQuery::getDefaultLangWhenNoTranslationAvailable(), $this->request->getSession()->getLocale());
$this->configureI18nProcessing($search);
$id = $this->getId();

View File

@@ -31,8 +31,6 @@ use Thelia\Core\Template\Element\LoopResultRow;
use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
use Thelia\Core\Template\Loop\Argument\Argument;
use Thelia\Model\Tools\ModelCriteriaTools;
use Thelia\Model\CurrencyQuery;
use Thelia\Model\ConfigQuery;
@@ -69,12 +67,8 @@ class Currency extends BaseLoop
{
$search = CurrencyQuery::create();
$backendContext = $this->getBackend_context();
$lang = $this->getLang();
/* manage translations */
ModelCriteriaTools::getI18n($backendContext, $lang, $search, ConfigQuery::getDefaultLangWhenNoTranslationAvailable(), $this->request->getSession()->getLocale(), array('NAME'));
$this->configureI18nProcessing($search, array('NAME'));
$id = $this->getId();

View File

@@ -31,8 +31,6 @@ use Thelia\Core\Template\Element\LoopResultRow;
use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
use Thelia\Core\Template\Loop\Argument\Argument;
use Thelia\Model\Tools\ModelCriteriaTools;
use Thelia\Model\Base\CategoryQuery;
use Thelia\Model\Base\ProductCategoryQuery;
use Thelia\Model\Base\FeatureQuery;
@@ -84,12 +82,8 @@ class Feature extends BaseLoop
{
$search = FeatureQuery::create();
$backendContext = $this->getBackend_context();
$lang = $this->getLang();
/* manage translations */
ModelCriteriaTools::getI18n($backendContext, $lang, $search, ConfigQuery::getDefaultLangWhenNoTranslationAvailable(), $this->request->getSession()->getLocale());
$this->configureI18nProcessing($search);
$id = $this->getId();

View File

@@ -31,8 +31,6 @@ use Thelia\Core\Template\Element\LoopResultRow;
use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
use Thelia\Core\Template\Loop\Argument\Argument;
use Thelia\Model\Tools\ModelCriteriaTools;
use Thelia\Model\Base\FeatureAvQuery;
use Thelia\Model\ConfigQuery;
use Thelia\Type\TypeCollection;
@@ -77,12 +75,8 @@ class FeatureAvailability extends BaseLoop
{
$search = FeatureAvQuery::create();
$backendContext = $this->getBackend_context();
$lang = $this->getLang();
/* manage translations */
ModelCriteriaTools::getI18n($backendContext, $lang, $search, ConfigQuery::getDefaultLangWhenNoTranslationAvailable(), $this->request->getSession()->getLocale());
$this->configureI18nProcessing($search);
$id = $this->getId();

View File

@@ -33,8 +33,6 @@ use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
use Thelia\Core\Template\Loop\Argument\Argument;
use Thelia\Log\Tlog;
use Thelia\Model\Tools\ModelCriteriaTools;
use Thelia\Model\Base\FeatureProductQuery;
use Thelia\Model\ConfigQuery;
use Thelia\Model\Map\FeatureAvTableMap;
@@ -70,7 +68,8 @@ class FeatureValue extends BaseLoop
new Type\EnumListType(array('alpha', 'alpha_reverse', 'manual', 'manual_reverse'))
),
'manual'
)
),
Argument::createIntTypeArgument('lang')
);
}
@@ -84,10 +83,8 @@ class FeatureValue extends BaseLoop
$search = FeatureProductQuery::create();
/* manage featureAv translations */
ModelCriteriaTools::getFrontEndI18n(
$this->configureI18nProcessing(
$search,
ConfigQuery::getDefaultLangWhenNoTranslationAvailable(),
$this->request->getSession()->getLocale(),
array('TITLE', 'CHAPO', 'DESCRIPTION', 'POSTSCRIPTUM'),
FeatureAvTableMap::TABLE_NAME,
'FEATURE_AV_ID',

View File

@@ -32,8 +32,6 @@ use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
use Thelia\Core\Template\Loop\Argument\Argument;
use Thelia\Log\Tlog;
use Thelia\Model\Tools\ModelCriteriaTools;
use Thelia\Model\FolderQuery;
use Thelia\Model\ConfigQuery;
use Thelia\Type\TypeCollection;
@@ -80,12 +78,8 @@ class Folder extends BaseLoop
{
$search = FolderQuery::create();
$backendContext = $this->getBackend_context();
$lang = $this->getLang();
/* manage translations */
$locale = ModelCriteriaTools::getI18n($backendContext, $lang, $search, ConfigQuery::getDefaultLangWhenNoTranslationAvailable(), $this->request->getSession()->getLocale());
$locale = $this->configureI18nProcessing($search);
$id = $this->getId();

View File

@@ -207,16 +207,8 @@ class Image extends BaseLoop
}
/**
* \Criteria::INNER_JOIN in second parameter for joinWithI18n exclude query without translation.
*
* @todo : verify here if we want results for row without translations.
*/
$search->joinWithI18n(
$this->request->getSession()->getLocale(),
(ConfigQuery::getDefaultLangWhenNoTranslationAvailable()) ? Criteria::LEFT_JOIN : Criteria::INNER_JOIN
);
/* manage translations */
$this->configureI18nProcessing($search);
$results = $this->search($search, $pagination);
@@ -295,6 +287,7 @@ class Image extends BaseLoop
),
'manual'
),
Argument::createIntTypeArgument('lang'),
Argument::createIntTypeArgument('width'),
Argument::createIntTypeArgument('height'),

View File

@@ -33,8 +33,6 @@ use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
use Thelia\Core\Template\Loop\Argument\Argument;
use Thelia\Log\Tlog;
use Thelia\Model\Tools\ModelCriteriaTools;
use Thelia\Model\CategoryQuery;
use Thelia\Model\Map\FeatureProductTableMap;
use Thelia\Model\Map\ProductPriceTableMap;
@@ -138,12 +136,8 @@ class Product extends BaseLoop
{
$search = ProductQuery::create();
$backendContext = $this->getBackend_context();
$lang = $this->getLang();
/* manage translations */
$locale = ModelCriteriaTools::getI18n($backendContext, $lang, $search, ConfigQuery::getDefaultLangWhenNoTranslationAvailable(), $this->request->getSession()->getLocale());
$locale = $this->configureI18nProcessing($search);
$attributeNonStrictMatch = $this->getAttribute_non_strict_match();
$isPSELeftJoinList = array();

View File

@@ -31,8 +31,6 @@ use Thelia\Core\Template\Element\LoopResultRow;
use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
use Thelia\Core\Template\Loop\Argument\Argument;
use Thelia\Model\Tools\ModelCriteriaTools;
use Thelia\Model\CustomerTitleQuery;
use Thelia\Model\ConfigQuery;
@@ -67,12 +65,8 @@ class Title extends BaseLoop
{
$search = CustomerTitleQuery::create();
$backendContext = $this->getBackend_context();
$lang = $this->getLang();
/* manage translations */
ModelCriteriaTools::getI18n($backendContext, $lang, $search, ConfigQuery::getDefaultLangWhenNoTranslationAvailable(), $this->request->getSession()->getLocale(), array('SHORT', 'LONG'));
$this->configureI18nProcessing($search, array('SHORT', 'LONG'));
$id = $this->getId();

View File

@@ -52,7 +52,7 @@ class DataAccessFunctions extends AbstractSmartyPlugin
*/
public function adminDataAccess($params, &$smarty)
{
return $this->userDataAccess("Admin User", SecurityContext::CONTEXT_BACK_OFFICE, $params);
return $this->userDataAccess("Admin User", $this->securityContext->getAdminUser(), $params);
}
/**
@@ -64,7 +64,7 @@ class DataAccessFunctions extends AbstractSmartyPlugin
*/
public function customerDataAccess($params, &$smarty)
{
return $this->userDataAccess("Customer User", SecurityContext::CONTEXT_FRONT_OFFICE, $params);
return $this->userDataAccess("Customer User", $this->securityContext->getCustomerUser(), $params);
}
/**
@@ -75,12 +75,11 @@ class DataAccessFunctions extends AbstractSmartyPlugin
* @return string the value of the requested attribute
* @throws InvalidArgumentException if the object does not have the requested attribute.
*/
protected function userDataAccess($objectLabel, $context, $params)
protected function userDataAccess($objectLabel, $user, $params)
{
$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($attribute));

View File

@@ -46,11 +46,6 @@ class Security extends AbstractSmartyPlugin
*/
public function checkAuthFunction($params, &$smarty)
{
// Context: 'front' or 'admin'
$context = $this->getNormalizedParam($params, 'context');
$this->securityContext->setContext($context);
$roles = $this->_explode($this->getParam($params, 'roles'));
$permissions = $this->_explode($this->getParam($params, 'permissions'));

View File

@@ -4,10 +4,10 @@ namespace Thelia\Model;
use Propel\Runtime\Connection\ConnectionInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Thelia\Core\Event\Internal\CartEvent;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Model\Base\CartItem as BaseCartItem;
use Thelia\Model\ConfigQuery;
use Thelia\Core\Event\CartEvent;
class CartItem extends BaseCartItem
{

View File

@@ -50,7 +50,7 @@ class Category extends BaseCategory
->findOne()
;
return $last->getPosition() + 1;
return $last != null ? $last->getPosition() + 1 : 1;
}
/**
@@ -76,6 +76,4 @@ class Category extends BaseCategory
return $countProduct;
}
}

View File

@@ -3,7 +3,6 @@
namespace Thelia\Model;
use Symfony\Component\Config\Definition\Exception\Exception;
use Thelia\Core\Event\Internal\CustomerEvent;
use Thelia\Model\Base\Customer as BaseCustomer;
use Thelia\Model\Exception\InvalidArgumentException;
@@ -17,6 +16,7 @@ use Propel\Runtime\Connection\ConnectionInterface;
use Propel\Runtime\Propel;
use Thelia\Model\Map\CustomerTableMap;
use Thelia\Core\Security\Role\Role;
use Thelia\Core\Event\CustomerEvent;
/**
* Skeleton subclass for representing a row from the 'customer' table.

View File

@@ -6,6 +6,7 @@ use Propel\Runtime\ActiveQuery\Criteria;
use Propel\Runtime\ActiveQuery\Join;
use Propel\Runtime\ActiveQuery\ModelCriteria;
use Thelia\Model\Base\LangQuery;
use Thelia\Model\ConfigQuery;
/**
* Class ModelCriteriaTools
@@ -17,13 +18,12 @@ class ModelCriteriaTools
{
/**
* @param ModelCriteria $search
* @param $defaultLangWithoutTranslation
* @param $askedLocale
* @param $requestedLocale
* @param array $columns
* @param null $foreignTable
* @param string $foreignKey
*/
public static function getFrontEndI18n(ModelCriteria &$search, $defaultLangWithoutTranslation, $askedLocale, $columns = array('TITLE', 'CHAPO', 'DESCRIPTION', 'POSTSCRIPTUM'), $foreignTable = null, $foreignKey = 'ID', $forceReturn = false)
public static function getFrontEndI18n(ModelCriteria &$search, $requestedLocale, $columns, $foreignTable, $foreignKey, $forceReturn = false)
{
if($foreignTable === null) {
$foreignTable = $search->getTableMap()->getName();
@@ -32,21 +32,24 @@ class ModelCriteriaTools
$aliasPrefix = $foreignTable . '_';
}
$askedLocaleI18nAlias = $aliasPrefix . 'asked_locale_i18n';
$defaultLangWithoutTranslation = ConfigQuery::getDefaultLangWhenNoTranslationAvailable();
$requestedLocaleI18nAlias = $aliasPrefix . 'requested_locale_i18n';
$defaultLocaleI18nAlias = $aliasPrefix . 'default_locale_i18n';
if($defaultLangWithoutTranslation == 0) {
$askedLocaleJoin = new Join();
$askedLocaleJoin->addExplicitCondition($search->getTableMap()->getName(), $foreignKey, null, $foreignTable . '_i18n', 'ID', $askedLocaleI18nAlias);
$askedLocaleJoin->setJoinType($forceReturn === false ? Criteria::INNER_JOIN : Criteria::LEFT_JOIN);
$requestedLocaleJoin = new Join();
$requestedLocaleJoin->addExplicitCondition($search->getTableMap()->getName(), $foreignKey, null, $foreignTable . '_i18n', 'ID', $requestedLocaleI18nAlias);
$requestedLocaleJoin->setJoinType($forceReturn === false ? Criteria::INNER_JOIN : Criteria::LEFT_JOIN);
$search->addJoinObject($askedLocaleJoin, $askedLocaleI18nAlias)
->addJoinCondition($askedLocaleI18nAlias ,'`' . $askedLocaleI18nAlias . '`.LOCALE = ?', $askedLocale, null, \PDO::PARAM_STR);
$search->addJoinObject($requestedLocaleJoin, $requestedLocaleI18nAlias)
->addJoinCondition($requestedLocaleI18nAlias ,'`' . $requestedLocaleI18nAlias . '`.LOCALE = ?', $requestedLocale, null, \PDO::PARAM_STR);
$search->withColumn('NOT ISNULL(`' . $askedLocaleI18nAlias . '`.`ID`)', $aliasPrefix . 'IS_TRANSLATED');
$search->withColumn('NOT ISNULL(`' . $requestedLocaleI18nAlias . '`.`ID`)', $aliasPrefix . 'IS_TRANSLATED');
foreach($columns as $column) {
$search->withColumn('`' . $askedLocaleI18nAlias . '`.`' . $column . '`', $aliasPrefix . 'i18n_' . $column);
$search->withColumn('`' . $requestedLocaleI18nAlias . '`.`' . $column . '`', $aliasPrefix . 'i18n_' . $column);
}
} else {
$defaultLocale = LangQuery::create()->findOneById($defaultLangWithoutTranslation)->getLocale();
@@ -58,26 +61,26 @@ class ModelCriteriaTools
$search->addJoinObject($defaultLocaleJoin, $defaultLocaleI18nAlias)
->addJoinCondition($defaultLocaleI18nAlias ,'`' . $defaultLocaleI18nAlias . '`.LOCALE = ?', $defaultLocale, null, \PDO::PARAM_STR);
$askedLocaleJoin = new Join();
$askedLocaleJoin->addExplicitCondition($search->getTableMap()->getName(), $foreignKey, null, $foreignTable . '_i18n', 'ID', $askedLocaleI18nAlias);
$askedLocaleJoin->setJoinType(Criteria::LEFT_JOIN);
$requestedLocaleJoin = new Join();
$requestedLocaleJoin->addExplicitCondition($search->getTableMap()->getName(), $foreignKey, null, $foreignTable . '_i18n', 'ID', $requestedLocaleI18nAlias);
$requestedLocaleJoin->setJoinType(Criteria::LEFT_JOIN);
$search->addJoinObject($askedLocaleJoin, $askedLocaleI18nAlias)
->addJoinCondition($askedLocaleI18nAlias ,'`' . $askedLocaleI18nAlias . '`.LOCALE = ?', $askedLocale, null, \PDO::PARAM_STR);
$search->addJoinObject($requestedLocaleJoin, $requestedLocaleI18nAlias)
->addJoinCondition($requestedLocaleI18nAlias ,'`' . $requestedLocaleI18nAlias . '`.LOCALE = ?', $requestedLocale, null, \PDO::PARAM_STR);
$search->withColumn('NOT ISNULL(`' . $askedLocaleI18nAlias . '`.`ID`)', $aliasPrefix . 'IS_TRANSLATED');
$search->withColumn('NOT ISNULL(`' . $requestedLocaleI18nAlias . '`.`ID`)', $aliasPrefix . 'IS_TRANSLATED');
if(!$forceReturn) {
$search->where('NOT ISNULL(`' . $askedLocaleI18nAlias . '`.ID)')->_or()->where('NOT ISNULL(`' . $defaultLocaleI18nAlias . '`.ID)');
if($forceReturn === false) {
$search->where('NOT ISNULL(`' . $requestedLocaleI18nAlias . '`.ID)')->_or()->where('NOT ISNULL(`' . $defaultLocaleI18nAlias . '`.ID)');
}
foreach($columns as $column) {
$search->withColumn('CASE WHEN NOT ISNULL(`' . $askedLocaleI18nAlias . '`.ID) THEN `' . $askedLocaleI18nAlias . '`.`' . $column . '` ELSE `' . $defaultLocaleI18nAlias . '`.`' . $column . '` END', $aliasPrefix . 'i18n_' . $column);
$search->withColumn('CASE WHEN NOT ISNULL(`' . $requestedLocaleI18nAlias . '`.ID) THEN `' . $requestedLocaleI18nAlias . '`.`' . $column . '` ELSE `' . $defaultLocaleI18nAlias . '`.`' . $column . '` END', $aliasPrefix . 'i18n_' . $column);
}
}
}
public static function getBackEndI18n(ModelCriteria &$search, $askedLocale, $columns = array('TITLE', 'CHAPO', 'DESCRIPTION', 'POSTSCRIPTUM'), $foreignTable = null, $foreignKey = 'ID')
public static function getBackEndI18n(ModelCriteria &$search, $requestedLocale, $columns = array('TITLE', 'CHAPO', 'DESCRIPTION', 'POSTSCRIPTUM'), $foreignTable = null, $foreignKey = 'ID')
{
if($foreignTable === null) {
$foreignTable = $search->getTableMap()->getName();
@@ -86,39 +89,46 @@ class ModelCriteriaTools
$aliasPrefix = $foreignTable . '_';
}
$askedLocaleI18nAlias = $aliasPrefix . 'asked_locale_i18n';
$requestedLocaleI18nAlias = 'requested_locale_i18n';
$askedLocaleJoin = new Join();
$askedLocaleJoin->addExplicitCondition($search->getTableMap()->getName(), $foreignKey, null, $foreignTable . '_i18n', 'ID', $askedLocaleI18nAlias);
$askedLocaleJoin->setJoinType(Criteria::LEFT_JOIN);
$requestedLocaleJoin = new Join();
$requestedLocaleJoin->addExplicitCondition($search->getTableMap()->getName(), $foreignKey, null, $foreignTable . '_i18n', 'ID', $requestedLocaleI18nAlias);
$requestedLocaleJoin->setJoinType(Criteria::LEFT_JOIN);
$search->addJoinObject($askedLocaleJoin, $askedLocaleI18nAlias)
->addJoinCondition($askedLocaleI18nAlias ,'`' . $askedLocaleI18nAlias . '`.LOCALE = ?', $askedLocale, null, \PDO::PARAM_STR);
$search->addJoinObject($requestedLocaleJoin, $requestedLocaleI18nAlias)
->addJoinCondition($requestedLocaleI18nAlias ,'`' . $requestedLocaleI18nAlias . '`.LOCALE = ?', $requestedLocale, null, \PDO::PARAM_STR);
$search->withColumn('NOT ISNULL(`' . $askedLocaleI18nAlias . '`.`ID`)', $aliasPrefix . 'IS_TRANSLATED');
$search->withColumn('NOT ISNULL(`' . $requestedLocaleI18nAlias . '`.`ID`)', $aliasPrefix . 'IS_TRANSLATED');
foreach($columns as $column) {
$search->withColumn('`' . $askedLocaleI18nAlias . '`.`' . $column . '`', $aliasPrefix . 'i18n_' . $column);
$search->withColumn('`' . $requestedLocaleI18nAlias . '`.`' . $column . '`', $aliasPrefix . 'i18n_' . $column);
}
}
public static function getI18n($backendContext, $lang, ModelCriteria &$search, $defaultLangWithoutTranslation, $currentLocale, $columns = array('TITLE', 'CHAPO', 'DESCRIPTION', 'POSTSCRIPTUM'), $foreignTable = null, $foreignKey = 'ID')
public static function getI18n($backendContext, $requestedLangId, ModelCriteria &$search, $currentLocale, $columns, $foreignTable, $foreignKey, $forceReturn = false)
{
if($lang !== null) {
$localeSearch = LangQuery::create()->findOneById($lang);
if($localeSearch === null) {
throw new \InvalidArgumentException('Incorrect lang argument given in attribute loop');
// If a lang has been requested, find the related Lang object, and get the locale
if ($requestedLangId !== null) {
$localeSearch = LangQuery::create()->findOneById($requestedLangId);
if ($localeSearch === null) {
throw new \InvalidArgumentException(sprintf('Incorrect lang argument given in attribute loop: lang ID %d not found', $requestedLangId));
}
$locale = $localeSearch->getLocale();
}
else {
// Use the currently defined locale
$locale = $currentLocale;
}
$askedLocale = $lang === null ? $currentLocale : $localeSearch->getLocale();
if($backendContext) {
self::getBackEndI18n($search, $askedLocale, $columns, $foreignTable, $foreignKey);
// Call the proper method depending on the context: front or back
if ($backendContext) {
self::getBackEndI18n($search, $locale, $columns, $foreignTable, $foreignKey);
} else {
self::getFrontEndI18n($search, $defaultLangWithoutTranslation, $askedLocale, $columns, $foreignTable, $foreignKey);
self::getFrontEndI18n($search, $locale, $columns, $foreignTable, $foreignKey, $forceReturn);
}
return $askedLocale;
return $locale;
}
}

View File

@@ -1,4 +1,4 @@
/*! X-editable - v1.4.6
/*! X-editable - v1.4.6
* In-place editing with Twitter Bootstrap, jQuery UI or pure jQuery
* http://github.com/vitalets/x-editable
* Copyright (c) 2013 Vitaliy Potapov; Licensed MIT */
@@ -18,45 +18,45 @@
vertical-align: top;
margin-left: 7px;
/* inline-block emulation for IE7*/
zoom: 1;
zoom: 1;
*display: inline;
}
.editable-buttons.editable-buttons-bottom {
display: block;
display: block;
margin-top: 7px;
margin-left: 0;
}
.editable-input {
vertical-align: top;
vertical-align: top;
display: inline-block; /* should be inline to take effect of parent's white-space: nowrap */
width: auto; /* bootstrap-responsive has width: 100% that breakes layout */
white-space: normal; /* reset white-space decalred in parent*/
/* display-inline emulation for IE7*/
zoom: 1;
*display: inline;
zoom: 1;
*display: inline;
}
.editable-buttons .editable-cancel {
margin-left: 7px;
margin-left: 7px;
}
/*for jquery-ui buttons need set height to look more pretty*/
.editable-buttons button.ui-button-icon-only {
height: 24px;
height: 24px;
width: 30px;
}
.editableform-loading {
background: url('../img/loading.gif') center center no-repeat;
background: url('../img/loading.gif') center center no-repeat;
height: 25px;
width: auto;
min-width: 25px;
width: auto;
min-width: 25px;
}
.editable-inline .editableform-loading {
background-position: left 5px;
background-position: left 5px;
}
.editable-error-block {
@@ -68,17 +68,17 @@
/*add padding for jquery ui*/
.editable-error-block.ui-state-error {
padding: 3px;
}
padding: 3px;
}
.editable-error {
color: red;
color: red;
}
/* ---- For specific types ---- */
.editableform .editable-date {
padding: 0;
padding: 0;
margin: 0;
float: left;
}
@@ -86,25 +86,25 @@
/* move datepicker icon to center of add-on button. See https://github.com/vitalets/x-editable/issues/183 */
.editable-inline .add-on .icon-th {
margin-top: 3px;
margin-left: 1px;
margin-left: 1px;
}
/* checklist vertical alignment */
.editable-checklist label input[type="checkbox"],
.editable-checklist label input[type="checkbox"],
.editable-checklist label span {
vertical-align: middle;
margin: 0;
}
.editable-checklist label {
white-space: nowrap;
white-space: nowrap;
}
/* set exact width of textarea to fit buttons toolbar */
.editable-wysihtml5 {
width: 566px;
height: 250px;
width: 566px;
height: 250px;
}
/* clear button shown as link in date inputs */
@@ -119,16 +119,16 @@
.editable-clear-x {
background: url('../img/clear.png') center center no-repeat;
display: block;
width: 13px;
width: 13px;
height: 13px;
position: absolute;
opacity: 0.6;
z-index: 100;
top: 50%;
right: 6px;
margin-top: -6px;
}
.editable-clear-x:hover {
@@ -140,49 +140,49 @@
}
.editable-container.editable-popup {
max-width: none !important; /* without this rule poshytip/tooltip does not stretch */
}
}
.editable-container.popover {
width: auto; /* without this rule popover does not stretch */
}
.editable-container.editable-inline {
display: inline-block;
display: inline-block;
vertical-align: middle;
width: auto;
/* inline-block emulation for IE7*/
zoom: 1;
*display: inline;
zoom: 1;
*display: inline;
}
.editable-container.ui-widget {
font-size: inherit; /* jqueryui widget font 1.1em too big, overwrite it */
z-index: 9990; /* should be less than select2 dropdown z-index to close dropdown first when click */
}
.editable-click,
a.editable-click,
.editable-click,
a.editable-click,
a.editable-click:hover {
text-decoration: none;
border-bottom: dashed 1px #0088cc;
border-bottom: dotted 1px #0088cc;
}
.editable-click.editable-disabled,
a.editable-click.editable-disabled,
.editable-click.editable-disabled,
a.editable-click.editable-disabled,
a.editable-click.editable-disabled:hover {
color: #585858;
color: #585858;
cursor: default;
border-bottom: none;
}
.editable-empty, .editable-empty:hover, .editable-empty:focus{
font-style: italic;
color: #DD1144;
font-style: italic;
color: #DD1144;
/* border-bottom: none; */
text-decoration: none;
}
.editable-unsaved {
font-weight: bold;
font-weight: bold;
}
.editable-unsaved:after {
@@ -194,12 +194,12 @@ a.editable-click.editable-disabled:hover {
-moz-transition: background-color 1400ms ease-out;
-o-transition: background-color 1400ms ease-out;
-ms-transition: background-color 1400ms ease-out;
transition: background-color 1400ms ease-out;
transition: background-color 1400ms ease-out;
}
/*see https://github.com/vitalets/x-editable/issues/139 */
.form-horizontal .editable
{
{
padding-top: 5px;
display:inline-block;
}

View File

@@ -717,10 +717,4 @@ label {
// Center the alert box (20px bottom margin) in the table cell
padding: 20px 20px 0 20px;
}
}
// -- Editable tweaks ---------------------------------------------------------
.editable-click, a.editable-click, a.editable-click:hover {
border-bottom: 1px dotted #0088CC;
}

View File

@@ -241,7 +241,7 @@ $(function() {
$.ajax({
url : "{url path='admin/catalog/category'}",
data : {
id : $(this).data('id'),
category_id : $(this).data('id'),
action : 'visibilityToggle'
}
});

View File

@@ -12,11 +12,11 @@
{if $action == 'edit'}
{intl l='Editing %cat' cat="{$TITLE}"}
{else}
{$TITLE} <a href="{url path="admin/catalog/category/edit/$ID"}" title="{intl l='Edit this category'}">{intl l="(edit)"}</a>
{$TITLE} <a href="{url path='admin/catalog/category' id="$ID" action='edit'}" title="{intl l='Edit this category'}">{intl l="(edit)"}</a>
{/if}
</li>
{else}
<li><a href="{url path="admin/catalog/category/browse/$ID"}">{$TITLE}</a> <span class="divider">/</span></li>
<li><a href="{url path='admin/catalog/category' id="$ID" action='browse'}">{$TITLE}</a> <span class="divider">/</span></li>
{/if}
{/loop}
{/ifloop}

View File

@@ -12,7 +12,7 @@
<ul class="nav nav-pills">
{loop name="lang_list" type="lang" default_only={$default_only}}
<li {if $IS_DEFAULT}class="active"{/if}>
<a href="#" title="{intl l="Edit information for %lng" lng=$TITLE}">
<a href="#" title="{intl l="Edit information in %lng" lng=$TITLE}">
<img src="{image file="../assets/img/flags/{$CODE}.gif"}" alt="{intl l=$TITLE}" />
</a>
</li>