Skip to content
Browse files

Added the Controller & History.

Also added the SymfonyServiceContainer.

Fixed a few tests.
  • Loading branch information...
1 parent 8b7d49b commit 6dd1d842c303535cd80d7fdd422560e6d542dd66 @enyo committed
Showing with 4,172 additions and 85 deletions.
  1. +422 −0 library/Controller/Controller.php
  2. +30 −0 library/Controller/ControllerExceptions.php
  3. +106 −0 library/Controller/ControllerFactory.php
  4. +103 −0 library/Controller/LocationDelegate.php
  5. +25 −0 library/Controller/LocationDelegateDomainProvider.php
  6. +49 −0 library/Controller/MessageDelegate.php
  7. +98 −71 library/Dao/Dao.php
  8. +0 −1 library/Dao/DaoKeyListIterator.php
  9. +161 −0 library/History/History.php
  10. +108 −0 library/SymfonyServiceContainer/services.xsd
  11. +359 −0 library/SymfonyServiceContainer/sfServiceContainer.php
  12. +49 −0 library/SymfonyServiceContainer/sfServiceContainerAutoloader.php
  13. +351 −0 library/SymfonyServiceContainer/sfServiceContainerBuilder.php
  14. +45 −0 library/SymfonyServiceContainer/sfServiceContainerDumper.php
  15. +231 −0 library/SymfonyServiceContainer/sfServiceContainerDumperGraphviz.php
  16. +23 −0 library/SymfonyServiceContainer/sfServiceContainerDumperInterface.php
  17. +359 −0 library/SymfonyServiceContainer/sfServiceContainerDumperPhp.php
  18. +213 −0 library/SymfonyServiceContainer/sfServiceContainerDumperXml.php
  19. +201 −0 library/SymfonyServiceContainer/sfServiceContainerDumperYaml.php
  20. +39 −0 library/SymfonyServiceContainer/sfServiceContainerInterface.php
  21. +113 −0 library/SymfonyServiceContainer/sfServiceContainerLoader.php
  22. +101 −0 library/SymfonyServiceContainer/sfServiceContainerLoaderFile.php
  23. +50 −0 library/SymfonyServiceContainer/sfServiceContainerLoaderFileIni.php
  24. +282 −0 library/SymfonyServiceContainer/sfServiceContainerLoaderFileXml.php
  25. +216 −0 library/SymfonyServiceContainer/sfServiceContainerLoaderFileYaml.php
  26. +23 −0 library/SymfonyServiceContainer/sfServiceContainerLoaderInterface.php
  27. +243 −0 library/SymfonyServiceContainer/sfServiceDefinition.php
  28. +44 −0 library/SymfonyServiceContainer/sfServiceParameter.php
  29. +44 −0 library/SymfonyServiceContainer/sfServiceReference.php
  30. +73 −0 library/SymfonyServiceContainer/sfServiceSimpleXMLElement.php
  31. +0 −2 phpunit/library/Config/ConfigTest.php
  32. +0 −2 phpunit/library/File/ImageFileTest.php
  33. +6 −3 phpunit/library/Record/Record.CoerceTest.php
  34. +4 −4 phpunit/library/Record/Record.LazyLoading.php
  35. +0 −2 phpunit/library/Record/RecordTest.php
  36. +1 −0 phpunit/setup.php
View
422 library/Controller/Controller.php
@@ -0,0 +1,422 @@
+<?php
+
+/**
+ * This file contains the Controller definition.
+ *
+ * @author Matthias Loitsch <matthias@loitsch.com>
+ * @copyright Copyright (c) 2010, I-Netcompany
+ * @package Controller
+ */
+/**
+ * Including all exceptions
+ */
+include dirname(__FILE__) . '/ControllerExceptions.php';
+
+/**
+ * Including exceptions
+ */
+require_class('DispatcherException', dirname(__FILE__) . '/DispatcherExceptions.php');
+
+/**
+ * The Controller is the base class for every Controller type.
+ *
+ * When a Controller gets initialized, the constructor calls
+ * - authorize()
+ * - initialize()
+ * - validate()
+ * in that order.
+ *
+ * You then get the html output from the Controller, by calling getHtml()
+ *
+ *
+ * @author Matthias Loitsch <matthias@loitsch.com>
+ * @copyright Copyright (c) 2009, Matthias Loitsch
+ * @package Controller
+ */
+abstract class Controller {
+
+ /**
+ * Contains the action name. Eg.: index
+ * @var array
+ */
+ protected $action;
+ /**
+ * Containes the action parameters. Eg.: array('em@il.com', 1);
+ * @var array
+ */
+ protected $actionParameters = array();
+ /**
+ * You can set this, to use another template than the default controller template.
+ * @var string If not set, the controller and action names are used.
+ */
+ private $templateName;
+ /**
+ * Eg.: Register or login should not be kept in the history.
+ * @var bool Defines if the site should stay in the history.
+ */
+ protected $keepInHistory = true;
+ /**
+ * @var Theme
+ */
+ protected $theme;
+ /**
+ * @var MessageUtils
+ */
+ private $messageDelegate;
+ /**
+ *
+ * @var Data
+ */
+ protected $currentData;
+ /**
+ *
+ * @var LocationDelegate
+ */
+ protected $locationDelegate;
+ /**
+ *
+ * @var History
+ */
+ protected $history;
+
+ /**
+ * @param Theme $theme
+ * @param MessageDelegate $messageDelegate
+ * @param LocationDelegate $locationDelegate
+ * @param History $history
+ */
+ public function __construct(Theme $theme, MessageDelegate $messageDelegate, LocationDelegate $locationDelegate, History $history) {
+ $this->theme = $theme;
+ $this->messageDelegate = $messageDelegate;
+ $this->history = $history;
+ $this->setLocationDelegate($locationDelegate);
+ }
+
+ /**
+ * Overwrite this function to return a title (html meta tag <title></title>)
+ *
+ * @return string
+ */
+ public function getTitle() {
+ return 'Site Title';
+ }
+
+ /**
+ * Returns the controller name without Controller at the end.
+ * @return string
+ */
+ public function getName() {
+ return str_replace('Controller', '', get_class($this));
+ }
+
+ /**
+ * Returns the action
+ * @return string
+ */
+ public function getAction() {
+ return $this->action;
+ }
+
+ /**
+ *
+ * @param string $action
+ */
+ public function setAction($action) {
+ $this->action = $action;
+ }
+
+ /**
+ * @return array
+ */
+ public function getActionParameters() {
+ return $this->actionParameters;
+ }
+
+ /**
+ * @param array $actionParameters
+ */
+ public function setActionParameters(array $actionParameters) {
+ $this->actionParameters = $actionParameters;
+ }
+
+ /**
+ * Returns either $templateName or, if not set, the controller name + the action (eg.: product.show).
+ *
+ * @return string
+ * @uses $templateName
+ * @see setTemplateName()
+ */
+ public function getTemplateName() {
+ if ($this->templateName) {
+ $templateName = $this->templateName;
+ } else {
+ $templateName = $this->convertPhpNameToTemplateName($this->getName());
+ if ($this->getAction() !== 'index') {
+ $templateName .= '.' . $this->convertPhpNameToTemplateName($this->getAction());
+ }
+ }
+
+ return $templateName;
+ }
+
+ /**
+ * @param string $templateName
+ * @uses $templateName
+ * @see getTemplateName()
+ */
+ public function setTemplateName($templateName) {
+ $this->templateName = $templateName;
+ }
+
+ /**
+ * @return bool
+ */
+ public function keepInHistory() {
+ return $this->keepInHistory;
+ }
+
+ /**
+ * Calls authorize, prepare and validate in this order.
+ * The ControllerFactory calls initialize when creating a controller, if $skipInitialization == false
+ *
+ * If you skip it, make sure you call all methods yourself!
+ *
+ * If validate() throws a ErrorMessageException, the exception gets caught,
+ * and the message added to the message list.
+ *
+ *
+ * @see authorize()
+ * @see prepare()
+ * @see validate()
+ * @see ErrorMessageException
+ */
+ final public function initialize() {
+ if (($error = $this->locationDelegate->getUrlErrorMessage()) !== null) {
+ $this->addErrorMessage($error);
+ }
+
+ if (($success = $this->locationDelegate->getUrlSuccessMessage()) !== null) {
+ $this->addSuccessMessage($success);
+ }
+
+ try {
+ $this->authorize();
+ $this->prepare();
+ } catch (DatabaseException $e) {
+ Log::error($e->getMessage(), 'Controller', array('siteName' => $this->getSiteName()));
+ throw new ControllerException('Database error.');
+ }
+ if ($this->keepInHistory()) {
+ $this->history->addUrl($this->getUrl());
+ }
+ }
+
+ /**
+ * This is the first function called in initialize().
+ * If the user needs special rights to view a page, this is the place to check for it.
+ *
+ * @see initialize()
+ */
+ public function authorize() {
+
+ }
+
+ /**
+ * This is the second function called in initialize().
+ * If the site needs some preparing (e.g.: Reading some GET vars, or setting main variables), this
+ * is the place to do it.
+ *
+ * You should mainly put stuff in here, that makes sense for the whole controller, for all actions.
+ *
+ * @see initialize()
+ */
+ public function prepare() {
+
+ }
+
+ /**
+ * @param LocationDelegate $locationDelegate
+ */
+ public function setLocationDelegate(LocationDelegate $locationDelegate) {
+ $locationDelegate->setController($this);
+ $this->locationDelegate = $locationDelegate;
+ }
+
+ /**
+ * @return LocationDelegate
+ */
+ public function getLocationDelegate() {
+ return $this->locationDelegate;
+ }
+
+ /**
+ * Wrapper for MessageUtils::addErrorMessage()
+ *
+ * @param string|array $message
+ * @see MessageUtils::addErrorMessage()
+ */
+ public function addErrorMessage($message) {
+ $this->messageDelegate->addErrorMessage($message);
+ }
+
+ /**
+ * Wrapper for MessageUtils::addSuccessMessage()
+ *
+ * @param string|array $message
+ * @see MessageUtils::addSuccessMessage()
+ */
+ public function addSuccessMessage($message) {
+ $this->messageDelegate->addSuccessMessage($message);
+ }
+
+ /**
+ * Wrapper for LocationDelegate
+ *
+ * @param string $targetControllerName if null, the current url is used.
+ * @param string,... $action A list of possible action strings.
+ * @param array $get
+ * @uses LocationDelegate::getUrl()
+ */
+ public function getUrl() {
+ $params = func_get_args();
+ return call_user_func_array(array($this->locationDelegate, 'getUrl'), func_get_args());
+ }
+
+ /**
+ * Wrapper for LocationDelegate
+ *
+ * @param string $targetControllerName if null, the current url is used.
+ * @param string,... $action A list of possible action strings.
+ * @param array $get
+ * @uses LocationDelegate::getLink()
+ */
+ public function getLink() {
+ $params = func_get_args();
+ return call_user_func_array(array($this->locationDelegate, 'getLink'), func_get_args());
+ }
+
+ /**
+ * Wrapper for LocationDelegate
+ *
+ * @param string $targetControllerName if null, the current url is used.
+ * @param [string..] $action A list of possible action strings.
+ * @param array $get
+ * @uses getUrl()
+ */
+ public function redirect() {
+ $params = func_get_args();
+ return call_user_func_array(array($this->locationDelegate, 'redirect'), func_get_args());
+ }
+
+ /**
+ * Wrapper for LocationDelegate
+ *
+ * @param string $error
+ * @param string $targetControllerName if null, the current url is used.
+ * @param [string..] $action A list of possible action strings.
+ * @param array $get
+ */
+ public function redirectWithError() {
+ $params = func_get_args();
+ return call_user_func_array(array($this->locationDelegate, 'redirectWithError'), func_get_args());
+ }
+
+ /**
+ * Wrapper for LocationDelegate
+ *
+ * @param string $success
+ * @param string $targetControllerName if null, the current url is used.
+ * @param [string..] $action A list of possible action strings.
+ * @param array $get
+ */
+ public function redirectWithSuccess() {
+ $params = func_get_args();
+ return call_user_func_array(array($this->locationDelegate, 'redirectWithSuccess'), func_get_args());
+ }
+
+ /**
+ * Wrapper for LocationDelegate
+ *
+ * @param string $url
+ * @uses $locationDelegate::redirectToUrl()
+ */
+ public function redirectToUrl($url) {
+ $params = func_get_args();
+ return call_user_func_array(array($this->locationDelegate, 'redirectToUrl'), func_get_args());
+ }
+
+ /**
+ * Assign a value to the data object.
+ * @param string $name
+ * @param mixed $value
+ */
+ protected function assign($name, $value) {
+ $this->currentData->assign($name, $value);
+ }
+
+ /**
+ * Gets the data object from the Theme object, then calls initData() and extendData() with it. So when you write
+ * a specific Controller implementation, overwrite extendData() to put your own data inside.
+ *
+ * It then calls the processSite() method on the theme and returns the output.
+ *
+ * If $initalizationFailed is true, then extendDate is *not* called, and processSite
+ * is called with the error template name.
+ *
+ * @param bool $output If true, directly output the result, do not return it.
+ * @see extendData()
+ * @see Theme
+ * @see Theme::processSite()
+ * @todo handle errors in url parsing better!
+ */
+ public function render($output = true) {
+ $this->assign('errorMessages', $this->messageDelegate->getErrorMessages());
+ $this->assign('successMessages', $this->messageDelegate->getSuccessMessages());
+
+ $this->theme->processSite($this->getTemplateName(), $this->currentData, $output);
+ }
+
+ /**
+ * Renders the error site.
+ */
+ public function renderError($errorCode = null, $output = true) {
+ $templateName = 'error';
+ if ($errorCode) {
+ $templateName .= '.' . $errorCode;
+ }
+ $this->setTemplateName($templateName);
+ $this->render($output);
+ }
+
+ /**
+ * eg: MyAccountController -> my_account
+ *
+ * @return string
+ */
+ protected function convertPhpNameToTemplateName($name) {
+ $templateName = lcfirst(str_replace('Controller', '', $name));
+ return preg_replace('/([A-Z])/e', 'strtolower("_$1")', $templateName);
+ }
+
+ /**
+ * Initializes the currentData object.
+ *
+ * Here the basic information is put in a Dwoo_Data object.
+ *
+ * @uses currentData
+ */
+ public function initData() {
+ $this->currentData = $this->theme->getDataObject();
+ }
+
+ /**
+ * This gets called after the current action has been executed.
+ *
+ * @uses currentData
+ */
+ public function extendData() {
+
+ }
+
+}
+
View
30 library/Controller/ControllerExceptions.php
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * This file contains all ControllerExceptions
+ *
+ * @author Matthias Loitsch <matthias@loitsch.com>
+ * @copyright Copyright (c) 2010, I-Netcompany
+ * @package Controller
+ */
+
+/**
+ * The ControllerException
+ * @author Matthias Loitsch <matthias@loitsch.com>
+ * @copyright Copyright (c) 2010, I-Netcompany
+ * @package Controller
+ */
+class ControllerException extends Exception {
+
+}
+
+/**
+ * Is thrown on errors.
+ * @author Matthias Loitsch <matthias@loitsch.com>
+ * @copyright Copyright (c) 2010, I-Netcompany
+ * @package Controller
+ */
+class Error extends ControllerException {
+
+}
+
View
106 library/Controller/ControllerFactory.php
@@ -0,0 +1,106 @@
+<?php
+
+/**
+ * This file contains the ControllerFactory definition.
+ *
+ * @author Matthias Loitsch <matthias@loitsch.com>
+ * @copyright Copyright (c) 2010, I-Netcompany
+ * @package Controller
+ */
+
+/**
+ * Thrown when a Controller is not found.
+ */
+class ControllerFactoryException extends Exception {
+
+}
+
+/**
+ * The ControllerFactory is the way to get a Controller for a site.
+ * It handles dependency injection and whatnot.
+ *
+ * @author Matthias Loitsch <matthias@loitsch.com>
+ * @copyright Copyright (c) 2009, Matthias Loitsch
+ * @package Controller
+ */
+abstract class ControllerFactory {
+
+ /**
+ * @var sfServiceContainer
+ */
+ protected $container;
+ /**
+ * Defines where the controllers reside.
+ * @var string
+ */
+ protected $controllerRootPath;
+ /**
+ * @var array
+ */
+ protected $availableAutowiredServices = array();
+
+ /**
+ * @param sfServiceContainer $container
+ * @param array $availableAutowiredServices A list of services the controller factory should autowire (dependency injection).
+ * @param string $controllerRootPath if you do not set it in the constructor,
+ * make sure you set it via setControllerRootPath
+ * before calling get() because this will result
+ * in an error otherwise.
+ */
+ public function __construct($container, $availableAutowiredServices = array(), $controllerRootPath = null) {
+ $this->container = $container;
+ $this->availableAutowiredServices = $availableAutowiredServices;
+ $this->setControllerRootPath($controllerRootPath);
+ }
+
+ /**
+ * Has to be called before get()
+ * @param string $path
+ */
+ public function setControllerRootPath($path) {
+ $this->controllerRootPath = $path;
+ }
+
+ /**
+ * Returns a specific controller, passing on all the objects the Factory got in the constructor.
+ *
+ * This method also takes care of dependency injections. If it finds a method
+ * called setShopDaoFactory() on the siteController for instance, it injects the factory.
+ *
+ * @param string $controllerName
+ * @param bool $skipInitialization If true, neither authorize(), initialize() nor validate() is called on the Controller.
+ * @return Controller
+ */
+ public function get($controllerName, $skipInitialization = false) {
+ if ( ! $this->controllerRootPath) trigger_error('The controller root path was not defined.', E_USER_ERROR);
+
+ $className = $controllerName . 'Controller';
+
+ $classUri = $this->controllerRootPath . $className . '.php';
+
+ if ( ! file_exists($classUri)) throw new ControllerFactoryException('File for controller does not exist.');
+
+ include $classUri;
+
+ if ( ! class_exists($className, false)) throw new ControllerFactoryException('File for controller did exist, but class was not defined.');
+
+ $siteController = $this->getController($className);
+
+ // Dependency injections
+ foreach ($this->availableAutowiredServices as $service) {
+ if (property_exists($siteController, $service)) {
+ $siteController->$service = $this->container->$service;
+ }
+ }
+
+ return $siteController;
+ }
+
+
+ /**
+ * @param string $className
+ * @return Controller
+ */
+ abstract protected function getController($className);
+
+}
View
103 library/Controller/LocationDelegate.php
@@ -0,0 +1,103 @@
+<?php
+
+/**
+ * This file contains the LocationDelegate interface definition.
+ *
+ * @author Matthias Loitsch <matthias@loitsch.com>
+ * @copyright Copyright (c) 2010, I-Netcompany
+ * @package Controller
+ */
+
+/**
+ * @author Matthias Loitsch <matthias@loitsch.com>
+ * @copyright Copyright (c) 2009, Matthias Loitsch
+ * @package Controller
+ */
+interface LocationDelegate {
+
+ /**
+ * @param Controller $controller
+ */
+ public function setController(Controller $controller);
+
+ /**
+ * A call to this could look like this:
+ *
+ * getUrl('address', 'delete', 2, array('confirmed' => true))
+ *
+ * This would result in:
+ * /address/delete/2?confirmed=true
+ * or
+ * ?controller=address&action=delete/2&confirmed=true
+ *
+ * If you want to redirect to the current url, use:
+ * getUrl()
+ * or if you want to pass get parameters to the current url, use:
+ * getUrl(null, array('confirmed' => true))
+ *
+ * @param string $targetControllerName if null, the current url is used.
+ * @param string,... $action A list of possible action strings.
+ * @param array $get
+ */
+ public function getUrl($targetControllerName = null);
+
+ /**
+ * The same as getUrl, but without session ID information, and with
+ * http://linktosite/ prepended.
+ *
+ * @param string $targetControllerName if null, the current url is used.
+ * @param string,... $action A list of possible action strings.
+ * @param array $get
+ * @see getUrl()
+ */
+ public function getLink($targetControllerName = null);
+
+ /**
+ * Uses getUrl to get the url, and redirect there.
+ *
+ * @param string $targetControllerName if null, the current url is used.
+ * @param [string..] $action A list of possible action strings.
+ * @param array $get
+ * @uses getUrl()
+ */
+ public function redirect($targetControllerName = null);
+
+ /**
+ * The same as redirect, but adds an encrypted error as get variable.
+ *
+ * @param string $error
+ * @param string $targetControllerName if null, the current url is used.
+ * @param [string..] $action A list of possible action strings.
+ * @param array $get
+ */
+ public function redirectWithError($error, $targetControllerName = null);
+
+ /**
+ * Returns an url error if set.
+ * @return string null if none
+ */
+ public function getUrlErrorMessage();
+
+ /**
+ * Returns an url success if set.
+ * @return string null if none
+ */
+ public function getUrlSuccessMessage();
+
+ /**
+ * The same as redirect, but adds an encrypted success as get variable.
+ *
+ * @param string $success
+ * @param string $targetControllerName if null, the current url is used.
+ * @param [string..] $action A list of possible action strings.
+ * @param array $get
+ */
+ public function redirectWithSuccess($success, $targetControllerName = null);
+
+ /**
+ * Redirects to url, and exits.
+ *
+ * @param string $url
+ */
+ public function redirectToUrl($url);
+}
View
25 library/Controller/LocationDelegateDomainProvider.php
@@ -0,0 +1,25 @@
+<?php
+/**
+ * This file contains the LocationDomainProviderInterface definition.
+ *
+ * @author Matthias Loitsch <matthias@loitsch.com>
+ * @copyright Copyright (c) 2010, I-Netcompany
+ * @package Controller
+ */
+
+/**
+ * @author Matthias Loitsch <matthias@loitsch.com>
+ * @copyright Copyright (c) 2009, Matthias Loitsch
+ * @package Controller
+ */
+interface LocationDelegateDomainProvider {
+
+ /**
+ * This method should cache the domain, so calling it multiple times does not
+ * impact performance.
+ *
+ * @return string the domain. Eg: www.shop.com:8080
+ */
+ public function getDomain();
+
+}
View
49 library/Controller/MessageDelegate.php
@@ -0,0 +1,49 @@
+<?php
+
+/**
+ * The file for the message delegate
+ *
+ * @author Matthias Loitsch <matthias@loitsch.com>
+ * @copyright Copyright (c) 2011, Matthias Loitsch
+ * @package Controller
+ * @subpackage Message
+ */
+
+/**
+ * The MessageDelegate ist used to store messages that should appear on screen.
+ *
+ * @author Matthias Loitsch <matthias@loitsch.com>
+ * @copyright Copyright (c) 2011, Matthias Loitsch
+ * @package Controller
+ * @subpackage Message
+ */
+interface MessageDelegate {
+
+ /**
+ * If you pass an array, every value will be added as message. This way
+ * you can pass multiple messages at once.
+ *
+ * @param string|array $message
+ */
+ public function addErrorMessage($message);
+
+ /**
+ * If you pass an array, every value will be added as message. This way
+ * you can pass multiple messages at once.
+ *
+ * @param string|array $message
+ */
+ public function addSuccessMessage($message);
+
+ /**
+ * @return array
+ */
+ public function getErrorMessages();
+
+ /**
+ * @return array
+ */
+ public function getSuccessMessages();
+
+}
+
View
169 library/Dao/Dao.php
@@ -18,11 +18,6 @@
include dirname(__FILE__) . '/DaoAttributeAssignment.php';
/**
- * Loading the Record Class
- */
-include dirname(dirname(__FILE__)) . '/Record/Record.php';
-
-/**
* Loading the Exceptions
*/
include dirname(__FILE__) . '/DaoExceptions.php';
@@ -38,9 +33,14 @@
include dirname(__FILE__) . '/DaoHashListIterator.php';
/**
+ * Loading the Record Class
+ */
+require_class('Record');
+
+/**
* Loading the Date Class
*/
-if ( ! class_exists('Date', false)) include dirname(dirname(__FILE__)) . '/Date/Date.php';
+require_class('Date');
/**
* This abstract base class for all Daos.
@@ -157,7 +157,7 @@ public function __construct() {
$this->defaultValueAttributes = array_merge($this->defaultValueAttributes, $this->additionalDefaultValueAttributes());
$this->attributeImportMapping = array_merge($this->attributeImportMapping, $this->additionalAttributeImportMapping());
- if ( ! $this->resourceName) {
+ if (!$this->resourceName) {
throw new DaoException('No resource name provided in class ' . get_class($this) . '.');
}
if (count($this->attributes) === 0) {
@@ -309,7 +309,7 @@ protected function additionalAttributeImportMapping() {
* @uses $references
*/
public function getReference($attributeName) {
- if ( ! isset($this->references[$attributeName])) {
+ if (!isset($this->references[$attributeName])) {
if ($this->getAttributeType($attributeName) !== Dao::REFERENCE) {
Log::fatal("Can't create a reference for an attribute that is not of type Dao::REFERENCE.", 'Dao', array('Resource' => $this->getResourceName(), 'Attribute' => $attributeName));
throw new DaoException("Can't create the reference for attribute $attributeName.");
@@ -317,13 +317,14 @@ public function getReference($attributeName) {
$methodName = 'get' . ucfirst($attributeName) . 'Reference';
- if ( ! method_exists($this, $methodName)) {
+ if (!method_exists($this, $methodName)) {
Log::fatal("Can't create a reference, because $methodName does not exist.", 'Dao', array('Resource' => $this->getResourceName(), 'Attribute' => $attributeName));
throw new DaoException("The method $methodName does not exist to create the reference.");
}
$reference = $this->$methodName();
- if ( ! $reference || ! is_a($reference, 'DaoReference')) trigger_error('The reference returned by ' . $this->resourceName . '/' . $methodName . ' is null or invalid.', E_USER_ERROR);
+ if (!$reference || !is_a($reference, 'DaoReference'))
+ trigger_error('The reference returned by ' . $this->resourceName . '/' . $methodName . ' is null or invalid.', E_USER_ERROR);
$reference->setSourceDao($this);
return $this->references[$attributeName] = $reference;
}
@@ -388,9 +389,11 @@ public function createDao($daoName) {
* @return Record
*/
public function get($map = null, $exportValues = true, $resourceName = null) {
- if ( ! $map) return $this->getRawRecord();
+ if (!$map)
+ return $this->getRawRecord();
$record = $this->find($map, $exportValues, $resourceName);
- if ( ! $record) throw new DaoNotFoundException('Did not find any record.');
+ if (!$record)
+ throw new DaoNotFoundException('Did not find any record.');
return $record;
}
@@ -404,7 +407,8 @@ public function get($map = null, $exportValues = true, $resourceName = null) {
*/
public function find($map, $exportValues = true, $resourceName = null) {
$data = $this->findData($map, $exportValues, $resourceName);
- if ( ! $data) return null;
+ if (!$data)
+ return null;
return $this->getRecordFromPreparedData($data);
}
@@ -417,7 +421,8 @@ public function find($map, $exportValues = true, $resourceName = null) {
*/
public function getData($map = null, $exportValues = true, $resourceName = null) {
$data = $this->findData($map, $exportValues, $resourceName);
- if ( ! $data) throw new DaoNotFoundException('Did not find any record.');
+ if (!$data)
+ throw new DaoNotFoundException('Did not find any record.');
return $data;
}
@@ -439,11 +444,9 @@ public function getData($map = null, $exportValues = true, $resourceName = null)
if (is_int($map)) {
$id = $map;
$map = array('id' => $map);
- }
- elseif (is_array($map) && array_key_exists('id', $map)) {
+ } elseif (is_array($map) && array_key_exists('id', $map)) {
$id = $map['id'];
- }
- elseif (is_a($map, 'Record')) {
+ } elseif (is_a($map, 'Record')) {
$id = $map->id;
}
@@ -460,7 +463,8 @@ public function getData($map = null, $exportValues = true, $resourceName = null)
$data = $this->doFindData($map, $exportValues, $resourceName);
- if ( ! $data) return null;
+ if (!$data)
+ return null;
$data = $this->prepareDataForRecord($data);
@@ -577,8 +581,10 @@ public function getAttributes() {
* @return int null if the attribute does not exist.
*/
public function getAttributeType($attributeName) {
- if (isset($this->attributes[$attributeName])) return $this->attributes[$attributeName];
- else return null;
+ if (isset($this->attributes[$attributeName]))
+ return $this->attributes[$attributeName];
+ else
+ return null;
}
/**
@@ -814,7 +820,7 @@ protected function convertAttributeNameToPhpName($attributeName) {
* @return bool
*/
public function notNull($attributeName) {
- return ! in_array($attributeName, $this->nullAttributes);
+ return!in_array($attributeName, $this->nullAttributes);
}
/**
@@ -841,10 +847,12 @@ protected function getInsertValues($record) {
$attributes = array();
$id = null;
foreach ($this->attributes as $attributeName => $type) {
- if ($type === Dao::IGNORE) continue;
+ if ($type === Dao::IGNORE)
+ continue;
if ($type === Dao::REFERENCE) {
$reference = $this->getReference($attributeName);
- if ( ! $reference->export()) continue;
+ if (!$reference->export())
+ continue;
$value = $record->getDirectly($attributeName);
}
else {
@@ -879,8 +887,7 @@ protected function getUpdateValues($record) {
$addToAttributes = true;
$value = $record->getDirectly($attributeName);
}
- }
- else {
+ } else {
$addToAttributes = true;
$value = $record->get($attributeName);
}
@@ -918,7 +925,8 @@ protected function getRecordFromPreparedData($data, $existsInDatabase = true) {
* @return Record
*/
public function getRecordFromData($data, $existsInDatabase = true, $prepareData = true) {
- if ($prepareData === true) $data = $this->prepareDataForRecord($data);
+ if ($prepareData === true)
+ $data = $this->prepareDataForRecord($data);
return $this->getRecordFromPreparedData($data);
}
@@ -947,7 +955,8 @@ protected function prepareDataForRecord($data) {
$neededValues = $this->attributes;
- if ( ! is_array($data)) trigger_error('The data provided was not an array (' . $this->resourceName . ').', E_USER_ERROR);
+ if (!is_array($data))
+ trigger_error('The data provided was not an array (' . $this->resourceName . ').', E_USER_ERROR);
foreach ($data as $attributeName => $value) {
$attributeName = $this->importAttributeName($attributeName);
@@ -956,13 +965,11 @@ protected function prepareDataForRecord($data) {
if ($this->attributes[$attributeName] !== Dao::IGNORE) {
$recordData[$attributeName] = $this->importValue($attributeName, $value, $this->attributes[$attributeName], $this->notNull($attributeName));
}
- }
- elseif (array_key_exists($attributeName, $this->additionalAttributes)) {
+ } elseif (array_key_exists($attributeName, $this->additionalAttributes)) {
if ($this->additionalAttributes[$attributeName] !== Dao::IGNORE) {
$recordData[$attributeName] = $this->importValue($attributeName, $value, $this->additionalAttributes[$attributeName], $this->notNull($attributeName));
}
- }
- else {
+ } else {
$trace = debug_backtrace();
trigger_error('The type for attribute "' . $attributeName . '" (resource: "' . $this->resourceName . '") is not defined', E_USER_WARNING);
}
@@ -973,8 +980,7 @@ protected function prepareDataForRecord($data) {
$trace = debug_backtrace();
trigger_error('The attribute "' . $attributeName . '" (resource: "' . $this->resourceName . '") was not transmitted from data source', E_USER_WARNING);
$recordData[$attributeName] = $this->coerce($attributeName, null, $type, false, $quiet = true);
- }
- else {
+ } else {
$recordData[$attributeName] = null;
}
}
@@ -1001,8 +1007,8 @@ public function getRawRecord() {
foreach ($this->attributes as $attributeName => $type) {
if (in_array($attributeName, $this->nullAttributes) || in_array($attributeName, $this->defaultValueAttributes)) {
$data[$attributeName] = null;
- }
- elseif ($type != Dao::IGNORE) $data[$attributeName] = $this->coerce($attributeName, null, $type, $allowNull = false, $quiet = true);
+ } elseif ($type != Dao::IGNORE)
+ $data[$attributeName] = $this->coerce($attributeName, null, $type, $allowNull = false, $quiet = true);
}
return $this->getRecordFromPreparedData($data, $existsInDatabase = false);
}
@@ -1021,16 +1027,16 @@ public function getRawRecord() {
* @return mixed
*/
public function importValue($attributeName, $externalValue, $type, $notNull = true) {
- if ( ! $notNull && $externalValue === null) {
+ if (!$notNull && $externalValue === null) {
return null;
}
try {
$importMethod = 'import' . (is_array($type) ? 'Enum' : $type);
- if ( ! method_exists($this, $importMethod)) throw new DaoException('The import method ' . $importMethod . ' does not exist.');
+ if (!method_exists($this, $importMethod))
+ throw new DaoException('The import method ' . $importMethod . ' does not exist.');
return $this->$importMethod($externalValue, $type, $attributeName);
- }
- catch (DaoException $e) {
+ } catch (DaoException $e) {
throw new DaoException('There was an error importing the attribute "' . $attributeName . '" in resource "' . $this->resourceName . '": ' . $e->getMessage());
}
}
@@ -1107,7 +1113,8 @@ public function importString($value) {
* @return string
*/
public function importEnum($value, $list) {
- if ( ! in_array($value, $list)) throw new DaoException("The value provided is not defined in the enum.");
+ if (!in_array($value, $list))
+ throw new DaoException("The value provided is not defined in the enum.");
return (string) $value;
}
@@ -1118,8 +1125,10 @@ public function importEnum($value, $list) {
* @return bool
*/
public function importBool($value) {
- if ( ! $value) return false;
- if (is_int($value)) return true;
+ if (!$value)
+ return false;
+ if (is_int($value))
+ return true;
$value = strtolower($value);
switch ($value) {
case 'false': case 'f': case '0': return false;
@@ -1148,7 +1157,8 @@ public function importSequence($value) {
* @return mixed
*/
public function importReference($value, $type, $attributeName) {
- if ($value === null) throw new DaoException('Reference is marked as not null, but the value to import is null.');
+ if ($value === null)
+ throw new DaoException('Reference is marked as not null, but the value to import is null.');
return $this->getReference($attributeName)->importValue($value);
}
@@ -1166,22 +1176,23 @@ public function importReference($value, $type, $attributeName) {
* @return mixed
*/
public function exportValue($attributeName, $internalValue, $type, $notNull = true) {
- if ( ! $notNull && $internalValue === NULL) return $this->exportNull();
+ if (!$notNull && $internalValue === NULL)
+ return $this->exportNull();
- if ($type === Dao::IGNORE) return $this->exportNull();
+ if ($type === Dao::IGNORE)
+ return $this->exportNull();
try {
if (is_array($type)) {
// Enum
$exportMethod = 'exportEnum';
- }
- else {
+ } else {
$exportMethod = 'export' . $type;
- if ( ! method_exists($this, $exportMethod)) throw new DaoException('The export method ' . $exportMethod . ' does not exist.');
+ if (!method_exists($this, $exportMethod))
+ throw new DaoException('The export method ' . $exportMethod . ' does not exist.');
}
return $this->$exportMethod($internalValue, $attributeName, $type);
- }
- catch (DaoException $e) {
+ } catch (DaoException $e) {
throw new DaoException('There was an error exporting the attribute "' . $attributeName . '" in resource "' . $this->resourceName . '": ' . $e->getMessage());
}
}
@@ -1290,7 +1301,8 @@ public function exportDateWithTime($date) {
* @return string
*/
public function exportEnum($value, $attributeName, $list) {
- if ( ! in_array($value, $list)) throw new DaoWrongValueException("The value provided is not defined in the enum.");
+ if (!in_array($value, $list))
+ throw new DaoWrongValueException("The value provided is not defined in the enum.");
return $this->exportString($value);
}
@@ -1340,19 +1352,21 @@ public function coerce($attributeName, $value, $type, $allowNull = false, $quiet
}
if (is_array($type)) {
- if ( ! count($type)) trigger_error("Invalid enum for '" . $this->getResourceName() . ".$attributeName'.", E_USER_ERROR);
+ if (!count($type))
+ trigger_error("Invalid enum for '" . $this->getResourceName() . ".$attributeName'.", E_USER_ERROR);
$coerceMethod = 'coerceEnum';
}
else {
$coerceMethod = 'coerce' . $type;
- if ( ! method_exists($this, $coerceMethod)) throw new DaoException('The coerce method ' . $coerceMethod . ' does not exist.');
+ if (!method_exists($this, $coerceMethod))
+ throw new DaoException('The coerce method ' . $coerceMethod . ' does not exist.');
}
return $this->$coerceMethod($value, $attributeName, $type);
- }
- catch (DaoCoerceException $e) {
+ } catch (DaoCoerceException $e) {
$message = $e->getMessage();
- if ( ! $quiet && ! empty($message)) trigger_error($message . " (" . $this->getResourceName() . ".$attributeName)", E_USER_WARNING);
+ if (!$quiet && !empty($message))
+ trigger_error($message . " (" . $this->getResourceName() . ".$attributeName)", E_USER_WARNING);
return $allowNull ? null : $e->getFallbackValue();
}
}
@@ -1367,9 +1381,11 @@ public function coerce($attributeName, $value, $type, $allowNull = false, $quiet
* @throws DaoCoerceException
*/
public function coerceId($id) {
- if (is_object($id) && $id instanceof Record) return $id->get('id');
+ if (is_object($id) && $id instanceof Record)
+ return $id->get('id');
- if (is_int($id) || is_numeric($id)) return (int) $id;
+ if (is_int($id) || is_numeric($id))
+ return (int) $id;
throw new DaoCoerceException(null, "Invalid id provided.");
}
@@ -1382,7 +1398,8 @@ public function coerceId($id) {
* @throws DaoCoerceException
*/
public function coerceEnum($value, $attributeName, $list) {
- if (in_array($value, $list)) return $value;
+ if (in_array($value, $list))
+ return $value;
throw new DaoCoerceException($list[0], "Invalid enum value provided.");
}
@@ -1393,8 +1410,10 @@ public function coerceEnum($value, $attributeName, $list) {
* @throws DaoCoerceException
*/
public function coerceBool($value) {
- if ($value === true || $value === 'true' || $value === '1' || $value === 1) return true;
- if ($value === false || $value === 'false' || $value === '0' || $value === 0) return false;
+ if ($value === true || $value === 'true' || $value === '1' || $value === 1)
+ return true;
+ if ($value === false || $value === 'false' || $value === '0' || $value === 0)
+ return false;
throw new DaoCoerceException(true, "Invalid boolean provided.");
}
@@ -1418,7 +1437,8 @@ public function coerceInteger($value) {
* @throws DaoCoerceException
*/
public function coerceFloat($value) {
- if (is_float($value) || is_numeric($value)) return (float) $value;
+ if (is_float($value) || is_numeric($value))
+ return (float) $value;
throw new DaoCoerceException(0.0, "Invalid float provided.");
}
@@ -1429,9 +1449,11 @@ public function coerceFloat($value) {
* @throws DaoCoerceException
*/
public function coerceDate($value) {
- if ($value instanceof Date) return $value->getTimestamp();
+ if ($value instanceof Date)
+ return $value->getTimestamp();
- if (is_numeric($value)) return (int) $value;
+ if (is_numeric($value))
+ return (int) $value;
throw new DaoCoerceException(time(), "Invalid date provided.");
}
@@ -1452,7 +1474,8 @@ public function coerceDateWithTime($value) {
* @throws DaoCoerceException
*/
public function coerceString($value) {
- if (is_string($value) || is_numeric($value)) return (string) $value;
+ if (is_string($value) || is_numeric($value))
+ return (string) $value;
throw new DaoCoerceException('', "Invalid date provided.");
}
@@ -1463,7 +1486,8 @@ public function coerceString($value) {
* @throws DaoCoerceException
*/
public function coerceSequence($value) {
- if (is_array($value)) return $value;
+ if (is_array($value))
+ return $value;
throw new DaoCoerceException(array(), "Invalid sequence provided.");
}
@@ -1489,21 +1513,24 @@ public function coerceReference($value, $attributeName) {
* @return array An array containing all attributes to sort by, escaped, and ASC or DESC appended. E.g.: array('name DESC', 'age');
*/
protected function interpretSortVariable($sort) {
- if ( ! is_array($sort)) {
+ if (!is_array($sort)) {
return $this->attributeExists($sort) ? array($this->exportAttributeName($sort)) : null;
}
- if (count($sort) == 0) return null;
+ if (count($sort) == 0)
+ return null;
$attributeArray = array();
if (self::isVector($sort)) {
foreach ($sort as $attributeName) {
- if ($this->attributeExists($attributeName)) $attributeArray[] = $this->exportAttributeName($attributeName);
+ if ($this->attributeExists($attributeName))
+ $attributeArray[] = $this->exportAttributeName($attributeName);
}
}
else {
foreach ($sort as $attributeName => $sort) {
- if ($this->attributeExists($attributeName)) $attributeArray[] = $this->exportAttributeName($attributeName) . ($sort == Dao::DESC ? ' desc' : '');
+ if ($this->attributeExists($attributeName))
+ $attributeArray[] = $this->exportAttributeName($attributeName) . ($sort == Dao::DESC ? ' desc' : '');
}
}
View
1 library/Dao/DaoKeyListIterator.php
@@ -90,7 +90,6 @@ public function next() {
/**
* Fetches the current data.
* @return array
- * @todo there should be exporting of the key... don't know if here!
*/
protected function getCurrentData() {
return $this->key() > $this->count() ? null : $this->dao->getData(array($this->keyName => $this->keyList[$this->key() - 1]));
View
161 library/History/History.php
@@ -0,0 +1,161 @@
+<?php
+
+/**
+ * The file for the History
+ *
+ * @author Matthias Loitsch <matthias@loitsch.com>
+ * @copyright Copyright (c) 2010, I-Netcompany
+ * @package History
+ */
+
+/**
+ * This class stores history information, so we can send a user back to any site in history.
+ * The history is stored in the $_SESSION['history'] array, where the last index is the last visited url.
+ * To store an url in the history, call addUrl()
+ *
+ * @author Matthias Loitsch <matthias@loitsch.com>
+ * @copyright Copyright (c) 2010, I-Netcompany
+ * @package History
+ */
+class History {
+
+ /**
+ * Number of urls to keep in history
+ * @var int
+ */
+ protected $historyLength = 10;
+
+ /* * #@+
+ * Different url positions to get.
+ *
+ * @var mixed
+ */
+ const FIRST = '__first__';
+ const LAST = '__last__';
+ const PREVIOUS = '__previous__';
+ /* * #@- */
+
+ /**
+ * Makes sure the session history array exists.
+ */
+ public function __construct() {
+ // Make sure the SESSION array exists.
+ if (!isset($_SESSION['history']) || !is_array($_SESSION['history'])) {
+ $this->clear();
+ }
+ }
+
+ /**
+ * @param int $length
+ * @see $historyLength
+ */
+ public function setHistoryLength($length) {
+ $this->historyLength = (int) $length;
+ $this->removeExcessUrls();
+ }
+
+ /**
+ * @return int
+ * @see $historyLength
+ */
+ public function getHistoryLength() {
+ return $this->historyLength;
+ }
+
+ /**
+ * @param string $url
+ */
+ public function addUrl($url) {
+
+ if (end($_SESSION['history']) != $url) {
+ // Don't insert urls twice.
+ $_SESSION['history'][] = $url;
+ $this->removeExcessUrls();
+ }
+ }
+
+ /**
+ * Ensures that only the allowed number of urls are stored in the history.
+ * Be careful: This function doesn't test if the Session array exists.
+ */
+ protected function removeExcessUrls() {
+ while (count($_SESSION['history']) > $this->historyLength) {
+ array_shift($_SESSION['history']);
+ }
+ }
+
+ /**
+ * Returns the last visited url in history.
+ * This is a wrapper for History::get(History::PREVIOUS);
+ *
+ * @return string
+ * @see get()
+ */
+ public function getPreviousUrl() {
+ return $this->get(self::PREVIOUS);
+ }
+
+ /**
+ * Gets a history object.
+ * This can be an index, to access some specific index of the history array, or one of:
+ * History::FIRST, History::LAST, History::PREVIOUS
+ *
+ * Returns null if not available.
+ *
+ * @param mixed $position
+ */
+ public function get($position) {
+ if (!isset($_SESSION['history']))
+ return null;
+
+ if (!is_int($position)) {
+ switch ($position) {
+ case self::FIRST:
+ $position = 0;
+ break;
+ case self::LAST:
+ if (count($_SESSION['history']) == 0)
+ return null;
+ $position = count($_SESSION['history']) - 1;
+ break;
+ case self::PREVIOUS:
+ if (count($_SESSION['history']) < 2)
+ return null;
+ $position = count($_SESSION['history']) - 2;
+ break;
+ default:
+ trigger_error('Unknown History position `' . $position . '`', E_USER_ERROR);
+ }
+ }
+
+ return isset($_SESSION['history'][$position]) ? $_SESSION['history'][$position] : null;
+ }
+
+ /**
+ * Returns an array containing the complete history.
+ * The last index, is the latest url inserted.
+ * Index 0 is the oldest url.
+ * @return array
+ */
+ public function getAll() {
+ return isset($_SESSION['history']) ? $_SESSION['history'] : array();
+ }
+
+ /**
+ * Sets an empty array in the session.
+ */
+ public function clear() {
+ $_SESSION['history'] = array();
+ }
+
+ /**
+ * Prints the history for debugging
+ */
+ public function printHistory() {
+ echo '<pre>';
+ print_r($_SESSION['history']);
+ echo '</pre>';
+ }
+
+}
+
View
108 library/SymfonyServiceContainer/services.xsd
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://symfony-project.org/2.0/container" targetNamespace="http://symfony-project.org/2.0/container" elementFormDefault="qualified">
+ <xs:element name="container" type="container" />
+
+ <xs:complexType name="container">
+ <xs:sequence>
+ <xs:element name="imports" type="imports" minOccurs="0" maxOccurs="1" />
+ <xs:element name="parameters" type="parameters" minOccurs="0" maxOccurs="1" />
+ <xs:element name="services" type="services" minOccurs="0" maxOccurs="1" />
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="services">
+ <xs:sequence>
+ <xs:element name="service" type="service" minOccurs="1" maxOccurs="unbounded" />
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="imports">
+ <xs:sequence>
+ <xs:element name="import" type="import" minOccurs="1" maxOccurs="unbounded" />
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="import">
+ <xs:attribute name="resource" type="xs:string" use="required" />
+ <xs:attribute name="class" type="xs:string" />
+ </xs:complexType>
+
+ <xs:complexType name="configurator">
+ <xs:attribute name="id" type="xs:string" />
+ <xs:attribute name="service" type="xs:string" />
+ <xs:attribute name="class" type="xs:string" />
+ <xs:attribute name="method" type="xs:string" />
+ <xs:attribute name="function" type="xs:string" />
+ </xs:complexType>
+
+ <xs:complexType name="service">
+ <xs:choice maxOccurs="unbounded">
+ <xs:element name="file" type="xs:string" minOccurs="0" maxOccurs="1" />
+ <xs:element name="argument" type="argument" minOccurs="0" maxOccurs="unbounded" />
+ <xs:element name="configurator" type="configurator" minOccurs="0" maxOccurs="1" />
+ <xs:element name="call" type="call" minOccurs="0" maxOccurs="unbounded" />
+ </xs:choice>
+ <xs:attribute name="id" type="xs:string" />
+ <xs:attribute name="class" type="xs:string" />
+ <xs:attribute name="shared" type="boolean" />
+ <xs:attribute name="constructor" type="xs:string" />
+ <xs:attribute name="alias" type="xs:string" />
+ </xs:complexType>
+
+ <xs:complexType name="parameters">
+ <xs:sequence>
+ <xs:element name="parameter" type="parameter" minOccurs="1" maxOccurs="unbounded" />
+ </xs:sequence>
+ <xs:attribute name="type" type="parameter_type" />
+ <xs:attribute name="key" type="xs:string" />
+ </xs:complexType>
+
+ <xs:complexType name="parameter" mixed="true">
+ <xs:sequence>
+ <xs:element name="parameter" type="parameter" minOccurs="0" maxOccurs="unbounded" />
+ </xs:sequence>
+ <xs:attribute name="type" type="parameter_type" />
+ <xs:attribute name="id" type="xs:string" />
+ <xs:attribute name="key" type="xs:string" />
+ </xs:complexType>
+
+ <xs:complexType name="argument" mixed="true">
+ <xs:choice maxOccurs="unbounded">
+ <xs:element name="argument" type="argument" minOccurs="0" maxOccurs="unbounded" />
+ <xs:element name="service" type="service" />
+ </xs:choice>
+ <xs:attribute name="type" type="argument_type" />
+ <xs:attribute name="id" type="xs:string" />
+ <xs:attribute name="key" type="xs:string" />
+ </xs:complexType>
+
+ <xs:complexType name="call" mixed="true">
+ <xs:choice maxOccurs="unbounded">
+ <xs:element name="argument" type="argument" minOccurs="0" maxOccurs="unbounded" />
+ <xs:element name="service" type="service" />
+ </xs:choice>
+ <xs:attribute name="method" type="xs:string" />
+ </xs:complexType>
+
+ <xs:simpleType name="parameter_type">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="collection" />
+ <xs:enumeration value="service" />
+ <xs:enumeration value="string" />
+ </xs:restriction>
+ </xs:simpleType>
+
+ <xs:simpleType name="argument_type">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="collection" />
+ <xs:enumeration value="service" />
+ <xs:enumeration value="string" />
+ </xs:restriction>
+ </xs:simpleType>
+
+ <xs:simpleType name="boolean">
+ <xs:restriction base="xs:string">
+ <xs:pattern value="(%.+%|true|false|1|0|off|on)" />
+ </xs:restriction>
+ </xs:simpleType>
+</xs:schema>
View
359 library/SymfonyServiceContainer/sfServiceContainer.php
@@ -0,0 +1,359 @@
+<?php
+
+/*
+ * This file is part of the symfony framework.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * This source file is subject to the MIT license that is bundled
+ * with this source code in the file LICENSE.
+ */
+
+/**
+ * sfServiceContainer is a dependency injection container.
+ *
+ * It gives access to object instances (services), and parameters.
+ *
+ * Services and parameters are simple key/pair stores.
+ *
+ * Parameters keys are case insensitive.
+ *
+ * A service id can contain lowercased letters, digits, underscores, and dots.
+ * Underscores are used to separate words, and dots to group services
+ * under namespaces:
+ *
+ * <ul>
+ * <li>request</li>
+ * <li>mysql_session_storage</li>
+ * <li>symfony.mysql_session_storage</li>
+ * </ul>
+ *
+ * A service can also be defined by creating a method named
+ * getXXXService(), where XXX is the camelized version of the id:
+ *
+ * <ul>
+ * <li>request -> getRequestService()</li>
+ * <li>mysql_session_storage -> getMysqlSessionStorageService()</li>
+ * <li>symfony.mysql_session_storage -> getSymfony_MysqlSessionStorageService()</li>
+ * </ul>
+ *
+ * @package symfony
+ * @subpackage dependency_injection
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ * @version SVN: $Id$
+ */
+class sfServiceContainer implements sfServiceContainerInterface, ArrayAccess, Iterator
+{
+ protected
+ $serviceIds = array(),
+ $parameters = array(),
+ $services = array(),
+ $count = 0;
+
+ /**
+ * Constructor.
+ *
+ * @param array $parameters An array of parameters
+ */
+ public function __construct(array $parameters = array())
+ {
+ $this->setParameters($parameters);
+ $this->setService('service_container', $this);
+ }
+
+ /**
+ * Sets the service container parameters.
+ *
+ * @param array $parameters An array of parameters
+ */
+ public function setParameters(array $parameters)
+ {
+ $this->parameters = array();
+ foreach ($parameters as $key => $value)
+ {
+ $this->parameters[strtolower($key)] = $value;
+ }
+ }
+
+ /**
+ * Adds parameters to the service container parameters.
+ *
+ * @param array $parameters An array of parameters
+ */
+ public function addParameters(array $parameters)
+ {
+ $this->setParameters(array_merge($this->parameters, $parameters));
+ }
+
+ /**
+ * Gets the service container parameters.
+ *
+ * @return array An array of parameters
+ */
+ public function getParameters()
+ {
+ return $this->parameters;
+ }
+
+ /**
+ * Gets a service container parameter.
+ *
+ * @param string $name The parameter name
+ *
+ * @return mixed The parameter value
+ *
+ * @throw InvalidArgumentException if the parameter is not defined
+ */
+ public function getParameter($name)
+ {
+ if (!$this->hasParameter($name))
+ {
+ throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name));
+ }
+
+ return $this->parameters[strtolower($name)];
+ }
+
+ /**
+ * Sets a service container parameter.
+ *
+ * @param string $name The parameter name
+ * @param mixed $parameters The parameter value
+ */
+ public function setParameter($name, $value)
+ {
+ $this->parameters[strtolower($name)] = $value;
+ }
+
+ /**
+ * Returns true if a parameter name is defined.
+ *
+ * @param string $name The parameter name
+ *
+ * @return Boolean true if the parameter name is defined, false otherwise
+ */
+ public function hasParameter($name)
+ {
+ return array_key_exists(strtolower($name), $this->parameters);
+ }
+
+ /**
+ * Sets a service.
+ *
+ * @param string $id The service identifier
+ * @param object $service The service instance
+ */
+ public function setService($id, $service)
+ {
+ $this->services[$id] = $service;
+ }
+
+ /**
+ * Returns true if the given service is defined.
+ *
+ * @param string $id The service identifier
+ *
+ * @return Boolean true if the service is defined, false otherwise
+ */
+ public function hasService($id)
+ {
+ return isset($this->services[$id]) || method_exists($this, 'get'.self::camelize($id).'Service');
+ }
+
+ /**
+ * Gets a service.
+ *
+ * If a service is both defined through a setService() method and
+ * with a set*Service() method, the former has always precedence.
+ *
+ * @param string $id The service identifier
+ *
+ * @return object The associated service
+ *
+ * @throw InvalidArgumentException if the service is not defined
+ */
+ public function getService($id)
+ {
+ if (isset($this->services[$id]))
+ {
+ return $this->services[$id];
+ }
+
+ if (method_exists($this, $method = 'get'.self::camelize($id).'Service'))
+ {
+ return $this->$method();
+ }
+
+ throw new InvalidArgumentException(sprintf('The service "%s" does not exist.', $id));
+ }
+
+ /**
+ * Gets all service ids.
+ *
+ * @return array An array of all defined service ids
+ */
+ public function getServiceIds()
+ {
+ $ids = array();
+ $r = new ReflectionClass($this);
+ foreach ($r->getMethods() as $method)
+ {
+ if (preg_match('/^get(.+)Service$/', $name = $method->getName(), $match))
+ {
+ $ids[] = self::underscore($match[1]);
+ }
+ }
+
+ return array_merge($ids, array_keys($this->services));
+ }
+
+ /**
+ * Returns true if the parameter name is defined (implements the ArrayAccess interface).
+ *
+ * @param string The parameter name
+ *
+ * @return Boolean true if the parameter name is defined, false otherwise
+ */
+ public function offsetExists($name)
+ {
+ return $this->hasParameter($name);
+ }
+
+ /**
+ * Gets a service container parameter (implements the ArrayAccess interface).
+ *
+ * @param string The parameter name
+ *
+ * @return mixed The parameter value
+ */
+ public function offsetGet($name)
+ {
+ return $this->getParameter($name);
+ }
+
+ /**
+ * Sets a parameter (implements the ArrayAccess interface).
+ *
+ * @param string The parameter name
+ * @param mixed The parameter value
+ */
+ public function offsetSet($name, $value)
+ {
+ $this->setParameter($name, $value);
+ }
+
+ /**
+ * Removes a parameter (implements the ArrayAccess interface).
+ *
+ * @param string The parameter name
+ */
+ public function offsetUnset($name)
+ {
+ unset($this->parameters[$name]);
+ }
+
+ /**
+ * Returns true if the container has a service with the given identifier.
+ *
+ * @param string The service identifier
+ *
+ * @return Boolean true if the container has a service with the given identifier, false otherwise
+ */
+ public function __isset($id)
+ {
+ return $this->hasService($id);
+ }
+
+ /**
+ * Gets the service associated with the given identifier.
+ *
+ * @param string The service identifier
+ *
+ * @return mixed The service instance associated with the given identifier
+ */
+ public function __get($id)
+ {
+ return $this->getService($id);
+ }
+
+ /**
+ * Sets a service.
+ *
+ * @param string The service identifier
+ * @param mixed A service instance
+ */
+ public function __set($id, $service)
+ {
+ $this->setService($id, $service);
+ }
+
+ /**
+ * Removes a service by identifier.
+ *
+ * @param string The service identifier
+ */
+ public function __unset($id)
+ {
+ throw new LogicException('You can\'t unset a service.');
+ }
+
+ /**
+ * Resets the service identifiers array to the beginning (implements the Iterator interface).
+ */
+ public function rewind()
+ {
+ $this->serviceIds = $this->getServiceIds();
+
+ $this->count = count($this->serviceIds);
+ }
+
+ /**
+ * Gets the key associated with the current service (implements the Iterator interface).
+ *
+ * @return string The service identifier
+ */
+ public function key()
+ {
+ return current($this->serviceIds);
+ }
+
+ /**
+ * Returns the current service (implements the Iterator interface).
+ *
+ * @return mixed The service
+ */
+ public function current()
+ {
+ return $this->getService(current($this->serviceIds));
+ }
+
+ /**
+ * Moves to the next service (implements the Iterator interface).
+ */
+ public function next()
+ {
+ next($this->serviceIds);
+
+ --$this->count;
+ }
+
+ /**
+ * Returns true if the current service is valid (implements the Iterator interface).
+ *
+ * @return boolean The validity of the current service; true if it is valid
+ */
+ public function valid()
+ {
+ return $this->count > 0;
+ }
+
+ static public function camelize($id)
+ {
+ return preg_replace(array('/(^|_|-)+(.)/e', '/\.(.)/e'), array("strtoupper('\\2')", "'_'.strtoupper('\\1')"), $id);
+ }
+
+ static public function underscore($id)
+ {
+ return strtolower(preg_replace(array('/_/', '/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'), array('.', '\\1_\\2', '\\1_\\2'), $id));
+ }
+}
View
49 library/SymfonyServiceContainer/sfServiceContainerAutoloader.php
@@ -0,0 +1,49 @@
+<?php
+
+/*
+ * This file is part of the symfony framework.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * This source file is subject to the MIT license that is bundled
+ * with this source code in the file LICENSE.
+ */
+
+/**
+ * sfServiceContainerAutoloader is an autoloader for the service container classes.
+ *
+ * @package symfony
+ * @subpackage dependency_injection
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ * @version SVN: $Id$
+ */
+class sfServiceContainerAutoloader
+{
+ /**
+ * Registers sfServiceContainerAutoloader as an SPL autoloader.
+ */
+ static public function register()
+ {
+ ini_set('unserialize_callback_func', 'spl_autoload_call');
+ spl_autoload_register(array(new self, 'autoload'));
+ }
+
+ /**
+ * Handles autoloading of classes.
+ *
+ * @param string $class A class name.
+ *
+ * @return boolean Returns true if the class has been loaded
+ */
+ public function autoload($class)
+ {
+ if (0 !== strpos($class, 'sfService'))
+ {
+ return false;
+ }
+
+ require dirname(__FILE__).'/'.$class.'.php';
+
+ return true;
+ }
+}
View
351 library/SymfonyServiceContainer/sfServiceContainerBuilder.php
@@ -0,0 +1,351 @@
+<?php
+
+/*
+ * This file is part of the symfony framework.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * This source file is subject to the MIT license that is bundled
+ * with this source code in the file LICENSE.
+ */
+
+/**
+ * sfServiceContainerBuilder is a DI container that provides an interface to build the services.
+ *
+ * @package symfony
+ * @subpackage dependency_injection
+ * @author Fabien Potencier <fabien.potencier@symfony-project.com>
+ * @version SVN: $Id: sfServiceContainerBuilder.php 269 2009-03-26 20:39:16Z fabien $
+ */
+class sfServiceContainerBuilder extends sfServiceContainer
+{
+ protected
+ $definitions = array(),
+ $aliases = array(),
+ $loading = array();
+
+ /**
+ * Sets a service.
+ *
+ * @param string $id The service identifier
+ * @param object $service The service instance
+ */
+ public function setService($id, $service)
+ {
+ unset($this->aliases[$id]);
+
+ parent::setService($id, $service);
+ }
+
+ /**
+ * Returns true if the given service is defined.
+ *
+ * @param string $id The service identifier
+ *
+ * @return Boolean true if the service is defined, false otherwise
+ */
+ public function hasService($id)
+ {
+ return isset($this->definitions[$id]) || isset($this->aliases[$id]) || parent::hasService($id);
+ }
+
+ /**
+ * Gets a service.
+ *
+ * @param string $id The service identifier
+ *
+ * @return object The associated service
+ *
+ * @throw InvalidArgumentException if the service is not defined
+ * @throw LogicException if the service has a circular reference to itself
+ */
+ public function getService($id)
+ {
+ try
+ {
+ return parent::getService($id);
+ }
+ catch (InvalidArgumentException $e)
+ {
+ if (isset($this->loading[$id]))
+ {
+ throw new LogicException(sprintf('The service "%s" has a circular reference to itself.', $id));
+ }
+
+ if (!$this->hasServiceDefinition($id) && isset($this->aliases[$id]))
+ {
+ return $this->getService($this->aliases[$id]);
+ }
+
+ $definition = $this->getServiceDefinition($id);
+
+ $this->loading[$id] = true;
+
+ if ($definition->isShared())
+ {
+ $service = $this->services[$id] = $this->createService($definition);
+ }
+ else
+ {
+ $service = $this->createService($definition);
+ }
+
+ unset($this->loading[$id]);
+
+ return $service;
+ }
+ }
+
+ /**
+ * Gets all service ids.
+ *
+ * @return array An array of all defined service ids
+ */
+ public function getServiceIds()
+ {
+ return array_unique(array_merge(array_keys($this->getServiceDefinitions()), array_keys($this->aliases), parent::getServiceIds()));
+ }
+
+ /**
+ * Sets an alias for an existing service.
+ *
+ * @param string $alias The alias to create
+ * @param string $id The service to alias
+ */
+ public function setAlias($alias, $id)
+ {
+ $this->aliases[$alias] = $id;
+ }
+
+ /**
+ * Gets all defined aliases.
+ *
+ * @return array An array of aliases