Merge branch 'master' of https://github.com/thelia/thelia into coupon

# By Manuel Raynaud (18) and others
# Via franck (9) and others
* 'master' of https://github.com/thelia/thelia: (39 commits)
  Working :
  Working :
  Working :
  Working :
  Fixed minor visual glitches
  Working : Resize countries flag + Add bootstrap-switch
  fix test suite
  clear asset cache in cache:cler command
  Added a 'development mode' to assetic smarty plugin
  rewriting router
  use good Request object
  Added Tools\URL test case, and a test case superclass for initializing Tools\URL
  remove unused UrlWritin controller
  create router for rewriting matching
  customer substitutions
  fix typo in front id
  Working : For attributes on labels
  Working : For attributes on labels
  add label_attr attribute to form smarty plugin
  start refactorin rewriting routing
  ...

Conflicts:
	core/lib/Thelia/Config/Resources/routing/front.xml
	templates/admin/default/assets/less/thelia/bootstrap-editable.less
	templates/admin/default/categories.html
This commit is contained in:
gmorel
2013-09-06 19:36:52 +02:00
118 changed files with 4702 additions and 1831 deletions

View File

@@ -143,7 +143,7 @@ class Cart extends BaseAction implements EventSubscriberInterface
return array( return array(
"action.addArticle" => array("addItem", 128), "action.addArticle" => array("addItem", 128),
"action.deleteArticle" => array("deleteItem", 128), "action.deleteArticle" => array("deleteItem", 128),
"action.changeArticle" => array("changeItem", 128), "action.updateArticle" => array("changeItem", 128),
); );
} }

View File

@@ -248,9 +248,9 @@ class Category extends BaseAction implements EventSubscriberInterface
TheliaEvents::CATEGORY_TOGGLE_VISIBILITY => array("toggleVisibility", 128), TheliaEvents::CATEGORY_TOGGLE_VISIBILITY => array("toggleVisibility", 128),
TheliaEvents::CATEGORY_CHANGE_POSITION => array("changePosition", 128), TheliaEvents::CATEGORY_CHANGE_POSITION => array("changePosition", 128),
"action.changeCategoryPositionU" => array("changePositionUp", 128), "action.updateCategoryPositionU" => array("changePositionUp", 128),
"action.changeCategoryPositionDown" => array("changePositionDown", 128), "action.updateCategoryPositionDown" => array("changePositionDown", 128),
"action.changeCategoryPosition" => array("changePosition", 128), "action.updateCategoryPosition" => array("changePosition", 128),
); );
} }
} }

View File

@@ -31,7 +31,7 @@ use Thelia\Model\Config as ConfigModel;
use Thelia\Core\Event\TheliaEvents; use Thelia\Core\Event\TheliaEvents;
use Thelia\Core\Event\ConfigChangeEvent; use Thelia\Core\Event\ConfigUpdateEvent;
use Thelia\Core\Event\ConfigCreateEvent; use Thelia\Core\Event\ConfigCreateEvent;
use Thelia\Core\Event\ConfigDeleteEvent; use Thelia\Core\Event\ConfigDeleteEvent;
@@ -65,9 +65,9 @@ class Config extends BaseAction implements EventSubscriberInterface
/** /**
* Change a configuration entry value * Change a configuration entry value
* *
* @param ConfigChangeEvent $event * @param ConfigUpdateEvent $event
*/ */
public function setValue(ConfigChangeEvent $event) public function setValue(ConfigUpdateEvent $event)
{ {
$search = ConfigQuery::create(); $search = ConfigQuery::create();
@@ -90,9 +90,9 @@ class Config extends BaseAction implements EventSubscriberInterface
/** /**
* Change a configuration entry * Change a configuration entry
* *
* @param ConfigChangeEvent $event * @param ConfigUpdateEvent $event
*/ */
public function modify(ConfigChangeEvent $event) public function modify(ConfigUpdateEvent $event)
{ {
$search = ConfigQuery::create(); $search = ConfigQuery::create();

View File

@@ -31,11 +31,11 @@ use Thelia\Model\Currency as CurrencyModel;
use Thelia\Core\Event\TheliaEvents; use Thelia\Core\Event\TheliaEvents;
use Thelia\Core\Event\CurrencyChangeEvent; use Thelia\Core\Event\CurrencyUpdateEvent;
use Thelia\Core\Event\CurrencyCreateEvent; use Thelia\Core\Event\CurrencyCreateEvent;
use Thelia\Core\Event\CurrencyDeleteEvent; use Thelia\Core\Event\CurrencyDeleteEvent;
use Thelia\Model\Map\CurrencyTableMap;
use Thelia\Model\ConfigQuery; use Thelia\Model\ConfigQuery;
use Thelia\Core\Event\CurrencyUpdatePositionEvent;
class Currency extends BaseAction implements EventSubscriberInterface class Currency extends BaseAction implements EventSubscriberInterface
{ {
@@ -67,9 +67,9 @@ class Currency extends BaseAction implements EventSubscriberInterface
/** /**
* Change a currency * Change a currency
* *
* @param CurrencyChangeEvent $event * @param CurrencyUpdateEvent $event
*/ */
public function update(CurrencyChangeEvent $event) public function update(CurrencyUpdateEvent $event)
{ {
$search = CurrencyQuery::create(); $search = CurrencyQuery::create();
@@ -93,9 +93,9 @@ class Currency extends BaseAction implements EventSubscriberInterface
/** /**
* Set the default currency * Set the default currency
* *
* @param CurrencyChangeEvent $event * @param CurrencyUpdateEvent $event
*/ */
public function setDefault(CurrencyChangeEvent $event) public function setDefault(CurrencyUpdateEvent $event)
{ {
$search = CurrencyQuery::create(); $search = CurrencyQuery::create();
@@ -107,6 +107,7 @@ class Currency extends BaseAction implements EventSubscriberInterface
CurrencyQuery::create()->filterByByDefault(true)->update(array('ByDefault' => false)); CurrencyQuery::create()->filterByByDefault(true)->update(array('ByDefault' => false));
$currency $currency
->setDispatcher($this->getDispatcher())
->setByDefault($event->getIsDefault()) ->setByDefault($event->getIsDefault())
->save() ->save()
; ;
@@ -139,7 +140,7 @@ class Currency extends BaseAction implements EventSubscriberInterface
$rates_url = ConfigQuery::read('currency_rate_update_url', 'http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml'); $rates_url = ConfigQuery::read('currency_rate_update_url', 'http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml');
$rate_data = file_get_contents($rates_url); $rate_data = @file_get_contents($rates_url);
if ($rate_data && $sxe = new \SimpleXMLElement($rate_data)) { if ($rate_data && $sxe = new \SimpleXMLElement($rate_data)) {
@@ -149,12 +150,38 @@ class Currency extends BaseAction implements EventSubscriberInterface
$rate = floatval($last['rate']); $rate = floatval($last['rate']);
if (null !== $currency = CurrencyQuery::create()->findOneByCode($code)) { if (null !== $currency = CurrencyQuery::create()->findOneByCode($code)) {
$currency->setRate($rate)->save(); $currency
->setDispatcher($this->getDispatcher())
->setRate($rate)
->save()
;
} }
} }
} }
else { else {
throw new \RuntimeException(sprintf("Failed to get currency rates data from URL %s", $url)); throw new \RuntimeException(sprintf("Failed to get currency rates data from URL %s", $rates_url));
}
}
/**
* Changes position, selecting absolute ou relative change.
*
* @param CategoryChangePositionEvent $event
*/
public function updatePosition(CurrencyUpdatePositionEvent $event)
{
if (null !== $currency = CurrencyQuery::create()->findOneById($event->getObjectId())) {
$currency->setDispatcher($this->getDispatcher());
$mode = $event->getMode();
if ($mode == CurrencyUpdatePositionEvent::POSITION_ABSOLUTE)
return $currency->changeAbsolutePosition($event->getPosition());
else if ($mode == CurrencyUpdatePositionEvent::POSITION_UP)
return $currency->movePositionUp();
else if ($mode == CurrencyUpdatePositionEvent::POSITION_DOWN)
return $currency->movePositionDown();
} }
} }
@@ -164,12 +191,12 @@ class Currency extends BaseAction implements EventSubscriberInterface
public static function getSubscribedEvents() public static function getSubscribedEvents()
{ {
return array( return array(
TheliaEvents::CURRENCY_CREATE => array("create", 128), TheliaEvents::CURRENCY_CREATE => array("create", 128),
TheliaEvents::CURRENCY_UPDATE => array("update", 128), TheliaEvents::CURRENCY_UPDATE => array("update", 128),
TheliaEvents::CURRENCY_DELETE => array("delete", 128), TheliaEvents::CURRENCY_DELETE => array("delete", 128),
TheliaEvents::CURRENCY_SET_DEFAULT => array("setDefault", 128), TheliaEvents::CURRENCY_SET_DEFAULT => array("setDefault", 128),
TheliaEvents::CURRENCY_UPDATE_RATES => array("updateRates", 128), TheliaEvents::CURRENCY_UPDATE_RATES => array("updateRates", 128),
TheliaEvents::CURRENCY_UPDATE_POSITION => array("updatePosition", 128)
); );
} }
} }

View File

@@ -269,8 +269,8 @@ class Image extends BaseAction implements EventSubscriberInterface
$event->setCacheFilepath($cacheFilePath); $event->setCacheFilepath($cacheFilePath);
$event->setCacheOriginalFilepath($originalImagePathInCache); $event->setCacheOriginalFilepath($originalImagePathInCache);
$event->setFileUrl(URL::absoluteUrl($processed_image_url, null, URL::PATH_TO_FILE)); $event->setFileUrl(URL::getInstance()->absoluteUrl($processed_image_url, null, URL::PATH_TO_FILE));
$event->setOriginalFileUrl(URL::absoluteUrl($original_image_url, null, URL::PATH_TO_FILE)); $event->setOriginalFileUrl(URL::getInstance()->absoluteUrl($original_image_url, null, URL::PATH_TO_FILE));
} }
/** /**
@@ -382,7 +382,7 @@ class Image extends BaseAction implements EventSubscriberInterface
{ {
$path = $this->getCachePathFromWebRoot($subdir); $path = $this->getCachePathFromWebRoot($subdir);
return URL::absoluteUrl(sprintf("%s/%s", $path, $safe_filename), null, URL::PATH_TO_FILE); return URL::getInstance()->absoluteUrl(sprintf("%s/%s", $path, $safe_filename), null, URL::PATH_TO_FILE);
} }
/** /**
@@ -494,4 +494,4 @@ class Image extends BaseAction implements EventSubscriberInterface
TheliaEvents::IMAGE_CLEAR_CACHE => array("clearCache", 128), TheliaEvents::IMAGE_CLEAR_CACHE => array("clearCache", 128),
); );
} }
} }

View File

@@ -31,7 +31,7 @@ use Thelia\Model\Message as MessageModel;
use Thelia\Core\Event\TheliaEvents; use Thelia\Core\Event\TheliaEvents;
use Thelia\Core\Event\MessageChangeEvent; use Thelia\Core\Event\MessageUpdateEvent;
use Thelia\Core\Event\MessageCreateEvent; use Thelia\Core\Event\MessageCreateEvent;
use Thelia\Core\Event\MessageDeleteEvent; use Thelia\Core\Event\MessageDeleteEvent;
@@ -65,9 +65,9 @@ class Message extends BaseAction implements EventSubscriberInterface
/** /**
* Change a message * Change a message
* *
* @param MessageChangeEvent $event * @param MessageUpdateEvent $event
*/ */
public function modify(MessageChangeEvent $event) public function modify(MessageUpdateEvent $event)
{ {
$search = MessageQuery::create(); $search = MessageQuery::create();

View File

@@ -0,0 +1,157 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Action;
use Thelia\Core\Event\BaseChangePositionEvent;
trait PositionManagementTrait {
const POSITION_UP
/**
* Changes object position, selecting absolute ou relative change.
*
* @param BaseChangePositionEvent $event
*/
public function changePosition(BaseChangePositionEvent $event)
{
if ($event->getMode() == BaseChangePositionEvent::POSITION_ABSOLUTE)
return $this->changeAbsolutePosition($event);
else
return $this->exchangePosition($event);
}
/**
* Move up or down a object
*
* @param BaseChangePositionEvent $event
*/
protected function exchangePosition(BaseChangePositionEvent $event)
{
$object = CategoryQuery::create()->findPk($event->getCategoryId());
if ($object !== null) {
// The current position of the object
$my_position = $object->getPosition();
// Find object to exchange position with
$search = CategoryQuery::create()
->filterByParent($object->getParent());
// Up or down ?
if ($event->getMode() == BaseChangePositionEvent::POSITION_UP) {
// Find the object immediately before me
$search->filterByPosition(array('max' => $my_position-1))->orderByPosition(Criteria::DESC);
} elseif ($event->getMode() == BaseChangePositionEvent::POSITION_DOWN) {
// Find the object immediately after me
$search->filterByPosition(array('min' => $my_position+1))->orderByPosition(Criteria::ASC);
} else
return;
$result = $search->findOne();
// If we found the proper object, exchange their positions
if ($result) {
$cnx = Propel::getWriteConnection(CategoryTableMap::DATABASE_NAME);
$cnx->beginTransaction();
try {
$object
->setDispatcher($this->getDispatcher())
->setPosition($result->getPosition())
->save()
;
$result->setPosition($my_position)->save();
$cnx->commit();
} catch (Exception $e) {
$cnx->rollback();
}
}
}
}
/**
* Changes object position
*
* @param BaseChangePositionEvent $event
*/
protected function changeAbsolutePosition(BaseChangePositionEvent $event)
{
$object = CategoryQuery::create()->findPk($event->getCategoryId());
if ($object !== null) {
// The required position
$new_position = $event->getPosition();
// The current position
$current_position = $object->getPosition();
if ($new_position != null && $new_position > 0 && $new_position != $current_position) {
// Find categories to offset
$search = CategoryQuery::create()->filterByParent($object->getParent());
if ($new_position > $current_position) {
// The new position is after the current position -> we will offset + 1 all categories located between us and the new position
$search->filterByPosition(array('min' => 1+$current_position, 'max' => $new_position));
$delta = -1;
} else {
// The new position is brefore the current position -> we will offset - 1 all categories located between us and the new position
$search->filterByPosition(array('min' => $new_position, 'max' => $current_position - 1));
$delta = 1;
}
$results = $search->find();
$cnx = Propel::getWriteConnection(CategoryTableMap::DATABASE_NAME);
$cnx->beginTransaction();
try {
foreach ($results as $result) {
$result->setPosition($result->getPosition() + $delta)->save($cnx);
}
$object
->setDispatcher($this->getDispatcher())
->setPosition($new_position)
->save($cnx)
;
$cnx->commit();
} catch (Exception $e) {
$cnx->rollback();
}
}
}
}
}

View File

@@ -24,6 +24,7 @@
namespace Thelia\Command; namespace Thelia\Command;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Filesystem\Exception\IOException; use Symfony\Component\Filesystem\Exception\IOException;
@@ -44,7 +45,14 @@ class CacheClear extends ContainerAwareCommand
{ {
$this $this
->setName("cache:clear") ->setName("cache:clear")
->setDescription("Invalidate all caches"); ->setDescription("Invalidate all caches")
->addOption(
"without-assets",
null,
InputOption::VALUE_NONE,
"remove cache assets"
)
;
} }
protected function execute(InputInterface $input, OutputInterface $output) protected function execute(InputInterface $input, OutputInterface $output)
@@ -52,20 +60,28 @@ class CacheClear extends ContainerAwareCommand
$cacheDir = $this->getContainer()->getParameter("kernel.cache_dir"); $cacheDir = $this->getContainer()->getParameter("kernel.cache_dir");
if (!is_writable($cacheDir)) { $this->clearCache($cacheDir, $output);
throw new \RuntimeException(sprintf('Unable to write in the "%s" directory', $cacheDir)); if(!$input->getOption("without-assets")) {
} $this->clearCache(THELIA_WEB_DIR . "/assets", $output);
$output->writeln(sprintf("Clearing cache in <info>%s</info> directory", $cacheDir));
$fs = new Filesystem();
try {
$fs->remove($cacheDir);
$output->writeln("<info>cache cleared successfully</info>");
} catch (IOException $e) {
$output->writeln(sprintf("error during clearing cache : %s", $e->getMessage()));
} }
} }
protected function clearCache($dir, OutputInterface $output)
{
if (!is_writable($dir)) {
throw new \RuntimeException(sprintf('Unable to write in the "%s" directory', $dir));
}
$output->writeln(sprintf("Clearing cache in <info>%s</info> directory", $dir));
$fs = new Filesystem();
try {
$fs->remove($dir);
$output->writeln(sprintf("<info>%s cache dir cleared successfully</info>", $dir));
} catch (IOException $e) {
$output->writeln(sprintf("error during clearing cache : %s", $e->getMessage()));
}
}
} }

View File

@@ -22,6 +22,11 @@
<tag name="kernel.event_subscriber"/> <tag name="kernel.event_subscriber"/>
</service> </service>
<service id="thelia.action.address" class="Thelia\Action\Address">
<argument type="service" id="service_container"/>
<tag name="kernel.event_subscriber"/>
</service>
<service id="thelia.action.image" class="Thelia\Action\Image"> <service id="thelia.action.image" class="Thelia\Action\Image">
<argument type="service" id="service_container"/> <argument type="service" id="service_container"/>
<tag name="kernel.event_subscriber"/> <tag name="kernel.event_subscriber"/>

View File

@@ -44,6 +44,9 @@
<form name="thelia.customer.login" class="Thelia\Form\CustomerLogin"/> <form name="thelia.customer.login" class="Thelia\Form\CustomerLogin"/>
<form name="thelia.admin.login" class="Thelia\Form\AdminLogin"/> <form name="thelia.admin.login" class="Thelia\Form\AdminLogin"/>
<form name="thelia.address.create" class="Thelia\Form\AddressCreateForm" />
<form name="thelia.address.update" class="Thelia\Form\AddressUpdateForm" />
<form name="thelia.admin.category.creation" class="Thelia\Form\CategoryCreationForm"/> <form name="thelia.admin.category.creation" class="Thelia\Form\CategoryCreationForm"/>
<form name="thelia.admin.category.deletion" class="Thelia\Form\CategoryDeletionForm"/> <form name="thelia.admin.category.deletion" class="Thelia\Form\CategoryDeletionForm"/>
@@ -75,6 +78,13 @@
<services> <services>
<!-- URL maganement -->
<service id="thelia.url.manager" class="Thelia\Tools\URL">
<argument type="service" id="service_container" />
<argument >%kernel.environment%</argument>
</service>
<service id="event_dispatcher" class="Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher"> <service id="event_dispatcher" class="Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher">
<argument type="service" id="service_container" /> <argument type="service" id="service_container" />
</service> </service>
@@ -122,6 +132,7 @@
<service id="smarty.plugin.assetic" class="Thelia\Core\Template\Smarty\Plugins\Assetic" > <service id="smarty.plugin.assetic" class="Thelia\Core\Template\Smarty\Plugins\Assetic" >
<tag name="thelia.parser.register_plugin"/> <tag name="thelia.parser.register_plugin"/>
<argument>%kernel.environment%</argument>
</service> </service>
<service id="smarty.plugin.theliasyntax" class="Thelia\Core\Template\Smarty\Plugins\TheliaSyntax" > <service id="smarty.plugin.theliasyntax" class="Thelia\Core\Template\Smarty\Plugins\TheliaSyntax" >

View File

@@ -75,6 +75,10 @@
<argument key="debug">%kernel.debug%</argument> <argument key="debug">%kernel.debug%</argument>
</argument> </argument>
<argument type="service" id="request.context"/> <argument type="service" id="request.context"/>
<tag name="router.register" priority="254"/>
</service>
<service id="router.rewrite" class="Thelia\Core\Routing\RewritingRouter">
<tag name="router.register" priority="255"/> <tag name="router.register" priority="255"/>
</service> </service>

View File

@@ -70,7 +70,7 @@
<default key="_controller">Thelia\Controller\Admin\ConfigController::defaultAction</default> <default key="_controller">Thelia\Controller\Admin\ConfigController::defaultAction</default>
</route> </route>
<route id="admin.configuration.variables.change-values" path="/admin/configuration/variables/change-values"> <route id="admin.configuration.variables.update-values" path="/admin/configuration/variables/update-values">
<default key="_controller">Thelia\Controller\Admin\ConfigController::changeValuesAction</default> <default key="_controller">Thelia\Controller\Admin\ConfigController::changeValuesAction</default>
</route> </route>
@@ -78,11 +78,11 @@
<default key="_controller">Thelia\Controller\Admin\ConfigController::createAction</default> <default key="_controller">Thelia\Controller\Admin\ConfigController::createAction</default>
</route> </route>
<route id="admin.configuration.variables.change" path="/admin/configuration/variables/change"> <route id="admin.configuration.variables.update" path="/admin/configuration/variables/update">
<default key="_controller">Thelia\Controller\Admin\ConfigController::changeAction</default> <default key="_controller">Thelia\Controller\Admin\ConfigController::changeAction</default>
</route> </route>
<route id="admin.configuration.variables.save-change" path="/admin/configuration/variables/save-change"> <route id="admin.configuration.variables.save" path="/admin/configuration/variables/save">
<default key="_controller">Thelia\Controller\Admin\ConfigController::saveChangeAction</default> <default key="_controller">Thelia\Controller\Admin\ConfigController::saveChangeAction</default>
</route> </route>
@@ -100,11 +100,11 @@
<default key="_controller">Thelia\Controller\Admin\MessageController::createAction</default> <default key="_controller">Thelia\Controller\Admin\MessageController::createAction</default>
</route> </route>
<route id="admin.configuration.messages.change" path="/admin/configuration/messages/change"> <route id="admin.configuration.messages.update" path="/admin/configuration/messages/update">
<default key="_controller">Thelia\Controller\Admin\MessageController::changeAction</default> <default key="_controller">Thelia\Controller\Admin\MessageController::changeAction</default>
</route> </route>
<route id="admin.configuration.messages.save-change" path="/admin/configuration/messages/save-change"> <route id="admin.configuration.messages.save" path="/admin/configuration/messages/save">
<default key="_controller">Thelia\Controller\Admin\MessageController::saveChangeAction</default> <default key="_controller">Thelia\Controller\Admin\MessageController::saveChangeAction</default>
</route> </route>
@@ -122,11 +122,11 @@
<default key="_controller">Thelia\Controller\Admin\CurrencyController::createAction</default> <default key="_controller">Thelia\Controller\Admin\CurrencyController::createAction</default>
</route> </route>
<route id="admin.configuration.currencies.change" path="/admin/configuration/currencies/change"> <route id="admin.configuration.currencies.update" path="/admin/configuration/currencies/update">
<default key="_controller">Thelia\Controller\Admin\CurrencyController::changeAction</default> <default key="_controller">Thelia\Controller\Admin\CurrencyController::changeAction</default>
</route> </route>
<route id="admin.configuration.currencies.save-change" path="/admin/configuration/currencies/save-change"> <route id="admin.configuration.currencies.save" path="/admin/configuration/currencies/save">
<default key="_controller">Thelia\Controller\Admin\CurrencyController::saveChangeAction</default> <default key="_controller">Thelia\Controller\Admin\CurrencyController::saveChangeAction</default>
</route> </route>
@@ -142,6 +142,10 @@
<default key="_controller">Thelia\Controller\Admin\CurrencyController::deleteAction</default> <default key="_controller">Thelia\Controller\Admin\CurrencyController::deleteAction</default>
</route> </route>
<route id="admin.configuration.currencies.update-position" path="/admin/configuration/currencies/update-position">
<default key="_controller">Thelia\Controller\Admin\CurrencyController::updatePositionAction</default>
</route>
<!-- The default route, to display a template --> <!-- The default route, to display a template -->
<route id="admin.processTemplate" path="/admin/{template}"> <route id="admin.processTemplate" path="/admin/{template}">

View File

@@ -29,8 +29,18 @@
<!-- end customer routes --> <!-- end customer routes -->
<!-- customer address routes --> <!-- customer address routes -->
<route id="customer.adress.create" path="/customer/address/create" > <route id="address.create" path="/address/create" >
<default key="_controller">Thelia\Controller\Front\CustomerAddressController::createAction</default> <default key="_controller">Thelia\Controller\Front\AddressController::createAction</default>
<default key="_view">address</default>
</route>
<route id="address.edit" path="/address/edit/{address_id}">
<default key="_controller">Thelia\Controller\Front\DefaultController::noAction</default>
<default key="_view">address_edit</default>
</route>
<route id="address.update" path="/address/update" >
<default key="_controller">Thelia\Controller\Front\AddressController::updateAction</default>
</route> </route>
<!-- end customer address routes --> <!-- end customer address routes -->
@@ -40,7 +50,7 @@
<default key="_view">cart</default> <default key="_view">cart</default>
</route> </route>
<route id="cart.change.process" path="/cart/delete/{cart_item}"> <route id="cart.delete.process" path="/cart/delete/{cart_item}">
<default key="_controller">Thelia\Controller\Front\CartController::deleteItem</default> <default key="_controller">Thelia\Controller\Front\CartController::deleteItem</default>
<default key="_view">cart</default> <default key="_view">cart</default>
</route> </route>
@@ -50,9 +60,4 @@
<default key="_view">cart</default> <default key="_view">cart</default>
</route> </route>
<!--<route id="url-rewriting.check" path="/{rewritten_url}" methods="GET">-->
<!--<default key="_controller">Thelia\Controller\Front\UrlRewritingController::check</default>-->
<!--<requirement key="rewritten_url">.*</requirement>-->
<!--</route>-->
</routes> </routes>

View File

@@ -85,10 +85,16 @@ class BaseAdminController extends BaseController
/** /**
* Return a general error page * Return a general error page
* *
* @param mixed $message a message string, or an exception instance
*
* @return \Symfony\Component\HttpFoundation\Response * @return \Symfony\Component\HttpFoundation\Response
*/ */
protected function errorPage($message) protected function errorPage($message)
{ {
if ($message instanceof \Exception) {
$message = sprintf("Sorry, an error occured: %s", $message->getMessage());
}
return $this->render('general_error', array( return $this->render('general_error', array(
"error_message" => $message) "error_message" => $message)
); );
@@ -168,24 +174,31 @@ class BaseAdminController extends BaseController
* @param unknown $urlParameters the URL parametrs, as a var/value pair array * @param unknown $urlParameters the URL parametrs, as a var/value pair array
*/ */
public function redirectToRoute($routeId, $urlParameters = array()) { public function redirectToRoute($routeId, $urlParameters = array()) {
$this->redirect(URL::absoluteUrl($this->getRoute($routeId), $urlParameters)); $this->redirect(URL::getInstance()->absoluteUrl($this->getRoute($routeId), $urlParameters));
} }
/** /**
* Get the current edition lang ID, checking if a change was requested in the current request * Get the current edition lang ID, checking if a change was requested in the current request.
*/ */
protected function getCurrentEditionLangId() { protected function getCurrentEditionLang() {
return $this->getRequest()->get(
'edit_language_id', // Return the new language if a change is required.
$this->getSession()->getAdminEditionLangId() if (null !== $edit_language_id = $this->getRequest()->get('edit_language_id', null)) {
);
if (null !== $edit_language = LangQuery::create()->findOneById($edit_language_id)) {
return $edit_language;
}
}
// Otherwise return the lang stored in session.
return $this->getSession()->getAdminEditionLang();
} }
/** /**
* A simple helper to get the current edition locale, from the session edition language ID * A simple helper to get the current edition locale.
*/ */
protected function getCurrentEditionLocale() { protected function getCurrentEditionLocale() {
return LangQuery::create()->findOneById($this->getCurrentEditionLangId())->getLocale(); return $this->getCurrentEditionLang()->getLocale();
} }
/** /**
@@ -217,23 +230,14 @@ class BaseAdminController extends BaseController
$session = $this->getSession(); $session = $this->getSession();
$edition_language = $this->getCurrentEditionLangId();
// Current back-office (not edition) language
$current_lang = LangQuery::create()->findOneById($session->getLangId());
// Find the current edit language ID // Find the current edit language ID
$edition_language = LangQuery::create()->findOneById($this->getCurrentEditionLangId()); $edition_language = $this->getCurrentEditionLang();
// Prepare common template variables // Prepare common template variables
$args = array_merge($args, array( $args = array_merge($args, array(
'locale' => $session->getLocale(), 'locale' => $session->getLang()->getLocale(),
'lang_code' => $session->getLang(), 'lang_code' => $session->getLang()->getCode(),
'lang_id' => $session->getLangId(), 'lang_id' => $session->getLang()->getId(),
'datetime_format' => $current_lang->getDateTimeFormat(),
'date_format' => $current_lang->getDateFormat(),
'time_format' => $current_lang->getTimeFormat(),
'edit_language_id' => $edition_language->getId(), 'edit_language_id' => $edition_language->getId(),
'edit_language_locale' => $edition_language->getLocale(), 'edit_language_locale' => $edition_language->getLocale(),
@@ -242,7 +246,7 @@ class BaseAdminController extends BaseController
)); ));
// Update the current edition language in session // Update the current edition language in session
$this->getSession()->setAdminEditionLangId($edition_language->getId()); $this->getSession()->setAdminEditionLang($edition_language);
// Render the template. // Render the template.
try { try {
@@ -253,7 +257,7 @@ class BaseAdminController extends BaseController
catch (AuthenticationException $ex) { catch (AuthenticationException $ex) {
// User is not authenticated, and templates requires authentication -> redirect to login page // User is not authenticated, and templates requires authentication -> redirect to login page
// We user login_tpl as a path, not a template. // We user login_tpl as a path, not a template.
Redirect::exec(URL::absoluteUrl($ex->getLoginTemplate())); Redirect::exec(URL::getInstance()->absoluteUrl($ex->getLoginTemplate()));
} }
catch (AuthorizationException $ex) { catch (AuthorizationException $ex) {
// User is not allowed to perform the required action. Return the error page instead of the requested page. // User is not allowed to perform the required action. Return the error page instead of the requested page.

View File

@@ -26,7 +26,7 @@ namespace Thelia\Controller\Admin;
use Thelia\Core\Event\ConfigDeleteEvent; use Thelia\Core\Event\ConfigDeleteEvent;
use Thelia\Core\Event\TheliaEvents; use Thelia\Core\Event\TheliaEvents;
use Thelia\Tools\URL; use Thelia\Tools\URL;
use Thelia\Core\Event\ConfigChangeEvent; use Thelia\Core\Event\ConfigUpdateEvent;
use Thelia\Core\Event\ConfigCreateEvent; use Thelia\Core\Event\ConfigCreateEvent;
use Thelia\Log\Tlog; use Thelia\Log\Tlog;
use Thelia\Form\Exception\FormValidationException; use Thelia\Form\Exception\FormValidationException;
@@ -154,7 +154,7 @@ class ConfigController extends BaseAdminController
public function changeAction() { public function changeAction() {
// Check current user authorization // Check current user authorization
if (null !== $response = $this->checkAuth("admin.configuration.variables.change")) return $response; if (null !== $response = $this->checkAuth("admin.configuration.variables.update")) return $response;
// Load the config object // Load the config object
$config = ConfigQuery::create() $config = ConfigQuery::create()
@@ -196,7 +196,7 @@ class ConfigController extends BaseAdminController
public function saveChangeAction() { public function saveChangeAction() {
// Check current user authorization // Check current user authorization
if (null !== $response = $this->checkAuth("admin.configuration.variables.change")) return $response; if (null !== $response = $this->checkAuth("admin.configuration.variables.update")) return $response;
$message = false; $message = false;
@@ -214,7 +214,7 @@ class ConfigController extends BaseAdminController
// Get the form field values // Get the form field values
$data = $form->getData(); $data = $form->getData();
$changeEvent = new ConfigChangeEvent($data['id']); $changeEvent = new ConfigUpdateEvent($data['id']);
// Create and dispatch the change event // Create and dispatch the change event
$changeEvent $changeEvent
@@ -284,13 +284,13 @@ class ConfigController extends BaseAdminController
public function changeValuesAction() { public function changeValuesAction() {
// Check current user authorization // Check current user authorization
if (null !== $response = $this->checkAuth("admin.configuration.variables.change")) return $response; if (null !== $response = $this->checkAuth("admin.configuration.variables.update")) return $response;
$variables = $this->getRequest()->get('variable', array()); $variables = $this->getRequest()->get('variable', array());
// Process all changed variables // Process all changed variables
foreach($variables as $id => $value) { foreach($variables as $id => $value) {
$event = new ConfigChangeEvent($id); $event = new ConfigUpdateEvent($id);
$event->setValue($value); $event->setValue($value);
$this->dispatch(TheliaEvents::CONFIG_SETVALUE, $event); $this->dispatch(TheliaEvents::CONFIG_SETVALUE, $event);

View File

@@ -26,7 +26,7 @@ namespace Thelia\Controller\Admin;
use Thelia\Core\Event\CurrencyDeleteEvent; use Thelia\Core\Event\CurrencyDeleteEvent;
use Thelia\Core\Event\TheliaEvents; use Thelia\Core\Event\TheliaEvents;
use Thelia\Tools\URL; use Thelia\Tools\URL;
use Thelia\Core\Event\CurrencyChangeEvent; use Thelia\Core\Event\CurrencyUpdateEvent;
use Thelia\Core\Event\CurrencyCreateEvent; use Thelia\Core\Event\CurrencyCreateEvent;
use Thelia\Log\Tlog; use Thelia\Log\Tlog;
use Thelia\Form\Exception\FormValidationException; use Thelia\Form\Exception\FormValidationException;
@@ -34,6 +34,7 @@ use Thelia\Core\Security\Exception\AuthorizationException;
use Thelia\Model\CurrencyQuery; use Thelia\Model\CurrencyQuery;
use Thelia\Form\CurrencyModificationForm; use Thelia\Form\CurrencyModificationForm;
use Thelia\Form\CurrencyCreationForm; use Thelia\Form\CurrencyCreationForm;
use Thelia\Core\Event\CurrencyUpdatePositionEvent;
/** /**
* Manages currencies sent by mail * Manages currencies sent by mail
@@ -124,7 +125,7 @@ class CurrencyController extends BaseAdminController
} }
catch (\Exception $ex) { catch (\Exception $ex) {
// Any other error // Any other error
$error_msg = sprintf("Sorry, an error occured: %s", $ex->getMessage()); $error_msg = $ex;
} }
if ($error_msg !== false) { if ($error_msg !== false) {
@@ -153,7 +154,7 @@ class CurrencyController extends BaseAdminController
public function changeAction() { public function changeAction() {
// Check current user authorization // Check current user authorization
if (null !== $response = $this->checkAuth("admin.configuration.currencies.change")) return $response; if (null !== $response = $this->checkAuth("admin.configuration.currencies.update")) return $response;
// Load the currency object // Load the currency object
$currency = CurrencyQuery::create() $currency = CurrencyQuery::create()
@@ -191,7 +192,7 @@ class CurrencyController extends BaseAdminController
public function saveChangeAction() { public function saveChangeAction() {
// Check current user authorization // Check current user authorization
if (null !== $response = $this->checkAuth("admin.configuration.currencies.change")) return $response; if (null !== $response = $this->checkAuth("admin.configuration.currencies.update")) return $response;
$error_msg = false; $error_msg = false;
@@ -209,7 +210,7 @@ class CurrencyController extends BaseAdminController
// Get the form field values // Get the form field values
$data = $form->getData(); $data = $form->getData();
$changeEvent = new CurrencyChangeEvent($data['id']); $changeEvent = new CurrencyUpdateEvent($data['id']);
// Create and dispatch the change event // Create and dispatch the change event
$changeEvent $changeEvent
@@ -231,7 +232,7 @@ class CurrencyController extends BaseAdminController
// just redirect to the edit page again. // just redirect to the edit page again.
if ($this->getRequest()->get('save_mode') == 'stay') { if ($this->getRequest()->get('save_mode') == 'stay') {
$this->redirectToRoute( $this->redirectToRoute(
"admin.configuration.currencies.change", "admin.configuration.currencies.update",
array('currency_id' => $currency_id) array('currency_id' => $currency_id)
); );
} }
@@ -245,7 +246,7 @@ class CurrencyController extends BaseAdminController
} }
catch (\Exception $ex) { catch (\Exception $ex) {
// Any other error // Any other error
$error_msg = sprintf("Sorry, an error occured: %s", $ex->getMessage()); $error_msg = $ex;
} }
if ($error_msg !== false) { if ($error_msg !== false) {
@@ -271,9 +272,9 @@ class CurrencyController extends BaseAdminController
*/ */
public function setDefaultAction() { public function setDefaultAction() {
// Check current user authorization // Check current user authorization
if (null !== $response = $this->checkAuth("admin.configuration.currencies.change")) return $response; if (null !== $response = $this->checkAuth("admin.configuration.currencies.update")) return $response;
$changeEvent = new CurrencyChangeEvent($this->getRequest()->get('currency_id', 0)); $changeEvent = new CurrencyUpdateEvent($this->getRequest()->get('currency_id', 0));
// Create and dispatch the change event // Create and dispatch the change event
$changeEvent->setIsDefault(true); $changeEvent->setIsDefault(true);
@@ -283,7 +284,7 @@ class CurrencyController extends BaseAdminController
} }
catch (\Exception $ex) { catch (\Exception $ex) {
// Any error // Any error
return $this->errorPage(sprintf("Sorry, an error occured: %s", $ex->getMessage())); return $this->errorPage($ex);
} }
$this->redirectToRoute('admin.configuration.currencies.default'); $this->redirectToRoute('admin.configuration.currencies.default');
@@ -294,19 +295,55 @@ class CurrencyController extends BaseAdminController
*/ */
public function updateRatesAction() { public function updateRatesAction() {
// Check current user authorization // Check current user authorization
if (null !== $response = $this->checkAuth("admin.configuration.currencies.change")) return $response; if (null !== $response = $this->checkAuth("admin.configuration.currencies.update")) return $response;
try { try {
$this->dispatch(TheliaEvents::CURRENCY_UPDATE_RATES); $this->dispatch(TheliaEvents::CURRENCY_UPDATE_RATES);
} }
catch (\Exception $ex) { catch (\Exception $ex) {
// Any error // Any error
return $this->errorPage(sprintf("Sorry, an error occured: %s", $ex->getMessage())); return $this->errorPage($ex);
} }
$this->redirectToRoute('admin.configuration.currencies.default'); $this->redirectToRoute('admin.configuration.currencies.default');
} }
/**
* Update currencyposition
*/
public function updatePositionAction() {
// Check current user authorization
if (null !== $response = $this->checkAuth("admin.configuration.currencies.update")) return $response;
try {
$mode = $this->getRequest()->get('mode', null);
if ($mode == 'up')
$mode = CurrencyUpdatePositionEvent::POSITION_UP;
else if ($mode == 'down')
$mode = CurrencyUpdatePositionEvent::POSITION_DOWN;
else
$mode = CurrencyUpdatePositionEvent::POSITION_ABSOLUTE;
$position = $this->getRequest()->get('position', null);
$event = new CurrencyUpdatePositionEvent(
$this->getRequest()->get('currency_id', null),
$mode,
$this->getRequest()->get('position', null)
);
$this->dispatch(TheliaEvents::CURRENCY_UPDATE_POSITION, $event);
}
catch (\Exception $ex) {
// Any error
return $this->errorPage($ex);
}
$this->redirectToRoute('admin.configuration.currencies.default');
}
/** /**
* Delete a currency object * Delete a currency object
* *

View File

@@ -26,7 +26,7 @@ namespace Thelia\Controller\Admin;
use Thelia\Core\Event\MessageDeleteEvent; use Thelia\Core\Event\MessageDeleteEvent;
use Thelia\Core\Event\TheliaEvents; use Thelia\Core\Event\TheliaEvents;
use Thelia\Tools\URL; use Thelia\Tools\URL;
use Thelia\Core\Event\MessageChangeEvent; use Thelia\Core\Event\MessageUpdateEvent;
use Thelia\Core\Event\MessageCreateEvent; use Thelia\Core\Event\MessageCreateEvent;
use Thelia\Log\Tlog; use Thelia\Log\Tlog;
use Thelia\Form\Exception\FormValidationException; use Thelia\Form\Exception\FormValidationException;
@@ -133,7 +133,7 @@ class MessageController extends BaseAdminController
public function changeAction() { public function changeAction() {
// Check current user authorization // Check current user authorization
if (null !== $response = $this->checkAuth("admin.configuration.messages.change")) return $response; if (null !== $response = $this->checkAuth("admin.configuration.messages.update")) return $response;
// Load the message object // Load the message object
$message = MessageQuery::create() $message = MessageQuery::create()
@@ -173,7 +173,7 @@ class MessageController extends BaseAdminController
public function saveChangeAction() { public function saveChangeAction() {
// Check current user authorization // Check current user authorization
if (null !== $response = $this->checkAuth("admin.configuration.messages.change")) return $response; if (null !== $response = $this->checkAuth("admin.configuration.messages.update")) return $response;
$message = false; $message = false;
@@ -191,7 +191,7 @@ class MessageController extends BaseAdminController
// Get the form field values // Get the form field values
$data = $form->getData(); $data = $form->getData();
$changeEvent = new MessageChangeEvent($data['id']); $changeEvent = new MessageUpdateEvent($data['id']);
// Create and dispatch the change event // Create and dispatch the change event
$changeEvent $changeEvent
@@ -215,7 +215,7 @@ class MessageController extends BaseAdminController
// just redirect to the edit page again. // just redirect to the edit page again.
if ($this->getRequest()->get('save_mode') == 'stay') { if ($this->getRequest()->get('save_mode') == 'stay') {
$this->redirectToRoute( $this->redirectToRoute(
"admin.configuration.messages.change", "admin.configuration.messages.update",
array('message_id' => $message_id) array('message_id' => $message_id)
); );
} }
@@ -265,6 +265,6 @@ class MessageController extends BaseAdminController
$this->dispatch(TheliaEvents::MESSAGE_DELETE, $event); $this->dispatch(TheliaEvents::MESSAGE_DELETE, $event);
$this->redirect(URL::adminViewUrl('messages')); $this->redirect(URL::getInstance()->adminViewUrl('messages'));
} }
} }

View File

@@ -24,33 +24,42 @@
namespace Thelia\Controller\Front; namespace Thelia\Controller\Front;
use Thelia\Core\Event\AddressCreateOrUpdateEvent; use Thelia\Core\Event\AddressCreateOrUpdateEvent;
use Thelia\Core\Event\TheliaEvents; use Thelia\Core\Event\TheliaEvents;
use Thelia\Form\AddressForm; use Thelia\Form\AddressCreateForm;
use Thelia\Form\AddressUpdateForm;
use Thelia\Form\Exception\FormValidationException; use Thelia\Form\Exception\FormValidationException;
use Thelia\Model\Base\AddressQuery;
use Thelia\Model\Customer; use Thelia\Model\Customer;
use Thelia\Tools\URL; use Thelia\Tools\URL;
/** /**
* Class CustomerAddressController * Class AddressController
* @package Thelia\Controller\Front * @package Thelia\Controller\Front
* @author Manuel Raynaud <mraynaud@openstudio.fr> * @author Manuel Raynaud <mraynaud@openstudio.fr>
*/ */
class CustomerAddressController extends BaseFrontController class AddressController extends BaseFrontController
{ {
/**
* Create controller.
* Check if customer is logged in
*
* Dispatch TheliaEvents::ADDRESS_CREATE event
*/
public function createAction() public function createAction()
{ {
if ($this->getSecurityContext()->hasCustomerUser() === false) { if ($this->getSecurityContext()->hasCustomerUser() === false) {
$this->redirect(URL::getIndexPage()); $this->redirect(URL::getInstance()->getIndexPage());
} }
$addressCreate = new AddressForm($this->getRequest()); $addressCreate = new AddressCreateForm($this->getRequest());
try { try {
$customer = $this->getSecurityContext()->getCustomerUser(); $customer = $this->getSecurityContext()->getCustomerUser();
$form = $this->validateForm($addressCreate, "post"); $form = $this->validateForm($addressCreate, "post");
$event = $this->createAddressEvent($form->getData(), $customer); $event = $this->createAddressEvent($form);
$event->setCustomer($customer);
$this->dispatch(TheliaEvents::ADDRESS_CREATE, $event); $this->dispatch(TheliaEvents::ADDRESS_CREATE, $event);
$this->redirectSuccess($addressCreate); $this->redirectSuccess($addressCreate);
@@ -74,23 +83,76 @@ class CustomerAddressController extends BaseFrontController
} }
} }
protected function createAddressEvent($data, Customer $customer) public function updateAction()
{
$request = $this->getRequest();
if ($this->getSecurityContext()->hasCustomerUser() === false) {
$this->redirectToRoute("home");
}
if(null === $address_id = $request->get("address_id")) {
$this->redirectToRoute("home");
}
$addressUpdate = new AddressUpdateForm($request);
try {
$customer = $this->getSecurityContext()->getCustomerUser();
$form = $this->validateForm($addressUpdate);
$address = AddressQuery::create()->findPk($address_id);
if (null === $address) {
$this->redirectToRoute("home");
}
if($address->getCustomer()->getId() != $customer->getId()) {
$this->redirectToRoute("home");
}
$event = $this->createAddressEvent($form);
$event->setAddress($address);
$this->dispatch(TheliaEvents::ADDRESS_UPDATE, $event);
$this->redirectSuccess($addressUpdate);
}catch (FormValidationException $e) {
$message = sprintf("Please check your input: %s", $e->getMessage());
}
catch (\Exception $e) {
$message = sprintf("Sorry, an error occured: %s", $e->getMessage());
}
if ($message !== false) {
\Thelia\Log\Tlog::getInstance()->error(sprintf("Error during address creation process : %s", $message));
$addressUpdate->setErrorMessage($message);
$this->getParserContext()
->addForm($addressUpdate)
->setGeneralError($message)
;
}
}
protected function createAddressEvent($form)
{ {
return new AddressCreateOrUpdateEvent( return new AddressCreateOrUpdateEvent(
$data["label"], $form->get("label")->getData(),
$data["title"], $form->get("title")->getData(),
$data["firstname"], $form->get("firstname")->getData(),
$data["lastname"], $form->get("lastname")->getData(),
$data["address1"], $form->get("address1")->getData(),
$data["address2"], $form->get("address2")->getData(),
$data["address3"], $form->get("address3")->getData(),
$data["zipcode"], $form->get("zipcode")->getData(),
$data["city"], $form->get("city")->getData(),
$data["country"], $form->get("country")->getData(),
$data["cellpone"], $form->get("cellphone")->getData(),
$data["phone"], $form->get("phone")->getData(),
$data["company"], $form->get("company")->getData()
$customer
); );
} }
} }

View File

@@ -23,6 +23,7 @@
namespace Thelia\Controller\Front; namespace Thelia\Controller\Front;
use Thelia\Controller\BaseController; use Thelia\Controller\BaseController;
use Thelia\Tools\URL;
class BaseFrontController extends BaseController class BaseFrontController extends BaseController
{ {
@@ -44,6 +45,6 @@ class BaseFrontController extends BaseController
* @param unknown $urlParameters the URL parametrs, as a var/value pair array * @param unknown $urlParameters the URL parametrs, as a var/value pair array
*/ */
public function redirectToRoute($routeId, $urlParameters = array()) { public function redirectToRoute($routeId, $urlParameters = array()) {
$this->redirect(URL::absoluteUrl($this->getRoute($routeId), $urlParameters)); $this->redirect(URL::getInstance()->absoluteUrl($this->getRoute($routeId), $urlParameters));
} }
} }

View File

@@ -202,7 +202,7 @@ class CustomerController extends BaseFrontController
} }
// Redirect to home page // Redirect to home page
$this->redirect(URL::getIndexPage()); $this->redirect(URL::getInstance()->getIndexPage());
} }
/** /**

View File

@@ -46,23 +46,30 @@ class DefaultController extends BaseFrontController
*/ */
public function noAction(Request $request) public function noAction(Request $request)
{ {
if(ConfigQuery::isRewritingEnable()) { $view = null;
/* Does the query GET parameters match a rewritten URL ? */
$rewrittenUrl = URL::init()->retrieveCurrent($request);
if($rewrittenUrl->rewrittenUrl !== null) {
/* 301 redirection to rewritten URL */
$this->redirect($rewrittenUrl->rewrittenUrl, 301);
}
}
if (! $view = $request->query->get('view')) { if (! $view = $request->query->get('view')) {
$view = "index";
if ($request->request->has('view')) { if ($request->request->has('view')) {
$view = $request->request->get('view'); $view = $request->request->get('view');
} }
} }
if(null !== $view) {
$request->attributes->set('_view', $view);
}
$request->attributes->set('_view', $view); if (null === $view && null === $request->attributes->get("_view")) {
$request->attributes->set("_view", "index");
}
if(ConfigQuery::isRewritingEnable()) {
if($request->attributes->get('_rewritten', false) === false) {
/* Does the query GET parameters match a rewritten URL ? */
$rewrittenUrl = URL::getInstance()->retrieveCurrent($request);
if($rewrittenUrl->rewrittenUrl !== null) {
/* 301 redirection to rewritten URL */
$this->redirect($rewrittenUrl->rewrittenUrl, 301);
}
}
}
} }
} }

View File

@@ -1,81 +0,0 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Controller\Front;
use Thelia\Core\HttpFoundation\Request;
use Thelia\Exception\UrlRewritingException;
use Thelia\Model\ConfigQuery;
use Thelia\Tools\URL;
class UrlRewritingController extends BaseFrontController
{
public function check(Request $request, $rewritten_url)
{
if(ConfigQuery::isRewritingEnable()) {
try {
$rewrittenUrlData = URL::init()->resolve($rewritten_url);
} catch(UrlRewritingException $e) {
switch($e->getCode()) {
case UrlRewritingException::URL_NOT_FOUND :
return $this->pageNotFound();
break;
default:
throw $e;
}
}
/* is the URL redirected ? */
if(null !== $rewrittenUrlData->redirectedToUrl) {
$this->redirect($rewrittenUrlData->redirectedToUrl, 301);
}
/* define GET arguments in request */
if(null !== $rewrittenUrlData->view) {
$request->query->set('view', $rewrittenUrlData->view);
if(null !== $rewrittenUrlData->viewId) {
$request->query->set($rewrittenUrlData->view . '_id', $rewrittenUrlData->viewId);
}
}
if(null !== $rewrittenUrlData->locale) {
$request->query->set('locale', $rewrittenUrlData->locale);
}
foreach($rewrittenUrlData->otherParameters as $parameter => $value) {
$request->query->set($parameter, $value);
}
}
if (! $view = $request->query->get('view')) {
$view = "index";
if ($request->request->has('view')) {
$view = $request->request->get('view');
}
}
$request->attributes->set('_view', $view);
}
}

View File

@@ -32,7 +32,7 @@ use Thelia\Model\Customer;
* @package Thelia\Core\Event * @package Thelia\Core\Event
* @author Manuel Raynaud <mraynaud@openstudio.fr> * @author Manuel Raynaud <mraynaud@openstudio.fr>
*/ */
class AddressCreateOrUpdateEvent extends Event class AddressCreateOrUpdateEvent extends ActionEvent
{ {
/** /**
* @var string address label * @var string address label

View File

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

View File

@@ -0,0 +1,77 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Core\Event;
class BaseUpdatePositionEvent extends ActionEvent
{
const POSITION_UP = 1;
const POSITION_DOWN = 2;
const POSITION_ABSOLUTE = 3;
protected $object_id;
protected $mode;
protected $position;
protected $object;
public function __construct($object_id, $mode, $position = null)
{
$this->object_id = $object_id;
$this->mode = $mode;
$this->position = $position;
}
public function getMode()
{
return $this->mode;
}
public function setMode($mode)
{
$this->mode = $mode;
return $this;
}
public function getPosition()
{
return $this->position;
}
public function setPosition($position)
{
$this->position = $position;
return $this;
}
public function getObjectId()
{
return $this->object_id;
}
public function setObjectId($object_id)
{
$this->object_id = $object_id;
return $this;
}
}

View File

@@ -26,7 +26,7 @@ namespace Thelia\Core\Event;
use Symfony\Component\EventDispatcher\Event; use Symfony\Component\EventDispatcher\Event;
use Thelia\Model\Cart; use Thelia\Model\Cart;
class CartEvent extends Event class CartEvent extends ActionEvent
{ {
protected $cart; protected $cart;
protected $quantity; protected $quantity;

View File

@@ -22,64 +22,7 @@
/*************************************************************************************/ /*************************************************************************************/
namespace Thelia\Core\Event; namespace Thelia\Core\Event;
use Thelia\Model\Category;
class CategoryChangePositionEvent extends ActionEvent class CurrencyUpdatePositionEvent extends BaseUpdatePositionEvent
{ {
const POSITION_UP = 1; }
const POSITION_DOWN = 2;
const POSITION_ABSOLUTE = 3;
protected $category_id;
protected $mode;
protected $position;
protected $category;
public function __construct($category_id, $mode, $position = null)
{
$this->category_id = $category_id;
$this->mode = $mode;
$this->position = $position;
}
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;
}
public function getCategoryId()
{
return $this->category_id;
}
public function setCategoryId($category_id)
{
$this->category_id = $category_id;
}
}

View File

@@ -25,7 +25,7 @@ namespace Thelia\Core\Event;
use Thelia\Model\Category; use Thelia\Model\Category;
class CategoryCreateEvent extends ActionEvent class CategoryUpdateEvent extends ActionEvent
{ {
protected $category_id; protected $category_id;
protected $locale; protected $locale;

View File

@@ -25,7 +25,7 @@ namespace Thelia\Core\Event;
use Thelia\Model\Config; use Thelia\Model\Config;
class ConfigChangeEvent extends ConfigCreateEvent class ConfigUpdateEvent extends ConfigCreateEvent
{ {
protected $config_id; protected $config_id;

View File

@@ -24,7 +24,7 @@
namespace Thelia\Core\Event; namespace Thelia\Core\Event;
use Thelia\Model\Currency; use Thelia\Model\Currency;
class CurrencyChangeEvent extends CurrencyCreateEvent class CurrencyUpdateEvent extends CurrencyCreateEvent
{ {
protected $currency_id; protected $currency_id;
protected $is_default; protected $is_default;

View File

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

View File

@@ -13,7 +13,7 @@ namespace Thelia\Core\Event;
use Symfony\Component\EventDispatcher\Event; use Symfony\Component\EventDispatcher\Event;
use Thelia\Model\Customer; use Thelia\Model\Customer;
class CustomerCreateOrUpdateEvent extends Event { class CustomerCreateOrUpdateEvent extends ActionEvent {
//base parameters for creating new customer //base parameters for creating new customer
protected $title; protected $title;

View File

@@ -25,7 +25,7 @@ namespace Thelia\Core\Event;
use Thelia\Model\Message; use Thelia\Model\Message;
class MessageChangeEvent extends MessageCreateEvent class MessageUpdateEvent extends MessageCreateEvent
{ {
protected $message_id; protected $message_id;

View File

@@ -88,12 +88,13 @@ final class TheliaEvents
/** /**
* Sent once the customer change form has been successfully validated, and before customer update in the database. * Sent once the customer change form has been successfully validated, and before customer update in the database.
*/ */
const BEFORE_CHANGECUSTOMER = "action.before_updateCustomer"; const BEFORE_UPDATECUSTOMER = "action.before_updateCustomer";
/** /**
* Sent just after a successful update of a customer in the database. * Sent just after a successful update of a customer in the database.
*/ */
const AFTER_CHANGECUSTOMER = "action.after_updateCustomer"; const AFTER_UPDATECUSTOMER = "action.after_updateCustomer";
// -- ADDRESS MANAGEMENT ---------------------------------------------------------
/** /**
* sent for address creation * sent for address creation
*/ */
@@ -104,6 +105,17 @@ final class TheliaEvents
*/ */
const ADDRESS_UPDATE = "action.updateAddress"; const ADDRESS_UPDATE = "action.updateAddress";
const BEFORE_CREATEADDRESS = "action.before_createAddress";
const AFTER_CREATEADDRESS = "action.after_createAddress";
const BEFORE_UPDATEADDRESS = "action.before_updateAddress";
const AFTER_UPDATEADDRESS = "action.after_updateAddress";
const BEFORE_DELETEADDRESS = "action.before_deleteAddress";
const AFTER_DELETEADDRESS = "action.after_deleteAddress";
// -- END ADDRESS MANAGEMENT ---------------------------------------------------------
/** /**
* Sent once the category creation form has been successfully validated, and before category insertion in the database. * Sent once the category creation form has been successfully validated, and before category insertion in the database.
*/ */
@@ -124,7 +136,7 @@ final class TheliaEvents
/** /**
* Change category position * Change category position
*/ */
const CATEGORY_CHANGE_POSITION = "action.changeCategoryPosition"; const CATEGORY_CHANGE_POSITION = "action.updateCategoryPosition";
/** /**
* Sent just after a successful insert of a new category in the database. * Sent just after a successful insert of a new category in the database.
@@ -344,12 +356,12 @@ final class TheliaEvents
// -- Currencies management --------------------------------------------- // -- Currencies management ---------------------------------------------
const CURRENCY_CREATE = "action.createCurrency"; const CURRENCY_CREATE = "action.createCurrency";
const CURRENCY_UPDATE = "action.updateCurrency"; const CURRENCY_UPDATE = "action.updateCurrency";
const CURRENCY_DELETE = "action.deleteCurrency"; const CURRENCY_DELETE = "action.deleteCurrency";
const CURRENCY_SET_DEFAULT = "action.setDefaultCurrency"; const CURRENCY_SET_DEFAULT = "action.setDefaultCurrency";
const CURRENCY_UPDATE_RATES = "action.updateCurrencyRates"; const CURRENCY_UPDATE_RATES = "action.updateCurrencyRates";
const CURRENCY_UPDATE_POSITION = "action.updateCurrencyPosition";
const BEFORE_CREATECURRENCY = "action.before_createCurrency"; const BEFORE_CREATECURRENCY = "action.before_createCurrency";
const AFTER_CREATECURRENCY = "action.after_createCurrency"; const AFTER_CREATECURRENCY = "action.after_createCurrency";

View File

@@ -86,7 +86,7 @@ class ViewListener implements EventSubscriberInterface
} catch (AuthenticationException $ex) { } catch (AuthenticationException $ex) {
// Redirect to the login template // Redirect to the login template
Redirect::exec(URL::viewUrl($ex->getLoginTemplate())); Redirect::exec($this->container->get('thelia.url.manager')->viewUrl($ex->getLoginTemplate()));
} }
} }

View File

@@ -41,55 +41,29 @@ use Thelia\Model\Lang;
*/ */
class Session extends BaseSession class Session extends BaseSession
{ {
// -- Language ------------------------------------------------------------
public function getLocale()
{
return $this->get("locale", "en_US");
}
public function setLocale($locale)
{
$this->set("locale", $locale);
return $this;
}
/** /**
* @return \Thelia\Model\Lang|null * @return \Thelia\Model\Lang|null
*/ */
public function getLang() public function getLang()
{ {
return $this->get("lang"); return $this->get("thelia.current.lang", Lang::getDefaultLanguage());
} }
public function setLang(Lang $lang) public function setLang(Lang $lang)
{ {
$this->set("lang", $lang); $this->set("thelia.current.lang", $lang);
return $this; return $this;
} }
public function getLangId() public function getAdminEditionLang()
{ {
return $this->get("lang_id", Lang::getDefaultLanguage()->getId()); return $this->get('thelia.admin.edition.lang', Lang::getDefaultLanguage());
} }
public function setLangId($langId) public function setAdminEditionLang($langId)
{ {
$this->set("lang_id", $langId); $this->set('thelia.admin.edition.lang', $langId);
return $this;
}
public function getAdminEditionLangId()
{
return $this->get('admin.edition_language', Lang::getDefaultLanguage()->getId());
}
public function setAdminEditionLangId($langId)
{
$this->set('admin.edition_language', $langId);
return $this; return $this;
} }
@@ -98,43 +72,43 @@ class Session extends BaseSession
public function setCustomerUser(UserInterface $user) public function setCustomerUser(UserInterface $user)
{ {
$this->set('customer_user', $user); $this->set('thelia.customer_user', $user);
return $this; return $this;
} }
public function getCustomerUser() public function getCustomerUser()
{ {
return $this->get('customer_user'); return $this->get('thelia.customer_user');
} }
public function clearCustomerUser() public function clearCustomerUser()
{ {
return $this->remove('customer_user'); return $this->remove('thelia.customer_user');
} }
// -- Admin user ----------------------------------------------------------- // -- Admin user -----------------------------------------------------------
public function setAdminUser(UserInterface $user) public function setAdminUser(UserInterface $user)
{ {
$this->set('admin_user', $user); $this->set('thelia.admin_user', $user);
return $this; return $this;
} }
public function getAdminUser() public function getAdminUser()
{ {
return $this->get('admin_user'); return $this->get('thelia.admin_user');
} }
public function clearAdminUser() public function clearAdminUser()
{ {
return $this->remove('admin_user'); return $this->remove('thelia.admin_user');
} }
// -- Return page ---------------------------------------------------------- // -- Return page ----------------------------------------------------------
public function setReturnToUrl($url) public function setReturnToUrl($url)
{ {
$this->set('return_to_url', $url); $this->set('thelia.return_to_url', $url);
return $this; return $this;
} }
@@ -144,7 +118,7 @@ class Session extends BaseSession
*/ */
public function getReturnToUrl() public function getReturnToUrl()
{ {
return $this->get('return_to_url', URL::getIndexPage()); return $this->get('thelia.return_to_url', URL::getInstance()->getIndexPage());
} }
// -- Cart ------------------------------------------------------------------ // -- Cart ------------------------------------------------------------------
@@ -156,7 +130,7 @@ class Session extends BaseSession
*/ */
public function getCart() public function getCart()
{ {
$cart_id = $this->get("cart_id"); $cart_id = $this->get("thelia.cart_id");
$cart = null; $cart = null;
if ($cart_id) { if ($cart_id) {
$cart = CartQuery::create()->findPk($cart_id); $cart = CartQuery::create()->findPk($cart_id);
@@ -193,7 +167,7 @@ class Session extends BaseSession
*/ */
public function setCart($cart_id) public function setCart($cart_id)
{ {
$this->set("cart_id", $cart_id); $this->set("thelia.cart_id", $cart_id);
return $this; return $this;
} }
} }

View File

@@ -0,0 +1,219 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Core\Routing;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Exception\InvalidParameterException;
use Symfony\Component\Routing\Exception\MethodNotAllowedException;
use Symfony\Component\Routing\Exception\MissingMandatoryParametersException;
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
use Symfony\Component\Routing\Exception\RouteNotFoundException;
use Symfony\Component\Routing\Matcher\RequestMatcherInterface;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\RouterInterface;
use Thelia\Exception\RedirectException;
use Thelia\Exception\UrlRewritingException;
use Thelia\Model\ConfigQuery;
use Thelia\Tools\Redirect;
use Thelia\Tools\URL;
/**
* Class RewritingRouter
* @package Thelia\Core\Routing
* @author Manuel Raynaud <mraynaud@openstudio.fr>
* @author Etienne Roudeix <eroudeix@openstudio.fr>
*/
class RewritingRouter implements RouterInterface, RequestMatcherInterface
{
/**
* @var RequestContext The context
*/
protected $context;
/**
* @var options, don't use for now but mandatory
*/
protected $options;
/**
* Sets the request context.
*
* @param RequestContext $context The context
*
* @api
*/
public function setContext(RequestContext $context)
{
// TODO: Implement setContext() method.
$this->context = $context;
}
/**
* Gets the request context.
*
* @return RequestContext The context
*
* @api
*/
public function getContext()
{
// TODO: Implement getContext() method.
return $this->context;
}
public function setOption($key, $value)
{
//NOTHING TO DO FOR NOW
}
/**
* Gets the RouteCollection instance associated with this Router.
*
* @return RouteCollection A RouteCollection instance
*/
public function getRouteCollection()
{
return new RouteCollection();
}
/**
* Generates a URL or path for a specific route based on the given parameters.
*
* Parameters that reference placeholders in the route pattern will substitute them in the
* path or host. Extra params are added as query string to the URL.
*
* When the passed reference type cannot be generated for the route because it requires a different
* host or scheme than the current one, the method will return a more comprehensive reference
* that includes the required params. For example, when you call this method with $referenceType = ABSOLUTE_PATH
* but the route requires the https scheme whereas the current scheme is http, it will instead return an
* ABSOLUTE_URL with the https scheme and the current host. This makes sure the generated URL matches
* the route in any case.
*
* If there is no route with the given name, the generator must throw the RouteNotFoundException.
*
* @param string $name The name of the route
* @param mixed $parameters An array of parameters
* @param Boolean|string $referenceType The type of reference to be generated (one of the constants)
*
* @return string The generated URL
*
* @throws RouteNotFoundException If the named route doesn't exist
* @throws MissingMandatoryParametersException When some parameters are missing that are mandatory for the route
* @throws InvalidParameterException When a parameter value for a placeholder is not correct because
* it does not match the requirement
*
* @api
*/
public function generate($name, $parameters = array(), $referenceType = self::ABSOLUTE_PATH)
{
// TODO: Implement generate() method.
}
/**
* Tries to match a URL path with a set of routes.
*
* If the matcher can not find information, it must throw one of the exceptions documented
* below.
*
* @param string $pathinfo The path info to be parsed (raw format, i.e. not urldecoded)
*
* @return array An array of parameters
*
* @throws ResourceNotFoundException If the resource could not be found
* @throws MethodNotAllowedException If the resource was found but the request method is not allowed
*
* @api
*/
public function match($pathinfo)
{
throw new ResourceNotFoundException("impossible to find route with this method, please use matchRequest method");
}
/**
* Tries to match a request with a set of routes.
*
* If the matcher can not find information, it must throw one of the exceptions documented
* below.
*
* @param Request $request The request to match
*
* @throws \Exception|\Thelia\Exception\UrlRewritingException
* @throws \Symfony\Component\Routing\Exception\ResourceNotFoundException
* @throws \Thelia\Exception\RedirectException
* @return array An array of parameters
*
*/
public function matchRequest(Request $request)
{
if(ConfigQuery::isRewritingEnable()) {
try {
$rewrittenUrlData = URL::getInstance()->resolve($request->getPathInfo());
} catch(UrlRewritingException $e) {
switch($e->getCode()) {
case UrlRewritingException::URL_NOT_FOUND :
throw new ResourceNotFoundException();
break;
default:
throw $e;
}
}
/* is the URL redirected ? */
if(null !== $rewrittenUrlData->redirectedToUrl) {
$this->redirect($rewrittenUrlData->redirectedToUrl, 301);
}
/* define GET arguments in request */
if(null !== $rewrittenUrlData->view) {
$request->attributes->set('_view', $rewrittenUrlData->view);
if(null !== $rewrittenUrlData->viewId) {
$request->query->set($rewrittenUrlData->view . '_id', $rewrittenUrlData->viewId);
}
}
if(null !== $rewrittenUrlData->locale) {
$request->query->set('locale', $rewrittenUrlData->locale);
}
foreach($rewrittenUrlData->otherParameters as $parameter => $value) {
$request->query->set($parameter, $value);
}
return array (
'_controller' => 'Thelia\\Controller\\Front\\DefaultController::noAction',
'_route' => 'rewrite',
'_rewritten' => true,
);
}
throw new ResourceNotFoundException();
}
protected function redirect($url, $status = 302)
{
Redirect::exec($url, $status);
}
}

View File

@@ -43,15 +43,16 @@ class AsseticHelper
* Generates assets from $asset_path in $output_path, using $filters. * Generates assets from $asset_path in $output_path, using $filters.
* *
* @param string $asset_path the full path to the asset file (or file collection) * @param string $asset_path the full path to the asset file (or file collection)
* @param unknown $output_path the full disk path to the output directory (shoud be visible to web server) * @param string $output_path the full disk path to the output directory (shoud be visible to web server)
* @param unknown $output_url the URL to the generated asset directory * @param string $output_url the URL to the generated asset directory
* @param unknown $asset_type the asset type: css, js, ... The generated files will have this extension. Pass an empty string to use the asset source extension. * @param string $asset_type the asset type: css, js, ... The generated files will have this extension. Pass an empty string to use the asset source extension.
* @param unknown $filters a list of filters, as defined below (see switch($filter_name) ...) * @param array $filters a list of filters, as defined below (see switch($filter_name) ...)
* @param unknown $debug true / false * @param boolean $debug true / false
* @param boolean $dev_mode true / false. If true, assets are not cached and always compiled.
* @throws \InvalidArgumentException if an invalid filter name is found * @throws \InvalidArgumentException if an invalid filter name is found
* @return string The URL to the generated asset file. * @return string The URL to the generated asset file.
*/ */
public function asseticize($asset_path, $output_path, $output_url, $asset_type, $filters, $debug) public function asseticize($asset_path, $output_path, $output_url, $asset_type, $filters, $debug, $dev_mode = false)
{ {
$asset_name = basename($asset_path); $asset_name = basename($asset_path);
$asset_dir = dirname($asset_path); $asset_dir = dirname($asset_path);
@@ -106,17 +107,49 @@ class AsseticHelper
$factory->setDebug($debug); $factory->setDebug($debug);
$factory->addWorker(new CacheBustingWorker()); $factory->addWorker(new CacheBustingWorker('-'));
// Prepare the assets writer // We do not pass the filter list here, juste to get the asset file name
$writer = new AssetWriter($output_path); $asset = $factory->createAsset($asset_name);
$asset = $factory->createAsset($asset_name, $filter_list); $asset_target_path = $asset->getTargetPath();
$cache = new AssetCache($asset, new FilesystemCache($output_path)); $target_file = sprintf("%s/%s", $output_path, $asset_target_path);
$writer->writeAsset($cache); // As it seems that assetic cannot handle a real file cache, let's do the job ourselves.
// It works only if the CacheBustingWorker is used, as a new file name is generated for each version.
//
// the previous version of the file is deleted, by getting the first part of the ouput file name
// (the one before '-'), and delete aby file beginning with the same string. Example:
// old name: 3bc974a-dfacc1f.css
// new name: 3bc974a-ad3ef47.css
//
// before generating 3bc974a-ad3ef47.css, delete 3bc974a-* files.
//
if ($dev_mode == true || ! file_exists($target_file)) {
return rtrim($output_url, '/').'/'.$asset->getTargetPath(); // Delete previous version of the file
list($commonPart, $dummy) = explode('-', $asset_target_path);
foreach (glob("$output_path/$commonPart-*") as $filename) {
@unlink($filename);
}
// Apply filters now
foreach ($filter_list as $filter) {
if ('?' != $filter[0]) {
$asset->ensureFilter($fm->get($filter));
}
elseif (!$debug) {
$asset->ensureFilter($fm->get(substr($filter, 1)));
}
}
$writer = new AssetWriter($output_path);
$writer->writeAsset($asset);
}
return rtrim($output_url, '/').'/'.$asset_target_path;
} }
} }

View File

@@ -69,7 +69,7 @@ abstract class BaseI18nLoop extends BaseLoop
$this->getBackend_context(), $this->getBackend_context(),
$this->getLang(), $this->getLang(),
$search, $search,
$this->request->getSession()->getLocale(), $this->request->getSession()->getLang()->getLocale(),
$columns, $columns,
$foreignTable, $foreignTable,
$foreignKey, $foreignKey,

View File

@@ -239,31 +239,6 @@ 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. * this function have to be implement in your own loop class.

View File

@@ -64,7 +64,7 @@ class Address extends BaseLoop
), ),
'current' 'current'
), ),
Argument::createBooleanTypeArgument('default'), Argument::createBooleanTypeArgument('default', false),
Argument::createIntListTypeArgument('exclude') Argument::createIntListTypeArgument('exclude')
); );
} }
@@ -99,10 +99,9 @@ class Address extends BaseLoop
$default = $this->getDefault(); $default = $this->getDefault();
if ($default === true) { if ($default === true) {
$search->filterByIsDefault(1, Criteria::EQUAL); $search->filterByIsDefault(1, Criteria::EQUAL);
} elseif ($default === false) {
$search->filterByIsDefault(1, Criteria::NOT_EQUAL);
} }
$exclude = $this->getExclude(); $exclude = $this->getExclude();
@@ -119,7 +118,7 @@ class Address extends BaseLoop
$loopResultRow = new LoopResultRow($loopResult, $address, $this->versionable, $this->timestampable, $this->countable); $loopResultRow = new LoopResultRow($loopResult, $address, $this->versionable, $this->timestampable, $this->countable);
$loopResultRow $loopResultRow
->set("ID", $address->getId()) ->set("ID", $address->getId())
->set("NAME", $address->getName()) ->set("LABEL", $address->getLabel())
->set("CUSTOMER", $address->getCustomerId()) ->set("CUSTOMER", $address->getCustomerId())
->set("TITLE", $address->getTitleId()) ->set("TITLE", $address->getTitleId())
->set("COMPANY", $address->getCompany()) ->set("COMPANY", $address->getCompany())

View File

@@ -71,10 +71,12 @@ class Cart extends BaseLoop
*/ */
public function exec(&$pagination) public function exec(&$pagination)
{ {
$cartItems = $cart->getCartItems();
$result = new LoopResult($cartItems);
$cart = $this->getCart($this->request); $cart = $this->getCart($this->request);
$cartItems = $cart->getCartItems();
$result = new LoopResult($cartItems);
if ($cart === null) { if ($cart === null) {
return $result; return $result;

View File

@@ -166,7 +166,7 @@ class Config extends BaseI18nLoop
->set("POSTSCRIPTUM" , $result->getVirtualColumn('i18n_POSTSCRIPTUM')) ->set("POSTSCRIPTUM" , $result->getVirtualColumn('i18n_POSTSCRIPTUM'))
->set("HIDDEN" , $result->getHidden()) ->set("HIDDEN" , $result->getHidden())
->set("SECURED" , $result->getSecured()) ->set("SECURED" , $result->getSecured())
; ;
$loopResult->addRow($loopResultRow); $loopResult->addRow($loopResultRow);
} }

View File

@@ -34,18 +34,22 @@ class SmartyAssetsManager
private $web_root; private $web_root;
private $path_relative_to_web_root; private $path_relative_to_web_root;
private $developmentMode;
/** /**
* Creates a new SmartyAssetsManager instance * Creates a new SmartyAssetsManager instance
* *
* @param string $web_root the disk path to the web root * @param string $web_root the disk path to the web root
* @param string $path_relative_to_web_root the path (relative to web root) where the assets will be generated * @param string $path_relative_to_web_root the path (relative to web root) where the assets will be generated
* @param boolean $developmentMode true / false. If true, assets are not cached, and always generated.
*/ */
public function __construct($web_root, $path_relative_to_web_root) public function __construct($web_root, $path_relative_to_web_root, $developmentMode)
{ {
$this->web_root = $web_root; $this->web_root = $web_root;
$this->path_relative_to_web_root = $path_relative_to_web_root; $this->path_relative_to_web_root = $path_relative_to_web_root;
$this->developmentMode = $developmentMode;
$this->assetic_manager = new AsseticHelper(); $this->assetic_manager = new AsseticHelper();
} }
@@ -70,10 +74,11 @@ class SmartyAssetsManager
$url = $this->assetic_manager->asseticize( $url = $this->assetic_manager->asseticize(
$asset_dir.'/'.$asset_file, $asset_dir.'/'.$asset_file,
$this->web_root."/".$this->path_relative_to_web_root, $this->web_root."/".$this->path_relative_to_web_root,
URL::absoluteUrl($this->path_relative_to_web_root, null, URL::PATH_TO_FILE /* path only */), URL::getInstance()->absoluteUrl($this->path_relative_to_web_root, null, URL::PATH_TO_FILE /* path only */),
$assetType, $assetType,
$filters, $filters,
$debug $debug,
$this->developmentMode
); );
return $url; return $url;

View File

@@ -70,12 +70,12 @@ class AdminUtilities extends AbstractSmartyPlugin
if ($permissions == null || $this->securityContext->isGranted("ADMIN", array($permission))) { if ($permissions == null || $this->securityContext->isGranted("ADMIN", array($permission))) {
return sprintf( return sprintf(
'<a href="%s"><i class="icon-arrow-up"></i></a><span class="%s" data-id="%s">%s</span><a href="%s"><i class="icon-arrow-down"></i></a>', '<a href="%s"><i class="glyphicon glyphicon-arrow-up"></i></a><span class="%s" data-id="%s">%s</span><a href="%s"><i class="glyphicon glyphicon-arrow-down"></i></a>',
URL::absoluteUrl("$path/positionUp", array($url_parameter => $id)), URL::getInstance()->absoluteUrl($path, array('mode' => 'up', $url_parameter => $id)),
$in_place_edit_class, $in_place_edit_class,
$id, $id,
$position, $position,
URL::absoluteUrl("$path/positionDown", array($url_parameter => $id)) URL::getInstance()->absoluteUrl($path, array('mode' => 'down', $url_parameter => $id))
); );
} }
else { else {
@@ -121,11 +121,11 @@ class AdminUtilities extends AbstractSmartyPlugin
} }
if (! empty($icon)) if (! empty($icon))
$output = sprintf('<i class="icon icon-chevron-%s"></i> ', $icon); $output = sprintf('<i class="glyphicon glyphicon-chevron-%s"></i> ', $icon);
else else
$output = ''; $output = '';
return sprintf('%s<a href="%s">%s</a>', $output, URL::absoluteUrl($path, array('order' => $order_change)), $label); return sprintf('%s<a href="%s">%s</a>', $output, URL::getInstance()->absoluteUrl($path, array('order' => $order_change)), $label);
} }

View File

@@ -32,13 +32,13 @@ class Assetic extends AbstractSmartyPlugin
{ {
public $assetManager; public $assetManager;
public function __construct() public function __construct($developmentMode)
{ {
$web_root = THELIA_WEB_DIR; $web_root = THELIA_WEB_DIR;
$asset_dir_from_web_root = ConfigQuery::read('asset_dir_from_web_root', 'assets'); $asset_dir_from_web_root = ConfigQuery::read('asset_dir_from_web_root', 'assets');
$this->assetManager = new SmartyAssetsManager($web_root, $asset_dir_from_web_root); $this->assetManager = new SmartyAssetsManager($web_root, $asset_dir_from_web_root, $developmentMode == 'dev');
} }
public function blockJavascripts($params, $content, \Smarty_Internal_Template $template, &$repeat) public function blockJavascripts($params, $content, \Smarty_Internal_Template $template, &$repeat)

View File

@@ -68,14 +68,14 @@ class DataAccessFunctions extends AbstractSmartyPlugin
} }
/** /**
* Provides access to user attributes using the accessors. * @param $objectLabel
* @param $user
* @param $params
* *
* @param array $params * @return string
* @param unknown $smarty * @throws \InvalidArgumentException
* @return string the value of the requested attribute
* @throws InvalidArgumentException if the object does not have the requested attribute.
*/ */
protected function userDataAccess($objectLabel, $user, $params) protected function userDataAccess($objectLabel, $user, $params)
{ {
$attribute = $this->getNormalizedParam($params, array('attribute', 'attrib', 'attr')); $attribute = $this->getNormalizedParam($params, array('attribute', 'attrib', 'attr'));

View File

@@ -130,6 +130,7 @@ class Form extends AbstractSmartyPlugin
} }
$template->assign("label", $formFieldView->vars["label"]); $template->assign("label", $formFieldView->vars["label"]);
$template->assign("label_attr", $formFieldView->vars["label_attr"]);
$errors = $formFieldView->vars["errors"]; $errors = $formFieldView->vars["errors"];

View File

@@ -136,8 +136,23 @@ class TheliaLoop extends AbstractSmartyPlugin
} }
if ($loopResults->valid()) { if ($loopResults->valid()) {
$loopResultRow = $loopResults->current(); $loopResultRow = $loopResults->current();
// On first iteration, save variables that may be overwritten by this loop
if (! isset($this->varstack[$name])) {
$saved_vars = array();
$varlist = $loopResultRow->getVars();
foreach ($varlist as $var) {
$saved_vars[$var] = $template->getTemplateVars($var);
}
$this->varstack[$name] = $saved_vars;
}
foreach ($loopResultRow->getVarVal() as $var => $val) { foreach ($loopResultRow->getVarVal() as $var => $val) {
$template->assign($var, $val); $template->assign($var, $val);
} }

View File

@@ -51,7 +51,7 @@ class UrlGenerator extends AbstractSmartyPlugin
$target = $this->getParam($params, 'target', null); $target = $this->getParam($params, 'target', null);
$url = URL::absoluteUrl($path, $this->getArgsFromParam($params, array('path', 'target'))); $url = URL::getInstance()->absoluteUrl($path, $this->getArgsFromParam($params, array('path', 'target')));
if ($target != null) $url .= '#'.$target; if ($target != null) $url .= '#'.$target;
@@ -102,7 +102,7 @@ class UrlGenerator extends AbstractSmartyPlugin
$args = $this->getArgsFromParam($params, array('view', 'action', 'target')); $args = $this->getArgsFromParam($params, array('view', 'action', 'target'));
if (! empty($action)) $args['action'] = $action; if (! empty($action)) $args['action'] = $action;
return $forAdmin ? URL::adminViewUrl($view, $args) : URL::viewUrl($view, $args); return $forAdmin ? URL::getInstance()->adminViewUrl($view, $args) : URL::getInstance()->viewUrl($view, $args);
} }
/** /**
@@ -169,16 +169,16 @@ class UrlGenerator extends AbstractSmartyPlugin
protected function getCurrentUrl() protected function getCurrentUrl()
{ {
return URL::init()->retrieveCurrent($this->request)->toString(); return URL::getInstance()->retrieveCurrent($this->request)->toString();
} }
protected function getReturnToUrl() protected function getReturnToUrl()
{ {
return URL::absoluteUrl($this->request->getSession()->getReturnToUrl()); return URL::getInstance()->absoluteUrl($this->request->getSession()->getReturnToUrl());
} }
protected function getIndexUrl() protected function getIndexUrl()
{ {
return Url::getIndexPage(); return URL::getInstance()->getIndexPage();
} }
} }

View File

@@ -66,6 +66,8 @@ class SmartyParser extends Smarty implements ParserInterface
$this->debugging = $debug; $this->debugging = $debug;
$this->escape_html = true;
// Prevent smarty ErrorException: Notice: Undefined index bla bla bla... // Prevent smarty ErrorException: Notice: Undefined index bla bla bla...
$this->error_reporting = E_ALL ^ E_NOTICE; $this->error_reporting = E_ALL ^ E_NOTICE;

View File

@@ -122,6 +122,11 @@ class TheliaHttpKernel extends HttpKernel
*/ */
protected function initParam(Request $request) protected function initParam(Request $request)
{ {
// Ensure an instaciation of URL service, which is accessed as a pseudo-singleton
// in the rest of the application.
// See Thelia\Tools\URL class.
$this->container->get('thelia.url.manager');
$lang = $this->detectLang($request); $lang = $this->detectLang($request);
if ($lang) { if ($lang) {
@@ -139,6 +144,7 @@ class TheliaHttpKernel extends HttpKernel
protected function detectLang(Request $request) protected function detectLang(Request $request)
{ {
$lang = null; $lang = null;
//first priority => lang parameter present in request (get or post) //first priority => lang parameter present in request (get or post)
if ($request->query->has("lang")) { if ($request->query->has("lang")) {
$lang = Model\LangQuery::create()->findOneByCode($request->query->get("lang")); $lang = Model\LangQuery::create()->findOneByCode($request->query->get("lang"));

View File

@@ -26,11 +26,11 @@ use Symfony\Component\Validator\Constraints\NotBlank;
/** /**
* Class AddressForm * Class AddressCreateForm
* @package Thelia\Form * @package Thelia\Form
* @author Manuel Raynaud <mraynaud@openstudio.fr> * @author Manuel Raynaud <mraynaud@openstudio.fr>
*/ */
class AddressForm extends BaseForm class AddressCreateForm extends BaseForm
{ {
/** /**
@@ -60,7 +60,8 @@ class AddressForm extends BaseForm
"constraints" => array( "constraints" => array(
new NotBlank() new NotBlank()
), ),
"label" => "address name" "label" => "address name",
"required" => true
)) ))
->add("title", "text", array( ->add("title", "text", array(
"constraints" => array( "constraints" => array(

View File

@@ -0,0 +1,69 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Form;
use Symfony\Component\Validator\Constraints\NotBlank;
/**
* Class AddressUpdateForm
* @package Thelia\Form
* @author Manuel Raynaud <mraynaud@openstudio.fr>
*/
class AddressUpdateForm extends AddressCreateForm {
/**
*
* in this function you add all the fields you need for your Form.
* Form this you have to call add method on $this->formBuilder attribute :
*
* $this->formBuilder->add("name", "text")
* ->add("email", "email", array(
* "attr" => array(
* "class" => "field"
* ),
* "label" => "email",
* "constraints" => array(
* new \Symfony\Component\Validator\Constraints\NotBlank()
* )
* )
* )
* ->add('age', 'integer');
*
* @return null
*/
protected function buildForm()
{
parent::buildForm();
}
/**
* @return string the name of you form. This name must be unique
*/
public function getName()
{
return "thelia_address_update";
}
}

View File

@@ -135,7 +135,7 @@ abstract class BaseForm
$successUrl = $default; $successUrl = $default;
} }
return URL::absoluteUrl($successUrl); return URL::getInstance()->absoluteUrl($successUrl);
} }
public function createView() public function createView()

View File

@@ -67,6 +67,10 @@ class CartAdd extends BaseForm
new Constraints\Callback(array("methods" => array( new Constraints\Callback(array("methods" => array(
array($this, "checkProduct") array($this, "checkProduct")
))) )))
),
"label" => "product",
"label_attr" => array(
"for" => "cart_product"
) )
)) ))
->add("product_sale_elements_id", "text", array( ->add("product_sale_elements_id", "text", array(

View File

@@ -32,6 +32,10 @@ class CategoryCreationForm extends BaseForm
->add("title", "text", array( ->add("title", "text", array(
"constraints" => array( "constraints" => array(
new NotBlank() new NotBlank()
),
"label" => "Category title *",
"label_attr" => array(
"for" => "title"
) )
)) ))
->add("parent", "integer", array( ->add("parent", "integer", array(

View File

@@ -40,11 +40,47 @@ class CurrencyCreationForm extends BaseForm
} }
$this->formBuilder $this->formBuilder
->add("name" , "text" , array("constraints" => array(new NotBlank()))) ->add("name" , "text" , array(
->add("locale" , "text" , array("constraints" => array(new NotBlank()))) "constraints" => array(
->add("symbol" , "text" , array("constraints" => array(new NotBlank()))) new NotBlank()
->add("rate" , "text" , array("constraints" => array(new NotBlank()))) ),
->add("code" , "text" , array("constraints" => $code_constraints)) "label" => "Name *",
"label_attr" => array(
"for" => "name"
))
)
->add("locale" , "text" , array(
"constraints" => array(
new NotBlank()
))
)
->add("symbol" , "text" , array(
"constraints" => array(
new NotBlank()
),
"label" => "Symbol *",
"label_attr" => array(
"for" => "symbol"
))
)
->add("rate" , "text" , array(
"constraints" => array(
new NotBlank()
),
"label" => "Rate from &euro; *",
"label_attr" => array(
"for" => "rate"
))
)
->add("code" , "text" , array(
"constraints" => array(
new NotBlank()
),
"label" => "ISO 4217 code *",
"label_attr" => array(
"for" => "iso_4217_code"
))
)
; ;
} }

View File

@@ -2,21 +2,73 @@
namespace Thelia\Model; namespace Thelia\Model;
use Propel\Runtime\Connection\ConnectionInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Thelia\Core\Event\AddressEvent;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Model\Base\Address as BaseAddress; use Thelia\Model\Base\Address as BaseAddress;
class Address extends BaseAddress { class Address extends BaseAddress {
use \Thelia\Model\Tools\ModelEventDispatcherTrait;
protected $dispatcher; /**
* Code to be run before inserting to database
public function setDispatcher(EventDispatcherInterface $dispatcher) * @param ConnectionInterface $con
* @return boolean
*/
public function preInsert(ConnectionInterface $con = null)
{ {
$this->dispatcher = $dispatcher; $this->dispatchEvent(TheliaEvents::BEFORE_CREATEADDRESS, new AddressEvent($this));
return true;
} }
public function getDispatcher() /**
* Code to be run after inserting to database
* @param ConnectionInterface $con
*/
public function postInsert(ConnectionInterface $con = null)
{ {
return $this->dispatcher; $this->dispatchEvent(TheliaEvents::AFTER_CREATEADDRESS, new AddressEvent($this));
}
/**
* Code to be run before updating the object in database
* @param ConnectionInterface $con
* @return boolean
*/
public function preUpdate(ConnectionInterface $con = null)
{
$this->dispatchEvent(TheliaEvents::BEFORE_UPDATEADDRESS, new AddressEvent($this));
return true;
}
/**
* Code to be run after updating the object in database
* @param ConnectionInterface $con
*/
public function postUpdate(ConnectionInterface $con = null)
{
$this->dispatchEvent(TheliaEvents::AFTER_UPDATEADDRESS, new AddressEvent($this));
}
/**
* Code to be run before deleting the object in database
* @param ConnectionInterface $con
* @return boolean
*/
public function preDelete(ConnectionInterface $con = null)
{
$this->dispatchEvent(TheliaEvents::BEFORE_DELETEADDRESS, new AddressEvent($this));
return true;
}
/**
* Code to be run after deleting the object in database
* @param ConnectionInterface $con
*/
public function postDelete(ConnectionInterface $con = null)
{
$this->dispatchEvent(TheliaEvents::AFTER_DELETEADDRESS, new AddressEvent($this));
} }
} }

View File

@@ -85,10 +85,40 @@ abstract class Lang implements ActiveRecordInterface
protected $url; protected $url;
/** /**
* The value for the position field. * The value for the date_format field.
* @var int * @var string
*/ */
protected $position; protected $date_format;
/**
* The value for the time_format field.
* @var string
*/
protected $time_format;
/**
* The value for the datetime_format field.
* @var string
*/
protected $datetime_format;
/**
* The value for the decimal_separator field.
* @var string
*/
protected $decimal_separator;
/**
* The value for the thousands_separator field.
* @var string
*/
protected $thousands_separator;
/**
* The value for the decimals field.
* @var string
*/
protected $decimals;
/** /**
* The value for the by_default field. * The value for the by_default field.
@@ -96,6 +126,12 @@ abstract class Lang implements ActiveRecordInterface
*/ */
protected $by_default; protected $by_default;
/**
* The value for the position field.
* @var int
*/
protected $position;
/** /**
* The value for the created_at field. * The value for the created_at field.
* @var string * @var string
@@ -426,14 +462,69 @@ abstract class Lang implements ActiveRecordInterface
} }
/** /**
* Get the [position] column value. * Get the [date_format] column value.
* *
* @return int * @return string
*/ */
public function getPosition() public function getDateFormat()
{ {
return $this->position; return $this->date_format;
}
/**
* Get the [time_format] column value.
*
* @return string
*/
public function getTimeFormat()
{
return $this->time_format;
}
/**
* Get the [datetime_format] column value.
*
* @return string
*/
public function getDatetimeFormat()
{
return $this->datetime_format;
}
/**
* Get the [decimal_separator] column value.
*
* @return string
*/
public function getDecimalSeparator()
{
return $this->decimal_separator;
}
/**
* Get the [thousands_separator] column value.
*
* @return string
*/
public function getThousandsSeparator()
{
return $this->thousands_separator;
}
/**
* Get the [decimals] column value.
*
* @return string
*/
public function getDecimals()
{
return $this->decimals;
} }
/** /**
@@ -447,6 +538,17 @@ abstract class Lang implements ActiveRecordInterface
return $this->by_default; return $this->by_default;
} }
/**
* Get the [position] column value.
*
* @return int
*/
public function getPosition()
{
return $this->position;
}
/** /**
* Get the [optionally formatted] temporal [created_at] column value. * Get the [optionally formatted] temporal [created_at] column value.
* *
@@ -593,25 +695,130 @@ abstract class Lang implements ActiveRecordInterface
} // setUrl() } // setUrl()
/** /**
* Set the value of [position] column. * Set the value of [date_format] column.
* *
* @param int $v new value * @param string $v new value
* @return \Thelia\Model\Lang The current object (for fluent API support) * @return \Thelia\Model\Lang The current object (for fluent API support)
*/ */
public function setPosition($v) public function setDateFormat($v)
{ {
if ($v !== null) { if ($v !== null) {
$v = (int) $v; $v = (string) $v;
} }
if ($this->position !== $v) { if ($this->date_format !== $v) {
$this->position = $v; $this->date_format = $v;
$this->modifiedColumns[] = LangTableMap::POSITION; $this->modifiedColumns[] = LangTableMap::DATE_FORMAT;
} }
return $this; return $this;
} // setPosition() } // setDateFormat()
/**
* Set the value of [time_format] column.
*
* @param string $v new value
* @return \Thelia\Model\Lang The current object (for fluent API support)
*/
public function setTimeFormat($v)
{
if ($v !== null) {
$v = (string) $v;
}
if ($this->time_format !== $v) {
$this->time_format = $v;
$this->modifiedColumns[] = LangTableMap::TIME_FORMAT;
}
return $this;
} // setTimeFormat()
/**
* Set the value of [datetime_format] column.
*
* @param string $v new value
* @return \Thelia\Model\Lang The current object (for fluent API support)
*/
public function setDatetimeFormat($v)
{
if ($v !== null) {
$v = (string) $v;
}
if ($this->datetime_format !== $v) {
$this->datetime_format = $v;
$this->modifiedColumns[] = LangTableMap::DATETIME_FORMAT;
}
return $this;
} // setDatetimeFormat()
/**
* Set the value of [decimal_separator] column.
*
* @param string $v new value
* @return \Thelia\Model\Lang The current object (for fluent API support)
*/
public function setDecimalSeparator($v)
{
if ($v !== null) {
$v = (string) $v;
}
if ($this->decimal_separator !== $v) {
$this->decimal_separator = $v;
$this->modifiedColumns[] = LangTableMap::DECIMAL_SEPARATOR;
}
return $this;
} // setDecimalSeparator()
/**
* Set the value of [thousands_separator] column.
*
* @param string $v new value
* @return \Thelia\Model\Lang The current object (for fluent API support)
*/
public function setThousandsSeparator($v)
{
if ($v !== null) {
$v = (string) $v;
}
if ($this->thousands_separator !== $v) {
$this->thousands_separator = $v;
$this->modifiedColumns[] = LangTableMap::THOUSANDS_SEPARATOR;
}
return $this;
} // setThousandsSeparator()
/**
* Set the value of [decimals] column.
*
* @param string $v new value
* @return \Thelia\Model\Lang The current object (for fluent API support)
*/
public function setDecimals($v)
{
if ($v !== null) {
$v = (string) $v;
}
if ($this->decimals !== $v) {
$this->decimals = $v;
$this->modifiedColumns[] = LangTableMap::DECIMALS;
}
return $this;
} // setDecimals()
/** /**
* Set the value of [by_default] column. * Set the value of [by_default] column.
@@ -634,6 +841,27 @@ abstract class Lang implements ActiveRecordInterface
return $this; return $this;
} // setByDefault() } // setByDefault()
/**
* Set the value of [position] column.
*
* @param int $v new value
* @return \Thelia\Model\Lang The current object (for fluent API support)
*/
public function setPosition($v)
{
if ($v !== null) {
$v = (int) $v;
}
if ($this->position !== $v) {
$this->position = $v;
$this->modifiedColumns[] = LangTableMap::POSITION;
}
return $this;
} // setPosition()
/** /**
* Sets the value of [created_at] column to a normalized version of the date/time value specified. * Sets the value of [created_at] column to a normalized version of the date/time value specified.
* *
@@ -728,19 +956,37 @@ abstract class Lang implements ActiveRecordInterface
$col = $row[TableMap::TYPE_NUM == $indexType ? 4 + $startcol : LangTableMap::translateFieldName('Url', TableMap::TYPE_PHPNAME, $indexType)]; $col = $row[TableMap::TYPE_NUM == $indexType ? 4 + $startcol : LangTableMap::translateFieldName('Url', TableMap::TYPE_PHPNAME, $indexType)];
$this->url = (null !== $col) ? (string) $col : null; $this->url = (null !== $col) ? (string) $col : null;
$col = $row[TableMap::TYPE_NUM == $indexType ? 5 + $startcol : LangTableMap::translateFieldName('Position', TableMap::TYPE_PHPNAME, $indexType)]; $col = $row[TableMap::TYPE_NUM == $indexType ? 5 + $startcol : LangTableMap::translateFieldName('DateFormat', TableMap::TYPE_PHPNAME, $indexType)];
$this->position = (null !== $col) ? (int) $col : null; $this->date_format = (null !== $col) ? (string) $col : null;
$col = $row[TableMap::TYPE_NUM == $indexType ? 6 + $startcol : LangTableMap::translateFieldName('ByDefault', TableMap::TYPE_PHPNAME, $indexType)]; $col = $row[TableMap::TYPE_NUM == $indexType ? 6 + $startcol : LangTableMap::translateFieldName('TimeFormat', TableMap::TYPE_PHPNAME, $indexType)];
$this->time_format = (null !== $col) ? (string) $col : null;
$col = $row[TableMap::TYPE_NUM == $indexType ? 7 + $startcol : LangTableMap::translateFieldName('DatetimeFormat', TableMap::TYPE_PHPNAME, $indexType)];
$this->datetime_format = (null !== $col) ? (string) $col : null;
$col = $row[TableMap::TYPE_NUM == $indexType ? 8 + $startcol : LangTableMap::translateFieldName('DecimalSeparator', TableMap::TYPE_PHPNAME, $indexType)];
$this->decimal_separator = (null !== $col) ? (string) $col : null;
$col = $row[TableMap::TYPE_NUM == $indexType ? 9 + $startcol : LangTableMap::translateFieldName('ThousandsSeparator', TableMap::TYPE_PHPNAME, $indexType)];
$this->thousands_separator = (null !== $col) ? (string) $col : null;
$col = $row[TableMap::TYPE_NUM == $indexType ? 10 + $startcol : LangTableMap::translateFieldName('Decimals', TableMap::TYPE_PHPNAME, $indexType)];
$this->decimals = (null !== $col) ? (string) $col : null;
$col = $row[TableMap::TYPE_NUM == $indexType ? 11 + $startcol : LangTableMap::translateFieldName('ByDefault', TableMap::TYPE_PHPNAME, $indexType)];
$this->by_default = (null !== $col) ? (int) $col : null; $this->by_default = (null !== $col) ? (int) $col : null;
$col = $row[TableMap::TYPE_NUM == $indexType ? 7 + $startcol : LangTableMap::translateFieldName('CreatedAt', TableMap::TYPE_PHPNAME, $indexType)]; $col = $row[TableMap::TYPE_NUM == $indexType ? 12 + $startcol : LangTableMap::translateFieldName('Position', TableMap::TYPE_PHPNAME, $indexType)];
$this->position = (null !== $col) ? (int) $col : null;
$col = $row[TableMap::TYPE_NUM == $indexType ? 13 + $startcol : LangTableMap::translateFieldName('CreatedAt', TableMap::TYPE_PHPNAME, $indexType)];
if ($col === '0000-00-00 00:00:00') { if ($col === '0000-00-00 00:00:00') {
$col = null; $col = null;
} }
$this->created_at = (null !== $col) ? PropelDateTime::newInstance($col, null, '\DateTime') : null; $this->created_at = (null !== $col) ? PropelDateTime::newInstance($col, null, '\DateTime') : null;
$col = $row[TableMap::TYPE_NUM == $indexType ? 8 + $startcol : LangTableMap::translateFieldName('UpdatedAt', TableMap::TYPE_PHPNAME, $indexType)]; $col = $row[TableMap::TYPE_NUM == $indexType ? 14 + $startcol : LangTableMap::translateFieldName('UpdatedAt', TableMap::TYPE_PHPNAME, $indexType)];
if ($col === '0000-00-00 00:00:00') { if ($col === '0000-00-00 00:00:00') {
$col = null; $col = null;
} }
@@ -753,7 +999,7 @@ abstract class Lang implements ActiveRecordInterface
$this->ensureConsistency(); $this->ensureConsistency();
} }
return $startcol + 9; // 9 = LangTableMap::NUM_HYDRATE_COLUMNS. return $startcol + 15; // 15 = LangTableMap::NUM_HYDRATE_COLUMNS.
} catch (Exception $e) { } catch (Exception $e) {
throw new PropelException("Error populating \Thelia\Model\Lang object", 0, $e); throw new PropelException("Error populating \Thelia\Model\Lang object", 0, $e);
@@ -988,12 +1234,30 @@ abstract class Lang implements ActiveRecordInterface
if ($this->isColumnModified(LangTableMap::URL)) { if ($this->isColumnModified(LangTableMap::URL)) {
$modifiedColumns[':p' . $index++] = 'URL'; $modifiedColumns[':p' . $index++] = 'URL';
} }
if ($this->isColumnModified(LangTableMap::POSITION)) { if ($this->isColumnModified(LangTableMap::DATE_FORMAT)) {
$modifiedColumns[':p' . $index++] = 'POSITION'; $modifiedColumns[':p' . $index++] = 'DATE_FORMAT';
}
if ($this->isColumnModified(LangTableMap::TIME_FORMAT)) {
$modifiedColumns[':p' . $index++] = 'TIME_FORMAT';
}
if ($this->isColumnModified(LangTableMap::DATETIME_FORMAT)) {
$modifiedColumns[':p' . $index++] = 'DATETIME_FORMAT';
}
if ($this->isColumnModified(LangTableMap::DECIMAL_SEPARATOR)) {
$modifiedColumns[':p' . $index++] = 'DECIMAL_SEPARATOR';
}
if ($this->isColumnModified(LangTableMap::THOUSANDS_SEPARATOR)) {
$modifiedColumns[':p' . $index++] = 'THOUSANDS_SEPARATOR';
}
if ($this->isColumnModified(LangTableMap::DECIMALS)) {
$modifiedColumns[':p' . $index++] = 'DECIMALS';
} }
if ($this->isColumnModified(LangTableMap::BY_DEFAULT)) { if ($this->isColumnModified(LangTableMap::BY_DEFAULT)) {
$modifiedColumns[':p' . $index++] = 'BY_DEFAULT'; $modifiedColumns[':p' . $index++] = 'BY_DEFAULT';
} }
if ($this->isColumnModified(LangTableMap::POSITION)) {
$modifiedColumns[':p' . $index++] = 'POSITION';
}
if ($this->isColumnModified(LangTableMap::CREATED_AT)) { if ($this->isColumnModified(LangTableMap::CREATED_AT)) {
$modifiedColumns[':p' . $index++] = 'CREATED_AT'; $modifiedColumns[':p' . $index++] = 'CREATED_AT';
} }
@@ -1026,12 +1290,30 @@ abstract class Lang implements ActiveRecordInterface
case 'URL': case 'URL':
$stmt->bindValue($identifier, $this->url, PDO::PARAM_STR); $stmt->bindValue($identifier, $this->url, PDO::PARAM_STR);
break; break;
case 'POSITION': case 'DATE_FORMAT':
$stmt->bindValue($identifier, $this->position, PDO::PARAM_INT); $stmt->bindValue($identifier, $this->date_format, PDO::PARAM_STR);
break;
case 'TIME_FORMAT':
$stmt->bindValue($identifier, $this->time_format, PDO::PARAM_STR);
break;
case 'DATETIME_FORMAT':
$stmt->bindValue($identifier, $this->datetime_format, PDO::PARAM_STR);
break;
case 'DECIMAL_SEPARATOR':
$stmt->bindValue($identifier, $this->decimal_separator, PDO::PARAM_STR);
break;
case 'THOUSANDS_SEPARATOR':
$stmt->bindValue($identifier, $this->thousands_separator, PDO::PARAM_STR);
break;
case 'DECIMALS':
$stmt->bindValue($identifier, $this->decimals, PDO::PARAM_STR);
break; break;
case 'BY_DEFAULT': case 'BY_DEFAULT':
$stmt->bindValue($identifier, $this->by_default, PDO::PARAM_INT); $stmt->bindValue($identifier, $this->by_default, PDO::PARAM_INT);
break; break;
case 'POSITION':
$stmt->bindValue($identifier, $this->position, PDO::PARAM_INT);
break;
case 'CREATED_AT': case 'CREATED_AT':
$stmt->bindValue($identifier, $this->created_at ? $this->created_at->format("Y-m-d H:i:s") : null, PDO::PARAM_STR); $stmt->bindValue($identifier, $this->created_at ? $this->created_at->format("Y-m-d H:i:s") : null, PDO::PARAM_STR);
break; break;
@@ -1116,15 +1398,33 @@ abstract class Lang implements ActiveRecordInterface
return $this->getUrl(); return $this->getUrl();
break; break;
case 5: case 5:
return $this->getPosition(); return $this->getDateFormat();
break; break;
case 6: case 6:
return $this->getByDefault(); return $this->getTimeFormat();
break; break;
case 7: case 7:
return $this->getCreatedAt(); return $this->getDatetimeFormat();
break; break;
case 8: case 8:
return $this->getDecimalSeparator();
break;
case 9:
return $this->getThousandsSeparator();
break;
case 10:
return $this->getDecimals();
break;
case 11:
return $this->getByDefault();
break;
case 12:
return $this->getPosition();
break;
case 13:
return $this->getCreatedAt();
break;
case 14:
return $this->getUpdatedAt(); return $this->getUpdatedAt();
break; break;
default: default:
@@ -1160,10 +1460,16 @@ abstract class Lang implements ActiveRecordInterface
$keys[2] => $this->getCode(), $keys[2] => $this->getCode(),
$keys[3] => $this->getLocale(), $keys[3] => $this->getLocale(),
$keys[4] => $this->getUrl(), $keys[4] => $this->getUrl(),
$keys[5] => $this->getPosition(), $keys[5] => $this->getDateFormat(),
$keys[6] => $this->getByDefault(), $keys[6] => $this->getTimeFormat(),
$keys[7] => $this->getCreatedAt(), $keys[7] => $this->getDatetimeFormat(),
$keys[8] => $this->getUpdatedAt(), $keys[8] => $this->getDecimalSeparator(),
$keys[9] => $this->getThousandsSeparator(),
$keys[10] => $this->getDecimals(),
$keys[11] => $this->getByDefault(),
$keys[12] => $this->getPosition(),
$keys[13] => $this->getCreatedAt(),
$keys[14] => $this->getUpdatedAt(),
); );
$virtualColumns = $this->virtualColumns; $virtualColumns = $this->virtualColumns;
foreach($virtualColumns as $key => $virtualColumn) foreach($virtualColumns as $key => $virtualColumn)
@@ -1220,15 +1526,33 @@ abstract class Lang implements ActiveRecordInterface
$this->setUrl($value); $this->setUrl($value);
break; break;
case 5: case 5:
$this->setPosition($value); $this->setDateFormat($value);
break; break;
case 6: case 6:
$this->setByDefault($value); $this->setTimeFormat($value);
break; break;
case 7: case 7:
$this->setCreatedAt($value); $this->setDatetimeFormat($value);
break; break;
case 8: case 8:
$this->setDecimalSeparator($value);
break;
case 9:
$this->setThousandsSeparator($value);
break;
case 10:
$this->setDecimals($value);
break;
case 11:
$this->setByDefault($value);
break;
case 12:
$this->setPosition($value);
break;
case 13:
$this->setCreatedAt($value);
break;
case 14:
$this->setUpdatedAt($value); $this->setUpdatedAt($value);
break; break;
} // switch() } // switch()
@@ -1260,10 +1584,16 @@ abstract class Lang implements ActiveRecordInterface
if (array_key_exists($keys[2], $arr)) $this->setCode($arr[$keys[2]]); if (array_key_exists($keys[2], $arr)) $this->setCode($arr[$keys[2]]);
if (array_key_exists($keys[3], $arr)) $this->setLocale($arr[$keys[3]]); if (array_key_exists($keys[3], $arr)) $this->setLocale($arr[$keys[3]]);
if (array_key_exists($keys[4], $arr)) $this->setUrl($arr[$keys[4]]); if (array_key_exists($keys[4], $arr)) $this->setUrl($arr[$keys[4]]);
if (array_key_exists($keys[5], $arr)) $this->setPosition($arr[$keys[5]]); if (array_key_exists($keys[5], $arr)) $this->setDateFormat($arr[$keys[5]]);
if (array_key_exists($keys[6], $arr)) $this->setByDefault($arr[$keys[6]]); if (array_key_exists($keys[6], $arr)) $this->setTimeFormat($arr[$keys[6]]);
if (array_key_exists($keys[7], $arr)) $this->setCreatedAt($arr[$keys[7]]); if (array_key_exists($keys[7], $arr)) $this->setDatetimeFormat($arr[$keys[7]]);
if (array_key_exists($keys[8], $arr)) $this->setUpdatedAt($arr[$keys[8]]); if (array_key_exists($keys[8], $arr)) $this->setDecimalSeparator($arr[$keys[8]]);
if (array_key_exists($keys[9], $arr)) $this->setThousandsSeparator($arr[$keys[9]]);
if (array_key_exists($keys[10], $arr)) $this->setDecimals($arr[$keys[10]]);
if (array_key_exists($keys[11], $arr)) $this->setByDefault($arr[$keys[11]]);
if (array_key_exists($keys[12], $arr)) $this->setPosition($arr[$keys[12]]);
if (array_key_exists($keys[13], $arr)) $this->setCreatedAt($arr[$keys[13]]);
if (array_key_exists($keys[14], $arr)) $this->setUpdatedAt($arr[$keys[14]]);
} }
/** /**
@@ -1280,8 +1610,14 @@ abstract class Lang implements ActiveRecordInterface
if ($this->isColumnModified(LangTableMap::CODE)) $criteria->add(LangTableMap::CODE, $this->code); if ($this->isColumnModified(LangTableMap::CODE)) $criteria->add(LangTableMap::CODE, $this->code);
if ($this->isColumnModified(LangTableMap::LOCALE)) $criteria->add(LangTableMap::LOCALE, $this->locale); if ($this->isColumnModified(LangTableMap::LOCALE)) $criteria->add(LangTableMap::LOCALE, $this->locale);
if ($this->isColumnModified(LangTableMap::URL)) $criteria->add(LangTableMap::URL, $this->url); if ($this->isColumnModified(LangTableMap::URL)) $criteria->add(LangTableMap::URL, $this->url);
if ($this->isColumnModified(LangTableMap::POSITION)) $criteria->add(LangTableMap::POSITION, $this->position); if ($this->isColumnModified(LangTableMap::DATE_FORMAT)) $criteria->add(LangTableMap::DATE_FORMAT, $this->date_format);
if ($this->isColumnModified(LangTableMap::TIME_FORMAT)) $criteria->add(LangTableMap::TIME_FORMAT, $this->time_format);
if ($this->isColumnModified(LangTableMap::DATETIME_FORMAT)) $criteria->add(LangTableMap::DATETIME_FORMAT, $this->datetime_format);
if ($this->isColumnModified(LangTableMap::DECIMAL_SEPARATOR)) $criteria->add(LangTableMap::DECIMAL_SEPARATOR, $this->decimal_separator);
if ($this->isColumnModified(LangTableMap::THOUSANDS_SEPARATOR)) $criteria->add(LangTableMap::THOUSANDS_SEPARATOR, $this->thousands_separator);
if ($this->isColumnModified(LangTableMap::DECIMALS)) $criteria->add(LangTableMap::DECIMALS, $this->decimals);
if ($this->isColumnModified(LangTableMap::BY_DEFAULT)) $criteria->add(LangTableMap::BY_DEFAULT, $this->by_default); if ($this->isColumnModified(LangTableMap::BY_DEFAULT)) $criteria->add(LangTableMap::BY_DEFAULT, $this->by_default);
if ($this->isColumnModified(LangTableMap::POSITION)) $criteria->add(LangTableMap::POSITION, $this->position);
if ($this->isColumnModified(LangTableMap::CREATED_AT)) $criteria->add(LangTableMap::CREATED_AT, $this->created_at); if ($this->isColumnModified(LangTableMap::CREATED_AT)) $criteria->add(LangTableMap::CREATED_AT, $this->created_at);
if ($this->isColumnModified(LangTableMap::UPDATED_AT)) $criteria->add(LangTableMap::UPDATED_AT, $this->updated_at); if ($this->isColumnModified(LangTableMap::UPDATED_AT)) $criteria->add(LangTableMap::UPDATED_AT, $this->updated_at);
@@ -1351,8 +1687,14 @@ abstract class Lang implements ActiveRecordInterface
$copyObj->setCode($this->getCode()); $copyObj->setCode($this->getCode());
$copyObj->setLocale($this->getLocale()); $copyObj->setLocale($this->getLocale());
$copyObj->setUrl($this->getUrl()); $copyObj->setUrl($this->getUrl());
$copyObj->setPosition($this->getPosition()); $copyObj->setDateFormat($this->getDateFormat());
$copyObj->setTimeFormat($this->getTimeFormat());
$copyObj->setDatetimeFormat($this->getDatetimeFormat());
$copyObj->setDecimalSeparator($this->getDecimalSeparator());
$copyObj->setThousandsSeparator($this->getThousandsSeparator());
$copyObj->setDecimals($this->getDecimals());
$copyObj->setByDefault($this->getByDefault()); $copyObj->setByDefault($this->getByDefault());
$copyObj->setPosition($this->getPosition());
$copyObj->setCreatedAt($this->getCreatedAt()); $copyObj->setCreatedAt($this->getCreatedAt());
$copyObj->setUpdatedAt($this->getUpdatedAt()); $copyObj->setUpdatedAt($this->getUpdatedAt());
if ($makeNew) { if ($makeNew) {
@@ -1393,8 +1735,14 @@ abstract class Lang implements ActiveRecordInterface
$this->code = null; $this->code = null;
$this->locale = null; $this->locale = null;
$this->url = null; $this->url = null;
$this->position = null; $this->date_format = null;
$this->time_format = null;
$this->datetime_format = null;
$this->decimal_separator = null;
$this->thousands_separator = null;
$this->decimals = null;
$this->by_default = null; $this->by_default = null;
$this->position = null;
$this->created_at = null; $this->created_at = null;
$this->updated_at = null; $this->updated_at = null;
$this->alreadyInSave = false; $this->alreadyInSave = false;

View File

@@ -23,8 +23,14 @@ use Thelia\Model\Map\LangTableMap;
* @method ChildLangQuery orderByCode($order = Criteria::ASC) Order by the code column * @method ChildLangQuery orderByCode($order = Criteria::ASC) Order by the code column
* @method ChildLangQuery orderByLocale($order = Criteria::ASC) Order by the locale column * @method ChildLangQuery orderByLocale($order = Criteria::ASC) Order by the locale column
* @method ChildLangQuery orderByUrl($order = Criteria::ASC) Order by the url column * @method ChildLangQuery orderByUrl($order = Criteria::ASC) Order by the url column
* @method ChildLangQuery orderByPosition($order = Criteria::ASC) Order by the position column * @method ChildLangQuery orderByDateFormat($order = Criteria::ASC) Order by the date_format column
* @method ChildLangQuery orderByTimeFormat($order = Criteria::ASC) Order by the time_format column
* @method ChildLangQuery orderByDatetimeFormat($order = Criteria::ASC) Order by the datetime_format column
* @method ChildLangQuery orderByDecimalSeparator($order = Criteria::ASC) Order by the decimal_separator column
* @method ChildLangQuery orderByThousandsSeparator($order = Criteria::ASC) Order by the thousands_separator column
* @method ChildLangQuery orderByDecimals($order = Criteria::ASC) Order by the decimals column
* @method ChildLangQuery orderByByDefault($order = Criteria::ASC) Order by the by_default column * @method ChildLangQuery orderByByDefault($order = Criteria::ASC) Order by the by_default column
* @method ChildLangQuery orderByPosition($order = Criteria::ASC) Order by the position column
* @method ChildLangQuery orderByCreatedAt($order = Criteria::ASC) Order by the created_at column * @method ChildLangQuery orderByCreatedAt($order = Criteria::ASC) Order by the created_at column
* @method ChildLangQuery orderByUpdatedAt($order = Criteria::ASC) Order by the updated_at column * @method ChildLangQuery orderByUpdatedAt($order = Criteria::ASC) Order by the updated_at column
* *
@@ -33,8 +39,14 @@ use Thelia\Model\Map\LangTableMap;
* @method ChildLangQuery groupByCode() Group by the code column * @method ChildLangQuery groupByCode() Group by the code column
* @method ChildLangQuery groupByLocale() Group by the locale column * @method ChildLangQuery groupByLocale() Group by the locale column
* @method ChildLangQuery groupByUrl() Group by the url column * @method ChildLangQuery groupByUrl() Group by the url column
* @method ChildLangQuery groupByPosition() Group by the position column * @method ChildLangQuery groupByDateFormat() Group by the date_format column
* @method ChildLangQuery groupByTimeFormat() Group by the time_format column
* @method ChildLangQuery groupByDatetimeFormat() Group by the datetime_format column
* @method ChildLangQuery groupByDecimalSeparator() Group by the decimal_separator column
* @method ChildLangQuery groupByThousandsSeparator() Group by the thousands_separator column
* @method ChildLangQuery groupByDecimals() Group by the decimals column
* @method ChildLangQuery groupByByDefault() Group by the by_default column * @method ChildLangQuery groupByByDefault() Group by the by_default column
* @method ChildLangQuery groupByPosition() Group by the position column
* @method ChildLangQuery groupByCreatedAt() Group by the created_at column * @method ChildLangQuery groupByCreatedAt() Group by the created_at column
* @method ChildLangQuery groupByUpdatedAt() Group by the updated_at column * @method ChildLangQuery groupByUpdatedAt() Group by the updated_at column
* *
@@ -50,8 +62,14 @@ use Thelia\Model\Map\LangTableMap;
* @method ChildLang findOneByCode(string $code) Return the first ChildLang filtered by the code column * @method ChildLang findOneByCode(string $code) Return the first ChildLang filtered by the code column
* @method ChildLang findOneByLocale(string $locale) Return the first ChildLang filtered by the locale column * @method ChildLang findOneByLocale(string $locale) Return the first ChildLang filtered by the locale column
* @method ChildLang findOneByUrl(string $url) Return the first ChildLang filtered by the url column * @method ChildLang findOneByUrl(string $url) Return the first ChildLang filtered by the url column
* @method ChildLang findOneByPosition(int $position) Return the first ChildLang filtered by the position column * @method ChildLang findOneByDateFormat(string $date_format) Return the first ChildLang filtered by the date_format column
* @method ChildLang findOneByTimeFormat(string $time_format) Return the first ChildLang filtered by the time_format column
* @method ChildLang findOneByDatetimeFormat(string $datetime_format) Return the first ChildLang filtered by the datetime_format column
* @method ChildLang findOneByDecimalSeparator(string $decimal_separator) Return the first ChildLang filtered by the decimal_separator column
* @method ChildLang findOneByThousandsSeparator(string $thousands_separator) Return the first ChildLang filtered by the thousands_separator column
* @method ChildLang findOneByDecimals(string $decimals) Return the first ChildLang filtered by the decimals column
* @method ChildLang findOneByByDefault(int $by_default) Return the first ChildLang filtered by the by_default column * @method ChildLang findOneByByDefault(int $by_default) Return the first ChildLang filtered by the by_default column
* @method ChildLang findOneByPosition(int $position) Return the first ChildLang filtered by the position column
* @method ChildLang findOneByCreatedAt(string $created_at) Return the first ChildLang filtered by the created_at column * @method ChildLang findOneByCreatedAt(string $created_at) Return the first ChildLang filtered by the created_at column
* @method ChildLang findOneByUpdatedAt(string $updated_at) Return the first ChildLang filtered by the updated_at column * @method ChildLang findOneByUpdatedAt(string $updated_at) Return the first ChildLang filtered by the updated_at column
* *
@@ -60,8 +78,14 @@ use Thelia\Model\Map\LangTableMap;
* @method array findByCode(string $code) Return ChildLang objects filtered by the code column * @method array findByCode(string $code) Return ChildLang objects filtered by the code column
* @method array findByLocale(string $locale) Return ChildLang objects filtered by the locale column * @method array findByLocale(string $locale) Return ChildLang objects filtered by the locale column
* @method array findByUrl(string $url) Return ChildLang objects filtered by the url column * @method array findByUrl(string $url) Return ChildLang objects filtered by the url column
* @method array findByPosition(int $position) Return ChildLang objects filtered by the position column * @method array findByDateFormat(string $date_format) Return ChildLang objects filtered by the date_format column
* @method array findByTimeFormat(string $time_format) Return ChildLang objects filtered by the time_format column
* @method array findByDatetimeFormat(string $datetime_format) Return ChildLang objects filtered by the datetime_format column
* @method array findByDecimalSeparator(string $decimal_separator) Return ChildLang objects filtered by the decimal_separator column
* @method array findByThousandsSeparator(string $thousands_separator) Return ChildLang objects filtered by the thousands_separator column
* @method array findByDecimals(string $decimals) Return ChildLang objects filtered by the decimals column
* @method array findByByDefault(int $by_default) Return ChildLang objects filtered by the by_default column * @method array findByByDefault(int $by_default) Return ChildLang objects filtered by the by_default column
* @method array findByPosition(int $position) Return ChildLang objects filtered by the position column
* @method array findByCreatedAt(string $created_at) Return ChildLang objects filtered by the created_at column * @method array findByCreatedAt(string $created_at) Return ChildLang objects filtered by the created_at column
* @method array findByUpdatedAt(string $updated_at) Return ChildLang objects filtered by the updated_at column * @method array findByUpdatedAt(string $updated_at) Return ChildLang objects filtered by the updated_at column
* *
@@ -152,7 +176,7 @@ abstract class LangQuery extends ModelCriteria
*/ */
protected function findPkSimple($key, $con) protected function findPkSimple($key, $con)
{ {
$sql = 'SELECT ID, TITLE, CODE, LOCALE, URL, POSITION, BY_DEFAULT, CREATED_AT, UPDATED_AT FROM lang WHERE ID = :p0'; $sql = 'SELECT ID, TITLE, CODE, LOCALE, URL, DATE_FORMAT, TIME_FORMAT, DATETIME_FORMAT, DECIMAL_SEPARATOR, THOUSANDS_SEPARATOR, DECIMALS, BY_DEFAULT, POSITION, CREATED_AT, UPDATED_AT FROM lang WHERE ID = :p0';
try { try {
$stmt = $con->prepare($sql); $stmt = $con->prepare($sql);
$stmt->bindValue(':p0', $key, PDO::PARAM_INT); $stmt->bindValue(':p0', $key, PDO::PARAM_INT);
@@ -399,44 +423,177 @@ abstract class LangQuery extends ModelCriteria
} }
/** /**
* Filter the query on the position column * Filter the query on the date_format column
* *
* Example usage: * Example usage:
* <code> * <code>
* $query->filterByPosition(1234); // WHERE position = 1234 * $query->filterByDateFormat('fooValue'); // WHERE date_format = 'fooValue'
* $query->filterByPosition(array(12, 34)); // WHERE position IN (12, 34) * $query->filterByDateFormat('%fooValue%'); // WHERE date_format LIKE '%fooValue%'
* $query->filterByPosition(array('min' => 12)); // WHERE position > 12
* </code> * </code>
* *
* @param mixed $position The value to use as filter. * @param string $dateFormat The value to use as filter.
* Use scalar values for equality. * Accepts wildcards (* and % trigger a LIKE)
* Use array values for in_array() equivalent.
* Use associative array('min' => $minValue, 'max' => $maxValue) for intervals.
* @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL
* *
* @return ChildLangQuery The current query, for fluid interface * @return ChildLangQuery The current query, for fluid interface
*/ */
public function filterByPosition($position = null, $comparison = null) public function filterByDateFormat($dateFormat = null, $comparison = null)
{ {
if (is_array($position)) { if (null === $comparison) {
$useMinMax = false; if (is_array($dateFormat)) {
if (isset($position['min'])) {
$this->addUsingAlias(LangTableMap::POSITION, $position['min'], Criteria::GREATER_EQUAL);
$useMinMax = true;
}
if (isset($position['max'])) {
$this->addUsingAlias(LangTableMap::POSITION, $position['max'], Criteria::LESS_EQUAL);
$useMinMax = true;
}
if ($useMinMax) {
return $this;
}
if (null === $comparison) {
$comparison = Criteria::IN; $comparison = Criteria::IN;
} elseif (preg_match('/[\%\*]/', $dateFormat)) {
$dateFormat = str_replace('*', '%', $dateFormat);
$comparison = Criteria::LIKE;
} }
} }
return $this->addUsingAlias(LangTableMap::POSITION, $position, $comparison); return $this->addUsingAlias(LangTableMap::DATE_FORMAT, $dateFormat, $comparison);
}
/**
* Filter the query on the time_format column
*
* Example usage:
* <code>
* $query->filterByTimeFormat('fooValue'); // WHERE time_format = 'fooValue'
* $query->filterByTimeFormat('%fooValue%'); // WHERE time_format LIKE '%fooValue%'
* </code>
*
* @param string $timeFormat The value to use as filter.
* Accepts wildcards (* and % trigger a LIKE)
* @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL
*
* @return ChildLangQuery The current query, for fluid interface
*/
public function filterByTimeFormat($timeFormat = null, $comparison = null)
{
if (null === $comparison) {
if (is_array($timeFormat)) {
$comparison = Criteria::IN;
} elseif (preg_match('/[\%\*]/', $timeFormat)) {
$timeFormat = str_replace('*', '%', $timeFormat);
$comparison = Criteria::LIKE;
}
}
return $this->addUsingAlias(LangTableMap::TIME_FORMAT, $timeFormat, $comparison);
}
/**
* Filter the query on the datetime_format column
*
* Example usage:
* <code>
* $query->filterByDatetimeFormat('fooValue'); // WHERE datetime_format = 'fooValue'
* $query->filterByDatetimeFormat('%fooValue%'); // WHERE datetime_format LIKE '%fooValue%'
* </code>
*
* @param string $datetimeFormat The value to use as filter.
* Accepts wildcards (* and % trigger a LIKE)
* @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL
*
* @return ChildLangQuery The current query, for fluid interface
*/
public function filterByDatetimeFormat($datetimeFormat = null, $comparison = null)
{
if (null === $comparison) {
if (is_array($datetimeFormat)) {
$comparison = Criteria::IN;
} elseif (preg_match('/[\%\*]/', $datetimeFormat)) {
$datetimeFormat = str_replace('*', '%', $datetimeFormat);
$comparison = Criteria::LIKE;
}
}
return $this->addUsingAlias(LangTableMap::DATETIME_FORMAT, $datetimeFormat, $comparison);
}
/**
* Filter the query on the decimal_separator column
*
* Example usage:
* <code>
* $query->filterByDecimalSeparator('fooValue'); // WHERE decimal_separator = 'fooValue'
* $query->filterByDecimalSeparator('%fooValue%'); // WHERE decimal_separator LIKE '%fooValue%'
* </code>
*
* @param string $decimalSeparator The value to use as filter.
* Accepts wildcards (* and % trigger a LIKE)
* @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL
*
* @return ChildLangQuery The current query, for fluid interface
*/
public function filterByDecimalSeparator($decimalSeparator = null, $comparison = null)
{
if (null === $comparison) {
if (is_array($decimalSeparator)) {
$comparison = Criteria::IN;
} elseif (preg_match('/[\%\*]/', $decimalSeparator)) {
$decimalSeparator = str_replace('*', '%', $decimalSeparator);
$comparison = Criteria::LIKE;
}
}
return $this->addUsingAlias(LangTableMap::DECIMAL_SEPARATOR, $decimalSeparator, $comparison);
}
/**
* Filter the query on the thousands_separator column
*
* Example usage:
* <code>
* $query->filterByThousandsSeparator('fooValue'); // WHERE thousands_separator = 'fooValue'
* $query->filterByThousandsSeparator('%fooValue%'); // WHERE thousands_separator LIKE '%fooValue%'
* </code>
*
* @param string $thousandsSeparator The value to use as filter.
* Accepts wildcards (* and % trigger a LIKE)
* @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL
*
* @return ChildLangQuery The current query, for fluid interface
*/
public function filterByThousandsSeparator($thousandsSeparator = null, $comparison = null)
{
if (null === $comparison) {
if (is_array($thousandsSeparator)) {
$comparison = Criteria::IN;
} elseif (preg_match('/[\%\*]/', $thousandsSeparator)) {
$thousandsSeparator = str_replace('*', '%', $thousandsSeparator);
$comparison = Criteria::LIKE;
}
}
return $this->addUsingAlias(LangTableMap::THOUSANDS_SEPARATOR, $thousandsSeparator, $comparison);
}
/**
* Filter the query on the decimals column
*
* Example usage:
* <code>
* $query->filterByDecimals('fooValue'); // WHERE decimals = 'fooValue'
* $query->filterByDecimals('%fooValue%'); // WHERE decimals LIKE '%fooValue%'
* </code>
*
* @param string $decimals The value to use as filter.
* Accepts wildcards (* and % trigger a LIKE)
* @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL
*
* @return ChildLangQuery The current query, for fluid interface
*/
public function filterByDecimals($decimals = null, $comparison = null)
{
if (null === $comparison) {
if (is_array($decimals)) {
$comparison = Criteria::IN;
} elseif (preg_match('/[\%\*]/', $decimals)) {
$decimals = str_replace('*', '%', $decimals);
$comparison = Criteria::LIKE;
}
}
return $this->addUsingAlias(LangTableMap::DECIMALS, $decimals, $comparison);
} }
/** /**
@@ -480,6 +637,47 @@ abstract class LangQuery extends ModelCriteria
return $this->addUsingAlias(LangTableMap::BY_DEFAULT, $byDefault, $comparison); return $this->addUsingAlias(LangTableMap::BY_DEFAULT, $byDefault, $comparison);
} }
/**
* Filter the query on the position column
*
* Example usage:
* <code>
* $query->filterByPosition(1234); // WHERE position = 1234
* $query->filterByPosition(array(12, 34)); // WHERE position IN (12, 34)
* $query->filterByPosition(array('min' => 12)); // WHERE position > 12
* </code>
*
* @param mixed $position The value to use as filter.
* Use scalar values for equality.
* Use array values for in_array() equivalent.
* Use associative array('min' => $minValue, 'max' => $maxValue) for intervals.
* @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL
*
* @return ChildLangQuery The current query, for fluid interface
*/
public function filterByPosition($position = null, $comparison = null)
{
if (is_array($position)) {
$useMinMax = false;
if (isset($position['min'])) {
$this->addUsingAlias(LangTableMap::POSITION, $position['min'], Criteria::GREATER_EQUAL);
$useMinMax = true;
}
if (isset($position['max'])) {
$this->addUsingAlias(LangTableMap::POSITION, $position['max'], Criteria::LESS_EQUAL);
$useMinMax = true;
}
if ($useMinMax) {
return $this;
}
if (null === $comparison) {
$comparison = Criteria::IN;
}
}
return $this->addUsingAlias(LangTableMap::POSITION, $position, $comparison);
}
/** /**
* Filter the query on the created_at column * Filter the query on the created_at column
* *

View File

@@ -13,6 +13,8 @@ class Category extends BaseCategory
{ {
use \Thelia\Model\Tools\ModelEventDispatcherTrait; use \Thelia\Model\Tools\ModelEventDispatcherTrait;
use \Thelia\Model\Tools\PositionManagementTrait;
/** /**
* @return int number of child for the current category * @return int number of child for the current category
*/ */
@@ -23,7 +25,7 @@ class Category extends BaseCategory
public function getUrl($locale) public function getUrl($locale)
{ {
return URL::init()->retrieve('category', $this->getId(), $locale)->toString(); return URL::getInstance()->retrieve('category', $this->getId(), $locale)->toString();
} }
/** /**
@@ -46,18 +48,6 @@ class Category extends BaseCategory
$this->save(); $this->save();
} }
public function getNextPosition($parent) {
$last = CategoryQuery::create()
->filterByParent($parent)
->orderByPosition(Criteria::DESC)
->limit(1)
->findOne()
;
return $last != null ? $last->getPosition() + 1 : 1;
}
/** /**
* *
* count all products for current category and sub categories * count all products for current category and sub categories

View File

@@ -9,6 +9,6 @@ class Content extends BaseContent
{ {
public function getUrl($locale) public function getUrl($locale)
{ {
return URL::init()->retrieve('content', $this->getId(), $locale)->toString(); return URL::getInstance()->retrieve('content', $this->getId(), $locale)->toString();
} }
} }

View File

@@ -11,6 +11,8 @@ class Currency extends BaseCurrency {
use \Thelia\Model\Tools\ModelEventDispatcherTrait; use \Thelia\Model\Tools\ModelEventDispatcherTrait;
use \Thelia\Model\Tools\PositionManagementTrait;
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
@@ -18,6 +20,9 @@ class Currency extends BaseCurrency {
{ {
$this->dispatchEvent(TheliaEvents::BEFORE_CREATECURRENCY, new CurrencyEvent($this)); $this->dispatchEvent(TheliaEvents::BEFORE_CREATECURRENCY, new CurrencyEvent($this));
// Set the current position for the new object
$this->setPosition($this->getNextPosition());
return true; return true;
} }

View File

@@ -2,7 +2,7 @@
namespace Thelia\Model; namespace Thelia\Model;
use Symfony\Component\Config\Definition\Exception\Exception; use Propel\Runtime\Exception\PropelException;
use Thelia\Model\AddressQuery; use Thelia\Model\AddressQuery;
use Thelia\Model\Base\Customer as BaseCustomer; use Thelia\Model\Base\Customer as BaseCustomer;
@@ -115,7 +115,7 @@ class Customer extends BaseCustomer implements UserInterface
$con->commit(); $con->commit();
} catch(Exception $e) { } catch(PropelException $e) {
$con->rollback(); $con->rollback();
throw $e; throw $e;
} }
@@ -225,7 +225,7 @@ class Customer extends BaseCustomer implements UserInterface
*/ */
public function preUpdate(ConnectionInterface $con = null) public function preUpdate(ConnectionInterface $con = null)
{ {
$this->dispatchEvent(TheliaEvents::BEFORE_CHANGECUSTOMER, new CustomerEvent($this)); $this->dispatchEvent(TheliaEvents::BEFORE_UPDATECUSTOMER, new CustomerEvent($this));
return true; return true;
} }
@@ -234,7 +234,7 @@ class Customer extends BaseCustomer implements UserInterface
*/ */
public function postUpdate(ConnectionInterface $con = null) public function postUpdate(ConnectionInterface $con = null)
{ {
$this->dispatchEvent(TheliaEvents::AFTER_CHANGECUSTOMER, new CustomerEvent($this)); $this->dispatchEvent(TheliaEvents::AFTER_UPDATECUSTOMER, new CustomerEvent($this));
} }
/** /**

View File

@@ -17,7 +17,7 @@ class Folder extends BaseFolder
public function getUrl($locale) public function getUrl($locale)
{ {
return URL::init()->retrieve('folder', $this->getId(), $locale)->toString(); return URL::getInstance()->retrieve('folder', $this->getId(), $locale)->toString();
} }
/** /**

View File

@@ -9,48 +9,15 @@ class Lang extends BaseLang {
/** /**
* Return the default language object, using a local variable to cache it. * Return the default language object, using a local variable to cache it.
* *
* @throws RuntimeException * @throws \RuntimeException
*/ */
private static $default_lang = null;
public static function getDefaultLanguage() { public static function getDefaultLanguage() {
if (self::$default_lang == null) {
$default_lang = LangQuery::create()->findOneByByDefault(true);
if ($default_lang == null) throw new RuntimeException("No default language is defined. Please define one."); $default_lang = LangQuery::create()->findOneByByDefault(1);
}
if ($default_lang == null) throw new \RuntimeException("No default language is defined. Please define one.");
return $default_lang; return $default_lang;
} }
public function getDateFormat()
{
return "d/m/Y";
}
public function getTimeFormat()
{
return "H:i:s";
}
public function getDateTimeFormat()
{
return "d/m/Y H:i:s";
}
public function getDecimalSeparator()
{
return ".";
}
public function getThousandsSeparator()
{
return " ";
}
public function getDecimals()
{
return 2;
}
} }

View File

@@ -57,7 +57,7 @@ class LangTableMap extends TableMap
/** /**
* The total number of columns * The total number of columns
*/ */
const NUM_COLUMNS = 9; const NUM_COLUMNS = 15;
/** /**
* The number of lazy-loaded columns * The number of lazy-loaded columns
@@ -67,7 +67,7 @@ class LangTableMap extends TableMap
/** /**
* The number of columns to hydrate (NUM_COLUMNS - NUM_LAZY_LOAD_COLUMNS) * The number of columns to hydrate (NUM_COLUMNS - NUM_LAZY_LOAD_COLUMNS)
*/ */
const NUM_HYDRATE_COLUMNS = 9; const NUM_HYDRATE_COLUMNS = 15;
/** /**
* the column name for the ID field * the column name for the ID field
@@ -95,15 +95,45 @@ class LangTableMap extends TableMap
const URL = 'lang.URL'; const URL = 'lang.URL';
/** /**
* the column name for the POSITION field * the column name for the DATE_FORMAT field
*/ */
const POSITION = 'lang.POSITION'; const DATE_FORMAT = 'lang.DATE_FORMAT';
/**
* the column name for the TIME_FORMAT field
*/
const TIME_FORMAT = 'lang.TIME_FORMAT';
/**
* the column name for the DATETIME_FORMAT field
*/
const DATETIME_FORMAT = 'lang.DATETIME_FORMAT';
/**
* the column name for the DECIMAL_SEPARATOR field
*/
const DECIMAL_SEPARATOR = 'lang.DECIMAL_SEPARATOR';
/**
* the column name for the THOUSANDS_SEPARATOR field
*/
const THOUSANDS_SEPARATOR = 'lang.THOUSANDS_SEPARATOR';
/**
* the column name for the DECIMALS field
*/
const DECIMALS = 'lang.DECIMALS';
/** /**
* the column name for the BY_DEFAULT field * the column name for the BY_DEFAULT field
*/ */
const BY_DEFAULT = 'lang.BY_DEFAULT'; const BY_DEFAULT = 'lang.BY_DEFAULT';
/**
* the column name for the POSITION field
*/
const POSITION = 'lang.POSITION';
/** /**
* the column name for the CREATED_AT field * the column name for the CREATED_AT field
*/ */
@@ -126,12 +156,12 @@ class LangTableMap extends TableMap
* e.g. self::$fieldNames[self::TYPE_PHPNAME][0] = 'Id' * e.g. self::$fieldNames[self::TYPE_PHPNAME][0] = 'Id'
*/ */
protected static $fieldNames = array ( protected static $fieldNames = array (
self::TYPE_PHPNAME => array('Id', 'Title', 'Code', 'Locale', 'Url', 'Position', 'ByDefault', 'CreatedAt', 'UpdatedAt', ), self::TYPE_PHPNAME => array('Id', 'Title', 'Code', 'Locale', 'Url', 'DateFormat', 'TimeFormat', 'DatetimeFormat', 'DecimalSeparator', 'ThousandsSeparator', 'Decimals', 'ByDefault', 'Position', 'CreatedAt', 'UpdatedAt', ),
self::TYPE_STUDLYPHPNAME => array('id', 'title', 'code', 'locale', 'url', 'position', 'byDefault', 'createdAt', 'updatedAt', ), self::TYPE_STUDLYPHPNAME => array('id', 'title', 'code', 'locale', 'url', 'dateFormat', 'timeFormat', 'datetimeFormat', 'decimalSeparator', 'thousandsSeparator', 'decimals', 'byDefault', 'position', 'createdAt', 'updatedAt', ),
self::TYPE_COLNAME => array(LangTableMap::ID, LangTableMap::TITLE, LangTableMap::CODE, LangTableMap::LOCALE, LangTableMap::URL, LangTableMap::POSITION, LangTableMap::BY_DEFAULT, LangTableMap::CREATED_AT, LangTableMap::UPDATED_AT, ), self::TYPE_COLNAME => array(LangTableMap::ID, LangTableMap::TITLE, LangTableMap::CODE, LangTableMap::LOCALE, LangTableMap::URL, LangTableMap::DATE_FORMAT, LangTableMap::TIME_FORMAT, LangTableMap::DATETIME_FORMAT, LangTableMap::DECIMAL_SEPARATOR, LangTableMap::THOUSANDS_SEPARATOR, LangTableMap::DECIMALS, LangTableMap::BY_DEFAULT, LangTableMap::POSITION, LangTableMap::CREATED_AT, LangTableMap::UPDATED_AT, ),
self::TYPE_RAW_COLNAME => array('ID', 'TITLE', 'CODE', 'LOCALE', 'URL', 'POSITION', 'BY_DEFAULT', 'CREATED_AT', 'UPDATED_AT', ), self::TYPE_RAW_COLNAME => array('ID', 'TITLE', 'CODE', 'LOCALE', 'URL', 'DATE_FORMAT', 'TIME_FORMAT', 'DATETIME_FORMAT', 'DECIMAL_SEPARATOR', 'THOUSANDS_SEPARATOR', 'DECIMALS', 'BY_DEFAULT', 'POSITION', 'CREATED_AT', 'UPDATED_AT', ),
self::TYPE_FIELDNAME => array('id', 'title', 'code', 'locale', 'url', 'position', 'by_default', 'created_at', 'updated_at', ), self::TYPE_FIELDNAME => array('id', 'title', 'code', 'locale', 'url', 'date_format', 'time_format', 'datetime_format', 'decimal_separator', 'thousands_separator', 'decimals', 'by_default', 'position', 'created_at', 'updated_at', ),
self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, 7, 8, ) self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, )
); );
/** /**
@@ -141,12 +171,12 @@ class LangTableMap extends TableMap
* e.g. self::$fieldKeys[self::TYPE_PHPNAME]['Id'] = 0 * e.g. self::$fieldKeys[self::TYPE_PHPNAME]['Id'] = 0
*/ */
protected static $fieldKeys = array ( protected static $fieldKeys = array (
self::TYPE_PHPNAME => array('Id' => 0, 'Title' => 1, 'Code' => 2, 'Locale' => 3, 'Url' => 4, 'Position' => 5, 'ByDefault' => 6, 'CreatedAt' => 7, 'UpdatedAt' => 8, ), self::TYPE_PHPNAME => array('Id' => 0, 'Title' => 1, 'Code' => 2, 'Locale' => 3, 'Url' => 4, 'DateFormat' => 5, 'TimeFormat' => 6, 'DatetimeFormat' => 7, 'DecimalSeparator' => 8, 'ThousandsSeparator' => 9, 'Decimals' => 10, 'ByDefault' => 11, 'Position' => 12, 'CreatedAt' => 13, 'UpdatedAt' => 14, ),
self::TYPE_STUDLYPHPNAME => array('id' => 0, 'title' => 1, 'code' => 2, 'locale' => 3, 'url' => 4, 'position' => 5, 'byDefault' => 6, 'createdAt' => 7, 'updatedAt' => 8, ), self::TYPE_STUDLYPHPNAME => array('id' => 0, 'title' => 1, 'code' => 2, 'locale' => 3, 'url' => 4, 'dateFormat' => 5, 'timeFormat' => 6, 'datetimeFormat' => 7, 'decimalSeparator' => 8, 'thousandsSeparator' => 9, 'decimals' => 10, 'byDefault' => 11, 'position' => 12, 'createdAt' => 13, 'updatedAt' => 14, ),
self::TYPE_COLNAME => array(LangTableMap::ID => 0, LangTableMap::TITLE => 1, LangTableMap::CODE => 2, LangTableMap::LOCALE => 3, LangTableMap::URL => 4, LangTableMap::POSITION => 5, LangTableMap::BY_DEFAULT => 6, LangTableMap::CREATED_AT => 7, LangTableMap::UPDATED_AT => 8, ), self::TYPE_COLNAME => array(LangTableMap::ID => 0, LangTableMap::TITLE => 1, LangTableMap::CODE => 2, LangTableMap::LOCALE => 3, LangTableMap::URL => 4, LangTableMap::DATE_FORMAT => 5, LangTableMap::TIME_FORMAT => 6, LangTableMap::DATETIME_FORMAT => 7, LangTableMap::DECIMAL_SEPARATOR => 8, LangTableMap::THOUSANDS_SEPARATOR => 9, LangTableMap::DECIMALS => 10, LangTableMap::BY_DEFAULT => 11, LangTableMap::POSITION => 12, LangTableMap::CREATED_AT => 13, LangTableMap::UPDATED_AT => 14, ),
self::TYPE_RAW_COLNAME => array('ID' => 0, 'TITLE' => 1, 'CODE' => 2, 'LOCALE' => 3, 'URL' => 4, 'POSITION' => 5, 'BY_DEFAULT' => 6, 'CREATED_AT' => 7, 'UPDATED_AT' => 8, ), self::TYPE_RAW_COLNAME => array('ID' => 0, 'TITLE' => 1, 'CODE' => 2, 'LOCALE' => 3, 'URL' => 4, 'DATE_FORMAT' => 5, 'TIME_FORMAT' => 6, 'DATETIME_FORMAT' => 7, 'DECIMAL_SEPARATOR' => 8, 'THOUSANDS_SEPARATOR' => 9, 'DECIMALS' => 10, 'BY_DEFAULT' => 11, 'POSITION' => 12, 'CREATED_AT' => 13, 'UPDATED_AT' => 14, ),
self::TYPE_FIELDNAME => array('id' => 0, 'title' => 1, 'code' => 2, 'locale' => 3, 'url' => 4, 'position' => 5, 'by_default' => 6, 'created_at' => 7, 'updated_at' => 8, ), self::TYPE_FIELDNAME => array('id' => 0, 'title' => 1, 'code' => 2, 'locale' => 3, 'url' => 4, 'date_format' => 5, 'time_format' => 6, 'datetime_format' => 7, 'decimal_separator' => 8, 'thousands_separator' => 9, 'decimals' => 10, 'by_default' => 11, 'position' => 12, 'created_at' => 13, 'updated_at' => 14, ),
self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, 7, 8, ) self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, )
); );
/** /**
@@ -170,8 +200,14 @@ class LangTableMap extends TableMap
$this->addColumn('CODE', 'Code', 'VARCHAR', false, 10, null); $this->addColumn('CODE', 'Code', 'VARCHAR', false, 10, null);
$this->addColumn('LOCALE', 'Locale', 'VARCHAR', false, 45, null); $this->addColumn('LOCALE', 'Locale', 'VARCHAR', false, 45, null);
$this->addColumn('URL', 'Url', 'VARCHAR', false, 255, null); $this->addColumn('URL', 'Url', 'VARCHAR', false, 255, null);
$this->addColumn('POSITION', 'Position', 'INTEGER', false, null, null); $this->addColumn('DATE_FORMAT', 'DateFormat', 'VARCHAR', false, 45, null);
$this->addColumn('TIME_FORMAT', 'TimeFormat', 'VARCHAR', false, 45, null);
$this->addColumn('DATETIME_FORMAT', 'DatetimeFormat', 'VARCHAR', false, 45, null);
$this->addColumn('DECIMAL_SEPARATOR', 'DecimalSeparator', 'VARCHAR', false, 45, null);
$this->addColumn('THOUSANDS_SEPARATOR', 'ThousandsSeparator', 'VARCHAR', false, 45, null);
$this->addColumn('DECIMALS', 'Decimals', 'VARCHAR', false, 45, null);
$this->addColumn('BY_DEFAULT', 'ByDefault', 'TINYINT', false, null, null); $this->addColumn('BY_DEFAULT', 'ByDefault', 'TINYINT', false, null, null);
$this->addColumn('POSITION', 'Position', 'INTEGER', false, null, null);
$this->addColumn('CREATED_AT', 'CreatedAt', 'TIMESTAMP', false, null, null); $this->addColumn('CREATED_AT', 'CreatedAt', 'TIMESTAMP', false, null, null);
$this->addColumn('UPDATED_AT', 'UpdatedAt', 'TIMESTAMP', false, null, null); $this->addColumn('UPDATED_AT', 'UpdatedAt', 'TIMESTAMP', false, null, null);
} // initialize() } // initialize()
@@ -339,8 +375,14 @@ class LangTableMap extends TableMap
$criteria->addSelectColumn(LangTableMap::CODE); $criteria->addSelectColumn(LangTableMap::CODE);
$criteria->addSelectColumn(LangTableMap::LOCALE); $criteria->addSelectColumn(LangTableMap::LOCALE);
$criteria->addSelectColumn(LangTableMap::URL); $criteria->addSelectColumn(LangTableMap::URL);
$criteria->addSelectColumn(LangTableMap::POSITION); $criteria->addSelectColumn(LangTableMap::DATE_FORMAT);
$criteria->addSelectColumn(LangTableMap::TIME_FORMAT);
$criteria->addSelectColumn(LangTableMap::DATETIME_FORMAT);
$criteria->addSelectColumn(LangTableMap::DECIMAL_SEPARATOR);
$criteria->addSelectColumn(LangTableMap::THOUSANDS_SEPARATOR);
$criteria->addSelectColumn(LangTableMap::DECIMALS);
$criteria->addSelectColumn(LangTableMap::BY_DEFAULT); $criteria->addSelectColumn(LangTableMap::BY_DEFAULT);
$criteria->addSelectColumn(LangTableMap::POSITION);
$criteria->addSelectColumn(LangTableMap::CREATED_AT); $criteria->addSelectColumn(LangTableMap::CREATED_AT);
$criteria->addSelectColumn(LangTableMap::UPDATED_AT); $criteria->addSelectColumn(LangTableMap::UPDATED_AT);
} else { } else {
@@ -349,8 +391,14 @@ class LangTableMap extends TableMap
$criteria->addSelectColumn($alias . '.CODE'); $criteria->addSelectColumn($alias . '.CODE');
$criteria->addSelectColumn($alias . '.LOCALE'); $criteria->addSelectColumn($alias . '.LOCALE');
$criteria->addSelectColumn($alias . '.URL'); $criteria->addSelectColumn($alias . '.URL');
$criteria->addSelectColumn($alias . '.POSITION'); $criteria->addSelectColumn($alias . '.DATE_FORMAT');
$criteria->addSelectColumn($alias . '.TIME_FORMAT');
$criteria->addSelectColumn($alias . '.DATETIME_FORMAT');
$criteria->addSelectColumn($alias . '.DECIMAL_SEPARATOR');
$criteria->addSelectColumn($alias . '.THOUSANDS_SEPARATOR');
$criteria->addSelectColumn($alias . '.DECIMALS');
$criteria->addSelectColumn($alias . '.BY_DEFAULT'); $criteria->addSelectColumn($alias . '.BY_DEFAULT');
$criteria->addSelectColumn($alias . '.POSITION');
$criteria->addSelectColumn($alias . '.CREATED_AT'); $criteria->addSelectColumn($alias . '.CREATED_AT');
$criteria->addSelectColumn($alias . '.UPDATED_AT'); $criteria->addSelectColumn($alias . '.UPDATED_AT');
} }

View File

@@ -9,6 +9,6 @@ class Product extends BaseProduct
{ {
public function getUrl($locale) public function getUrl($locale)
{ {
return URL::init()->retrieve('product', $this->getId(), $locale)->toString(); return URL::getInstance()->retrieve('product', $this->getId(), $locale)->toString();
} }
} }

View File

@@ -44,6 +44,11 @@ trait ModelEventDispatcherTrait {
return $this; return $this;
} }
public function getDispatcher()
{
return $this->dispatcher;
}
protected function dispatchEvent($eventName, ActionEvent $event) protected function dispatchEvent($eventName, ActionEvent $event)
{ {
if (!is_null($this->dispatcher)) { if (!is_null($this->dispatcher)) {

View File

@@ -0,0 +1,190 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Model\Tools;
use Propel\Runtime\ActiveQuery\PropelQuery;
use Propel\Runtime\ActiveQuery\Criteria;
use Propel\Runtime\Propel;
trait PositionManagementTrait {
/**
* Create an instancer of this object query
*/
private function createQuery() {
return PropelQuery::from(__CLASS__);
}
/**
* Return the database name from this object's table map.
*/
private function getDatabaseNameFromMap() {
$class = new \ReflectionClass(self::TABLE_MAP);
return $class->getConstant('DATABASE_NAME');
}
/**
* Get the position of the next inserted object
*/
public function getNextPosition($parent = null) {
$query = $this->createQuery()
->orderByPosition(Criteria::DESC)
->limit(1);
if ($parent !== null) $last->filterByParent($parent);
$last = $query->findOne()
;
return $last != null ? $last->getPosition() + 1 : 1;
}
/**
* Move up a object
*/
public function movePositionUp() {
$this->movePositionUpOrDown(true);
}
/**
* Move down a object
*/
public function movePositionDown() {
$this->movePositionUpOrDown(false);
}
/**
* Move up or down a object
*
* @param the exchange mode: go up (POSITION_UP) or go down (POSITION_DOWN)
*/
protected function movePositionUpOrDown($up = true)
{
// The current position of the object
$my_position = $this->getPosition();
// Find object to exchange position with
$search = $this->createQuery();
if (method_exists($this, 'getParent')) $search->filterByParent($this->getParent());
// Up or down ?
if ($up === true) {
// Find the object immediately before me
$search->filterByPosition(array('max' => $my_position-1))->orderByPosition(Criteria::DESC);
}
else {
// Find the object immediately after me
$search->filterByPosition(array('min' => $my_position+1))->orderByPosition(Criteria::ASC);
}
$result = $search->findOne();
// If we found the proper object, exchange their positions
if ($result) {
$cnx = Propel::getWriteConnection($this->getDatabaseName());
$cnx->beginTransaction();
try {
$this
->setPosition($result->getPosition())
->save()
;
$result->setDispatcher($this->getDispatcher())->setPosition($my_position)->save();
$cnx->commit();
} catch (Exception $e) {
$cnx->rollback();
}
}
}
/**
* Simply return the database name, from the constant in the MAP class.
*/
protected function getDatabaseName() {
// Find DATABASE_NAME constant
$mapClassName = self::TABLE_MAP;
return $mapClassName::DATABASE_NAME;
}
/**
* Changes object position
*
* @param newPosition
*/
public function changeAbsolutePosition($newPosition)
{
// The current position
$current_position = $this->getPosition();
if ($newPosition != null && $newPosition > 0 && $newPosition != $current_position) {
// Find categories to offset
$search = $this->createQuery();
if (method_exists($this, 'getParent')) $search->filterByParent($this->getParent());
if ($newPosition > $current_position) {
// The new position is after the current position -> we will offset + 1 all categories located between us and the new position
$search->filterByPosition(array('min' => 1+$current_position, 'max' => $newPosition));
$delta = -1;
} else {
// The new position is brefore the current position -> we will offset - 1 all categories located between us and the new position
$search->filterByPosition(array('min' => $newPosition, 'max' => $current_position - 1));
$delta = 1;
}
$results = $search->find();
$cnx = Propel::getWriteConnection($this->getDatabaseName());
$cnx->beginTransaction();
try {
foreach ($results as $result) {
$result->setDispatcher($this->getDispatcher())->setPosition($result->getPosition() + $delta)->save($cnx);
}
$this
->setPosition($newPosition)
->save($cnx)
;
$cnx->commit();
} catch (Exception $e) {
$cnx->rollback();
}
}
}
}

View File

@@ -58,6 +58,8 @@ class RewritingResolver
public function load($rewrittenUrl) public function load($rewrittenUrl)
{ {
$rewrittenUrl = ltrim($rewrittenUrl, '/');
$this->search = $this->rewritingUrlQuery->getResolverSearch($rewrittenUrl); $this->search = $this->rewritingUrlQuery->getResolverSearch($rewrittenUrl);
if($this->search->count() == 0) { if($this->search->count() == 0) {

View File

@@ -66,7 +66,8 @@ class RewritingRetriever
$allParametersWithoutView[$view . '_id'] = $viewId; $allParametersWithoutView[$view . '_id'] = $viewId;
} }
$this->url = URL::viewUrl($view, $allParametersWithoutView); $this->rewrittenUrl = null;
$this->url = URL::getInstance()->viewUrl($view, $allParametersWithoutView);
if($this->search !== null) { if($this->search !== null) {
$this->rewrittenUrl = $this->search->getUrl(); $this->rewrittenUrl = $this->search->getUrl();
} }
@@ -93,7 +94,8 @@ class RewritingRetriever
$allParametersWithoutView[$view . '_id'] = $viewId; $allParametersWithoutView[$view . '_id'] = $viewId;
} }
$this->url = URL::viewUrl($view, $allParametersWithoutView); $this->rewrittenUrl = null;
$this->url = URL::getInstance()->viewUrl($view, $allParametersWithoutView);
if($this->search !== null) { if($this->search !== null) {
$this->rewrittenUrl = $this->search->getUrl(); $this->rewrittenUrl = $this->search->getUrl();
} }

View File

@@ -30,13 +30,14 @@ use Thelia\Core\HttpFoundation\Session\Session;
use Thelia\Action\Image; use Thelia\Action\Image;
use Thelia\Core\Event\ImageEvent; use Thelia\Core\Event\ImageEvent;
use Thelia\Model\ConfigQuery; use Thelia\Model\ConfigQuery;
use Thelia\Tools\URL;
/** /**
* Class ImageTest * Class ImageTest
* *
* @package Thelia\Tests\Action\ImageTest * @package Thelia\Tests\Action\ImageTest
*/ */
class ImageTest extends \PHPUnit_Framework_TestCase class ImageTest extends \Thelia\Tests\TestCaseWithURLToolSetup
{ {
protected $request; protected $request;
@@ -50,6 +51,11 @@ class ImageTest extends \PHPUnit_Framework_TestCase
$container->set("event_dispatcher", $dispatcher); $container->set("event_dispatcher", $dispatcher);
$request = new Request();
$request->setSession($this->session);
$container->set("request", $request);
return $container; return $container;
} }

View File

@@ -47,6 +47,7 @@ class CacheClearTest extends \PHPUnit_Framework_TestCase
$fs = new Filesystem(); $fs = new Filesystem();
$fs->mkdir($this->cache_dir); $fs->mkdir($this->cache_dir);
$fs->mkdir(THELIA_WEB_DIR . "/assets");
} }
public function testCacheClear() public function testCacheClear()

View File

@@ -23,7 +23,7 @@
namespace Thelia\Tests\Controller; namespace Thelia\Tests\Controller;
use Symfony\Component\HttpFoundation\Request; use Thelia\Core\HttpFoundation\Request;
use Thelia\Controller\Front\DefaultController; use Thelia\Controller\Front\DefaultController;
/** /**
@@ -43,7 +43,7 @@ class DefaultControllerTest extends \PHPUnit_Framework_TestCase
$this->assertEquals($request->attributes->get('_view'), "index"); $this->assertEquals($request->attributes->get('_view'), "index");
} }
public function testNoActionWithQuery() public function testNoActionWithGetParam()
{ {
$defaultController = new DefaultController(); $defaultController = new DefaultController();
$request = new Request(array( $request = new Request(array(
@@ -55,15 +55,59 @@ class DefaultControllerTest extends \PHPUnit_Framework_TestCase
$this->assertEquals($request->attributes->get('_view'), 'foo'); $this->assertEquals($request->attributes->get('_view'), 'foo');
} }
public function testNoActionWithRequest() public function testNoActionWithPostParam()
{ {
$defaultController = new DefaultController(); $defaultController = new DefaultController();
$request = new Request(array(), array( $request = new Request(
"view" => "foo" array(),
)); array("view" => "foo")
);
$defaultController->noAction($request); $defaultController->noAction($request);
$this->assertEquals($request->attributes->get('_view'), 'foo'); $this->assertEquals($request->attributes->get('_view'), 'foo');
} }
public function testNoActionWithAttribute()
{
$defaultController = new DefaultController();
$request = new Request(
array(),
array(),
array("_view" => "foo")
);
$defaultController->noAction($request);
$this->assertEquals($request->attributes->get('_view'), 'foo');
}
public function testNoActionWithAttributeAndQuery()
{
$defaultController = new DefaultController();
$request = new Request(
array("view" => "bar"),
array(),
array("_view" => "foo")
);
$defaultController->noAction($request);
$this->assertEquals($request->attributes->get('_view'), 'bar');
}
public function testNoActionWithAttributeAndRequest()
{
$defaultController = new DefaultController();
$request = new Request(
array(),
array("view" => "bar"),
array("_view" => "foo")
);
$defaultController->noAction($request);
$this->assertEquals($request->attributes->get('_view'), 'bar');
}
} }

View File

@@ -34,7 +34,7 @@ use Thelia\Core\HttpFoundation\Session\Session;
* @author Etienne Roudeix <eroudeix@openstudio.fr> * @author Etienne Roudeix <eroudeix@openstudio.fr>
* *
*/ */
abstract class BaseLoopTestor extends \PHPUnit_Framework_TestCase abstract class BaseLoopTestor extends \Thelia\Tests\TestCaseWithURLToolSetup
{ {
protected $request; protected $request;
protected $dispatcher; protected $dispatcher;

View File

@@ -71,7 +71,7 @@ class RewritingRetrieverTest extends \PHPUnit_Framework_TestCase
$retriever->loadViewUrl('view', 'fr_FR', 1); $retriever->loadViewUrl('view', 'fr_FR', 1);
$this->assertEquals('foo.html', $retriever->rewrittenUrl); $this->assertEquals('foo.html', $retriever->rewrittenUrl);
$this->assertEquals(URL::viewUrl('view', array('locale' => 'fr_FR', 'view_id' => 1)), $retriever->url); $this->assertEquals(URL::getInstance()->viewUrl('view', array('locale' => 'fr_FR', 'view_id' => 1)), $retriever->url);
} }
public function testLoadSpecificUrl() public function testLoadSpecificUrl()
@@ -93,6 +93,6 @@ class RewritingRetrieverTest extends \PHPUnit_Framework_TestCase
$retriever->loadSpecificUrl('view', 'fr_FR', 1, array('foo0' => 'bar0', 'foo1' => 'bar1')); $retriever->loadSpecificUrl('view', 'fr_FR', 1, array('foo0' => 'bar0', 'foo1' => 'bar1'));
$this->assertEquals('foo.html', $retriever->rewrittenUrl); $this->assertEquals('foo.html', $retriever->rewrittenUrl);
$this->assertEquals(URL::viewUrl('view', array('foo0' => 'bar0', 'foo1' => 'bar1', 'locale' => 'fr_FR', 'view_id' => 1)), $retriever->url); $this->assertEquals(URL::getInstance()->viewUrl('view', array('foo0' => 'bar0', 'foo1' => 'bar1', 'locale' => 'fr_FR', 'view_id' => 1)), $retriever->url);
} }
} }

View File

@@ -0,0 +1,64 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Tests;
/**
* This class provides URL Tool class initialisation
*
* @package Thelia\Tests\TestCaseWithURLSetup
*/
class TestCaseWithURLToolSetup extends \PHPUnit_Framework_TestCase {
public function __construct() {
$this->setupURLTool();
}
protected function setupURLTool() {
$container = new \Symfony\Component\DependencyInjection\ContainerBuilder();
$context = new \Symfony\Component\Routing\RequestContext(
'/thelia/index.php',
'GET',
'localhost',
'http',
80,
443,
'/path/to/action'
);
$router = $this->getMockBuilder("Symfony\Component\Routing\Router")
->disableOriginalConstructor()
->getMock();
$router->expects($this->any())
->method('getContext')
->will($this->returnValue($context));
$container->set("router.admin", $router);
new \Thelia\Tools\URL($container);
}
}

View File

@@ -28,10 +28,208 @@ use Thelia\Tools\URL;
/** /**
* *
* @author Etienne Roudeix <eroudeix@openstudio.fr> * @author Etienne Roudeix <eroudeix@openstudio.fr>
* @author Franck Allimant <eroudeix@openstudio.fr>
* *
*/ */
class URLTest extends \PHPUnit_Framework_TestCase class URLTest extends \PHPUnit_Framework_TestCase
{ {
protected $context;
public function setUp()
{
$container = new \Symfony\Component\DependencyInjection\ContainerBuilder();
$router = $this->getMockBuilder("Symfony\Component\Routing\Router")
->disableOriginalConstructor()
->getMock();
$this->context = new \Symfony\Component\Routing\RequestContext(
'/thelia/index.php',
'GET',
'localhost',
'http',
80,
443,
'/path/to/action'
);
$router->expects($this->any())
->method('getContext')
->will($this->returnValue($this->context));
$container->set("router.admin", $router);
new \Thelia\Tools\URL($container);
}
public function testGetIndexPage() {
$this->context->setBaseUrl('/thelia/index.php');
$url = \Thelia\Tools\URL::getInstance()->getIndexPage();
$this->assertEquals('http://localhost/thelia/index.php', $url);
$this->context->setBaseUrl('/thelia/');
$url = \Thelia\Tools\URL::getInstance()->getIndexPage();
$this->assertEquals('http://localhost/thelia/', $url);
$this->context->setBaseUrl('/thelia');
$url = \Thelia\Tools\URL::getInstance()->getIndexPage();
$this->assertEquals('http://localhost/thelia', $url);
$this->context->setBaseUrl('/');
$url = \Thelia\Tools\URL::getInstance()->getIndexPage();
$this->assertEquals('http://localhost/', $url);
}
public function testGetBaseUrl() {
$this->context->setBaseUrl('/thelia/index.php');
$url = \Thelia\Tools\URL::getInstance()->getBaseUrl();
$this->assertEquals('http://localhost/thelia/index.php', $url);
$this->context->setBaseUrl('/thelia/');
$url = \Thelia\Tools\URL::getInstance()->getBaseUrl();
$this->assertEquals('http://localhost/thelia/', $url);
$this->context->setBaseUrl('/');
$url = \Thelia\Tools\URL::getInstance()->getBaseUrl();
$this->assertEquals('http://localhost/', $url);
}
public function testAbsoluteUrl() {
$this->context->setBaseUrl('/');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('/path/to/action');
$this->assertEquals('http://localhost/path/to/action', $url);
$this->context->setBaseUrl('/thelia/');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('/path/to/action');
$this->assertEquals('http://localhost/thelia/path/to/action', $url);
$this->context->setBaseUrl('/thelia');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('/path/to/action');
$this->assertEquals('http://localhost/thelia/path/to/action', $url);
$this->context->setBaseUrl('/thelia/index.php');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('/path/to/action');
$this->assertEquals('http://localhost/thelia/index.php/path/to/action', $url);
}
public function testAbsoluteUrlOnAbsolutePath() {
$this->context->setBaseUrl('/thelia/index.php');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('http://myhost/path/to/action');
$this->assertEquals('http://myhost/path/to/action', $url);
$this->context->setBaseUrl('/thelia/');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('http://myhost/path/to/action');
$this->assertEquals('http://myhost/path/to/action', $url);
$this->context->setBaseUrl('/');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('http://myhost/path/to/action');
$this->assertEquals('http://myhost/path/to/action', $url);
}
public function testAbsoluteUrlOnAbsolutePathWithParameters() {
$this->context->setBaseUrl('/thelia/index.php');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('http://myhost/path/to/action', array("p1" => "v1", "p2" => "v2"));
$this->assertEquals('http://myhost/path/to/action?p1=v1&p2=v2', $url);
$this->context->setBaseUrl('/thelia/');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('http://myhost/path/to/action', array("p1" => "v1", "p2" => "v2"));
$this->assertEquals('http://myhost/path/to/action?p1=v1&p2=v2', $url);
$this->context->setBaseUrl('/');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('http://myhost/path/to/action', array("p1" => "v1", "p2" => "v2"));
$this->assertEquals('http://myhost/path/to/action?p1=v1&p2=v2', $url);
}
public function testAbsoluteUrlOnAbsolutePathWithParametersAddParameters() {
$this->context->setBaseUrl('/thelia/index.php');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('http://myhost/path/to/action?p0=v0', array("p1" => "v1", "p2" => "v2"));
$this->assertEquals('http://myhost/path/to/action?p0=v0&p1=v1&p2=v2', $url);
$this->context->setBaseUrl('/thelia/');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('http://myhost/path/to/action?p0=v0', array("p1" => "v1", "p2" => "v2"));
$this->assertEquals('http://myhost/path/to/action?p0=v0&p1=v1&p2=v2', $url);
$this->context->setBaseUrl('/');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('http://myhost/path/to/action?p0=v0', array("p1" => "v1", "p2" => "v2"));
$this->assertEquals('http://myhost/path/to/action?p0=v0&p1=v1&p2=v2', $url);
}
public function testAbsoluteUrlWithParameters() {
$this->context->setBaseUrl('/thelia/index.php');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('/path/to/action', array("p1" => "v1", "p2" => "v2"));
$this->assertEquals('http://localhost/thelia/index.php/path/to/action?p1=v1&p2=v2', $url);
$this->context->setBaseUrl('/thelia/');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('/path/to/action', array("p1" => "v1", "p2" => "v2"));
$this->assertEquals('http://localhost/thelia/path/to/action?p1=v1&p2=v2', $url);
$this->context->setBaseUrl('/thelia');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('/path/to/action', array("p1" => "v1", "p2" => "v2"));
$this->assertEquals('http://localhost/thelia/path/to/action?p1=v1&p2=v2', $url);
$this->context->setBaseUrl('/thelia');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('path/to/action', array("p1" => "v1", "p2" => "v2"));
$this->assertEquals('http://localhost/thelia/path/to/action?p1=v1&p2=v2', $url);
$this->context->setBaseUrl('/');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('/path/to/action', array("p1" => "v1", "p2" => "v2"));
$this->assertEquals('http://localhost/path/to/action?p1=v1&p2=v2', $url);
}
public function testAbsoluteUrlPathOnly() {
$this->context->setBaseUrl('/thelia/index.php');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('/path/to/action', array(), URL::PATH_TO_FILE);
$this->assertEquals('http://localhost/thelia/path/to/action', $url);
}
public function testAbsoluteUrlPathOnlyWithParameters() {
$this->context->setBaseUrl('/thelia/index.php');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('/path/to/action', array("p1" => "v1", "p2" => "v2"), URL::PATH_TO_FILE);
$this->assertEquals('http://localhost/thelia/path/to/action?p1=v1&p2=v2', $url);
$this->context->setBaseUrl('/thelia/');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('/path/to/action', array("p1" => "v1", "p2" => "v2"), URL::PATH_TO_FILE);
$this->assertEquals('http://localhost/thelia/path/to/action?p1=v1&p2=v2', $url);
$this->context->setBaseUrl('/');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('/path/to/action', array("p1" => "v1", "p2" => "v2"), URL::PATH_TO_FILE);
$this->assertEquals('http://localhost/path/to/action?p1=v1&p2=v2', $url);
}
public function testAbsoluteUrlFromIndexWithParameters() {
$this->context->setBaseUrl('/thelia/index.php');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('/', array("p1" => "v1", "p2" => "v2"));
$this->assertEquals('http://localhost/thelia/index.php/?p1=v1&p2=v2', $url);
$this->context->setBaseUrl('/thelia/');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('/', array("p1" => "v1", "p2" => "v2"));
$this->assertEquals('http://localhost/thelia/?p1=v1&p2=v2', $url);
$this->context->setBaseUrl('/');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('/', array("p1" => "v1", "p2" => "v2"));
$this->assertEquals('http://localhost/?p1=v1&p2=v2', $url);
}
public function testAbsoluteUrlPathOnlyFromIndexWithParameters() {
$this->context->setBaseUrl('/thelia/index.php');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('/', array("p1" => "v1", "p2" => "v2"), URL::PATH_TO_FILE);
$this->assertEquals('http://localhost/thelia/?p1=v1&p2=v2', $url);
$this->context->setBaseUrl('/thelia/');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('/', array("p1" => "v1", "p2" => "v2"), URL::PATH_TO_FILE);
$this->assertEquals('http://localhost/thelia/?p1=v1&p2=v2', $url);
$this->context->setBaseUrl('/');
$url = \Thelia\Tools\URL::getInstance()->absoluteUrl('/', array("p1" => "v1", "p2" => "v2"), URL::PATH_TO_FILE);
$this->assertEquals('http://localhost/?p1=v1&p2=v2', $url);
}
public function testRetrieve() public function testRetrieve()
{ {

View File

@@ -23,38 +23,89 @@
namespace Thelia\Tools; namespace Thelia\Tools;
use Symfony\Component\HttpFoundation\Request;
use Thelia\Model\ConfigQuery; use Thelia\Model\ConfigQuery;
use Thelia\Rewriting\RewritingResolver; use Thelia\Rewriting\RewritingResolver;
use Thelia\Rewriting\RewritingRetriever; use Thelia\Rewriting\RewritingRetriever;
use Thelia\Core\HttpFoundation\Request;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Routing\RequestContext;
class URL class URL
{ {
protected $resolver = null; protected $resolver = null;
protected $retriever = null; protected $retriever = null;
protected $requestContext;
const PATH_TO_FILE = true; const PATH_TO_FILE = true;
const WITH_INDEX_PAGE = false; const WITH_INDEX_PAGE = false;
public function __construct() protected static $instance = null;
public function __construct(ContainerInterface $container)
{ {
// Allow singleton style calls once intanciated.
// For this to work, the URL service has to be instanciated very early. This is done manually
// in TheliaHttpKernel, by calling $this->container->get('thelia.url.manager');
self::$instance = $this;
$this->requestContext = $container->get('router.admin')->getContext();
$this->retriever = new RewritingRetriever(); $this->retriever = new RewritingRetriever();
$this->resolver = new RewritingResolver(); $this->resolver = new RewritingResolver();
} }
public static function getIndexPage() /**
{ * Return this class instance, only once instanciated.
return ConfigQuery::read('base_url', '/') . "index_dev.php"; // FIXME ! *
* @throws \RuntimeException if the class has not been instanciated.
* @return \Thelia\Tools\URL the instance.
*/
public static function getInstance() {
if (self::$instance == null) throw new \RuntimeException("URL instance is not initialized.");
return self::$instance;
} }
public static function init() /**
* Return the base URL, either the base_url defined in Config, or the URL
* of the current language, if 'one_domain_foreach_lang' is enabled.
*
* @return string the base URL, with a trailing '/'
*/
public function getBaseUrl()
{ {
return new URL(); if ($host = $this->requestContext->getHost()) {
$scheme = $this->requestContext->getScheme();
$port = '';
if ('http' === $scheme && 80 != $this->requestContext->getHttpPort()) {
$port = ':'.$this->requestContext->getHttpPort();
} elseif ('https' === $scheme && 443 != $this->requestContext->getHttpsPort()) {
$port = ':'.$this->requestContext->getHttpsPort();
}
$schemeAuthority = "$scheme://$host"."$port";
}
return $schemeAuthority.$this->requestContext->getBaseUrl();
}
/**
* @return string the index page, which is in fact the base URL.
*/
public function getIndexPage()
{
// The index page is the base URL :)
return $this->getBaseUrl();
} }
/** /**
* Returns the Absolute URL for a given path relative to web root. By default, * Returns the Absolute URL for a given path relative to web root. By default,
* the index.php (or index_dev.php) script name is added to the URL, use * the script name (index_dev.php) is added to the URL in dev_environment, use
* $path_only = true to get a path without the index script. * $path_only = true to get a path without the index script.
* *
* @param string $path the relative path * @param string $path the relative path
@@ -63,19 +114,21 @@ class URL
* *
* @return string The generated URL * @return string The generated URL
*/ */
public static function absoluteUrl($path, array $parameters = null, $path_only = self::WITH_INDEX_PAGE) public function absoluteUrl($path, array $parameters = null, $path_only = self::WITH_INDEX_PAGE)
{ {
// Already absolute ? // Already absolute ?
if (substr($path, 0, 4) != 'http') { if (substr($path, 0, 4) != 'http') {
/** $base_url = $this->getBaseUrl();
* @etienne : can't be done here for it's already done in ::viewUrl / ::adminViewUrl
* @franck : should be done, as absoluteUrl() is sometimes called directly (see UrlGenerator::generateUrlFunction())
*/
$root = $path_only == self::PATH_TO_FILE ? ConfigQuery::read('base_url', '/') : self::getIndexPage();
//$root = $path_only == self::PATH_TO_FILE ? ConfigQuery::read('base_url', '/') : '';
$base = rtrim($root, '/') . '/' . ltrim($path, '/'); // If only a path is requested, be sure to remove the script name (index.php or index_dev.php), if any.
if ($path_only == self::PATH_TO_FILE) {
// As the base_url always ends with '/', if we don't find / at the end, we have a script.
if (substr($base_url, -1) != '/') $base_url = dirname($base_url);
}
// Normalize the given path
$base = rtrim($base_url, '/') . '/' . ltrim($path, '/');
} else } else
$base = $path; $base = $path;
@@ -90,6 +143,7 @@ class URL
$sepChar = strstr($base, '?') === false ? '?' : '&'; $sepChar = strstr($base, '?') === false ? '?' : '&';
if ('' !== $queryString = rtrim($queryString, "&")) $queryString = $sepChar . $queryString; if ('' !== $queryString = rtrim($queryString, "&")) $queryString = $sepChar . $queryString;
return $base . $queryString; return $base . $queryString;
} }
@@ -101,11 +155,11 @@ class URL
* *
* @return string The generated URL * @return string The generated URL
*/ */
public static function adminViewUrl($viewName, array $parameters = array()) public function adminViewUrl($viewName, array $parameters = array())
{ {
$path = sprintf("%s/admin/%s", self::getIndexPage(), $viewName); // FIXME ! view= should not be required, check routing parameters $path = sprintf("%s/admin/%s", $this->getIndexPage(), $viewName);
return self::absoluteUrl($path, $parameters); return $this->absoluteUrl($path, $parameters);
} }
/** /**
@@ -116,72 +170,71 @@ class URL
* *
* @return string The generated URL * @return string The generated URL
*/ */
public static function viewUrl($viewName, array $parameters = array()) public function viewUrl($viewName, array $parameters = array())
{ {
$path = sprintf("?view=%s", $viewName); $path = sprintf("?view=%s", $viewName);
return self::absoluteUrl($path, $parameters); return $this->absoluteUrl($path, $parameters);
}
/**
* Retrieve a rewritten URL from a view, a view id and a locale
*
* @param $view
* @param $viewId
* @param $viewLocale
*
* @return RewritingRetriever You can access $url and $rewrittenUrl properties
*/
public function retrieve($view, $viewId, $viewLocale)
{
if(ConfigQuery::isRewritingEnable()) {
$this->retriever->loadViewUrl($view, $viewLocale, $viewId);
}
return $this->retriever;
} }
/** /**
* Retrieve a rewritten URL from a view, a view id and a locale * Retrieve a rewritten URL from the current GET parameters
* *
* @param $view * @param Request $request
* @param $viewId *
* @param $viewLocale * @return RewritingRetriever You can access $url and $rewrittenUrl properties or use toString method
* */
* @return RewritingRetriever You can access $url and $rewrittenUrl properties public function retrieveCurrent(Request $request)
*/ {
public function retrieve($view, $viewId, $viewLocale) if(ConfigQuery::isRewritingEnable()) {
{ $view = $request->attributes->get('_view', null);
if(ConfigQuery::isRewritingEnable()) { $viewLocale = $request->query->get('locale', null);
$this->retriever->loadViewUrl($view, $viewLocale, $viewId); $viewId = $view === null ? null : $request->query->get($view . '_id', null);
}
return $this->retriever; $allOtherParameters = $request->query->all();
} if($view !== null) {
unset($allOtherParameters['view']);
if($viewId !== null) {
unset($allOtherParameters[$view . '_id']);
}
}
if($viewLocale !== null) {
unset($allOtherParameters['locale']);
}
/** $this->retriever->loadSpecificUrl($view, $viewLocale, $viewId, $allOtherParameters);
* Retrieve a rewritten URL from the current GET parameters }
*
* @param Request $request
*
* @return RewritingRetriever You can access $url and $rewrittenUrl properties or use toString method
*/
public function retrieveCurrent(Request $request)
{
if(ConfigQuery::isRewritingEnable()) {
$view = $request->query->get('view', null);
$viewLocale = $request->query->get('locale', null);
$viewId = $view === null ? null : $request->query->get($view . '_id', null);
$allOtherParameters = $request->query->all(); return $this->retriever;
if($view !== null) { }
unset($allOtherParameters['view']);
}
if($viewLocale !== null) {
unset($allOtherParameters['locale']);
}
if($viewId !== null) {
unset($allOtherParameters[$view . '_id']);
}
$this->retriever->loadSpecificUrl($view, $viewLocale, $viewId, $allOtherParameters); /**
} * Retrieve a rewritten URL from the current GET parameters or use toString method
*
return $this->retriever; * @param $url
} *
* @return RewritingResolver
/** */
* Retrieve a rewritten URL from the current GET parameters or use toString method public function resolve($url)
* {
* @param $url $this->resolver->load($url);
* return $this->resolver;
* @return RewritingResolver }
*/ }
public function resolve($url)
{
$this->resolver->load($url);
return $this->resolver;
}
}

View File

@@ -1631,8 +1631,8 @@
<a href="../classes/Thelia.Core.Event.TheliaEvents.html#constant_ADMIN_LOGIN" class="">ADMIN_LOGIN</a><br /> <a href="../classes/Thelia.Core.Event.TheliaEvents.html#constant_ADMIN_LOGIN" class="">ADMIN_LOGIN</a><br />
<a href="../classes/Thelia.Core.Event.TheliaEvents.html#constant_BEFORE_CREATECUSTOMER" class="">BEFORE_CREATECUSTOMER</a><br /> <a href="../classes/Thelia.Core.Event.TheliaEvents.html#constant_BEFORE_CREATECUSTOMER" class="">BEFORE_CREATECUSTOMER</a><br />
<a href="../classes/Thelia.Core.Event.TheliaEvents.html#constant_AFTER_CREATECUSTOMER" class="">AFTER_CREATECUSTOMER</a><br /> <a href="../classes/Thelia.Core.Event.TheliaEvents.html#constant_AFTER_CREATECUSTOMER" class="">AFTER_CREATECUSTOMER</a><br />
<a href="../classes/Thelia.Core.Event.TheliaEvents.html#constant_BEFORE_CHANGECUSTOMER" class="">BEFORE_CHANGECUSTOMER</a><br /> <a href="../classes/Thelia.Core.Event.TheliaEvents.html#constant_BEFORE_CHANGECUSTOMER" class="">BEFORE_UPDATECUSTOMER</a><br />
<a href="../classes/Thelia.Core.Event.TheliaEvents.html#constant_AFTER_CHANGECUSTOMER" class="">AFTER_CHANGECUSTOMER</a><br /> <a href="../classes/Thelia.Core.Event.TheliaEvents.html#constant_AFTER_CHANGECUSTOMER" class="">AFTER_UPDATECUSTOMER</a><br />
<a href="../classes/Thelia.Core.Event.TheliaEvents.html#constant_BEFORE_CREATECATEGORY" class="">BEFORE_CREATECATEGORY</a><br /> <a href="../classes/Thelia.Core.Event.TheliaEvents.html#constant_BEFORE_CREATECATEGORY" class="">BEFORE_CREATECATEGORY</a><br />
<a href="../classes/Thelia.Core.Event.TheliaEvents.html#constant_AFTER_CREATECATEGORY" class="">AFTER_CREATECATEGORY</a><br /> <a href="../classes/Thelia.Core.Event.TheliaEvents.html#constant_AFTER_CREATECATEGORY" class="">AFTER_CREATECATEGORY</a><br />
<a href="../classes/Thelia.Core.Event.TheliaEvents.html#constant_BEFORE_DELETECATEGORY" class="">BEFORE_DELETECATEGORY</a><br /> <a href="../classes/Thelia.Core.Event.TheliaEvents.html#constant_BEFORE_DELETECATEGORY" class="">BEFORE_DELETECATEGORY</a><br />
@@ -1891,8 +1891,8 @@
<div class="span8 content class"> <div class="span8 content class">
<a id="constant_BEFORE_CHANGECUSTOMER" name="constant_BEFORE_CHANGECUSTOMER" class="anchor"></a> <a id="constant_BEFORE_CHANGECUSTOMER" name="constant_BEFORE_CHANGECUSTOMER" class="anchor"></a>
<article id="constant_BEFORE_CHANGECUSTOMER" class="constant"> <article id="constant_BEFORE_CHANGECUSTOMER" class="constant">
<h3 class="">BEFORE_CHANGECUSTOMER</h3> <h3 class="">BEFORE_UPDATECUSTOMER</h3>
<pre class="signature">BEFORE_CHANGECUSTOMER</pre> <pre class="signature">BEFORE_UPDATECUSTOMER</pre>
<p><em>Sent once the customer change form has been successfully validated, and before customer update in the database.</em></p> <p><em>Sent once the customer change form has been successfully validated, and before customer update in the database.</em></p>
@@ -1913,8 +1913,8 @@
<div class="span8 content class"> <div class="span8 content class">
<a id="constant_AFTER_CHANGECUSTOMER" name="constant_AFTER_CHANGECUSTOMER" class="anchor"></a> <a id="constant_AFTER_CHANGECUSTOMER" name="constant_AFTER_CHANGECUSTOMER" class="anchor"></a>
<article id="constant_AFTER_CHANGECUSTOMER" class="constant"> <article id="constant_AFTER_CHANGECUSTOMER" class="constant">
<h3 class="">AFTER_CHANGECUSTOMER</h3> <h3 class="">AFTER_UPDATECUSTOMER</h3>
<pre class="signature">AFTER_CHANGECUSTOMER</pre> <pre class="signature">AFTER_UPDATECUSTOMER</pre>
<p><em>Sent just after a successful update of a customer in the database.</em></p> <p><em>Sent just after a successful update of a customer in the database.</em></p>

View File

@@ -109,7 +109,7 @@ class Category extends BaseAction implements EventSubscriberInterface
$customer = CustomerQuery::create()->findPk(1); $customer = CustomerQuery::create()->findPk(1);
try { try {
$customerEvent = new CustomerEvent($customer); $customerEvent = new CustomerEvent($customer);
$event->getDispatcher()->dispatch(TheliaEvents::BEFORE_CHANGECUSTOMER, $customerEvent); $event->getDispatcher()->dispatch(TheliaEvents::BEFORE_UPDATECUSTOMER, $customerEvent);
$data = $form->getData(); $data = $form->getData();
@@ -127,7 +127,7 @@ class Category extends BaseAction implements EventSubscriberInterface
); );
$customerEvent->customer = $customer; $customerEvent->customer = $customer;
$event->getDispatcher()->dispatch(TheliaEvents::AFTER_CHANGECUSTOMER, $customerEvent); $event->getDispatcher()->dispatch(TheliaEvents::AFTER_UPDATECUSTOMER, $customerEvent);
// Update the logged-in user, and redirect to the success URL (exits) // 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. // We don-t send the login event, as the customer si already logged.

View File

@@ -78,11 +78,11 @@ final class TheliaEvents
/** /**
* Sent once the customer change form has been successfully validated, and before customer update in the database. * Sent once the customer change form has been successfully validated, and before customer update in the database.
*/ */
const BEFORE_CHANGECUSTOMER = "action.before_changecustomer"; const BEFORE_UPDATECUSTOMER = "action.before_changecustomer";
/** /**
* Sent just after a successful update of a customer in the database. * Sent just after a successful update of a customer in the database.
*/ */
const AFTER_CHANGECUSTOMER = "action.after_changecustomer"; const AFTER_UPDATECUSTOMER = "action.after_changecustomer";
/** /**
* Sent once the category creation form has been successfully validated, and before category insertion in the database. * Sent once the category creation form has been successfully validated, and before category insertion in the database.

View File

@@ -125,7 +125,7 @@ class Customer extends BaseCustomer implements UserInterface
public function preUpdate(ConnectionInterface $con = null) public function preUpdate(ConnectionInterface $con = null)
{ {
$customerEvent = new CustomerEvent($this); $customerEvent = new CustomerEvent($this);
$this->dispatchEvent(TheliaEvents::BEFORE_CHANGECUSTOMER, $customerEvent); $this->dispatchEvent(TheliaEvents::BEFORE_UPDATECUSTOMER, $customerEvent);
return true; return true;
} }
@@ -133,7 +133,7 @@ class Customer extends BaseCustomer implements UserInterface
public function postUpdate(ConnectionInterface $con = null) public function postUpdate(ConnectionInterface $con = null)
{ {
$customerEvent = new CustomerEvent($this); $customerEvent = new CustomerEvent($this);
$this->dispatchEvent(TheliaEvents::AFTER_CHANGECUSTOMER, $customerEvent); $this->dispatchEvent(TheliaEvents::AFTER_UPDATECUSTOMER, $customerEvent);
} }
protected function dispatchEvent($eventName, CustomerEvent $customerEvent) protected function dispatchEvent($eventName, CustomerEvent $customerEvent)

View File

@@ -1,8 +1,8 @@
INSERT INTO `lang`(`id`,`title`,`code`,`locale`,`url`,`by_default`,`created_at`,`updated_at`)VALUES INSERT INTO `lang`(`id`,`title`,`code`,`locale`,`url`,`date_format`,`time_format`,`datetime_format`,`decimal_separator`,`thousands_separator`,`decimals`,`by_default`,`created_at`,`updated_at`)VALUES
(1, 'Français', 'fr', 'fr_FR', '','1', NOW(), NOW()), (1, 'Français', 'fr', 'fr_FR', '', 'd/m/Y', 'H:i:s', 'd/m/y H:i:s', ',', ' ', '2', '1', NOW(), NOW()),
(2, 'English', 'en', 'en_EN', '', '0', NOW(), NOW()), (2, 'English', 'en', 'en_EN', '', 'm-d-Y', 'h:i:s', 'm-d-Y h:i:s', '.', ' ', '2', '0', NOW(), NOW()),
(3, 'Espanol', 'es', 'es_ES', '', '0', NOW(), NOW()), (3, 'castellano', 'es', 'es_ES', '', 'm-d-Y', 'h:i:s', 'm-d-Y h:i:s', ',', '.', '2', '0', NOW(), NOW()),
(4, 'Italiano', 'it', 'it_IT', '','0', NOW(), NOW()); (4, 'Italiano', 'it', 'it_IT', '', 'd/m/Y', 'H:i:s', 'd/m/y H:i:s', ',', ' ', '2', '0', NOW(), NOW());
INSERT INTO `config` (`name`, `value`, `secured`, `hidden`, `created_at`, `updated_at`) VALUES INSERT INTO `config` (`name`, `value`, `secured`, `hidden`, `created_at`, `updated_at`) VALUES
('session_config.default', '1', 1, 1, NOW(), NOW()), ('session_config.default', '1', 1, 1, NOW(), NOW()),

View File

@@ -522,8 +522,14 @@ CREATE TABLE `lang`
`code` VARCHAR(10), `code` VARCHAR(10),
`locale` VARCHAR(45), `locale` VARCHAR(45),
`url` VARCHAR(255), `url` VARCHAR(255),
`position` INTEGER, `date_format` VARCHAR(45),
`time_format` VARCHAR(45),
`datetime_format` VARCHAR(45),
`decimal_separator` VARCHAR(45),
`thousands_separator` VARCHAR(45),
`decimals` VARCHAR(45),
`by_default` TINYINT, `by_default` TINYINT,
`position` INTEGER,
`created_at` DATETIME, `created_at` DATETIME,
`updated_at` DATETIME, `updated_at` DATETIME,
PRIMARY KEY (`id`) PRIMARY KEY (`id`)

View File

@@ -389,8 +389,14 @@
<column name="code" size="10" type="VARCHAR" /> <column name="code" size="10" type="VARCHAR" />
<column name="locale" size="45" type="VARCHAR" /> <column name="locale" size="45" type="VARCHAR" />
<column name="url" size="255" type="VARCHAR" /> <column name="url" size="255" type="VARCHAR" />
<column name="position" type="INTEGER" /> <column name="date_format" size="45" type="VARCHAR" />
<column name="time_format" size="45" type="VARCHAR" />
<column name="datetime_format" size="45" type="VARCHAR" />
<column name="decimal_separator" size="45" type="VARCHAR" />
<column name="thousands_separator" size="45" type="VARCHAR" />
<column name="decimals" size="45" type="VARCHAR" />
<column name="by_default" type="TINYINT" /> <column name="by_default" type="TINYINT" />
<column name="position" type="INTEGER" />
<behavior name="timestampable" /> <behavior name="timestampable" />
</table> </table>
<table name="folder" namespace="Thelia\Model"> <table name="folder" namespace="Thelia\Model">

View File

@@ -210,9 +210,7 @@
{block name="before-javascript-include"}{/block} {block name="before-javascript-include"}{/block}
{javascripts file='assets/js/jquery.min.js'} <script src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
<script src="{$asset_url}"></script>
{/javascripts}
{block name="after-javascript-include"}{/block} {block name="after-javascript-include"}{/block}

View File

@@ -1,205 +0,0 @@
/*! 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 */
.editableform {
margin-bottom: 0; /* overwrites bootstrap margin */
}
.editableform .control-group {
margin-bottom: 0; /* overwrites bootstrap margin */
white-space: nowrap; /* prevent wrapping buttons on new line */
line-height: 20px; /* overwriting bootstrap line-height. See #133 */
}
.editable-buttons {
display: inline-block; /* should be inline to take effect of parent's white-space: nowrap */
vertical-align: top;
margin-left: 7px;
/* inline-block emulation for IE7*/
zoom: 1;
*display: inline;
}
.editable-buttons.editable-buttons-bottom {
display: block;
margin-top: 7px;
margin-left: 0;
}
.editable-input {
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;
}
.editable-buttons .editable-cancel {
margin-left: 7px;
}
/*for jquery-ui buttons need set height to look more pretty*/
.editable-buttons button.ui-button-icon-only {
height: 24px;
width: 30px;
}
.editableform-loading {
background: url('../img/loading.gif') center center no-repeat;
height: 25px;
width: auto;
min-width: 25px;
}
.editable-inline .editableform-loading {
background-position: left 5px;
}
.editable-error-block {
max-width: 300px;
margin: 5px 0 0 0;
width: auto;
white-space: normal;
}
/*add padding for jquery ui*/
.editable-error-block.ui-state-error {
padding: 3px;
}
.editable-error {
color: red;
}
/* ---- For specific types ---- */
.editableform .editable-date {
padding: 0;
margin: 0;
float: left;
}
/* 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;
}
/* checklist vertical alignment */
.editable-checklist label input[type="checkbox"],
.editable-checklist label span {
vertical-align: middle;
margin: 0;
}
.editable-checklist label {
white-space: nowrap;
}
/* set exact width of textarea to fit buttons toolbar */
.editable-wysihtml5 {
width: 566px;
height: 250px;
}
/* clear button shown as link in date inputs */
.editable-clear {
clear: both;
font-size: 0.9em;
text-decoration: none;
text-align: right;
}
/* IOS-style clear button for text inputs */
.editable-clear-x {
background: url('../img/clear.png') center center no-repeat;
display: block;
width: 13px;
height: 13px;
position: absolute;
opacity: 0.6;
z-index: 100;
top: 50%;
right: 6px;
margin-top: -6px;
}
.editable-clear-x:hover {
opacity: 1;
}
.editable-pre-wrapped {
white-space: pre-wrap;
}
.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;
vertical-align: middle;
width: auto;
/* inline-block emulation for IE7*/
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,
a.editable-click:hover {
text-decoration: none;
border-bottom: dotted 1px #0088cc;
}
.editable-click.editable-disabled,
a.editable-click.editable-disabled,
a.editable-click.editable-disabled:hover {
color: #585858;
cursor: default;
border-bottom: none;
}
.editable-empty, .editable-empty:hover, .editable-empty:focus{
font-style: italic;
color: #DD1144;
/* border-bottom: none; */
text-decoration: none;
}
.editable-unsaved {
font-weight: bold;
}
.editable-unsaved:after {
/* content: '*'*/
}
.editable-bg-transition {
-webkit-transition: background-color 1400ms ease-out;
-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;
}
/*see https://github.com/vitalets/x-editable/issues/139 */
.form-horizontal .editable
{
padding-top: 5px;
display:inline-block;
}

File diff suppressed because one or more lines are too long

View File

Before

Width:  |  Height:  |  Size: 509 B

After

Width:  |  Height:  |  Size: 509 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -1,8 +1,7 @@
/*! X-editable - v1.4.6 /*! X-editable - v1.4.7
* In-place editing with Twitter Bootstrap, jQuery UI or pure jQuery * In-place editing with Twitter Bootstrap, jQuery UI or pure jQuery
* http://github.com/vitalets/x-editable * http://github.com/vitalets/x-editable
* Copyright (c) 2013 Vitaliy Potapov; Licensed MIT */ * Copyright (c) 2013 Vitaliy Potapov; Licensed MIT */
/** /**
Form with single input element, two buttons and two states: normal/loading. Form with single input element, two buttons and two states: normal/loading.
Applied as jQuery method to DIV tag (not to form tag!). This is because form can be in loading state when spinner shown. Applied as jQuery method to DIV tag (not to form tag!). This is because form can be in loading state when spinner shown.
@@ -33,6 +32,9 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
//set initial value //set initial value
//todo: may be add check: typeof str === 'string' ? //todo: may be add check: typeof str === 'string' ?
this.value = this.input.str2value(this.options.value); this.value = this.input.str2value(this.options.value);
//prerender: get input.$input
this.input.prerender();
}, },
initTemplate: function() { initTemplate: function() {
this.$form = $($.fn.editableform.template); this.$form = $($.fn.editableform.template);
@@ -80,9 +82,8 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
this.initInput(); this.initInput();
//append input to form //append input to form
this.input.prerender();
this.$form.find('div.editable-input').append(this.input.$tpl); this.$form.find('div.editable-input').append(this.input.$tpl);
//append form to container //append form to container
this.$div.append(this.$form); this.$div.append(this.$form);
@@ -620,8 +621,11 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
//error class attached to editable-error-block //error class attached to editable-error-block
$.fn.editableform.errorBlockClass = 'editable-error'; $.fn.editableform.errorBlockClass = 'editable-error';
//engine
$.fn.editableform.engine = 'jqeury';
}(window.jQuery)); }(window.jQuery));
/** /**
* EditableForm utilites * EditableForm utilites
*/ */
@@ -871,7 +875,7 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
}; };
}(window.jQuery)); }(window.jQuery));
/** /**
Attaches stand-alone container with editable-form to HTML element. Element is used only for positioning, value is not stored anywhere.<br> Attaches stand-alone container with editable-form to HTML element. Element is used only for positioning, value is not stored anywhere.<br>
This method applied internally in <code>$().editable()</code>. You should subscribe on it's events (save / cancel) to get profit of it.<br> This method applied internally in <code>$().editable()</code>. You should subscribe on it's events (save / cancel) to get profit of it.<br>
@@ -898,6 +902,8 @@ Applied as jQuery method.
containerDataName: null, //object name in element's .data() containerDataName: null, //object name in element's .data()
innerCss: null, //tbd in child class innerCss: null, //tbd in child class
containerClass: 'editable-container editable-popup', //css class applied to container element containerClass: 'editable-container editable-popup', //css class applied to container element
defaults: {}, //container itself defaults
init: function(element, options) { init: function(element, options) {
this.$element = $(element); this.$element = $(element);
//since 1.4.1 container do not use data-* directly as they already merged into options. //since 1.4.1 container do not use data-* directly as they already merged into options.
@@ -975,10 +981,9 @@ Applied as jQuery method.
throw new Error(this.containerName + ' not found. Have you included corresponding js file?'); throw new Error(this.containerName + ' not found. Have you included corresponding js file?');
} }
var cDef = $.fn[this.containerName].defaults;
//keys defined in container defaults go to container, others go to form //keys defined in container defaults go to container, others go to form
for(var k in this.options) { for(var k in this.options) {
if(k in cDef) { if(k in this.defaults) {
this.containerOptions[k] = this.options[k]; this.containerOptions[k] = this.options[k];
} else { } else {
this.formOptions[k] = this.options[k]; this.formOptions[k] = this.options[k];
@@ -1386,7 +1391,7 @@ Applied as jQuery method.
}; };
}(window.jQuery)); }(window.jQuery));
/** /**
* Editable Inline * Editable Inline
* --------------------- * ---------------------
@@ -1440,7 +1445,7 @@ Applied as jQuery method.
} }
}); });
}(window.jQuery)); }(window.jQuery));
/** /**
Makes editable any HTML element on the page. Applied as jQuery method. Makes editable any HTML element on the page. Applied as jQuery method.
@@ -2249,11 +2254,11 @@ Makes editable any HTML element on the page. Applied as jQuery method.
@since 1.4.5 @since 1.4.5
@default #FFFF80 @default #FFFF80
**/ **/
highlight: '#FFFF80' highlight: '#FFFF80'
}; };
}(window.jQuery)); }(window.jQuery));
/** /**
AbstractInput - base class for all editable inputs. AbstractInput - base class for all editable inputs.
It defines interface to be implemented by any input type. It defines interface to be implemented by any input type.
@@ -2415,7 +2420,7 @@ To create your own input you can inherit from this class.
}, },
// -------- helper functions -------- // -------- helper functions --------
setClass: function() { setClass: function() {
if(this.options.inputclass) { if(this.options.inputclass) {
this.$input.addClass(this.options.inputclass); this.$input.addClass(this.options.inputclass);
} }
@@ -2447,9 +2452,9 @@ To create your own input you can inherit from this class.
@property inputclass @property inputclass
@type string @type string
@default input-medium @default null
**/ **/
inputclass: 'input-medium', inputclass: null,
//scope for external methods (e.g. source defined as function) //scope for external methods (e.g. source defined as function)
//for internal use only //for internal use only
scope: null, scope: null,
@@ -2461,7 +2466,7 @@ To create your own input you can inherit from this class.
$.extend($.fn.editabletypes, {abstractinput: AbstractInput}); $.extend($.fn.editabletypes, {abstractinput: AbstractInput});
}(window.jQuery)); }(window.jQuery));
/** /**
List - abstract class for inputs that have source option loaded from js array or via ajax List - abstract class for inputs that have source option loaded from js array or via ajax
@@ -2783,7 +2788,7 @@ List - abstract class for inputs that have source option loaded from js array or
$.fn.editabletypes.list = List; $.fn.editabletypes.list = List;
}(window.jQuery)); }(window.jQuery));
/** /**
Text input Text input
@@ -2918,7 +2923,7 @@ $(function(){
$.fn.editabletypes.text = Text; $.fn.editabletypes.text = Text;
}(window.jQuery)); }(window.jQuery));
/** /**
Textarea input Textarea input
@@ -3030,7 +3035,7 @@ $(function(){
$.fn.editabletypes.textarea = Textarea; $.fn.editabletypes.textarea = Textarea;
}(window.jQuery)); }(window.jQuery));
/** /**
Select (dropdown) Select (dropdown)
@@ -3126,7 +3131,7 @@ $(function(){
$.fn.editabletypes.select = Select; $.fn.editabletypes.select = Select;
}(window.jQuery)); }(window.jQuery));
/** /**
List of checkboxes. List of checkboxes.
Internally value stored as javascript array of values. Internally value stored as javascript array of values.
@@ -3279,7 +3284,7 @@ $(function(){
$.fn.editabletypes.checklist = Checklist; $.fn.editabletypes.checklist = Checklist;
}(window.jQuery)); }(window.jQuery));
/** /**
HTML5 input types. HTML5 input types.
Following types are supported: Following types are supported:
@@ -3498,7 +3503,7 @@ Time
}); });
$.fn.editabletypes.time = Time; $.fn.editabletypes.time = Time;
}(window.jQuery)); }(window.jQuery));
/** /**
Select2 input. Based on amazing work of Igor Vaynberg https://github.com/ivaynberg/select2. Select2 input. Based on amazing work of Igor Vaynberg https://github.com/ivaynberg/select2.
Please see [original select2 docs](http://ivaynberg.github.com/select2) for detailed description and options. Please see [original select2 docs](http://ivaynberg.github.com/select2) for detailed description and options.
@@ -3817,13 +3822,13 @@ $(function(){
@type string @type string
@default ', ' @default ', '
**/ **/
viewseparator: ', ' viewseparator: ', '
}); });
$.fn.editabletypes.select2 = Constructor; $.fn.editabletypes.select2 = Constructor;
}(window.jQuery)); }(window.jQuery));
/** /**
* Combodate - 1.0.4 * Combodate - 1.0.4
* Dropdown date and time picker. * Dropdown date and time picker.
@@ -4276,7 +4281,7 @@ $(function(){
roundTime: true //whether to round minutes and seconds if step > 1 roundTime: true //whether to round minutes and seconds if step > 1
}; };
}(window.jQuery)); }(window.jQuery));
/** /**
Combodate input - dropdown date and time picker. Combodate input - dropdown date and time picker.
Based on [combodate](http://vitalets.github.com/combodate) plugin (included). To use it you should manually include [momentjs](http://momentjs.com). Based on [combodate](http://vitalets.github.com/combodate) plugin (included). To use it you should manually include [momentjs](http://momentjs.com).
@@ -4343,7 +4348,14 @@ $(function(){
$.extend(Constructor.prototype, { $.extend(Constructor.prototype, {
render: function () { render: function () {
this.$input.combodate(this.options.combodate); this.$input.combodate(this.options.combodate);
if($.fn.editableform.engine === 'bs3') {
this.$input.siblings().find('select').addClass('form-control');
}
if(this.options.inputclass) {
this.$input.siblings().find('select').addClass(this.options.inputclass);
}
//"clear" link //"clear" link
/* /*
if(this.options.clear) { if(this.options.clear) {
@@ -4466,31 +4478,73 @@ $(function(){
$.fn.editabletypes.combodate = Constructor; $.fn.editabletypes.combodate = Constructor;
}(window.jQuery)); }(window.jQuery));
/* /*
Editableform based on Twitter Bootstrap Editableform based on Twitter Bootstrap 3
*/ */
(function ($) { (function ($) {
"use strict"; "use strict";
//store parent methods
var pInitInput = $.fn.editableform.Constructor.prototype.initInput;
$.extend($.fn.editableform.Constructor.prototype, { $.extend($.fn.editableform.Constructor.prototype, {
initTemplate: function() { initTemplate: function() {
this.$form = $($.fn.editableform.template); this.$form = $($.fn.editableform.template);
this.$form.find('.control-group').addClass('form-group');
this.$form.find('.editable-error-block').addClass('help-block'); this.$form.find('.editable-error-block').addClass('help-block');
} },
initInput: function() {
pInitInput.apply(this);
//for bs3 set default class `input-sm` to standard inputs
var emptyInputClass = this.input.options.inputclass === null || this.input.options.inputclass === false;
var defaultClass = 'input-sm';
//bs3 add `form-control` class to standard inputs
var stdtypes = 'text,select,textarea,password,email,url,tel,number,range,time'.split(',');
if(~$.inArray(this.input.type, stdtypes)) {
this.input.$input.addClass('form-control');
if(emptyInputClass) {
this.input.options.inputclass = defaultClass;
this.input.$input.addClass(defaultClass);
}
}
//apply bs3 size class also to buttons (to fit size of control)
var $btn = this.$form.find('.editable-buttons');
var classes = emptyInputClass ? [defaultClass] : this.input.options.inputclass.split(' ');
for(var i=0; i<classes.length; i++) {
// `btn-sm` is default now
/*
if(classes[i].toLowerCase() === 'input-sm') {
$btn.find('button').addClass('btn-sm');
}
*/
if(classes[i].toLowerCase() === 'input-lg') {
$btn.find('button').removeClass('btn-sm').addClass('btn-lg');
}
}
}
}); });
//buttons //buttons
$.fn.editableform.buttons = '<button type="submit" class="btn btn-primary editable-submit"><i class="icon-ok icon-white"></i></button>'+ $.fn.editableform.buttons =
'<button type="button" class="btn editable-cancel"><i class="icon-remove"></i></button>'; '<button type="submit" class="btn btn-primary btn-sm editable-submit">'+
'<i class="glyphicon glyphicon-ok"></i>'+
'</button>'+
'<button type="button" class="btn btn-default btn-sm editable-cancel">'+
'<i class="glyphicon glyphicon-remove"></i>'+
'</button>';
//error classes //error classes
$.fn.editableform.errorGroupClass = 'error'; $.fn.editableform.errorGroupClass = 'has-error';
$.fn.editableform.errorBlockClass = null; $.fn.editableform.errorBlockClass = null;
//engine
}(window.jQuery)); $.fn.editableform.engine = 'bs3';
}(window.jQuery));
/** /**
* Editable Popover * Editable Popover3 (for Bootstrap 3)
* --------------------- * ---------------------
* requires bootstrap-popover.js * requires bootstrap-popover.js
*/ */
@@ -4500,15 +4554,16 @@ Editableform based on Twitter Bootstrap
//extend methods //extend methods
$.extend($.fn.editableContainer.Popup.prototype, { $.extend($.fn.editableContainer.Popup.prototype, {
containerName: 'popover', containerName: 'popover',
//for compatibility with bootstrap <= 2.2.1 (content inserted into <p> instead of directly .popover-content) containerDataName: 'bs.popover',
innerCss: $.fn.popover && $($.fn.popover.defaults.template).find('p').length ? '.popover-content p' : '.popover-content', innerCss: '.popover-content',
defaults: $.fn.popover.Constructor.DEFAULTS,
initContainer: function(){ initContainer: function(){
$.extend(this.containerOptions, { $.extend(this.containerOptions, {
trigger: 'manual', trigger: 'manual',
selector: false, selector: false,
content: ' ', content: ' ',
template: $.fn.popover.defaults.template template: this.defaults.template
}); });
//as template property is used in inputs, hide it from popover //as template property is used in inputs, hide it from popover
@@ -4548,10 +4603,11 @@ Editableform based on Twitter Bootstrap
/** /**
* move popover to new position. This function mainly copied from bootstrap-popover. * move popover to new position. This function mainly copied from bootstrap-popover.
*/ */
/*jshint laxcomma: true*/ /*jshint laxcomma: true, eqeqeq: false*/
setPosition: function () { setPosition: function () {
(function() { (function() {
/*
var $tip = this.tip() var $tip = this.tip()
, inside , inside
, pos , pos
@@ -4661,14 +4717,32 @@ Editableform based on Twitter Bootstrap
.offset(tp) .offset(tp)
.addClass(placement) .addClass(placement)
.addClass('in'); .addClass('in');
*/
var $tip = this.tip();
var placement = typeof this.options.placement == 'function' ?
this.options.placement.call(this, $tip[0], this.$element[0]) :
this.options.placement;
var pos = this.getPosition();
var actualWidth = $tip[0].offsetWidth;
var actualHeight = $tip[0].offsetHeight;
var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight);
this.applyPlacement(calculatedOffset, placement);
}).call(this.container()); }).call(this.container());
/*jshint laxcomma: false*/ /*jshint laxcomma: false, eqeqeq: true*/
} }
}); });
}(window.jQuery)); }(window.jQuery));
/* ========================================================= /* =========================================================
* bootstrap-datepicker.js * bootstrap-datepicker.js
* http://www.eyecon.ro/bootstrap-datepicker * http://www.eyecon.ro/bootstrap-datepicker
@@ -5923,7 +5997,7 @@ Editableform based on Twitter Bootstrap
}); });
}( window.jQuery )); }( window.jQuery ));
/** /**
Bootstrap-datepicker. Bootstrap-datepicker.
Description and examples: https://github.com/eternicode/bootstrap-datepicker. Description and examples: https://github.com/eternicode/bootstrap-datepicker.
@@ -6153,7 +6227,7 @@ $(function(){
$.fn.editabletypes.date = Date; $.fn.editabletypes.date = Date;
}(window.jQuery)); }(window.jQuery));
/** /**
Bootstrap datefield input - modification for inline mode. Bootstrap datefield input - modification for inline mode.
Shows normal <input type="text"> and binds popup datepicker. Shows normal <input type="text"> and binds popup datepicker.
@@ -6234,7 +6308,7 @@ Automatically shown in inline mode.
$.fn.editabletypes.datefield = DateField; $.fn.editabletypes.datefield = DateField;
}(window.jQuery)); }(window.jQuery));
/** /**
Bootstrap-datetimepicker. Bootstrap-datetimepicker.
Based on [smalot bootstrap-datetimepicker plugin](https://github.com/smalot/bootstrap-datetimepicker). Based on [smalot bootstrap-datetimepicker plugin](https://github.com/smalot/bootstrap-datetimepicker).
@@ -6478,7 +6552,7 @@ $(function(){
$.fn.editabletypes.datetime = DateTime; $.fn.editabletypes.datetime = DateTime;
}(window.jQuery)); }(window.jQuery));
/** /**
Bootstrap datetimefield input - datetime input for inline mode. Bootstrap datetimefield input - datetime input for inline mode.
Shows normal <input type="text"> and binds popup datetimepicker. Shows normal <input type="text"> and binds popup datetimepicker.
@@ -6555,273 +6629,4 @@ Automatically shown in inline mode.
$.fn.editabletypes.datetimefield = DateTimeField; $.fn.editabletypes.datetimefield = DateTimeField;
}(window.jQuery));
/**
Typeahead input (bootstrap only). Based on Twitter Bootstrap [typeahead](http://twitter.github.com/bootstrap/javascript.html#typeahead).
Depending on `source` format typeahead operates in two modes:
* **strings**:
When `source` defined as array of strings, e.g. `['text1', 'text2', 'text3' ...]`.
User can submit one of these strings or any text entered in input (even if it is not matching source).
* **objects**:
When `source` defined as array of objects, e.g. `[{value: 1, text: "text1"}, {value: 2, text: "text2"}, ...]`.
User can submit only values that are in source (otherwise `null` is submitted). This is more like *dropdown* behavior.
@class typeahead
@extends list
@since 1.4.1
@final
@example
<a href="#" id="country" data-type="typeahead" data-pk="1" data-url="/post" data-original-title="Input country"></a>
<script>
$(function(){
$('#country').editable({
value: 'ru',
source: [
{value: 'gb', text: 'Great Britain'},
{value: 'us', text: 'United States'},
{value: 'ru', text: 'Russia'}
]
});
});
</script>
**/
(function ($) {
"use strict";
var Constructor = function (options) {
this.init('typeahead', options, Constructor.defaults);
//overriding objects in config (as by default jQuery extend() is not recursive)
this.options.typeahead = $.extend({}, Constructor.defaults.typeahead, {
//set default methods for typeahead to work with objects
matcher: this.matcher,
sorter: this.sorter,
highlighter: this.highlighter,
updater: this.updater
}, options.typeahead);
};
$.fn.editableutils.inherit(Constructor, $.fn.editabletypes.list);
$.extend(Constructor.prototype, {
renderList: function() {
this.$input = this.$tpl.is('input') ? this.$tpl : this.$tpl.find('input[type="text"]');
//set source of typeahead
this.options.typeahead.source = this.sourceData;
//apply typeahead
this.$input.typeahead(this.options.typeahead);
//patch some methods in typeahead
var ta = this.$input.data('typeahead');
ta.render = $.proxy(this.typeaheadRender, ta);
ta.select = $.proxy(this.typeaheadSelect, ta);
ta.move = $.proxy(this.typeaheadMove, ta);
this.renderClear();
this.setClass();
this.setAttr('placeholder');
},
value2htmlFinal: function(value, element) {
if(this.getIsObjects()) {
var items = $.fn.editableutils.itemsByValue(value, this.sourceData);
$(element).text(items.length ? items[0].text : '');
} else {
$(element).text(value);
}
},
html2value: function (html) {
return html ? html : null;
},
value2input: function(value) {
if(this.getIsObjects()) {
var items = $.fn.editableutils.itemsByValue(value, this.sourceData);
this.$input.data('value', value).val(items.length ? items[0].text : '');
} else {
this.$input.val(value);
}
},
input2value: function() {
if(this.getIsObjects()) {
var value = this.$input.data('value'),
items = $.fn.editableutils.itemsByValue(value, this.sourceData);
if(items.length && items[0].text.toLowerCase() === this.$input.val().toLowerCase()) {
return value;
} else {
return null; //entered string not found in source
}
} else {
return this.$input.val();
}
},
/*
if in sourceData values <> texts, typeahead in "objects" mode:
user must pick some value from list, otherwise `null` returned.
if all values == texts put typeahead in "strings" mode:
anything what entered is submited.
*/
getIsObjects: function() {
if(this.isObjects === undefined) {
this.isObjects = false;
for(var i=0; i<this.sourceData.length; i++) {
if(this.sourceData[i].value !== this.sourceData[i].text) {
this.isObjects = true;
break;
}
}
}
return this.isObjects;
},
/*
Methods borrowed from text input
*/
activate: $.fn.editabletypes.text.prototype.activate,
renderClear: $.fn.editabletypes.text.prototype.renderClear,
postrender: $.fn.editabletypes.text.prototype.postrender,
toggleClear: $.fn.editabletypes.text.prototype.toggleClear,
clear: function() {
$.fn.editabletypes.text.prototype.clear.call(this);
this.$input.data('value', '');
},
/*
Typeahead option methods used as defaults
*/
/*jshint eqeqeq:false, curly: false, laxcomma: true, asi: true*/
matcher: function (item) {
return $.fn.typeahead.Constructor.prototype.matcher.call(this, item.text);
},
sorter: function (items) {
var beginswith = []
, caseSensitive = []
, caseInsensitive = []
, item
, text;
while (item = items.shift()) {
text = item.text;
if (!text.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item);
else if (~text.indexOf(this.query)) caseSensitive.push(item);
else caseInsensitive.push(item);
}
return beginswith.concat(caseSensitive, caseInsensitive);
},
highlighter: function (item) {
return $.fn.typeahead.Constructor.prototype.highlighter.call(this, item.text);
},
updater: function (item) {
this.$element.data('value', item.value);
return item.text;
},
/*
Overwrite typeahead's render method to store objects.
There are a lot of disscussion in bootstrap repo on this point and still no result.
See https://github.com/twitter/bootstrap/issues/5967
This function just store item via jQuery data() method instead of attr('data-value')
*/
typeaheadRender: function (items) {
var that = this;
items = $(items).map(function (i, item) {
// i = $(that.options.item).attr('data-value', item)
i = $(that.options.item).data('item', item);
i.find('a').html(that.highlighter(item));
return i[0];
});
//add option to disable autoselect of first line
//see https://github.com/twitter/bootstrap/pull/4164
if (this.options.autoSelect) {
items.first().addClass('active');
}
this.$menu.html(items);
return this;
},
//add option to disable autoselect of first line
//see https://github.com/twitter/bootstrap/pull/4164
typeaheadSelect: function () {
var val = this.$menu.find('.active').data('item')
if(this.options.autoSelect || val){
this.$element
.val(this.updater(val))
.change()
}
return this.hide()
},
/*
if autoSelect = false and nothing matched we need extra press onEnter that is not convinient.
This patch fixes it.
*/
typeaheadMove: function (e) {
if (!this.shown) return
switch(e.keyCode) {
case 9: // tab
case 13: // enter
case 27: // escape
if (!this.$menu.find('.active').length) return
e.preventDefault()
break
case 38: // up arrow
e.preventDefault()
this.prev()
break
case 40: // down arrow
e.preventDefault()
this.next()
break
}
e.stopPropagation()
}
/*jshint eqeqeq: true, curly: true, laxcomma: false, asi: false*/
});
Constructor.defaults = $.extend({}, $.fn.editabletypes.list.defaults, {
/**
@property tpl
@default <input type="text">
**/
tpl:'<input type="text">',
/**
Configuration of typeahead. [Full list of options](http://twitter.github.com/bootstrap/javascript.html#typeahead).
@property typeahead
@type object
@default null
**/
typeahead: null,
/**
Whether to show `clear` button
@property clear
@type boolean
@default true
**/
clear: true
});
$.fn.editabletypes.typeahead = Constructor;
}(window.jQuery)); }(window.jQuery));

View File

@@ -0,0 +1,382 @@
/*! ============================================================
* bootstrapSwitch v1.8 by Larentis Mattia @SpiritualGuru
* http://www.larentis.eu/
*
* Enhanced for radiobuttons by Stein, Peter @BdMdesigN
* http://www.bdmdesign.org/
*
* Project site:
* http://www.larentis.eu/switch/
* ============================================================
* Licensed under the Apache License, Version 2.0
* http://www.apache.org/licenses/LICENSE-2.0
* ============================================================ */
!function ($) {
"use strict";
$.fn['bootstrapSwitch'] = function (method) {
var inputSelector = 'input[type!="hidden"]';
var methods = {
init: function () {
return this.each(function () {
var $element = $(this)
, $div
, $switchLeft
, $switchRight
, $label
, $form = $element.closest('form')
, myClasses = ""
, classes = $element.attr('class')
, color
, moving
, onLabel = "ON"
, offLabel = "OFF"
, icon = false
, textLabel = false;
$.each(['switch-mini', 'switch-small', 'switch-large'], function (i, el) {
if (classes.indexOf(el) >= 0)
myClasses = el;
});
$element.addClass('has-switch');
if ($element.data('on') !== undefined)
color = "switch-" + $element.data('on');
if ($element.data('on-label') !== undefined)
onLabel = $element.data('on-label');
if ($element.data('off-label') !== undefined)
offLabel = $element.data('off-label');
if ($element.data('label-icon') !== undefined)
icon = $element.data('label-icon');
if ($element.data('text-label') !== undefined)
textLabel = $element.data('text-label');
$switchLeft = $('<span>')
.addClass("switch-left")
.addClass(myClasses)
.addClass(color)
.html(onLabel);
color = '';
if ($element.data('off') !== undefined)
color = "switch-" + $element.data('off');
$switchRight = $('<span>')
.addClass("switch-right")
.addClass(myClasses)
.addClass(color)
.html(offLabel);
$label = $('<label>')
.html("&nbsp;")
.addClass(myClasses)
.attr('for', $element.find(inputSelector).attr('id'));
if (icon) {
$label.html('<i class="icon ' + icon + '"></i>');
}
if (textLabel) {
$label.html('' + textLabel + '');
}
$div = $element.find(inputSelector).wrap($('<div>')).parent().data('animated', false);
if ($element.data('animated') !== false)
$div.addClass('switch-animate').data('animated', true);
$div
.append($switchLeft)
.append($label)
.append($switchRight);
$element.find('>div').addClass(
$element.find(inputSelector).is(':checked') ? 'switch-on' : 'switch-off'
);
if ($element.find(inputSelector).is(':disabled'))
$(this).addClass('deactivate');
var changeStatus = function ($this) {
if ($element.parent('label').is('.label-change-switch')) {
} else {
$this.siblings('label').trigger('mousedown').trigger('mouseup').trigger('click');
}
};
$element.on('keydown', function (e) {
if (e.keyCode === 32) {
e.stopImmediatePropagation();
e.preventDefault();
changeStatus($(e.target).find('span:first'));
}
});
$switchLeft.on('click', function (e) {
changeStatus($(this));
});
$switchRight.on('click', function (e) {
changeStatus($(this));
});
$element.find(inputSelector).on('change', function (e, skipOnChange) {
var $this = $(this)
, $element = $this.parent()
, thisState = $this.is(':checked')
, state = $element.is('.switch-off');
e.preventDefault();
$element.css('left', '');
if (state === thisState) {
if (thisState)
$element.removeClass('switch-off').addClass('switch-on');
else $element.removeClass('switch-on').addClass('switch-off');
if ($element.data('animated') !== false)
$element.addClass("switch-animate");
if (typeof skipOnChange === 'boolean' && skipOnChange)
return;
$element.parent().trigger('switch-change', {'el': $this, 'value': thisState})
}
});
$element.find('label').on('mousedown touchstart', function (e) {
var $this = $(this);
moving = false;
e.preventDefault();
e.stopImmediatePropagation();
$this.closest('div').removeClass('switch-animate');
if ($this.closest('.has-switch').is('.deactivate')) {
$this.unbind('click');
} else if ($this.closest('.switch-on').parent().is('.radio-no-uncheck')) {
$this.unbind('click');
} else {
$this.on('mousemove touchmove', function (e) {
var $element = $(this).closest('.make-switch')
, relativeX = (e.pageX || e.originalEvent.targetTouches[0].pageX) - $element.offset().left
, percent = (relativeX / $element.width()) * 100
, left = 25
, right = 75;
moving = true;
if (percent < left)
percent = left;
else if (percent > right)
percent = right;
$element.find('>div').css('left', (percent - right) + "%")
});
$this.on('click touchend', function (e) {
var $this = $(this)
, $myInputBox = $this.siblings('input');
e.stopImmediatePropagation();
e.preventDefault();
$this.unbind('mouseleave');
if (moving)
$myInputBox.prop('checked', !(parseInt($this.parent().css('left')) < -25));
else
$myInputBox.prop("checked", !$myInputBox.is(":checked"));
moving = false;
$myInputBox.trigger('change');
});
$this.on('mouseleave', function (e) {
var $this = $(this)
, $myInputBox = $this.siblings('input');
e.preventDefault();
e.stopImmediatePropagation();
$this.unbind('mouseleave mousemove');
$this.trigger('mouseup');
$myInputBox.prop('checked', !(parseInt($this.parent().css('left')) < -25)).trigger('change');
});
$this.on('mouseup', function (e) {
e.stopImmediatePropagation();
e.preventDefault();
$(this).trigger('mouseleave');
});
}
});
if ($form.data('bootstrapSwitch') !== 'injected') {
$form.bind('reset', function () {
setTimeout(function () {
$form.find('.make-switch').each(function () {
var $input = $(this).find(inputSelector);
$input.prop('checked', $input.is(':checked')).trigger('change');
});
}, 1);
});
$form.data('bootstrapSwitch', 'injected');
}
}
);
},
toggleActivation: function () {
var $this = $(this);
$this.toggleClass('deactivate');
$this.find(inputSelector).prop('disabled', $this.is('.deactivate'));
},
isActive: function () {
return !$(this).hasClass('deactivate');
},
setActive: function (active) {
var $this = $(this);
if (active) {
$this.removeClass('deactivate');
$this.find(inputSelector).removeAttr('disabled');
}
else {
$this.addClass('deactivate');
$this.find(inputSelector).attr('disabled', 'disabled');
}
},
toggleState: function (skipOnChange) {
var $input = $(this).find(':checkbox');
$input.prop('checked', !$input.is(':checked')).trigger('change', skipOnChange);
},
toggleRadioState: function (skipOnChange) {
var $radioinput = $(this).find(':radio');
$radioinput.not(':checked').prop('checked', !$radioinput.is(':checked')).trigger('change', skipOnChange);
},
toggleRadioStateAllowUncheck: function (uncheck, skipOnChange) {
var $radioinput = $(this).find(':radio');
if (uncheck) {
$radioinput.not(':checked').trigger('change', skipOnChange);
}
else {
$radioinput.not(':checked').prop('checked', !$radioinput.is(':checked')).trigger('change', skipOnChange);
}
},
setState: function (value, skipOnChange) {
$(this).find(inputSelector).prop('checked', value).trigger('change', skipOnChange);
},
setOnLabel: function (value) {
var $switchLeft = $(this).find(".switch-left");
$switchLeft.html(value);
},
setOffLabel: function (value) {
var $switchRight = $(this).find(".switch-right");
$switchRight.html(value);
},
setOnClass: function (value) {
var $switchLeft = $(this).find(".switch-left");
var color = '';
if (value !== undefined) {
if ($(this).attr('data-on') !== undefined) {
color = "switch-" + $(this).attr('data-on')
}
$switchLeft.removeClass(color);
color = "switch-" + value;
$switchLeft.addClass(color);
}
},
setOffClass: function (value) {
var $switchRight = $(this).find(".switch-right");
var color = '';
if (value !== undefined) {
if ($(this).attr('data-off') !== undefined) {
color = "switch-" + $(this).attr('data-off')
}
$switchRight.removeClass(color);
color = "switch-" + value;
$switchRight.addClass(color);
}
},
setAnimated: function (value) {
var $element = $(this).find(inputSelector).parent();
if (value === undefined) value = false;
$element.data('animated', value);
$element.attr('data-animated', value);
if ($element.data('animated') !== false) {
$element.addClass("switch-animate");
} else {
$element.removeClass("switch-animate");
}
},
setSizeClass: function (value) {
var $element = $(this);
var $switchLeft = $element.find(".switch-left");
var $switchRight = $element.find(".switch-right");
var $label = $element.find("label");
$.each(['switch-mini', 'switch-small', 'switch-large'], function (i, el) {
if (el !== value) {
$switchLeft.removeClass(el);
$switchRight.removeClass(el);
$label.removeClass(el);
} else {
$switchLeft.addClass(el);
$switchRight.addClass(el);
$label.addClass(el);
}
});
},
status: function () {
return $(this).find(inputSelector).is(':checked');
},
destroy: function () {
var $element = $(this)
, $div = $element.find('div')
, $form = $element.closest('form')
, $inputbox;
$div.find(':not(input)').remove();
$inputbox = $div.children();
$inputbox.unwrap().unwrap();
$inputbox.unbind('change');
if ($form) {
$form.unbind('reset');
$form.removeData('bootstrapSwitch');
}
return $inputbox;
}
};
if (methods[method])
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
else if (typeof method === 'object' || !method)
return methods.init.apply(this, arguments);
else
$.error('Method ' + method + ' does not exist!');
};
}(jQuery);
(function ($) {
$(function () {
$('.make-switch')['bootstrapSwitch']();
});
})(jQuery);

View File

@@ -0,0 +1,655 @@
/*! X-editable - v1.4.7
* In-place editing with Twitter Bootstrap, jQuery UI or pure jQuery
* http://github.com/vitalets/x-editable
* Copyright (c) 2013 Vitaliy Potapov; Licensed MIT */
.editableform {
margin-bottom: 0; /* overwrites bootstrap margin */
}
.editableform .control-group {
margin-bottom: 0; /* overwrites bootstrap margin */
white-space: nowrap; /* prevent wrapping buttons on new line */
line-height: 20px; /* overwriting bootstrap line-height. See #133 */
}
.editable-buttons {
display: inline-block; /* should be inline to take effect of parent's white-space: nowrap */
vertical-align: top;
margin-left: 7px;
/* inline-block emulation for IE7*/
zoom: 1;
*display: inline;
}
.editable-buttons.editable-buttons-bottom {
display: block;
margin-top: 7px;
margin-left: 0;
}
.editable-input {
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;
}
.editable-buttons .editable-cancel {
margin-left: 7px;
}
/*for jquery-ui buttons need set height to look more pretty*/
.editable-buttons button.ui-button-icon-only {
height: 24px;
width: 30px;
}
.editableform-loading {
background: url('@{imgDir}/loading.gif') center center no-repeat;
height: 25px;
width: auto;
min-width: 25px;
}
.editable-inline .editableform-loading {
background-position: left 5px;
}
.editable-error-block {
max-width: 300px;
margin: 5px 0 0 0;
width: auto;
white-space: normal;
}
/*add padding for jquery ui*/
.editable-error-block.ui-state-error {
padding: 3px;
}
.editable-error {
color: red;
}
/* ---- For specific types ---- */
.editableform .editable-date {
padding: 0;
margin: 0;
float: left;
}
/* 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;
}
/* checklist vertical alignment */
.editable-checklist label input[type="checkbox"],
.editable-checklist label span {
vertical-align: middle;
margin: 0;
}
.editable-checklist label {
white-space: nowrap;
}
/* set exact width of textarea to fit buttons toolbar */
.editable-wysihtml5 {
width: 566px;
height: 250px;
}
/* clear button shown as link in date inputs */
.editable-clear {
clear: both;
font-size: 0.9em;
text-decoration: none;
text-align: right;
}
/* IOS-style clear button for text inputs */
.editable-clear-x {
background: url('@{imgDir}/clear.png') center center no-repeat;
display: block;
width: 13px;
height: 13px;
position: absolute;
opacity: 0.6;
z-index: 100;
top: 50%;
right: 6px;
margin-top: -6px;
}
.editable-clear-x:hover {
opacity: 1;
}
.editable-pre-wrapped {
white-space: pre-wrap;
}
.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;
vertical-align: middle;
width: auto;
/* inline-block emulation for IE7*/
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,
a.editable-click:hover {
text-decoration: none;
border-bottom: dashed 1px #0088cc;
}
.editable-click.editable-disabled,
a.editable-click.editable-disabled,
a.editable-click.editable-disabled:hover {
color: #585858;
cursor: default;
border-bottom: none;
}
.editable-empty, .editable-empty:hover, .editable-empty:focus{
font-style: italic;
color: #DD1144;
/* border-bottom: none; */
text-decoration: none;
}
.editable-unsaved {
font-weight: bold;
}
.editable-unsaved:after {
/* content: '*'*/
}
.editable-bg-transition {
-webkit-transition: background-color 1400ms ease-out;
-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;
}
/*see https://github.com/vitalets/x-editable/issues/139 */
.form-horizontal .editable
{
padding-top: 5px;
display:inline-block;
}
/*!
* Datepicker for Bootstrap
*
* Copyright 2012 Stefan Petre
* Improvements by Andrew Rowls
* Licensed under the Apache License v2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
*/
.datepicker {
padding: 4px;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
direction: ltr;
/*.dow {
border-top: 1px solid #ddd !important;
}*/
}
.datepicker-inline {
width: 220px;
}
.datepicker.datepicker-rtl {
direction: rtl;
}
.datepicker.datepicker-rtl table tr td span {
float: right;
}
.datepicker-dropdown {
top: 0;
left: 0;
}
.datepicker-dropdown:before {
content: '';
display: inline-block;
border-left: 7px solid transparent;
border-right: 7px solid transparent;
border-bottom: 7px solid #ccc;
border-bottom-color: rgba(0, 0, 0, 0.2);
position: absolute;
top: -7px;
left: 6px;
}
.datepicker-dropdown:after {
content: '';
display: inline-block;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-bottom: 6px solid #ffffff;
position: absolute;
top: -6px;
left: 7px;
}
.datepicker > div {
display: none;
}
.datepicker.days div.datepicker-days {
display: block;
}
.datepicker.months div.datepicker-months {
display: block;
}
.datepicker.years div.datepicker-years {
display: block;
}
.datepicker table {
margin: 0;
}
.datepicker td,
.datepicker th {
text-align: center;
width: 20px;
height: 20px;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
border: none;
}
.table-striped .datepicker table tr td,
.table-striped .datepicker table tr th {
background-color: transparent;
}
.datepicker table tr td.day:hover {
background: #eeeeee;
cursor: pointer;
}
.datepicker table tr td.old,
.datepicker table tr td.new {
color: #999999;
}
.datepicker table tr td.disabled,
.datepicker table tr td.disabled:hover {
background: none;
color: #999999;
cursor: default;
}
.datepicker table tr td.today,
.datepicker table tr td.today:hover,
.datepicker table tr td.today.disabled,
.datepicker table tr td.today.disabled:hover {
background-color: #fde19a;
background-image: -moz-linear-gradient(top, #fdd49a, #fdf59a);
background-image: -ms-linear-gradient(top, #fdd49a, #fdf59a);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fdd49a), to(#fdf59a));
background-image: -webkit-linear-gradient(top, #fdd49a, #fdf59a);
background-image: -o-linear-gradient(top, #fdd49a, #fdf59a);
background-image: linear-gradient(top, #fdd49a, #fdf59a);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fdd49a', endColorstr='#fdf59a', GradientType=0);
border-color: #fdf59a #fdf59a #fbed50;
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
color: #000;
}
.datepicker table tr td.today:hover,
.datepicker table tr td.today:hover:hover,
.datepicker table tr td.today.disabled:hover,
.datepicker table tr td.today.disabled:hover:hover,
.datepicker table tr td.today:active,
.datepicker table tr td.today:hover:active,
.datepicker table tr td.today.disabled:active,
.datepicker table tr td.today.disabled:hover:active,
.datepicker table tr td.today.active,
.datepicker table tr td.today:hover.active,
.datepicker table tr td.today.disabled.active,
.datepicker table tr td.today.disabled:hover.active,
.datepicker table tr td.today.disabled,
.datepicker table tr td.today:hover.disabled,
.datepicker table tr td.today.disabled.disabled,
.datepicker table tr td.today.disabled:hover.disabled,
.datepicker table tr td.today[disabled],
.datepicker table tr td.today:hover[disabled],
.datepicker table tr td.today.disabled[disabled],
.datepicker table tr td.today.disabled:hover[disabled] {
background-color: #fdf59a;
}
.datepicker table tr td.today:active,
.datepicker table tr td.today:hover:active,
.datepicker table tr td.today.disabled:active,
.datepicker table tr td.today.disabled:hover:active,
.datepicker table tr td.today.active,
.datepicker table tr td.today:hover.active,
.datepicker table tr td.today.disabled.active,
.datepicker table tr td.today.disabled:hover.active {
background-color: #fbf069 \9;
}
.datepicker table tr td.today:hover:hover {
color: #000;
}
.datepicker table tr td.today.active:hover {
color: #fff;
}
.datepicker table tr td.range,
.datepicker table tr td.range:hover,
.datepicker table tr td.range.disabled,
.datepicker table tr td.range.disabled:hover {
background: #eeeeee;
-webkit-border-radius: 0;
-moz-border-radius: 0;
border-radius: 0;
}
.datepicker table tr td.range.today,
.datepicker table tr td.range.today:hover,
.datepicker table tr td.range.today.disabled,
.datepicker table tr td.range.today.disabled:hover {
background-color: #f3d17a;
background-image: -moz-linear-gradient(top, #f3c17a, #f3e97a);
background-image: -ms-linear-gradient(top, #f3c17a, #f3e97a);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f3c17a), to(#f3e97a));
background-image: -webkit-linear-gradient(top, #f3c17a, #f3e97a);
background-image: -o-linear-gradient(top, #f3c17a, #f3e97a);
background-image: linear-gradient(top, #f3c17a, #f3e97a);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f3c17a', endColorstr='#f3e97a', GradientType=0);
border-color: #f3e97a #f3e97a #edde34;
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
-webkit-border-radius: 0;
-moz-border-radius: 0;
border-radius: 0;
}
.datepicker table tr td.range.today:hover,
.datepicker table tr td.range.today:hover:hover,
.datepicker table tr td.range.today.disabled:hover,
.datepicker table tr td.range.today.disabled:hover:hover,
.datepicker table tr td.range.today:active,
.datepicker table tr td.range.today:hover:active,
.datepicker table tr td.range.today.disabled:active,
.datepicker table tr td.range.today.disabled:hover:active,
.datepicker table tr td.range.today.active,
.datepicker table tr td.range.today:hover.active,
.datepicker table tr td.range.today.disabled.active,
.datepicker table tr td.range.today.disabled:hover.active,
.datepicker table tr td.range.today.disabled,
.datepicker table tr td.range.today:hover.disabled,
.datepicker table tr td.range.today.disabled.disabled,
.datepicker table tr td.range.today.disabled:hover.disabled,
.datepicker table tr td.range.today[disabled],
.datepicker table tr td.range.today:hover[disabled],
.datepicker table tr td.range.today.disabled[disabled],
.datepicker table tr td.range.today.disabled:hover[disabled] {
background-color: #f3e97a;
}
.datepicker table tr td.range.today:active,
.datepicker table tr td.range.today:hover:active,
.datepicker table tr td.range.today.disabled:active,
.datepicker table tr td.range.today.disabled:hover:active,
.datepicker table tr td.range.today.active,
.datepicker table tr td.range.today:hover.active,
.datepicker table tr td.range.today.disabled.active,
.datepicker table tr td.range.today.disabled:hover.active {
background-color: #efe24b \9;
}
.datepicker table tr td.selected,
.datepicker table tr td.selected:hover,
.datepicker table tr td.selected.disabled,
.datepicker table tr td.selected.disabled:hover {
background-color: #9e9e9e;
background-image: -moz-linear-gradient(top, #b3b3b3, #808080);
background-image: -ms-linear-gradient(top, #b3b3b3, #808080);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#b3b3b3), to(#808080));
background-image: -webkit-linear-gradient(top, #b3b3b3, #808080);
background-image: -o-linear-gradient(top, #b3b3b3, #808080);
background-image: linear-gradient(top, #b3b3b3, #808080);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#b3b3b3', endColorstr='#808080', GradientType=0);
border-color: #808080 #808080 #595959;
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
color: #fff;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}
.datepicker table tr td.selected:hover,
.datepicker table tr td.selected:hover:hover,
.datepicker table tr td.selected.disabled:hover,
.datepicker table tr td.selected.disabled:hover:hover,
.datepicker table tr td.selected:active,
.datepicker table tr td.selected:hover:active,
.datepicker table tr td.selected.disabled:active,
.datepicker table tr td.selected.disabled:hover:active,
.datepicker table tr td.selected.active,
.datepicker table tr td.selected:hover.active,
.datepicker table tr td.selected.disabled.active,
.datepicker table tr td.selected.disabled:hover.active,
.datepicker table tr td.selected.disabled,
.datepicker table tr td.selected:hover.disabled,
.datepicker table tr td.selected.disabled.disabled,
.datepicker table tr td.selected.disabled:hover.disabled,
.datepicker table tr td.selected[disabled],
.datepicker table tr td.selected:hover[disabled],
.datepicker table tr td.selected.disabled[disabled],
.datepicker table tr td.selected.disabled:hover[disabled] {
background-color: #808080;
}
.datepicker table tr td.selected:active,
.datepicker table tr td.selected:hover:active,
.datepicker table tr td.selected.disabled:active,
.datepicker table tr td.selected.disabled:hover:active,
.datepicker table tr td.selected.active,
.datepicker table tr td.selected:hover.active,
.datepicker table tr td.selected.disabled.active,
.datepicker table tr td.selected.disabled:hover.active {
background-color: #666666 \9;
}
.datepicker table tr td.active,
.datepicker table tr td.active:hover,
.datepicker table tr td.active.disabled,
.datepicker table tr td.active.disabled:hover {
background-color: #006dcc;
background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
background-image: -ms-linear-gradient(top, #0088cc, #0044cc);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));
background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);
background-image: -o-linear-gradient(top, #0088cc, #0044cc);
background-image: linear-gradient(top, #0088cc, #0044cc);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);
border-color: #0044cc #0044cc #002a80;
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
color: #fff;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}
.datepicker table tr td.active:hover,
.datepicker table tr td.active:hover:hover,
.datepicker table tr td.active.disabled:hover,
.datepicker table tr td.active.disabled:hover:hover,
.datepicker table tr td.active:active,
.datepicker table tr td.active:hover:active,
.datepicker table tr td.active.disabled:active,
.datepicker table tr td.active.disabled:hover:active,
.datepicker table tr td.active.active,
.datepicker table tr td.active:hover.active,
.datepicker table tr td.active.disabled.active,
.datepicker table tr td.active.disabled:hover.active,
.datepicker table tr td.active.disabled,
.datepicker table tr td.active:hover.disabled,
.datepicker table tr td.active.disabled.disabled,
.datepicker table tr td.active.disabled:hover.disabled,
.datepicker table tr td.active[disabled],
.datepicker table tr td.active:hover[disabled],
.datepicker table tr td.active.disabled[disabled],
.datepicker table tr td.active.disabled:hover[disabled] {
background-color: #0044cc;
}
.datepicker table tr td.active:active,
.datepicker table tr td.active:hover:active,
.datepicker table tr td.active.disabled:active,
.datepicker table tr td.active.disabled:hover:active,
.datepicker table tr td.active.active,
.datepicker table tr td.active:hover.active,
.datepicker table tr td.active.disabled.active,
.datepicker table tr td.active.disabled:hover.active {
background-color: #003399 \9;
}
.datepicker table tr td span {
display: block;
width: 23%;
height: 54px;
line-height: 54px;
float: left;
margin: 1%;
cursor: pointer;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}
.datepicker table tr td span:hover {
background: #eeeeee;
}
.datepicker table tr td span.disabled,
.datepicker table tr td span.disabled:hover {
background: none;
color: #999999;
cursor: default;
}
.datepicker table tr td span.active,
.datepicker table tr td span.active:hover,
.datepicker table tr td span.active.disabled,
.datepicker table tr td span.active.disabled:hover {
background-color: #006dcc;
background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
background-image: -ms-linear-gradient(top, #0088cc, #0044cc);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));
background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);
background-image: -o-linear-gradient(top, #0088cc, #0044cc);
background-image: linear-gradient(top, #0088cc, #0044cc);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);
border-color: #0044cc #0044cc #002a80;
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
color: #fff;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}
.datepicker table tr td span.active:hover,
.datepicker table tr td span.active:hover:hover,
.datepicker table tr td span.active.disabled:hover,
.datepicker table tr td span.active.disabled:hover:hover,
.datepicker table tr td span.active:active,
.datepicker table tr td span.active:hover:active,
.datepicker table tr td span.active.disabled:active,
.datepicker table tr td span.active.disabled:hover:active,
.datepicker table tr td span.active.active,
.datepicker table tr td span.active:hover.active,
.datepicker table tr td span.active.disabled.active,
.datepicker table tr td span.active.disabled:hover.active,
.datepicker table tr td span.active.disabled,
.datepicker table tr td span.active:hover.disabled,
.datepicker table tr td span.active.disabled.disabled,
.datepicker table tr td span.active.disabled:hover.disabled,
.datepicker table tr td span.active[disabled],
.datepicker table tr td span.active:hover[disabled],
.datepicker table tr td span.active.disabled[disabled],
.datepicker table tr td span.active.disabled:hover[disabled] {
background-color: #0044cc;
}
.datepicker table tr td span.active:active,
.datepicker table tr td span.active:hover:active,
.datepicker table tr td span.active.disabled:active,
.datepicker table tr td span.active.disabled:hover:active,
.datepicker table tr td span.active.active,
.datepicker table tr td span.active:hover.active,
.datepicker table tr td span.active.disabled.active,
.datepicker table tr td span.active.disabled:hover.active {
background-color: #003399 \9;
}
.datepicker table tr td span.old,
.datepicker table tr td span.new {
color: #999999;
}
.datepicker th.datepicker-switch {
width: 145px;
}
.datepicker thead tr:first-child th,
.datepicker tfoot tr th {
cursor: pointer;
}
.datepicker thead tr:first-child th:hover,
.datepicker tfoot tr th:hover {
background: #eeeeee;
}
.datepicker .cw {
font-size: 10px;
width: 12px;
padding: 0 2px 0 5px;
vertical-align: middle;
}
.datepicker thead tr:first-child th.cw {
cursor: default;
background-color: transparent;
}
.input-append.date .add-on i,
.input-prepend.date .add-on i {
display: block;
cursor: pointer;
width: 16px;
height: 16px;
}
.input-daterange input {
text-align: center;
}
.input-daterange input:first-child {
-webkit-border-radius: 3px 0 0 3px;
-moz-border-radius: 3px 0 0 3px;
border-radius: 3px 0 0 3px;
}
.input-daterange input:last-child {
-webkit-border-radius: 0 3px 3px 0;
-moz-border-radius: 0 3px 3px 0;
border-radius: 0 3px 3px 0;
}
.input-daterange .add-on {
display: inline-block;
width: auto;
min-width: 16px;
height: 18px;
padding: 4px 5px;
font-weight: normal;
line-height: 18px;
text-align: center;
text-shadow: 0 1px 0 #ffffff;
vertical-align: middle;
background-color: #eeeeee;
border: 1px solid #ccc;
margin-left: -5px;
margin-right: -5px;
}

Some files were not shown because too many files have changed in this diff Show More