initial commit

This commit is contained in:
Chris Sewell
2012-11-28 03:55:08 -05:00
parent 7adb399b2e
commit cf140a2e97
3247 changed files with 492437 additions and 0 deletions

1
lib/symfony/VERSION Executable file
View File

@ -0,0 +1 @@
1.0.8

View File

@ -0,0 +1,457 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfAction executes all the logic for the current request.
*
* @package symfony
* @subpackage action
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfAction.class.php 3624 2007-03-17 10:57:03Z fabien $
*/
abstract class sfAction extends sfComponent
{
protected
$security = array();
/**
* Initializes this action.
*
* @param sfContext The current application context.
*
* @return bool true, if initialization completes successfully, otherwise false
*/
public function initialize($context)
{
parent::initialize($context);
// include security configuration
require(sfConfigCache::getInstance()->checkConfig(sfConfig::get('sf_app_module_dir_name').'/'.$this->getModuleName().'/'.sfConfig::get('sf_app_module_config_dir_name').'/security.yml', true));
return true;
}
/**
* Executes an application defined process prior to execution of this sfAction object.
*
* By default, this method is empty.
*/
public function preExecute()
{
}
/**
* Execute an application defined process immediately after execution of this sfAction object.
*
* By default, this method is empty.
*/
public function postExecute()
{
}
/**
* Forwards current action to the default 404 error action.
*
* @param string Message of the generated exception
*
* @throws sfError404Exception
*
*/
public function forward404($message = '')
{
throw new sfError404Exception($message);
}
/**
* Forwards current action to the default 404 error action unless the specified condition is true.
*
* @param bool A condition that evaluates to true or false
* @param string Message of the generated exception
*
* @throws sfError404Exception
*/
public function forward404Unless($condition, $message = '')
{
if (!$condition)
{
throw new sfError404Exception($message);
}
}
/**
* Forwards current action to the default 404 error action if the specified condition is true.
*
* @param bool A condition that evaluates to true or false
* @param string Message of the generated exception
*
* @throws sfError404Exception
*/
public function forward404If($condition, $message = '')
{
if ($condition)
{
throw new sfError404Exception($message);
}
}
/**
* Redirects current action to the default 404 error action (with browser redirection).
*
* This method stops the current code flow.
*
*/
public function redirect404()
{
return $this->redirect('/'.sfConfig::get('sf_error_404_module').'/'.sfConfig::get('sf_error_404_action'));
}
/**
* Forwards current action to a new one (without browser redirection).
*
* This method stops the action. So, no code is executed after a call to this method.
*
* @param string A module name
* @param string An action name
*
* @throws sfStopException
*/
public function forward($module, $action)
{
if (sfConfig::get('sf_logging_enabled'))
{
$this->getContext()->getLogger()->info('{sfAction} forward to action "'.$module.'/'.$action.'"');
}
$this->getController()->forward($module, $action);
throw new sfStopException();
}
/**
* If the condition is true, forwards current action to a new one (without browser redirection).
*
* This method stops the action. So, no code is executed after a call to this method.
*
* @param bool A condition that evaluates to true or false
* @param string A module name
* @param string An action name
*
* @throws sfStopException
*/
public function forwardIf($condition, $module, $action)
{
if ($condition)
{
$this->forward($module, $action);
}
}
/**
* Unless the condition is true, forwards current action to a new one (without browser redirection).
*
* This method stops the action. So, no code is executed after a call to this method.
*
* @param bool A condition that evaluates to true or false
* @param string A module name
* @param string An action name
*
* @throws sfStopException
*/
public function forwardUnless($condition, $module, $action)
{
if (!$condition)
{
$this->forward($module, $action);
}
}
/**
* Redirects current request to a new URL.
*
* 2 URL formats are accepted :
* - a full URL: http://www.google.com/
* - an internal URL (url_for() format): module/action
*
* This method stops the action. So, no code is executed after a call to this method.
*
* @param string Url
* @param string Status code (default to 302)
*
* @throws sfStopException
*/
public function redirect($url, $statusCode = 302)
{
$url = $this->getController()->genUrl($url, true);
if (sfConfig::get('sf_logging_enabled'))
{
$this->getContext()->getLogger()->info('{sfAction} redirect to "'.$url.'"');
}
$this->getController()->redirect($url, 0, $statusCode);
throw new sfStopException();
}
/**
* Redirects current request to a new URL, only if specified condition is true.
*
* This method stops the action. So, no code is executed after a call to this method.
*
* @param bool A condition that evaluates to true or false
* @param string url
*
* @throws sfStopException
*
* @see redirect
*/
public function redirectIf($condition, $url)
{
if ($condition)
{
$this->redirect($url);
}
}
/**
* Redirects current request to a new URL, unless specified condition is true.
*
* This method stops the action. So, no code is executed after a call to this method.
*
* @param bool A condition that evaluates to true or false
* @param string Url
*
* @throws sfStopException
*
* @see redirect
*/
public function redirectUnless($condition, $url)
{
if (!$condition)
{
$this->redirect($url);
}
}
/**
* Appends the given text to the response content and bypasses the built-in view system.
*
* This method must be called as with a return:
*
* <code>return $this->renderText('some text')</code>
*
* @param string Text to append to the response
*
* @return sfView::NONE
*/
public function renderText($text)
{
$this->getResponse()->setContent($this->getResponse()->getContent().$text);
return sfView::NONE;
}
/**
* Retrieves the default view to be executed when a given request is not served by this action.
*
* @return string A string containing the view name associated with this action
*/
public function getDefaultView()
{
return sfView::INPUT;
}
/**
* Retrieves the request methods on which this action will process validation and execution.
*
* @return int One of the following values:
*
* - sfRequest::GET
* - sfRequest::POST
* - sfRequest::PUT
* - sfRequest::DELETE
* - sfRequest::HEAD
* - sfRequest::NONE
*
* @see sfRequest
*/
public function getRequestMethods()
{
return sfRequest::GET
| sfRequest::POST
| sfRequest::PUT
| sfRequest::DELETE
| sfRequest::HEAD
| sfRequest::NONE;
}
/**
* Executes any post-validation error application logic.
*
* @return string A string containing the view name associated with this action
*/
public function handleError()
{
return sfView::ERROR;
}
/**
* Validates manually files and parameters.
*
* @return bool true, if validation completes successfully, otherwise false.
*/
public function validate()
{
return true;
}
/**
* Returns the security configuration for this module.
*
* @return string Current security configuration as an array
*/
public function getSecurityConfiguration()
{
return $this->security;
}
/**
* Overrides the current security configuration for this module.
*
* @param array The new security configuration
*/
public function setSecurityConfiguration($security)
{
$this->security = $security;
}
/**
* Indicates that this action requires security.
*
* @return bool true, if this action requires security, otherwise false.
*/
public function isSecure()
{
$actionName = strtolower($this->getActionName());
if (isset($this->security[$actionName]['is_secure']))
{
return $this->security[$actionName]['is_secure'];
}
if (isset($this->security['all']['is_secure']))
{
return $this->security['all']['is_secure'];
}
return false;
}
/**
* Gets credentials the user must have to access this action.
*
* @return mixed An array or a string describing the credentials the user must have to access this action
*/
public function getCredential()
{
$actionName = strtolower($this->getActionName());
if (isset($this->security[$actionName]['credentials']))
{
$credentials = $this->security[$actionName]['credentials'];
}
else if (isset($this->security['all']['credentials']))
{
$credentials = $this->security['all']['credentials'];
}
else
{
$credentials = null;
}
return $credentials;
}
/**
* Sets an alternate template for this sfAction.
*
* See 'Naming Conventions' in the 'Symfony View' documentation.
*
* @param string Template name
*/
public function setTemplate($name)
{
if (sfConfig::get('sf_logging_enabled'))
{
$this->getContext()->getLogger()->info('{sfAction} change template to "'.$name.'"');
}
$this->getResponse()->setParameter($this->getModuleName().'_'.$this->getActionName().'_template', $name, 'symfony/action/view');
}
/**
* Gets the name of the alternate template for this sfAction.
*
* WARNING: It only returns the template you set with the setTemplate() method,
* and does not return the template that you configured in your view.yml.
*
* See 'Naming Conventions' in the 'Symfony View' documentation.
*
* @return string Template name. Returns null if no template has been set within the action
*/
public function getTemplate()
{
return $this->getResponse()->getParameter($this->getModuleName().'_'.$this->getActionName().'_template', null, 'symfony/action/view');
}
/**
* Sets an alternate layout for this sfAction.
*
* To de-activate the layout, set the layout name to false.
*
* To revert the layout to the one configured in the view.yml, set the template name to null.
*
* @param mixed Layout name or false to de-activate the layout
*/
public function setLayout($name)
{
if (sfConfig::get('sf_logging_enabled'))
{
$this->getContext()->getLogger()->info('{sfAction} change layout to "'.$name.'"');
}
$this->getResponse()->setParameter($this->getModuleName().'_'.$this->getActionName().'_layout', $name, 'symfony/action/view');
}
/**
* Gets the name of the alternate layout for this sfAction.
*
* WARNING: It only returns the layout you set with the setLayout() method,
* and does not return the layout that you configured in your view.yml.
*
* @return mixed Layout name. Returns null if no layout has been set within the action
*/
public function getLayout()
{
return $this->getResponse()->getParameter($this->getModuleName().'_'.$this->getActionName().'_layout', null, 'symfony/action/view');
}
/**
* Changes the default view class used for rendering the template associated with the current action.
*
* @param string View class name
*/
public function setViewClass($class)
{
sfConfig::set('mod_'.strtolower($this->getModuleName()).'_view_class', $class);
}
}

View File

@ -0,0 +1,121 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfActionStack keeps a list of all requested actions and provides accessor
* methods for retrieving individual entries.
*
* @package symfony
* @subpackage action
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfActionStack.class.php 3198 2007-01-08 20:36:20Z fabien $
*/
class sfActionStack
{
protected
$stack = array();
/**
* Adds an entry to the action stack.
*
* @param string A module name
* @param string An action name
* @param sfAction An sfAction implementation instance
*
* @return sfActionStackEntry sfActionStackEntry instance
*/
public function addEntry($moduleName, $actionName, $actionInstance)
{
// create our action stack entry and add it to our stack
$actionEntry = new sfActionStackEntry($moduleName, $actionName, $actionInstance);
$this->stack[] = $actionEntry;
return $actionEntry;
}
/**
* Retrieves the entry at a specific index.
*
* @param int An entry index
*
* @return sfActionStackEntry An action stack entry implementation.
*/
public function getEntry($index)
{
$retval = null;
if ($index > -1 && $index < count($this->stack))
{
$retval = $this->stack[$index];
}
return $retval;
}
/**
* Removes the entry at a specific index.
*
* @param int An entry index
*
* @return sfActionStackEntry An action stack entry implementation.
*/
public function popEntry()
{
return array_pop($this->stack);
}
/**
* Retrieves the first entry.
*
* @return mixed An action stack entry implementation or null if there is no sfAction instance in the stack
*/
public function getFirstEntry()
{
$retval = null;
if (isset($this->stack[0]))
{
$retval = $this->stack[0];
}
return $retval;
}
/**
* Retrieves the last entry.
*
* @return mixed An action stack entry implementation or null if there is no sfAction instance in the stack
*/
public function getLastEntry()
{
$count = count($this->stack);
$retval = null;
if (isset($this->stack[0]))
{
$retval = $this->stack[$count - 1];
}
return $retval;
}
/**
* Retrieves the size of this stack.
*
* @return int The size of this stack.
*/
public function getSize()
{
return count($this->stack);
}
}

View File

@ -0,0 +1,115 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfActionStackEntry represents information relating to a single sfAction request during a single HTTP request.
*
* @package symfony
* @subpackage action
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfActionStackEntry.class.php 3198 2007-01-08 20:36:20Z fabien $
*/
class sfActionStackEntry
{
protected
$actionInstance = null,
$actionName = null,
$moduleName = null,
$presentation = null,
$viewInstance = null;
/**
* Class constructor.
*
* @param string A module name
* @param string An action name
* @param sfAction An sfAction implementation instance
*/
public function __construct($moduleName, $actionName, $actionInstance)
{
$this->actionName = $actionName;
$this->actionInstance = $actionInstance;
$this->moduleName = $moduleName;
}
/**
* Retrieves this entry's action name.
*
* @return string An action name
*/
public function getActionName()
{
return $this->actionName;
}
/**
* Retrieves this entry's action instance.
*
* @return sfAction An sfAction implementation instance
*/
public function getActionInstance()
{
return $this->actionInstance;
}
/**
* Retrieves this entry's view instance.
*
* @return sfView A sfView implementation instance.
*/
public function getViewInstance()
{
return $this->viewInstance;
}
/**
* Sets this entry's view instance.
*
* @param sfView A sfView implementation instance.
*/
public function setViewInstance($viewInstance)
{
$this->viewInstance = $viewInstance;
}
/**
* Retrieves this entry's module name.
*
* @return string A module name
*/
public function getModuleName()
{
return $this->moduleName;
}
/**
* Retrieves this entry's rendered view presentation.
*
* This will only exist if the view has processed and the render mode is set to sfView::RENDER_VAR.
*
* @return string Rendered view presentation
*/
public function & getPresentation()
{
return $this->presentation;
}
/**
* Sets the rendered presentation for this action.
*
* @param string A rendered presentation.
*/
public function setPresentation(&$presentation)
{
$this->presentation =& $presentation;
}
}

View File

@ -0,0 +1,57 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfActions executes all the logic for the current request.
*
* @package symfony
* @subpackage action
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfActions.class.php 3198 2007-01-08 20:36:20Z fabien $
*/
abstract class sfActions extends sfAction
{
/**
* Dispatches to the action defined by the 'action' parameter of the sfRequest object.
*
* This method try to execute the executeXXX() method of the current object where XXX is the
* defined action name.
*
* @return string A string containing the view name associated with this action
*
* @throws sfInitializationException
*
* @see sfAction
*/
public function execute()
{
// dispatch action
$actionToRun = 'execute'.ucfirst($this->getActionName());
if (!is_callable(array($this, $actionToRun)))
{
// action not found
$error = 'sfAction initialization failed for module "%s", action "%s". You must create a "%s" method.';
$error = sprintf($error, $this->getModuleName(), $this->getActionName(), $actionToRun);
throw new sfInitializationException($error);
}
if (sfConfig::get('sf_logging_enabled'))
{
$this->getContext()->getLogger()->info('{sfAction} call "'.get_class($this).'->'.$actionToRun.'()'.'"');
}
// run action
$ret = $this->$actionToRun();
return $ret;
}
}

View File

@ -0,0 +1,427 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfComponent.
*
* @package symfony
* @subpackage action
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfComponent.class.php 5380 2007-10-05 13:46:22Z noel $
*/
abstract class sfComponent
{
protected
$context = null,
$request = null,
$response = null,
$varHolder = null,
$requestParameterHolder = null;
/**
* Execute any application/business logic for this component.
*
* In a typical database-driven application, execute() handles application
* logic itself and then proceeds to create a model instance. Once the model
* instance is initialized it handles all business logic for the action.
*
* A model should represent an entity in your application. This could be a
* user account, a shopping cart, or even a something as simple as a
* single product.
*
* @return mixed A string containing the view name associated with this action
*/
abstract function execute();
/**
* Gets the module name associated with this component.
*
* @return string A module name
*/
public function getModuleName()
{
return $this->getContext()->getModuleName();
}
/**
* Gets the action name associated with this component.
*
* @return string An action name
*/
public function getActionName()
{
return $this->getContext()->getActionName();
}
/**
* Initializes this component.
*
* @param sfContext The current application context
*
* @return boolean true, if initialization completes successfully, otherwise false
*/
public function initialize($context)
{
$this->context = $context;
$this->varHolder = new sfParameterHolder();
$this->request = $context->getRequest();
$this->response = $context->getResponse();
$this->requestParameterHolder = $this->request->getParameterHolder();
return true;
}
/**
* Retrieves the current application context.
*
* @return sfContext The current sfContext instance
*/
public final function getContext()
{
return $this->context;
}
/**
* Retrieves the current logger instance.
*
* @return sfLogger The current sfLogger instance
*/
public final function getLogger()
{
return $this->context->getLogger();
}
/**
* Logs a message using the sfLogger object.
*
* @param mixed String or object containing the message to log
* @param string The priority of the message
* (available priorities: emerg, alert, crit, err, warning, notice, info, debug)
*
* @see sfLogger
*/
public function logMessage($message, $priority = 'info')
{
if (sfConfig::get('sf_logging_enabled'))
{
$this->context->getLogger()->log($message, constant('SF_LOG_'.strtoupper($priority)));
}
}
/**
* Displays a message as a short message in the sfWebDebug toolbar.
*
* @param string The message text
*
* @see sfWebDebug
*/
public function debugMessage($message)
{
if (sfConfig::get('sf_web_debug'))
{
sfWebDebug::getInstance()->logShortMessage($message);
}
}
/**
* Returns the value of a request parameter.
*
* This is a proxy method equivalent to:
*
* <code>$this->getRequest()->getParameterHolder()->get($name)</code>
*
* @param string The parameter name
*
* @return string The request parameter value
*/
public function getRequestParameter($name, $default = null)
{
return $this->requestParameterHolder->get($name, $default);
}
/**
* Returns true if a request parameter exists.
*
* This is a proxy method equivalent to:
*
* <code>$this->getRequest()->getParameterHolder()->has($name)</code>
*
* @param string The parameter name
* @return boolean true if the request parameter exists, false otherwise
*/
public function hasRequestParameter($name)
{
return $this->requestParameterHolder->has($name);
}
/**
* Retrieves the current sfRequest object.
*
* This is a proxy method equivalent to:
*
* <code>$this->getContext()->getRequest()</code>
*
* @return sfRequest The current sfRequest implementation instance
*/
public function getRequest()
{
return $this->request;
}
/**
* Retrieves the current sfResponse object.
*
* This is a proxy method equivalent to:
*
* <code>$this->getContext()->getResponse()</code>
*
* @return sfResponse The current sfResponse implementation instance
*/
public function getResponse()
{
return $this->response;
}
/**
* Retrieves the current sfController object.
*
* This is a proxy method equivalent to:
*
* <code>$this->getContext()->getController()</code>
*
* @return sfController The current sfController implementation instance
*/
public function getController()
{
return $this->getContext()->getController();
}
/**
* Retrieves the current sfUser object.
*
* This is a proxy method equivalent to:
*
* <code>$this->getContext()->getUser()</code>
*
* @return sfUser The current sfUser implementation instance
*/
public function getUser()
{
return $this->getContext()->getUser();
}
/**
* Sets a variable for the template.
*
* @param string The variable name
* @param mixed The variable value
*/
public function setVar($name, $value)
{
$this->varHolder->set($name, $value);
}
/**
* Gets a variable set for the template.
*
* @param string The variable name
* @return mixed The variable value
*/
public function getVar($name)
{
return $this->varHolder->get($name);
}
/**
* Gets the sfParameterHolder object that stores the template variables.
*
* @return sfParameterHolder The variable holder.
*/
public function getVarHolder()
{
return $this->varHolder;
}
/**
* Sets a variable for the template.
*
* This is a shortcut for:
*
* <code>$this->setVar('name', 'value')</code>
*
* @param string The variable name
* @param string The variable value
*
* @return boolean always true
*
* @see setVar()
*/
public function __set($key, $value)
{
return $this->varHolder->setByRef($key, $value);
}
/**
* Gets a variable for the template.
*
* This is a shortcut for:
*
* <code>$this->getVar('name')</code>
*
* @param string The variable name
*
* @return mixed The variable value
*
* @see getVar()
*/
public function & __get($key)
{
return $this->varHolder->get($key);
}
/**
* Returns true if a variable for the template is set.
*
* This is a shortcut for:
*
* <code>$this->getVarHolder()->has('name')</code>
*
* @param string The variable name
*
* @return boolean true if the variable is set
*/
public function __isset($name)
{
return $this->varHolder->has($name);
}
/**
* Removes a variable for the template.
*
* This is just really a shortcut for:
*
* <code>$this->getVarHolder()->remove('name')</code>
*
* @param string The variable Name
*/
public function __unset($name)
{
$this->varHolder->remove($name);
}
/**
* Sets a flash variable that will be passed to the very next action.
*
* @param string The name of the flash variable
* @param string The value of the flash variable
* @param boolean true if the flash have to persist for the following request (true by default)
*/
public function setFlash($name, $value, $persist = true)
{
$this->getUser()->setAttribute($name, $value, 'symfony/flash');
if ($persist)
{
// clear removal flag
$this->getUser()->getAttributeHolder()->remove($name, 'symfony/flash/remove');
}
else
{
$this->getUser()->setAttribute($name, true, 'symfony/flash/remove');
}
}
/**
* Gets a flash variable.
*
* @param string The name of the flash variable
*
* @return mixed The value of the flash variable
*/
public function getFlash($name)
{
return $this->getUser()->getAttribute($name, null, 'symfony/flash');
}
/**
* Returns true if a flash variable of the specified name exists.
*
* @param string The name of the flash variable
*
* @return boolean true if the variable exists, false otherwise
*/
public function hasFlash($name)
{
return $this->getUser()->hasAttribute($name, 'symfony/flash');
}
/**
* Sends and email from the current action.
*
* This methods calls a module/action with the sfMailView class.
*
* This is a shortcut for
*
* <code>$this->getController()->sendEmail($module, $action)</code>
*
* @param string A module name
* @param string An action name
*
* @return string The generated mail content
*
* @see sfMailView, getPresentationFor(), sfController
*/
public function sendEmail($module, $action)
{
return $this->getController()->getPresentationFor($module, $action, 'sfMail');
}
/**
* Returns the rendered view presentation of a given module/action.
*
* This is a shortcut for
*
* <code>$this->getController()->getPresentationFor($module, $action, $viewName)</code>
*
* @param string A module name
* @param string An action name
* @param string A View class name
*
* @return string The generated content
*
* @see sfController
*/
public function getPresentationFor($module, $action, $viewName = null)
{
return $this->getController()->getPresentationFor($module, $action, $viewName);
}
/**
* Calls methods defined via the sfMixer class.
*
* @param string The method name
* @param array The method arguments
*
* @return mixed The returned value of the called method
*
* @see sfMixer
*/
public function __call($method, $arguments)
{
if (!$callable = sfMixer::getCallable('sfComponent:'.$method))
{
throw new sfException(sprintf('Call to undefined method sfComponent::%s', $method));
}
array_unshift($arguments, $this);
return call_user_func_array($callable, $arguments);
}
}

View File

@ -0,0 +1,25 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfComponents.
*
* @package symfony
* @subpackage action
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfComponents.class.php 1415 2006-06-11 08:33:51Z fabien $
*/
abstract class sfComponents extends sfComponent
{
public function execute()
{
throw new sfInitializationException('sfComponents initialization failed');
}
}

View File

@ -0,0 +1,42 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
$sf_ez_lib_dir = sfConfig::get('sf_ez_lib_dir') ? sfConfig::get('sf_ez_lib_dir').'/' : '';
if (file_exists($sf_ez_lib_dir.'Base/src/base.php'))
{
// svn installation
require_once($sf_ez_lib_dir.'Base/src/base.php');
}
elseif (file_exists($sf_ez_lib_dir.'Base/base.php'))
{
// pear installation
require_once($sf_ez_lib_dir.'Base/base.php');
}
else
{
throw new sfAutoloadException('Invalid eZ component library path.');
}
/**
* This class makes easy to use ez components classes within symfony
*
* @package symfony
* @subpackage addon
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfEzComponentsBridge.class.php 5362 2007-10-04 06:40:04Z noel $
*/
class sfEzComponentsBridge
{
public static function autoload($class)
{
return ezcBase::autoload($class);
}
}

View File

@ -0,0 +1,92 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
if (sfConfig::get('sf_zend_lib_dir'))
{
set_include_path(sfConfig::get('sf_zend_lib_dir').PATH_SEPARATOR.get_include_path());
}
sfZendFrameworkBridge::requireZendLoader();
/**
* This class makes easy to use Zend Framework classes within symfony.
*
* @package symfony
* @subpackage addon
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfZendFrameworkBridge.class.php 4752 2007-07-31 08:58:33Z fabien $
*/
class sfZendFrameworkBridge
{
public static function autoload($class)
{
try
{
if (class_exists('Zend_Version'))
{
Zend_Loader::loadClass($class);
}
else
{
Zend::loadClass($class);
}
}
catch (Zend_Exception $e)
{
return false;
}
return true;
}
/**
* Detect and return the path to current Zend loader class.
*
* Starting from ZF 0.9.0 autoloading function has been moved
* from Zend.php to Zend/Version.php class.
* Starting from ZF 1.0.0 Zend.php class no longer exists.
*
* This function tries to detect whether Zend_Version exists
* and returns its path if yes.
* If the first step fails, the class will try to find Zend.php library
* available in ZF <= 0.9.0 and returns its path if its exists.
*
* If neither Zend/Version.php nor Zend.php exists,
* then this function will raise a sfAutoloadException exception.
*
* @return string Path to default Zend Loader class
* @throws sfAutoloadException
*
* @author Simone Carletti <weppos@weppos.net>
*/
public static function requireZendLoader()
{
// get base path according to sf setting
$base = sfConfig::get('sf_zend_lib_dir') ? sfConfig::get('sf_zend_lib_dir').'/' : '';
// first check whether Zend/Version.php exists
// Zend/Version.php is available starting from ZF 0.9.0
// Before ZF 0.9.0 you should call Zend.php
// Plese note that Zend.php is still available in ZF 0.9.0
// but it should not be called because deprecated
if (file_exists($base.'Zend/Version.php'))
{
require_once($base.'Zend/Version.php');
}
else if (file_exists($base.'Zend.php'))
{
require_once($base.'Zend.php');
}
else
{
throw new sfAutoloadException('Invalid Zend Framework library structure, unable to find Zend/Version.php (ZF >= 0.9.0) or Zend.php (ZF < 0.9.0) library');
}
}
}

View File

@ -0,0 +1,212 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfCreoleDatabase provides connectivity for the Creole database abstraction
* layer.
*
* <b>Optional parameters:</b>
*
* # <b>classpath</b> - [none] - An absolute filesystem path to the main
* Creole class file.
* # <b>database</b> - [none] - The database name.
* # <b>dsn</b> - [none] - The DSN formatted connection string.
* # <b>host</b> - [none] - The database host specifications.
* # <b>port</b> - [none] - The database port.
* # <b>encoding</b> - [none] - The database encoding.
* # <b>method</b> - [normal] - How to read connection parameters.
* Possible values are dsn, normal,
* server, and env. The dsn method reads
* them from the dsn parameter. The
* normal method reads them from the
* specified values. server reads them
* from $_SERVER where the keys to
* retrieve the values are what you
* specify the value as in the settings.
* env reads them from $_ENV and works
* like $_SERVER.
* # <b>no_assoc_lower</b> - [Off] - Turn off portabilty of resultset
* field names.
* # <b>password</b> - [none] - The database password.
* # <b>persistent</b> - [No] - Indicates that the connection should
* persistent.
* # <b>phptype</b> - [none] - The type of database (mysql, pgsql,
* etc).
* # <b>username</b> - [none] - The database username.
*
* @package symfony
* @subpackage database
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfCreoleDatabase.class.php 3329 2007-01-23 08:29:34Z fabien $
*/
class sfCreoleDatabase extends sfDatabase
{
/**
* Connect to the database.
*
* @throws <b>sfDatabaseException</b> If a connection could not be created.
*/
public function connect()
{
try
{
// determine how to get our settings
$method = $this->getParameter('method', 'normal');
switch ($method)
{
case 'normal':
// get parameters normally, and all are required
$database = $this->getParameter('database', null);
$hostspec = $this->getParameter('hostspec') ? $this->getParameter('hostspec') : ($this->getParameter('host') ? $this->getParameter('hostspec') : null);
$password = $this->getParameter('password', null);
$phptype = $this->getParameter('phptype', null);
$username = $this->getParameter('username', null);
$port = $this->getParameter('port', null);
$encoding = $this->getParameter('encoding', null);
$dsn = array('database' => $database,
'hostspec' => $hostspec,
'password' => $password,
'phptype' => $phptype,
'username' => $username,
'port' => $port,
'encoding' => $encoding);
break;
case 'dsn':
$dsn = $this->getParameter('dsn');
if ($dsn == null)
{
// missing required dsn parameter
$error = 'Database configuration specifies method "dsn", but is missing dsn parameter';
throw new sfDatabaseException($error);
}
break;
case 'server':
// construct a DSN connection string from existing $_SERVER values
$dsn =& $this->loadDSN($_SERVER);
break;
case 'env':
// construct a DSN connection string from existing $_ENV values
$dsn =& $this->loadDSN($_ENV);
break;
default:
// who knows what the user wants...
$error = 'Invalid CreoleDatabase parameter retrieval method "%s"';
$error = sprintf($error, $method);
throw new sfDatabaseException($error);
}
// get creole class path
$classPath = $this->getParameter('classpath');
// include the creole file
if ($classPath == null)
{
require_once('creole/Creole.php');
}
else
{
require_once($classPath);
}
// set our flags
$noAssocLower = $this->getParameter('no_assoc_lower', false);
$persistent = $this->getParameter('persistent', false);
$compatAssocLower = $this->getParameter('compat_assoc_lower', false);
$compatRtrimString = $this->getParameter('compat_rtrim_string', false);
$flags = 0;
$flags |= ($noAssocLower) ? Creole::NO_ASSOC_LOWER : 0;
$flags |= ($persistent) ? Creole::PERSISTENT : 0;
$flags |= ($compatAssocLower) ? Creole::COMPAT_ASSOC_LOWER : 0;
$flags |= ($compatRtrimString) ? Creole::COMPAT_RTRIM_STRING : 0;
// do the duuuurtay work, right thurr
if ($flags > 0)
{
$this->connection = Creole::getConnection($dsn, $flags);
}
else
{
$this->connection = Creole::getConnection($dsn);
}
// get our resource
$this->resource = $this->connection->getResource();
}
catch (SQLException $e)
{
// the connection's foobar'd
throw new sfDatabaseException($e->toString());
}
}
/**
* Load a DSN connection string from an existing array.
*
* @return array An associative array of connection parameters.
*/
protected function & loadDSN(&$array)
{
// determine if a dsn is set, otherwise use separate parameters
$dsn = $this->getParameter('dsn');
if ($dsn == null)
{
// list of available parameters
$available = array('database', 'hostspec', 'password', 'phptype', 'username', 'port');
$dsn = array();
// yes, i know variable variables are ugly, but let's avoid using
// an array for array's sake in this single spot in the source
foreach ($available as $parameter)
{
$$parameter = $this->getParameter($parameter);
$dsn[$parameter] = ($$parameter != null) ? $array[$$parameter] : null;
}
}
else
{
$dsn = $array[$dsn];
}
return $dsn;
}
/**
* Execute the shutdown procedure.
*
* @return void
*
* @throws <b>sfDatabaseException</b> If an error occurs while shutting down this database.
*/
public function shutdown()
{
if ($this->connection !== null)
{
@$this->connection->close();
}
}
}

View File

@ -0,0 +1,294 @@
<?php
/**
* Debug implementation of Connection.
*
* This is a Connection that implements the decorator pattern, wrapping around
* the true Connection object (stored in $childConnection). This Connection
* tracks information about queries executed and makes that information available
* for debugging purposes. The information tracked is the last query executed
* on the connection (getLastExecutedQuery()) and the total number of
* queries executed on the connection thus far (getNumQueriesExecuted()).
*
* To use this debug connection, you need to register it as a new Creole
* driver that handles all connection types. To do this, call the following
* before calling Creole::getConnection():
*
* <code>
* Creole::registerDriver('*', 'creole.drivers.debug.DebugConnection');
* </code>
*
* The next call to Creole::getConnection() will return an instance of
* DebugConnection.
*
* @author Michael Sims
* @package creole.drivers.debug
*/
class sfDebugConnection implements Connection
{
/** @var Connection */
private $childConnection = null;
/** @var int */
private $numQueriesExecuted = 0;
/** @var string */
private $lastExecutedQuery = '';
/**
* Optional PEAR Log class; if set queries will be logged at PEAR_LOG_INFO level.
* @var Log
*/
private static $logger;
/**
* Sets a Logger class (e.g. PEAR Log) to use for logging.
* The logger class must have a log() method. All messages are logged at default log level.
* @param object $logger
*/
public static function setLogger($logger)
{
self::$logger = $logger;
}
/**
* Returns the number of queries executed on this connection so far
*
* @return int
*/
public function getNumQueriesExecuted()
{
return $this->numQueriesExecuted;
}
/**
* Returns the last query executed on this connection
*
* @return string
*/
public function getLastExecutedQuery()
{
return $this->lastExecutedQuery;
}
/**
* connect()
*/
public function connect($dsninfo, $flags = 0)
{
if (!($driver = Creole::getDriver($dsninfo['phptype'])))
{
throw new SQLException("No driver has been registered to handle connection type: $type");
}
$connectionClass = Creole::import($driver);
$this->childConnection = new $connectionClass();
$this->log("{sfCreole} connect(): DSN: ". var_export($dsninfo, true) . ", FLAGS: " . var_export($flags, true));
return $this->childConnection->connect($dsninfo, $flags);
}
/**
* @see Connection::getDatabaseInfo()
*/
public function getDatabaseInfo()
{
return $this->childConnection->getDatabaseInfo();
}
/**
* @see Connection::getIdGenerator()
*/
public function getIdGenerator()
{
return $this->childConnection->getIdGenerator();
}
/**
* @see Connection::isConnected()
*/
public function isConnected()
{
return $this->childConnection->isConnected();
}
/**
* @see Connection::prepareStatement()
*/
public function prepareStatement($sql)
{
$this->log("{sfCreole} prepareStatement(): $sql");
$obj = $this->childConnection->prepareStatement($sql);
$objClass = get_class($obj);
return new $objClass($this, $sql);
}
/**
* @see Connection::createStatement()
*/
public function createStatement()
{
$obj = $this->childConnection->createStatement();
$objClass = get_class($obj);
return new $objClass($this);
}
/**
* @see Connection::applyLimit()
*/
public function applyLimit(&$sql, $offset, $limit)
{
$this->log("{sfCreole} applyLimit(): $sql, offset: $offset, limit: $limit");
return $this->childConnection->applyLimit($sql, $offset, $limit);
}
/**
* @see Connection::close()
*/
public function close()
{
$this->log("{sfCreole} close(): Closing connection.");
return $this->childConnection->close();
}
/**
* @see Connection::executeQuery()
*/
public function executeQuery($sql, $fetchmode = null)
{
$this->lastExecutedQuery = $sql;
$this->numQueriesExecuted++;
$elapsedTime = 0;
if (sfConfig::get('sf_debug') && sfConfig::get('sf_logging_enabled'))
{
$sqlTimer = sfTimerManager::getTimer('Database');
$timer = new sfTimer();
}
$retval = $this->childConnection->executeQuery($sql, $fetchmode);
if (sfConfig::get('sf_debug') && sfConfig::get('sf_logging_enabled'))
{
$sqlTimer->addTime();
$elapsedTime = $timer->getElapsedTime();
}
$this->log(sprintf("{sfCreole} executeQuery(): [%.2f ms] %s", $elapsedTime * 1000, $sql));
return $retval;
}
/**
* @see Connection::executeUpdate()
**/
public function executeUpdate($sql)
{
$this->log("{sfCreole} executeUpdate(): $sql");
$this->lastExecutedQuery = $sql;
$this->numQueriesExecuted++;
return $this->childConnection->executeUpdate($sql);
}
/**
* @see Connection::getUpdateCount()
*/
public function getUpdateCount()
{
return $this->childConnection->getUpdateCount();
}
/**
* @see Connection::prepareCall()
**/
public function prepareCall($sql)
{
$this->log("{sfCreole} prepareCall(): $sql");
return $this->childConnection->prepareCall($sql);
}
/**
* @see Connection::getResource()
*/
public function getResource()
{
return $this->childConnection->getResource();
}
/**
* @see Connection::connect()
*/
public function getDSN()
{
return $this->childConnection->getDSN();
}
/**
* @see Connection::getFlags()
*/
public function getFlags()
{
return $this->childConnection->getFlags();
}
/**
* @see Connection::begin()
*/
public function begin()
{
$this->log("{sfCreole} beginning transaction.");
return $this->childConnection->begin();
}
/**
* @see Connection::commit()
*/
public function commit()
{
$this->log("{sfCreole} committing transaction.");
return $this->childConnection->commit();
}
/**
* @see Connection::rollback()
*/
public function rollback()
{
$this->log("{sfCreole} rolling back transaction.");
return $this->childConnection->rollback();
}
/**
* @see Connection::setAutoCommit()
*/
public function setAutoCommit($bit)
{
$this->log("{sfCreole} setting autocommit to: ".var_export($bit, true));
return $this->childConnection->setAutoCommit($bit);
}
/**
* @see Connection::getAutoCommit()
*/
public function getAutoCommit()
{
return $this->childConnection->getAutoCommit();
}
/**
* Private function that logs message using specified logger (if provided).
* @param string $msg Message to log.
*/
private function log($msg)
{
if (self::$logger)
{
// message on one line
$msg = preg_replace("/\r?\n/", ' ', $msg);
self::$logger->log($msg);
}
}
public function __call($method, $arguments)
{
return $this->childConnection->$method($arguments);
}
}

View File

@ -0,0 +1,445 @@
<?php
/**
* sfMessageSource_Creole class file.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the BSD License.
*
* Copyright(c) 2004 by Qiang Xue. All rights reserved.
*
* To contact the author write to {@link mailto:qiang.xue@gmail.com Qiang Xue}
* The latest version of PRADO can be obtained from:
* {@link http://prado.sourceforge.net/}
*
* @author Wei Zhuo <weizhuo[at]gmail[dot]com>
* @version $Id: sfMessageSource_Creole.class.php 3245 2007-01-12 15:01:53Z fabien $
* @package symfony
* @subpackage i18n
*/
/*
CREATE TABLE `catalogue` (
`cat_id` int(11) NOT NULL auto_increment,
`name` varchar(100) NOT NULL default '',
`source_lang` varchar(100) NOT NULL default '',
`target_lang` varchar(100) NOT NULL default '',
`date_created` int(11) NOT NULL default '0',
`date_modified` int(11) NOT NULL default '0',
`author` varchar(255) NOT NULL default '',
PRIMARY KEY (`cat_id`)
);
CREATE TABLE `trans_unit` (
`msg_id` int(11) NOT NULL auto_increment,
`cat_id` int(11) NOT NULL default '1',
`source` text NOT NULL,
`target` text NOT NULL,
`comments` text NOT NULL,
`date_added` int(11) NOT NULL default '0',
`date_modified` int(11) NOT NULL default '0',
`author` varchar(255) NOT NULL default '',
`translated` tinyint(1) NOT NULL default '0',
PRIMARY KEY (`msg_id`)
);
*/
/**
* sfMessageSource_Creole class.
*
* Retrieve the message translation from a Creole supported database.
*
* See the MessageSource::factory() method to instantiate this class.
*
* @author RoVeRT <symfony[at]rovert[dot]net>
*/
class sfMessageSource_Creole extends sfMessageSource
{
/**
* A resource link to the database
* @var db
*/
protected $db;
/**
* Constructor.
* Create a new message source using Creole.
* @param string Creole datasource.
* @see MessageSource::factory();
*/
public function __construct($source)
{
$this->db = sfContext::getInstance()->getDatabaseConnection($source);
if ($this->db == null || !$this->db instanceof Connection)
{
$error = 'Creole dabatase connection doesn\'t exist. Unable to open session.';
throw new sfDatabaseException($error);
}
}
/**
* Destructor, close the database connection.
*/
public function __destruct()
{
}
/**
* Get the database connection.
* @return db database connection.
*/
public function connection()
{
return $this->db;
}
/**
* Get an array of messages for a particular catalogue and cultural
* variant.
* @param string the catalogue name + variant
* @return array translation messages.
*/
protected function &loadData($variant)
{
$sql = 'SELECT t.source, t.target, t.comments '.
'FROM trans_unit t, catalogue c '.
'WHERE c.cat_id = t.cat_id AND c.name = ? '.
'ORDER BY msg_id ASC';
$stmt = $this->db->prepareStatement($sql);
$rs = $stmt->executeQuery(array($variant), ResultSet::FETCHMODE_NUM);
$result = array();
$count = 0;
while ($rs->next())
{
$source = $rs->getString(1);
$result[$source][] = $rs->getString(2); //target
$result[$source][] = $count++; //id
$result[$source][] = $rs->getString(3); //comments
}
return $result;
}
/**
* Get the last modified unix-time for this particular catalogue+variant.
* We need to query the database to get the date_modified.
*
* @param string catalogue+variant
* @return int last modified in unix-time format.
*/
protected function getLastModified($source)
{
$sql = 'SELECT date_modified FROM catalogue WHERE name = ?';
$stmt = $this->db->prepareStatement($sql);
$rs = $stmt->executeQuery(array($source), ResultSet::FETCHMODE_NUM);
$result = $rs->next() ? $rs->getInt(1) : 0;
return $result;
}
/**
* Check if a particular catalogue+variant exists in the database.
*
* @param string catalogue+variant
* @return boolean true if the catalogue+variant is in the database, false otherwise.
*/
protected function isValidSource($variant)
{
$sql = 'SELECT COUNT(*) FROM catalogue WHERE name = ?';
$stmt = $this->db->prepareStatement($sql);
$rs = $stmt->executeQuery(array($variant), ResultSet::FETCHMODE_NUM);
$result = $rs->next() ? $rs->getInt(1) == 1 : false;
return $result;
}
/**
* Get all the variants of a particular catalogue.
*
* @param string catalogue name
* @return array list of all variants for this catalogue.
*/
protected function getCatalogueList($catalogue)
{
$variants = explode('_', $this->culture);
$catalogues = array($catalogue);
$variant = null;
for ($i = 0, $max = count($variants); $i < $max; $i++)
{
if (strlen($variants[$i]) > 0)
{
$variant .= ($variant) ? '_'.$variants[$i] : $variants[$i];
$catalogues[] = $catalogue.'.'.$variant;
}
}
return array_reverse($catalogues);
}
/**
* Retrieve catalogue details, array($cat_id, $variant, $count).
*
* @param string catalogue
* @return array catalogue details, array($cat_id, $variant, $count).
*/
protected function getCatalogueDetails($catalogue = 'messages')
{
if (empty($catalogue))
{
$catalogue = 'messages';
}
$variant = $catalogue.'.'.$this->culture;
$name = $this->getSource($variant);
$sql = 'SELECT cat_id FROM catalogue WHERE name = ?';
$stmt = $this->db->prepareStatement($sql);
$rs = $stmt->executeQuery(array($name), ResultSet::FETCHMODE_NUM);
if ($rs->getRecordCount() != 1)
{
return false;
}
$rs->next();
$cat_id = $rs->getInt(1);
//first get the catalogue ID
$sql = 'SELECT count(msg_id) FROM trans_unit WHERE cat_id = ?';
$stmt = $this->db->prepareStatement($sql);
$rs = $stmt->executeQuery(array($cat_id), ResultSet::FETCHMODE_NUM);
$rs->next();
$count = $rs->getInt(1);
return array($cat_id, $variant, $count);
}
/**
* Update the catalogue last modified time.
*
* @return boolean true if updated, false otherwise.
*/
protected function updateCatalogueTime($cat_id, $variant)
{
$time = time();
$sql = 'UPDATE catalogue SET date_modified = ? WHERE cat_id = ?';
$stmt = $this->db->prepareStatement($sql);
$result = $stmt->executeUpdate(array($time, $cat_id));
if (!empty($this->cache))
{
$this->cache->clean($variant, $this->culture);
}
return true;
}
/**
* Save the list of untranslated blocks to the translation source.
* If the translation was not found, you should add those
* strings to the translation source via the <b>append()</b> method.
*
* @param string the catalogue to add to
* @return boolean true if saved successfuly, false otherwise.
*/
function save($catalogue='messages')
{
$messages = $this->untranslated;
if (count($messages) <= 0)
{
return false;
}
$details = $this->getCatalogueDetails($catalogue);
if ($details)
{
list($cat_id, $variant, $count) = $details;
}
else
{
return false;
}
if ($cat_id <= 0)
{
return false;
}
$inserted = 0;
$time = time();
try
{
$sql = 'SELECT msg_id FROM trans_unit WHERE source = ?';
$stmt = $this->db->prepareStatement($sql);
foreach($messages as $key => $message)
{
$rs = $stmt->executeQuery(array($message), ResultSet::FETCHMODE_NUM);
if ($rs->next())
{
unset($messages[$key]);
}
}
}
catch (Exception $e)
{
}
try
{
$this->db->begin();
$sql = 'INSERT INTO trans_unit (cat_id, source, target, comments, date_added, date_modified) VALUES (?, ?, ?, ?, ?, ?)';
$stmt = $this->db->prepareStatement($sql);
foreach ($messages as $message)
{
$stmt->executeUpdate(array($cat_id, $message, '', '', $time, $time));
++$inserted;
}
$this->db->commit();
}
catch (Exception $e)
{
$this->db->rollback();
}
if ($inserted > 0)
{
$this->updateCatalogueTime($cat_id, $variant);
}
return $inserted > 0;
}
/**
* Delete a particular message from the specified catalogue.
*
* @param string the source message to delete.
* @param string the catalogue to delete from.
* @return boolean true if deleted, false otherwise.
*/
function delete($message, $catalogue='messages')
{
$details = $this->getCatalogueDetails($catalogue);
if ($details)
{
list($cat_id, $variant, $count) = $details;
}
else
{
return false;
}
$deleted = false;
$sql = 'DELETE FROM trans_unit WHERE cat_id = ? AND source = ?';
$stmt = $this->db->prepareStatement($sql);
$rows = $stmt->executeUpdate(array($cat_id, $message));
if ($rows == 1)
{
$deleted = $this->updateCatalogueTime($cat_id, $variant);
}
return $deleted;
}
/**
* Update the translation.
*
* @param string the source string.
* @param string the new translation string.
* @param string comments
* @param string the catalogue of the translation.
* @return boolean true if translation was updated, false otherwise.
*/
function update($text, $target, $comments, $catalogue='messages')
{
$details = $this->getCatalogueDetails($catalogue);
if ($details)
{
list($cat_id, $variant, $count) = $details;
}
else
{
return false;
}
$time = time();
$sql = 'UPDATE trans_unit SET target = ?, comments = ?, date_modified = ? WHERE cat_id = ? AND source = ?';
$updated = false;
$stmt = $this->db->prepareStatement($sql);
$rows = $stmt->executeUpdate(array($target, $comments, $time, $cat_id, $text));
if ($rows == 1)
{
$updated = $this->updateCatalogueTime($cat_id, $variant);
}
return $updated;
}
/**
* Returns a list of catalogue as key and all it variants as value.
*
* @return array list of catalogues
*/
function catalogues()
{
$sql = 'SELECT name FROM catalogue ORDER BY name';
$rs = $this->db->executeQuery($sql, ResultSet::FETCHMODE_NUM);
$result = array();
while ($rs->next())
{
$details = explode('.', $rs->getString(1));
if (!isset($details[1]))
{
$details[1] = null;
}
$result[] = $details;
}
return $result;
}
}

View File

@ -0,0 +1,307 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004, 2005 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004, 2005 Sean Kerr.
*
* The original version the file is based on is licensed under the LGPL, but a special license was granted.
* Please see the licenses/LICENSE.Agavi file
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Provides support for session storage using a CreoleDb database abstraction layer.
*
* <b>Required parameters:</b>
*
* # <b>db_table</b> - [none] - The database table in which session data will be
* stored.
*
* <b>Optional parameters:</b>
*
* # <b>database</b> - [default] - The database connection to use
* (see databases.ini).
* # <b>db_id_col</b> - [sess_id] - The database column in which the
* session id will be stored.
* # <b>db_data_col</b> - [sess_data] - The database column in which the
* session data will be stored.
* # <b>db_time_col</b> - [sess_time] - The database column in which the
* session timestamp will be stored.
* # <b>session_name</b> - [Agavi] - The name of the session.
*
* @package symfony
* @subpackage storage
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @author Veikko Mäkinen <mail@veikkomakinen.com>
* @version SVN: $Id: sfCreoleSessionStorage.class.php 2995 2006-12-09 18:01:32Z fabien $
*/
class sfCreoleSessionStorage extends sfSessionStorage
{
/**
* Creole Database Connection
* @var Connection
*/
protected $db;
/**
* Initialize this Storage.
*
* @param Context A Context instance.
* @param array An associative array of initialization parameters.
*
* @return bool true, if initialization completes successfully, otherwise
* false.
*
* @throws <b>InitializationException</b> If an error occurs while
* initializing this Storage.
*/
public function initialize($context, $parameters = null)
{
// disable auto_start
$parameters['auto_start'] = false;
// initialize the parent
parent::initialize($context, $parameters);
if (!$this->getParameterHolder()->has('db_table'))
{
// missing required 'db_table' parameter
$error = 'Factory configuration file is missing required "db_table" parameter for the Storage category';
throw new sfInitializationException($error);
}
// use this object as the session handler
session_set_save_handler(array($this, 'sessionOpen'),
array($this, 'sessionClose'),
array($this, 'sessionRead'),
array($this, 'sessionWrite'),
array($this, 'sessionDestroy'),
array($this, 'sessionGC'));
// start our session
session_start();
}
/**
* Close a session.
*
* @return bool true, if the session was closed, otherwise false.
*/
public function sessionClose()
{
// do nothing
return true;
}
/**
* Destroy a session.
*
* @param string A session ID.
*
* @return bool true, if the session was destroyed, otherwise an exception
* is thrown.
*
* @throws <b>DatabaseException</b> If the session cannot be destroyed.
*/
public function sessionDestroy($id)
{
// get table/column
$db_table = $this->getParameterHolder()->get('db_table');
$db_id_col = $this->getParameterHolder()->get('db_id_col', 'sess_id');
// delete the record associated with this id
$sql = 'DELETE FROM ' . $db_table . ' WHERE ' . $db_id_col . '=?';
try
{
$stmt = $this->db->prepareStatement($sql);
$stmt->setString(1, $id);
$stmt->executeUpdate();
}
catch (SQLException $e) {
$error = 'Creole SQLException was thrown when trying to manipulate session data. ';
$error .= 'Message: ' . $e->getMessage();
throw new sfDatabaseException($error);
}
}
/**
* Cleanup old sessions.
*
* @param int The lifetime of a session.
*
* @return bool true, if old sessions have been cleaned, otherwise an
* exception is thrown.
*
* @throws <b>DatabaseException</b> If any old sessions cannot be cleaned.
*/
public function sessionGC($lifetime)
{
// determine deletable session time
$time = time() - $lifetime;
// get table/column
$db_table = $this->getParameterHolder()->get('db_table');
$db_time_col = $this->getParameterHolder()->get('db_time_col', 'sess_time');
// delete the record associated with this id
$sql = 'DELETE FROM ' . $db_table . ' ' .
'WHERE ' . $db_time_col . ' < ' . $time;
try
{
$this->db->executeQuery($sql);
return true;
}
catch (SQLException $e)
{
$error = 'Creole SQLException was thrown when trying to manipulate session data. ';
$error .= 'Message: ' . $e->getMessage();
throw new sfDatabaseException($error);
}
}
/**
* Open a session.
*
* @param string
* @param string
*
* @return bool true, if the session was opened, otherwise an exception is
* thrown.
*
* @throws <b>DatabaseException</b> If a connection with the database does
* not exist or cannot be created.
*/
public function sessionOpen($path, $name)
{
// what database are we using?
$database = $this->getParameterHolder()->get('database', 'default');
// autoload propel propely if we're reusing the propel connection for session storage
if ($this->getContext()->getDatabaseManager()->getDatabase($database) instanceof sfPropelDatabase && !Propel::isInit())
{
$error = 'Creole dabatase connection is the same as the propel database connection, but could not be initialized.';
throw new sfDatabaseException($error);
}
$this->db = $this->getContext()->getDatabaseConnection($database);
if ($this->db == null || !$this->db instanceof Connection)
{
$error = 'Creole dabatase connection doesn\'t exist. Unable to open session.';
throw new sfDatabaseException($error);
}
return true;
}
/**
* Read a session.
*
* @param string A session ID.
*
* @return bool true, if the session was read, otherwise an exception is
* thrown.
*
* @throws <b>DatabaseException</b> If the session cannot be read.
*/
public function sessionRead($id)
{
// get table/columns
$db_table = $this->getParameterHolder()->get('db_table');
$db_data_col = $this->getParameterHolder()->get('db_data_col', 'sess_data');
$db_id_col = $this->getParameterHolder()->get('db_id_col', 'sess_id');
$db_time_col = $this->getParameterHolder()->get('db_time_col', 'sess_time');
try
{
$sql = 'SELECT ' . $db_data_col . ' FROM ' . $db_table . ' WHERE ' . $db_id_col . '=?';
$stmt = $this->db->prepareStatement($sql);
$stmt->setString(1, $id);
$dbRes = $stmt->executeQuery(ResultSet::FETCHMODE_NUM);
if ($dbRes->next())
{
$data = $dbRes->getString(1);
return $data;
}
else
{
// session does not exist, create it
$sql = 'INSERT INTO ' . $db_table . '('.$db_id_col.','.$db_data_col.','.$db_time_col;
$sql .= ') VALUES (?,?,?)';
$stmt = $this->db->prepareStatement($sql);
$stmt->setString(1, $id);
$stmt->setString(2, '');
$stmt->setInt(3, time());
$stmt->executeUpdate();
return '';
}
}
catch (SQLException $e)
{
$error = 'Creole SQLException was thrown when trying to manipulate session data. ';
$error .= 'Message: ' . $e->getMessage();
throw new sfDatabaseException($error);
}
}
/**
* Write session data.
*
* @param string A session ID.
* @param string A serialized chunk of session data.
*
* @return bool true, if the session was written, otherwise an exception is
* thrown.
*
* @throws <b>DatabaseException</b> If the session data cannot be written.
*/
public function sessionWrite($id, $data)
{
// get table/column
$db_table = $this->getParameterHolder()->get('db_table');
$db_data_col = $this->getParameterHolder()->get('db_data_col', 'sess_data');
$db_id_col = $this->getParameterHolder()->get('db_id_col', 'sess_id');
$db_time_col = $this->getParameterHolder()->get('db_time_col', 'sess_time');
$sql = 'UPDATE ' . $db_table . ' SET ' . $db_data_col . '=?, ' . $db_time_col . ' = ' . time() .
' WHERE ' . $db_id_col . '=?';
try
{
$stmt = $this->db->prepareStatement($sql);
$stmt->setString(1, $data);
$stmt->setString(2, $id);
$stmt->executeUpdate();
return true;
}
catch (SQLException $e)
{
$error = 'Creole SQLException was thrown when trying to manipulate session data. ';
$error .= 'Message: ' . $e->getMessage();
throw new sfDatabaseException($error);
}
return false;
}
/**
* Execute the shutdown procedure.
*
* @return void
*/
public function shutdown()
{
}
}

View File

@ -0,0 +1,61 @@
<?php
require_once 'propel/engine/builder/om/php5/PHP5ExtensionObjectBuilder.php';
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* @package symfony
* @subpackage addon
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: SfExtensionObjectBuilder.php 2624 2006-11-07 09:34:59Z fabien $
*/
class SfExtensionObjectBuilder extends PHP5ExtensionObjectBuilder
{
protected function addIncludes(&$script)
{
if (!DataModelBuilder::getBuildProperty('builderAddIncludes'))
{
return;
}
parent::addIncludes($script);
}
protected function addClassOpen(&$script)
{
$table = $this->getTable();
$tableName = $table->getName();
$tableDesc = $table->getDescription();
$baseClassname = $this->getObjectBuilder()->getClassname();
$script .= "
/**
* Subclass for representing a row from the '$tableName' table.
*
* $tableDesc
*
* @package ".$this->getPackage()."
*/
class ".$this->getClassname()." extends $baseClassname
{";
}
/**
* Closes class.
* @param string &$script The script will be modified in this method.
*/
protected function addClassClose(&$script)
{
$script .= "
}
";
}
}

View File

@ -0,0 +1,65 @@
<?php
require_once 'propel/engine/builder/om/php5/PHP5ExtensionPeerBuilder.php';
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* @package symfony
* @subpackage addon
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: SfExtensionPeerBuilder.php 2624 2006-11-07 09:34:59Z fabien $
*/
class SfExtensionPeerBuilder extends PHP5ExtensionPeerBuilder
{
protected function addIncludes(&$script)
{
if (!DataModelBuilder::getBuildProperty('builderAddIncludes'))
{
return;
}
parent::addIncludes($script);
}
/**
* Adds class phpdoc comment and openning of class.
* @param string &$script The script will be modified in this method.
*/
protected function addClassOpen(&$script)
{
$table = $this->getTable();
$tableName = $table->getName();
$tableDesc = $table->getDescription();
$baseClassname = $this->getPeerBuilder()->getClassname();
$script .= "
/**
* Subclass for performing query and update operations on the '$tableName' table.
*
* $tableDesc
*
* @package ".$this->getPackage()."
*/
class ".$this->getClassname()." extends $baseClassname
{";
}
/**
* Closes class.
* @param string &$script The script will be modified in this method.
*/
protected function addClassClose(&$script)
{
$script .= "
}
";
}
}

View File

@ -0,0 +1,53 @@
<?php
require_once 'propel/engine/builder/om/php5/PHP5MapBuilderBuilder.php';
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* @package symfony
* @subpackage addon
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: SfMapBuilderBuilder.php 3058 2006-12-16 17:17:26Z fabien $
*/
class SfMapBuilderBuilder extends PHP5MapBuilderBuilder
{
public function build()
{
if (!DataModelBuilder::getBuildProperty('builderAddComments'))
{
return sfToolkit::stripComments(parent::build());
}
return parent::build();
}
protected function addIncludes(&$script)
{
if (!DataModelBuilder::getBuildProperty('builderAddIncludes'))
{
return;
}
parent::addIncludes($script);
}
protected function addDoBuild(&$script)
{
parent::addDoBuild($script);
// fix http://propel.phpdb.org/trac/ticket/235: Column sizes not being inserted into [table]MapBuilder->DoBuild() by PHP5MapBuilderBuilder
$sizes = array();
foreach ($this->getTable()->getColumns() as $col)
{
$sizes[$col->getPhpName()] = !$col->getSize() ? 'null' : $col->getSize();
}
$script = preg_replace("/\\\$tMap\->addColumn\('([^']+)', '([^']+)', '([^']+)', CreoleTypes\:\:VARCHAR, (false|true)\)/e", '"\\\$tMap->addColumn(\'$1\', \'$2\', \'$3\', CreoleTypes::VARCHAR, $4, {$sizes[\'$2\']})"', $script);
}
}

View File

@ -0,0 +1,30 @@
<?php
require_once 'propel/engine/builder/om/php5/PHP5MultiExtendObjectBuilder.php';
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* @package symfony
* @subpackage addon
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: SfMultiExtendObjectBuilder.php 1919 2006-09-01 14:41:22Z fabien $
*/
class SfMultiExtendObjectBuilder extends PHP5MultiExtendObjectBuilder
{
protected function addIncludes(&$script)
{
if (!DataModelBuilder::getBuildProperty('builderAddIncludes'))
{
return;
}
parent::addIncludes($script);
}
}

View File

@ -0,0 +1,341 @@
<?php
require_once 'propel/engine/builder/om/php5/PHP5ComplexObjectBuilder.php';
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* @package symfony
* @subpackage addon
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: SfObjectBuilder.php 3493 2007-02-18 09:23:10Z fabien $
*/
class SfObjectBuilder extends PHP5ComplexObjectBuilder
{
public function build()
{
if (!DataModelBuilder::getBuildProperty('builderAddComments'))
{
return sfToolkit::stripComments(parent::build());
}
return parent::build();
}
protected function addIncludes(&$script)
{
if (!DataModelBuilder::getBuildProperty('builderAddIncludes'))
{
return;
}
parent::addIncludes($script);
// include the i18n classes if needed
if ($this->getTable()->getAttribute('isI18N'))
{
$relatedTable = $this->getDatabase()->getTable($this->getTable()->getAttribute('i18nTable'));
$script .= '
require_once \''.$this->getFilePath($this->getStubObjectBuilder()->getPackage().'.'.$relatedTable->getPhpName().'Peer').'\';
require_once \''.$this->getFilePath($this->getStubObjectBuilder()->getPackage().'.'.$relatedTable->getPhpName()).'\';
';
}
}
protected function addClassBody(&$script)
{
parent::addClassBody($script);
if ($this->getTable()->getAttribute('isI18N'))
{
if (count($this->getTable()->getPrimaryKey()) > 1)
{
throw new Exception('i18n support only works with a single primary key');
}
$this->addCultureAccessorMethod($script);
$this->addCultureMutatorMethod($script);
$this->addI18nMethods($script);
}
if (DataModelBuilder::getBuildProperty('builderAddBehaviors'))
{
$this->addCall($script);
}
}
protected function addCall(&$script)
{
$script .= "
public function __call(\$method, \$arguments)
{
if (!\$callable = sfMixer::getCallable('{$this->getClassname()}:'.\$method))
{
throw new sfException(sprintf('Call to undefined method {$this->getClassname()}::%s', \$method));
}
array_unshift(\$arguments, \$this);
return call_user_func_array(\$callable, \$arguments);
}
";
}
protected function addAttributes(&$script)
{
parent::addAttributes($script);
if ($this->getTable()->getAttribute('isI18N'))
{
$script .= '
/**
* The value for the culture field.
* @var string
*/
protected $culture;
';
}
}
protected function addCultureAccessorMethod(&$script)
{
$script .= '
public function getCulture()
{
return $this->culture;
}
';
}
protected function addCultureMutatorMethod(&$script)
{
$script .= '
public function setCulture($culture)
{
$this->culture = $culture;
}
';
}
protected function addI18nMethods(&$script)
{
$table = $this->getTable();
$pks = $table->getPrimaryKey();
$pk = $pks[0]->getPhpName();
foreach ($table->getReferrers() as $fk)
{
$tblFK = $fk->getTable();
if ($tblFK->getName() == $table->getAttribute('i18nTable'))
{
$className = $tblFK->getPhpName();
$culture = '';
$culture_peername = '';
foreach ($tblFK->getColumns() as $col)
{
if (("true" === strtolower($col->getAttribute('isCulture'))))
{
$culture = $col->getPhpName();
$culture_peername = PeerBuilder::getColumnName($col, $className);
}
}
foreach ($tblFK->getColumns() as $col)
{
if ($col->isPrimaryKey()) continue;
$script .= '
public function get'.$col->getPhpName().'()
{
$obj = $this->getCurrent'.$className.'();
return ($obj ? $obj->get'.$col->getPhpName().'() : null);
}
public function set'.$col->getPhpName().'($value)
{
$this->getCurrent'.$className.'()->set'.$col->getPhpName().'($value);
}
';
}
$script .= '
protected $current_i18n = array();
public function getCurrent'.$className.'()
{
if (!isset($this->current_i18n[$this->culture]))
{
$obj = '.$className.'Peer::retrieveByPK($this->get'.$pk.'(), $this->culture);
if ($obj)
{
$this->set'.$className.'ForCulture($obj, $this->culture);
}
else
{
$this->set'.$className.'ForCulture(new '.$className.'(), $this->culture);
$this->current_i18n[$this->culture]->set'.$culture.'($this->culture);
}
}
return $this->current_i18n[$this->culture];
}
public function set'.$className.'ForCulture($object, $culture)
{
$this->current_i18n[$culture] = $object;
$this->add'.$className.'($object);
}
';
}
}
}
protected function addDoSave(&$script)
{
$tmp = '';
parent::addDoSave($tmp);
// add autosave to i18n object even if the base object is not changed
$tmp = preg_replace_callback('#(\$this\->(.+?)\->isModified\(\))#', array($this, 'i18nDoSaveCallback'), $tmp);
$script .= $tmp;
}
private function i18nDoSaveCallback($matches)
{
$value = $matches[1];
// get the related class to see if it is a i18n one
$table = $this->getTable();
$column = null;
foreach ($table->getForeignKeys() as $fk)
{
if ($matches[2] == $this->getFKVarName($fk))
{
$column = $fk;
break;
}
}
$foreign_table = $this->getDatabase()->getTable($fk->getForeignTableName());
if ($foreign_table->getAttribute('isI18N'))
{
$foreign_tables_i18n_table = $this->getDatabase()->getTable($foreign_table->getAttribute('i18nTable'));
$value .= ' || $this->'.$matches[2].'->getCurrent'.$foreign_tables_i18n_table->getPhpName().'()->isModified()';
}
return $value;
}
protected function addDelete(&$script)
{
$tmp = '';
parent::addDelete($tmp);
if (DataModelBuilder::getBuildProperty('builderAddBehaviors'))
{
// add sfMixer call
$pre_mixer_script = "
foreach (sfMixer::getCallables('{$this->getClassname()}:delete:pre') as \$callable)
{
\$ret = call_user_func(\$callable, \$this, \$con);
if (\$ret)
{
return;
}
}
";
$post_mixer_script = "
foreach (sfMixer::getCallables('{$this->getClassname()}:delete:post') as \$callable)
{
call_user_func(\$callable, \$this, \$con);
}
";
$tmp = preg_replace('/{/', '{'.$pre_mixer_script, $tmp, 1);
$tmp = preg_replace('/}\s*$/', $post_mixer_script.' }', $tmp);
}
// update current script
$script .= $tmp;
}
protected function addSave(&$script)
{
$tmp = '';
parent::addSave($tmp);
// add support for created_(at|on) and updated_(at|on) columns
$date_script = '';
$updated = false;
$created = false;
foreach ($this->getTable()->getColumns() as $col)
{
$clo = strtolower($col->getName());
if (!$updated && in_array($clo, array('updated_at', 'updated_on')))
{
$updated = true;
$date_script .= "
if (\$this->isModified() && !\$this->isColumnModified(".$this->getColumnConstant($col)."))
{
\$this->set".$col->getPhpName()."(time());
}
";
}
else if (!$created && in_array($clo, array('created_at', 'created_on')))
{
$created = true;
$date_script .= "
if (\$this->isNew() && !\$this->isColumnModified(".$this->getColumnConstant($col)."))
{
\$this->set".$col->getPhpName()."(time());
}
";
}
}
$tmp = preg_replace('/{/', '{'.$date_script, $tmp, 1);
if (DataModelBuilder::getBuildProperty('builderAddBehaviors'))
{
// add sfMixer call
$pre_mixer_script = "
foreach (sfMixer::getCallables('{$this->getClassname()}:save:pre') as \$callable)
{
\$affectedRows = call_user_func(\$callable, \$this, \$con);
if (is_int(\$affectedRows))
{
return \$affectedRows;
}
}
";
$post_mixer_script = <<<EOF
foreach (sfMixer::getCallables('{$this->getClassname()}:save:post') as \$callable)
{
call_user_func(\$callable, \$this, \$con, \$affectedRows);
}
EOF;
$tmp = preg_replace('/{/', '{'.$pre_mixer_script, $tmp, 1);
$tmp = preg_replace('/(\$con\->commit\(\);)/', '$1'.$post_mixer_script, $tmp);
}
// update current script
$script .= $tmp;
}
}

View File

@ -0,0 +1,274 @@
<?php
require_once 'propel/engine/builder/om/php5/PHP5ComplexPeerBuilder.php';
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* @package symfony
* @subpackage addon
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: SfPeerBuilder.php 2534 2006-10-26 17:13:50Z fabien $
*/
class SfPeerBuilder extends PHP5ComplexPeerBuilder
{
public function build()
{
if (!DataModelBuilder::getBuildProperty('builderAddComments'))
{
return sfToolkit::stripComments(parent::build());
}
return parent::build();
}
protected function addIncludes(&$script)
{
if (!DataModelBuilder::getBuildProperty('builderAddIncludes'))
{
return;
}
parent::addIncludes($script);
}
protected function addSelectMethods(&$script)
{
parent::addSelectMethods($script);
if ($this->getTable()->getAttribute('isI18N'))
{
$this->addDoSelectWithI18n($script);
}
}
protected function addDoSelectWithI18n(&$script)
{
$table = $this->getTable();
$thisTableObjectBuilder = OMBuilder::getNewObjectBuilder($table);
$className = $table->getPhpName();
$pks = $table->getPrimaryKey();
$pk = PeerBuilder::getColumnName($pks[0], $className);
// get i18n table name and culture column name
foreach ($table->getReferrers() as $fk)
{
$tblFK = $fk->getTable();
if ($tblFK->getName() == $table->getAttribute('i18nTable'))
{
$i18nClassName = $tblFK->getPhpName();
// FIXME
$i18nPeerClassName = $i18nClassName.'Peer';
$i18nTable = $table->getDatabase()->getTable($tblFK->getName());
$i18nTableObjectBuilder = OMBuilder::getNewObjectBuilder($i18nTable);
$i18nTablePeerBuilder = OMBuilder::getNewPeerBuilder($i18nTable);
$i18nPks = $i18nTable->getPrimaryKey();
$i18nPk = PeerBuilder::getColumnName($i18nPks[0], $i18nClassName);
$culturePhpName = '';
$cultureColumnName = '';
foreach ($tblFK->getColumns() as $col)
{
if (("true" === strtolower($col->getAttribute('isCulture'))))
{
$culturePhpName = $col->getPhpName();
$cultureColumnName = PeerBuilder::getColumnName($col, $i18nClassName);
}
}
}
}
$script .= "
/**
* Selects a collection of $className objects pre-filled with their i18n objects.
*
* @return array Array of $className objects.
* @throws PropelException Any exceptions caught during processing will be
* rethrown wrapped into a PropelException.
*/
public static function doSelectWithI18n(Criteria \$c, \$culture = null, \$con = null)
{
if (\$culture === null)
{
\$culture = sfContext::getInstance()->getUser()->getCulture();
}
// Set the correct dbName if it has not been overridden
if (\$c->getDbName() == Propel::getDefaultDB())
{
\$c->setDbName(self::DATABASE_NAME);
}
".$this->getPeerClassname()."::addSelectColumns(\$c);
\$startcol = (".$this->getPeerClassname()."::NUM_COLUMNS - ".$this->getPeerClassname()."::NUM_LAZY_LOAD_COLUMNS) + 1;
".$i18nPeerClassName."::addSelectColumns(\$c);
\$c->addJoin(".$pk.", ".$i18nPk.");
\$c->add(".$cultureColumnName.", \$culture);
\$rs = ".$this->basePeerClassname."::doSelect(\$c, \$con);
\$results = array();
while(\$rs->next()) {
";
if ($table->getChildrenColumn()) {
$script .= "
\$omClass = ".$this->getPeerClassname()."::getOMClass(\$rs, 1);
";
} else {
$script .= "
\$omClass = ".$this->getPeerClassname()."::getOMClass();
";
}
$script .= "
\$cls = Propel::import(\$omClass);
\$obj1 = new \$cls();
\$obj1->hydrate(\$rs);
\$obj1->setCulture(\$culture);
";
// if ($i18nTable->getChildrenColumn()) {
$script .= "
\$omClass = ".$i18nTablePeerBuilder->getPeerClassname()."::getOMClass(\$rs, \$startcol);
";
// } else {
// $script .= "
// \$omClass = ".$i18nTablePeerBuilder->getPeerClassname()."::getOMClass();
//";
// }
$script .= "
\$cls = Propel::import(\$omClass);
\$obj2 = new \$cls();
\$obj2->hydrate(\$rs, \$startcol);
\$obj1->set".$i18nClassName."ForCulture(\$obj2, \$culture);
\$obj2->set".$className."(\$obj1);
\$results[] = \$obj1;
}
return \$results;
}
";
}
protected function addDoValidate(&$script)
{
$tmp = '';
parent::addDoValidate($tmp);
$script .= str_replace("return {$this->basePeerClassname}::doValidate(".$this->getPeerClassname()."::DATABASE_NAME, ".$this->getPeerClassname()."::TABLE_NAME, \$columns);\n",
"\$res = {$this->basePeerClassname}::doValidate(".$this->getPeerClassname()."::DATABASE_NAME, ".$this->getPeerClassname()."::TABLE_NAME, \$columns);\n".
" if (\$res !== true) {\n".
" \$request = sfContext::getInstance()->getRequest();\n".
" foreach (\$res as \$failed) {\n".
" \$col = ".$this->getPeerClassname()."::translateFieldname(\$failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);\n".
" \$request->setError(\$col, \$failed->getMessage());\n".
" }\n".
" }\n\n".
" return \$res;\n", $tmp);
}
protected function addDoSelectRS(&$script)
{
$tmp = '';
parent::addDoSelectRS($tmp);
if (DataModelBuilder::getBuildProperty('builderAddBehaviors'))
{
$mixer_script = "
foreach (sfMixer::getCallables('{$this->getClassname()}:addDoSelectRS:addDoSelectRS') as \$callable)
{
call_user_func(\$callable, '{$this->getClassname()}', \$criteria, \$con);
}
";
$tmp = preg_replace('/{/', '{'.$mixer_script, $tmp, 1);
}
$script .= $tmp;
}
protected function addDoUpdate(&$script)
{
$tmp = '';
parent::addDoUpdate($tmp);
if (DataModelBuilder::getBuildProperty('builderAddBehaviors'))
{
// add sfMixer call
$pre_mixer_script = "
foreach (sfMixer::getCallables('{$this->getClassname()}:doUpdate:pre') as \$callable)
{
\$ret = call_user_func(\$callable, '{$this->getClassname()}', \$values, \$con);
if (false !== \$ret)
{
return \$ret;
}
}
";
$post_mixer_script = "
foreach (sfMixer::getCallables('{$this->getClassname()}:doUpdate:post') as \$callable)
{
call_user_func(\$callable, '{$this->getClassname()}', \$values, \$con, \$ret);
}
return \$ret;
";
$tmp = preg_replace('/{/', '{'.$pre_mixer_script, $tmp, 1);
$tmp = preg_replace("/\t\treturn ([^}]+)/", "\t\t\$ret = $1".$post_mixer_script.' ', $tmp, 1);
}
$script .= $tmp;
}
protected function addDoInsert(&$script)
{
$tmp = '';
parent::addDoInsert($tmp);
if (DataModelBuilder::getBuildProperty('builderAddBehaviors'))
{
// add sfMixer call
$pre_mixer_script = "
foreach (sfMixer::getCallables('{$this->getClassname()}:doInsert:pre') as \$callable)
{
\$ret = call_user_func(\$callable, '{$this->getClassname()}', \$values, \$con);
if (false !== \$ret)
{
return \$ret;
}
}
";
$post_mixer_script = "
foreach (sfMixer::getCallables('{$this->getClassname()}:doInsert:post') as \$callable)
{
call_user_func(\$callable, '{$this->getClassname()}', \$values, \$con, \$pk);
}
return";
$tmp = preg_replace('/{/', '{'.$pre_mixer_script, $tmp, 1);
$tmp = preg_replace("/\t\treturn/", "\t\t".$post_mixer_script, $tmp, 1);
}
$script .= $tmp;
}
}

View File

@ -0,0 +1,46 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfGenerator is the abstract base class for all generators.
*
* @package symfony
* @subpackage database
* @author Olivier Verdier <Olivier.Verdier@gmail.com>
* @version SVN: $Id $
*/
class sfPropelDataRetriever
{
static public function retrieveObjects($class, $peerMethod = null)
{
if (!$classPath = sfCore::getClassPath($class.'Peer'))
{
throw new sfException(sprintf('Unable to find path for class "%s".', $class.'Peer'));
}
require_once($classPath);
if (!$peerMethod)
{
$peerMethod = 'doSelect';
}
$classPeer = $class.'Peer';
if (!is_callable(array($classPeer, $peerMethod)))
{
throw new sfException(sprintf('Peer method "%s" not found for class "%s"', $peerMethod, $classPeer));
}
$objects = call_user_func(array($classPeer, $peerMethod), new Criteria());
return $objects;
}
}

View File

@ -0,0 +1,114 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* A symfony database driver for Propel, derived from the native Creole driver.
*
* <b>Optional parameters:</b>
*
* # <b>datasource</b> - [symfony] - datasource to use for the connection
* # <b>is_default</b> - [false] - use as default if multiple connections
* are specified. The parameters
* that has been flagged using this param
* is be used when Propel is initialized
* via sfPropelAutoload.
*
* @package symfony
* @subpackage database
*
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfPropelDatabase.class.php 3493 2007-02-18 09:23:10Z fabien $
*/
class sfPropelDatabase extends sfCreoleDatabase
{
static protected
$config = array();
public function initialize($parameters = null, $name = 'propel')
{
parent::initialize($parameters);
if (!$this->hasParameter('datasource'))
{
$this->setParameter('datasource', $name);
}
$this->addConfig();
$is_default = $this->getParameter('is_default', false);
// first defined if none listed as default
if ($is_default || count(self::$config['propel']['datasources']) == 1)
{
$this->setDefaultConfig();
}
}
public function setDefaultConfig()
{
self::$config['propel']['datasources']['default'] = $this->getParameter('datasource');
}
public function addConfig()
{
if ($this->hasParameter('host'))
{
$this->setParameter('hostspec', $this->getParameter('host'));
}
if ($dsn = $this->getParameter('dsn'))
{
require_once('creole/Creole.php');
$params = Creole::parseDSN($dsn);
$options = array('phptype', 'hostspec', 'database', 'username', 'password', 'port', 'protocol', 'encoding', 'persistent');
foreach ($options as $option)
{
if (!$this->getParameter($option) && isset($params[$option]))
{
$this->setParameter($option, $params[$option]);
}
}
}
self::$config['propel']['datasources'][$this->getParameter('datasource')] =
array(
'adapter' => $this->getParameter('phptype'),
'connection' =>
array(
'phptype' => $this->getParameter('phptype'),
'hostspec' => $this->getParameter('hostspec'),
'database' => $this->getParameter('database'),
'username' => $this->getParameter('username'),
'password' => $this->getParameter('password'),
'port' => $this->getParameter('port'),
'encoding' => $this->getParameter('encoding'),
'persistent' => $this->getParameter('persistent'),
'protocol' => $this->getParameter('protocol'),
),
);
}
public static function getConfiguration()
{
return self::$config;
}
public function setConnectionParameter($key, $value)
{
if ($key == 'host')
{
$key = 'hostspec';
}
self::$config['propel']['datasources'][$this->getParameter('datasource')]['connection'][$key] = $value;
$this->setParameter($key, $value);
}
}

View File

@ -0,0 +1,72 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Propel Admin generator.
*
* This class generates an admin module with propel.
*
* @package symfony
* @subpackage generator
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfPropelAdminGenerator.class.php 3302 2007-01-18 13:42:46Z fabien $
*/
class sfPropelAdminGenerator extends sfPropelCrudGenerator
{
/**
* Initializes the current sfGenerator instance.
*
* @param sfGeneratorManager A sfGeneratorManager instance
*/
public function initialize($generatorManager)
{
parent::initialize($generatorManager);
$this->setGeneratorClass('sfPropelAdmin');
}
public function getAllColumns()
{
$phpNames = array();
foreach ($this->getTableMap()->getColumns() as $column)
{
$phpNames[] = new sfAdminColumn($column->getPhpName(), $column);
}
return $phpNames;
}
public function getAdminColumnForField($field, $flag = null)
{
$phpName = sfInflector::camelize($field);
return new sfAdminColumn($phpName, $this->getColumnForPhpName($phpName), $flag);
}
// returns a column phpName or null if none was found
public function getColumnForPhpName($phpName)
{
// search the matching column for this column name
foreach ($this->getTableMap()->getColumns() as $column)
{
if ($column->getPhpName() == $phpName)
{
$found = true;
return $column;
}
}
// not a "real" column, so we will simulate one
return null;
}
}

View File

@ -0,0 +1,144 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Propel CRUD generator.
*
* This class generates a basic CRUD module with propel.
*
* @package symfony
* @subpackage generator
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfPropelCrudGenerator.class.php 3302 2007-01-18 13:42:46Z fabien $
*/
class sfPropelCrudGenerator extends sfAdminGenerator
{
/**
* Initializes the current sfGenerator instance.
*
* @param sfGeneratorManager A sfGeneratorManager instance
*/
public function initialize($generatorManager)
{
parent::initialize($generatorManager);
$this->setGeneratorClass('sfPropelCrud');
}
/**
* Loads primary keys.
*
* This method is ORM dependant.
*
* @throws sfException
*/
protected function loadPrimaryKeys()
{
foreach ($this->tableMap->getColumns() as $column)
{
if ($column->isPrimaryKey())
{
$this->primaryKey[] = $column;
}
}
if (!count($this->primaryKey))
{
throw new sfException(sprintf('Cannot generate a module for a model without a primary key (%s)', $this->className));
}
}
/**
* Loads map builder classes.
*
* This method is ORM dependant.
*
* @throws sfException
*/
protected function loadMapBuilderClasses()
{
// we must load all map builder classes to be able to deal with foreign keys (cf. editSuccess.php template)
$classes = sfFinder::type('file')->name('*MapBuilder.php')->in(sfLoader::getModelDirs());
foreach ($classes as $class)
{
$class_map_builder = basename($class, '.php');
$maps[$class_map_builder] = new $class_map_builder();
if (!$maps[$class_map_builder]->isBuilt())
{
$maps[$class_map_builder]->doBuild();
}
if ($this->className == str_replace('MapBuilder', '', $class_map_builder))
{
$this->map = $maps[$class_map_builder];
}
}
if (!$this->map)
{
throw new sfException('The model class "'.$this->className.'" does not exist.');
}
$this->tableMap = $this->map->getDatabaseMap()->getTable(constant($this->className.'Peer::TABLE_NAME'));
}
/**
* Generates a PHP call to an object helper.
*
* @param string The helper name
* @param string The column name
* @param array An array of parameters
* @param array An array of local parameters
*
* @return string PHP code
*/
function getPHPObjectHelper($helperName, $column, $params, $localParams = array())
{
$params = $this->getObjectTagParams($params, $localParams);
return sprintf('object_%s($%s, \'%s\', %s)', $helperName, $this->getSingularName(), $this->getColumnGetter($column, false), $params);
}
/**
* Returns the getter either non-developped: 'getFoo' or developped: '$class->getFoo()'.
*
* @param string The column name
* @param boolean true if you want developped method names, false otherwise
* @param string The prefix value
*
* @return string PHP code
*/
function getColumnGetter($column, $developed = false, $prefix = '')
{
$getter = 'get'.$column->getPhpName();
if ($developed)
{
$getter = sprintf('$%s%s->%s()', $prefix, $this->getSingularName(), $getter);
}
return $getter;
}
/*
* Gets the PHP name of the related class name.
*
* Used for foreign keys only; this method should be removed when we use sfAdminColumn instead.
*
* @param string The column name
*
* @return string The PHP name of the related class name
*/
function getRelatedClassName($column)
{
$relatedTable = $this->getMap()->getDatabaseMap()->getTable($column->getRelatedTableName());
return $relatedTable->getPhpName();
}
}

View File

@ -0,0 +1,32 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* @package symfony
* @subpackage addon
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfPropelAutoload.php 2808 2006-11-25 07:22:49Z fabien $
*/
require_once 'propel/Propel.php';
if (sfConfig::get('sf_debug') && sfConfig::get('sf_logging_enabled'))
{
// register debug driver
require_once 'creole/Creole.php';
Creole::registerDriver('*', 'symfony.addon.creole.drivers.sfDebugConnection');
// register our logger
require_once(sfConfig::get('sf_symfony_lib_dir').'/addon/creole/drivers/sfDebugConnection.php');
sfDebugConnection::setLogger(sfLogger::getInstance());
}
// propel initialization
Propel::setConfiguration(sfPropelDatabase::getConfiguration());
Propel::initialize();

View File

@ -0,0 +1,89 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* @package symfony
* @subpackage addon
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfPropelBehavior.class.php 2453 2006-10-20 05:58:48Z fabien $
*/
class sfPropelBehavior
{
static protected $behaviors = array();
static public function registerMethods($name, $callables)
{
if (!isset(self::$behaviors[$name]))
{
self::$behaviors[$name] = array('methods' => array(), 'hooks' => array());
}
foreach ($callables as $callable)
{
self::$behaviors[$name]['methods'][] = $callable;
}
}
static public function registerHooks($name, $hooks)
{
if (!isset(self::$behaviors[$name]))
{
self::$behaviors[$name] = array('methods' => array(), 'hooks' => array());
}
foreach ($hooks as $hook => $callable)
{
if (!isset(self::$behaviors[$name]['hooks']))
{
self::$behaviors[$name]['hooks'][$hook] = array();
}
self::$behaviors[$name]['hooks'][$hook][] = $callable;
}
}
static public function add($class, $behaviors)
{
foreach ($behaviors as $name => $parameters)
{
if (is_int($name))
{
// no parameters
$name = $parameters;
}
else
{
// register parameters
foreach ($parameters as $key => $value)
{
sfConfig::set('propel_behavior_'.$name.'_'.$class.'_'.$key, $value);
}
}
if (!isset(self::$behaviors[$name]))
{
throw new sfConfigurationException(sprintf('Propel behavior "%s" is not registered', $name));
}
// register hooks
foreach (self::$behaviors[$name]['hooks'] as $hook => $callables)
{
foreach ($callables as $callable)
{
sfMixer::register('Base'.$class.$hook, $callable);
}
}
// register new methods
foreach (self::$behaviors[$name]['methods'] as $callable)
{
sfMixer::register('Base'.$class, $callable);
}
}
}
}

View File

@ -0,0 +1,385 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* This class is the Propel implementation of sfData. It interacts with the data source
* and loads data.
*
* @package symfony
* @subpackage addon
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfPropelData.class.php 5339 2007-10-01 07:35:33Z fabien $
*/
class sfPropelData extends sfData
{
protected
$maps = array(),
$deletedClasses = array(),
$con = null;
// symfony load-data (file|dir)
/**
* Loads data from a file or directory into a Propel data source
*
* @param mixed A file or directory path
* @param string The Propel connection name, default 'propel'
*
* @throws Exception If the database throws an error, rollback transaction and rethrows exception
*/
public function loadData($directory_or_file = null, $connectionName = 'propel')
{
$fixture_files = $this->getFiles($directory_or_file);
// wrap all database operations in a single transaction
$this->con = Propel::getConnection($connectionName);
try
{
$this->con->begin();
$this->doDeleteCurrentData($fixture_files);
$this->doLoadData($fixture_files);
$this->con->commit();
}
catch (Exception $e)
{
$this->con->rollback();
throw $e;
}
}
/**
* Implements the abstract loadDataFromArray method and loads the data using the generated data model.
*
* @param array The data to be loaded into the data source
*
* @throws Exception If data is unnamed.
* @throws sfException If an object defined in the model does not exist in the data
* @throws sfException If a column that does not exist is referenced
*/
public function loadDataFromArray($data)
{
if ($data === null)
{
// no data
return;
}
foreach ($data as $class => $datas)
{
$class = trim($class);
$peer_class = $class.'Peer';
// load map class
$this->loadMapBuilder($class);
$tableMap = $this->maps[$class]->getDatabaseMap()->getTable(constant($peer_class.'::TABLE_NAME'));
$column_names = call_user_func_array(array($peer_class, 'getFieldNames'), array(BasePeer::TYPE_FIELDNAME));
// iterate through datas for this class
// might have been empty just for force a table to be emptied on import
if (!is_array($datas))
{
continue;
}
foreach ($datas as $key => $data)
{
// create a new entry in the database
$obj = new $class();
if (!is_array($data))
{
throw new Exception(sprintf('You must give a name for each fixture data entry (class %s)'), $class);
}
foreach ($data as $name => $value)
{
// foreign key?
try
{
$column = $tableMap->getColumn($name);
if ($column->isForeignKey() && !is_null($value))
{
$relatedTable = $this->maps[$class]->getDatabaseMap()->getTable($column->getRelatedTableName());
if (!isset($this->object_references[$relatedTable->getPhpName().'_'.$value]))
{
$error = 'The object "%s" from class "%s" is not defined in your data file.';
$error = sprintf($error, $value, $relatedTable->getPhpName());
throw new sfException($error);
}
$value = $this->object_references[$relatedTable->getPhpName().'_'.$value];
}
}
catch (PropelException $e)
{
}
$pos = array_search($name, $column_names);
$method = 'set'.sfInflector::camelize($name);
if ($pos)
{
$obj->setByPosition($pos, $value);
}
else if (is_callable(array($obj, $method)))
{
$obj->$method($value);
}
else
{
$error = 'Column "%s" does not exist for class "%s"';
$error = sprintf($error, $name, $class);
throw new sfException($error);
}
}
$obj->save($this->con);
// save the id for future reference
if (method_exists($obj, 'getPrimaryKey'))
{
$this->object_references[$class.'_'.$key] = $obj->getPrimaryKey();
}
}
}
}
/**
* Clears existing data from the data source by reading the fixture files
* and deleting the existing data for only those classes that are mentioned
* in the fixtures.
*
* @param array The list of YAML files.
*
* @throws sfException If a class mentioned in a fixture can not be found
*/
protected function doDeleteCurrentData($fixture_files)
{
// delete all current datas in database
if (!$this->deleteCurrentData)
{
return;
}
rsort($fixture_files);
foreach ($fixture_files as $fixture_file)
{
$data = sfYaml::load($fixture_file);
if ($data === null)
{
// no data
continue;
}
$classes = array_keys($data);
krsort($classes);
foreach ($classes as $class)
{
$class = trim($class);
if (in_array($class, $this->deletedClasses))
{
continue;
}
$peer_class = $class.'Peer';
if (!$classPath = sfCore::getClassPath($peer_class))
{
throw new sfException(sprintf('Unable to find path for class "%s".', $peer_class));
}
require_once($classPath);
call_user_func(array($peer_class, 'doDeleteAll'), $this->con);
$this->deletedClasses[] = $class;
}
}
}
/**
* Loads the mappings for the classes
*
* @param string The model class name
*
* @throws sfException If the class cannot be found
*/
protected function loadMapBuilder($class)
{
$mapBuilderClass = $class.'MapBuilder';
if (!isset($this->maps[$class]))
{
if (!$classPath = sfCore::getClassPath($mapBuilderClass))
{
throw new sfException(sprintf('Unable to find path for class "%s".', $mapBuilderClass));
}
require_once($classPath);
$this->maps[$class] = new $mapBuilderClass();
$this->maps[$class]->doBuild();
}
}
/**
* Dumps data to fixture from one or more tables.
*
* @param string directory or file to dump to
* @param mixed name or names of tables to dump (or all to dump all tables)
* @param string connection name
*/
public function dumpData($directory_or_file = null, $tables = 'all', $connectionName = 'propel')
{
$sameFile = true;
if (is_dir($directory_or_file))
{
// multi files
$sameFile = false;
}
else
{
// same file
// delete file
}
$this->con = Propel::getConnection($connectionName);
// get tables
if ('all' === $tables || is_null($tables))
{
// load all map builder classes
$files = sfFinder::type('file')->name('*MapBuilder.php')->in(sfLoader::getModelDirs());
foreach ($files as $file)
{
$mapBuilderClass = basename($file, '.php');
$map = new $mapBuilderClass();
$map->doBuild();
}
$dbMap = Propel::getDatabaseMap($connectionName);
$tables = array();
foreach ($dbMap->getTables() as $table)
{
$tables[] = $table->getPhpName();
}
}
else if (!is_array($tables))
{
$tables = array($tables);
}
$dumpData = array();
// load map classes
array_walk($tables, array($this, 'loadMapBuilder'));
$tables = $this->fixOrderingOfForeignKeyData($tables);
foreach ($tables as $tableName)
{
$tableMap = $this->maps[$tableName]->getDatabaseMap()->getTable(constant($tableName.'Peer::TABLE_NAME'));
// get db info
$rs = $this->con->executeQuery('SELECT * FROM '.constant($tableName.'Peer::TABLE_NAME'));
while ($rs->next())
{
$pk = $tableName;
$values = array();
foreach ($tableMap->getColumns() as $column)
{
$col = strtolower($column->getColumnName());
if ($column->isPrimaryKey())
{
$pk .= '_'.$rs->get($col);
}
else if ($column->isForeignKey())
{
$relatedTable = $this->maps[$tableName]->getDatabaseMap()->getTable($column->getRelatedTableName());
$values[$col] = $relatedTable->getPhpName().'_'.$rs->get($col);
}
else
{
$values[$col] = $rs->get($col);
}
}
if (!isset($dumpData[$tableName]))
{
$dumpData[$tableName] = array();
}
$dumpData[$tableName][$pk] = $values;
}
}
// save to file(s)
if ($sameFile)
{
file_put_contents($directory_or_file, Spyc::YAMLDump($dumpData));
}
else
{
$i = 0;
foreach ($tables as $tableName)
{
if (!isset($dumpData[$tableName]))
{
continue;
}
file_put_contents(sprintf("%s/%03d-%s.yml", $directory_or_file, ++$i, $tableName), Spyc::YAMLDump(array($tableName => $dumpData[$tableName])));
}
}
}
/**
* Fixes the ordering of foreign key data, by outputting data a foreign key depends on before the table with the foreign key.
*
* @param array The array with the class names.
*/
public function fixOrderingOfForeignKeyData($classes)
{
// reordering classes to take foreign keys into account
for ($i = 0, $count = count($classes); $i < $count; $i++)
{
$class = $classes[$i];
$tableMap = $this->maps[$class]->getDatabaseMap()->getTable(constant($class.'Peer::TABLE_NAME'));
foreach ($tableMap->getColumns() as $column)
{
if ($column->isForeignKey())
{
$relatedTable = $this->maps[$class]->getDatabaseMap()->getTable($column->getRelatedTableName());
$relatedTablePos = array_search($relatedTable->getPhpName(), $classes);
// check if relatedTable is after the current table
if ($relatedTablePos > $i)
{
// move related table 1 position before current table
$classes = array_merge(
array_slice($classes, 0, $i),
array($classes[$relatedTablePos]),
array_slice($classes, $i, $relatedTablePos - $i),
array_slice($classes, $relatedTablePos + 1)
);
// we have moved a table, so let's see if we are done
return $this->fixOrderingOfForeignKeyData($classes);
}
}
}
}
return $classes;
}
}

View File

@ -0,0 +1,719 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
*
* @package symfony
* @subpackage addon
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author François Zaninotto <francois.zaninotto@symfony-project.com>
* @version SVN: $Id$
*/
class sfPropelDatabaseSchema
{
protected $connection_name = '';
protected $database = array();
public function asArray()
{
return array($this->connection_name => $this->database);
}
public function loadYAML($file)
{
$schema = sfYaml::load($file);
if (count($schema) > 1)
{
throw new sfException('A schema.yml must only contain 1 database entry.');
}
$tmp = array_keys($schema);
$this->connection_name = array_shift($tmp);
if ($this->connection_name)
{
$this->database = $schema[$this->connection_name];
$this->fixYAMLDatabase();
$this->fixYAMLI18n();
$this->fixYAMLColumns();
}
}
public function asXML()
{
$xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
$xml .= "<database name=\"$this->connection_name\"".$this->getAttributesFor($this->database).">\n";
// tables
foreach ($this->getChildren($this->database) as $tb_name => $table)
{
$xml .= "\n <table name=\"$tb_name\"".$this->getAttributesFor($table).">\n";
// columns
foreach ($this->getChildren($table) as $col_name => $column)
{
$xml .= " <column name=\"$col_name\"".$this->getAttributesForColumn($tb_name, $col_name, $column);
}
// indexes
if (isset($table['_indexes']))
{
foreach ($table['_indexes'] as $index_name => $index)
{
$xml .= " <index name=\"$index_name\">\n";
foreach ($index as $index_column)
{
$xml .= " <index-column name=\"$index_column\" />\n";
}
$xml .= " </index>\n";
}
}
// uniques
if (isset($table['_uniques']))
{
foreach ($table['_uniques'] as $unique_name => $index)
{
$xml .= " <unique name=\"$unique_name\">\n";
foreach ($index as $unique_column)
{
$xml .= " <unique-column name=\"$unique_column\" />\n";
}
$xml .= " </unique>\n";
}
}
// foreign-keys
if (isset($table['_foreignKeys']))
{
foreach ($table['_foreignKeys'] as $fkey_name => $fkey)
{
$xml .= " <foreign-key foreignTable=\"$fkey[foreignTable]\"";
// foreign key name
if (!is_numeric($fkey_name))
{
$xml .= " name=\"$fkey_name\"";
}
// onDelete
if (isset($fkey['onDelete']))
{
$xml .= " onDelete=\"$fkey[onDelete]\"";
}
// onUpdate
if (isset($fkey['onUpdate']))
{
$xml .= " onUpdate=\"$fkey[onUpdate]\"";
}
$xml .= ">\n";
// references
if (isset($fkey['references']))
{
foreach ($fkey['references'] as $reference)
{
$xml .= " <reference local=\"$reference[local]\" foreign=\"$reference[foreign]\" />\n";
}
}
$xml .= " </foreign-key>\n";
}
}
$xml .= " </table>\n";
}
$xml .= "\n</database>\n";
return $xml;
}
protected function fixYAMLDatabase()
{
if (!isset($this->database['_attributes']))
{
$this->database['_attributes'] = array();
}
// conventions for database attributes
$this->setIfNotSet($this->database['_attributes'], 'defaultIdMethod', 'native');
$this->setIfNotSet($this->database['_attributes'], 'noXsd', true);
$this->setIfNotSet($this->database['_attributes'], 'package', 'lib.model');
}
protected function fixYAMLI18n()
{
foreach ($this->getTables() as $i18n_table => $columns)
{
$pos = strpos($i18n_table, '_i18n');
$has_primary_key = false;
foreach ($columns as $column => $attributes)
{
if (is_array($attributes) && array_key_exists('primaryKey', $attributes))
{
$has_primary_key = true;
}
}
if ($pos > 0 && $pos == strlen($i18n_table) - 5 && !$has_primary_key)
{
// i18n table without primary key
$main_table = $this->findTable(substr($i18n_table, 0, $pos));
if ($main_table)
{
// set i18n attributes for main table
$this->setIfNotSet($this->database[$main_table]['_attributes'], 'isI18N', 1);
$this->setIfNotSet($this->database[$main_table]['_attributes'], 'i18nTable', $i18n_table);
// set id and culture columns for i18n table
$this->setIfNotSet($this->database[$i18n_table], 'id', array(
'type' => 'integer',
'required' => true,
'primaryKey' => true,
'foreignTable' => $main_table,
'foreignReference' => 'id',
'onDelete' => 'cascade'
));
$this->setIfNotSet($this->database[$i18n_table], 'culture', array(
'isCulture' => true,
'type' => 'varchar',
'size' => '7',
'required' => true,
'primaryKey' => true
));
}
else
{
throw new sfException(sprintf('Missing main table for internationalized table "%s".', $i18n_table));
}
}
}
}
protected function fixYAMLColumns()
{
foreach ($this->getTables() as $table => $columns)
{
$has_primary_key = false;
foreach ($columns as $column => $attributes)
{
if ($attributes == null)
{
// conventions for null attributes
if ($column == 'created_at' || $column == 'updated_at')
{
// timestamp convention
$this->database[$table][$column]['type']= 'timestamp';
}
if ($column == 'id')
{
// primary key convention
$this->database[$table]['id'] = array(
'type' => 'integer',
'required' => true,
'primaryKey' => true,
'autoincrement' => true
);
$has_primary_key = true;
}
$pos = strpos($column, '_id');
if ($pos > 0 && $pos == strlen($column) - 3)
{
// foreign key convention
$foreign_table = $this->findTable(substr($column, 0, $pos));
if ($foreign_table)
{
$this->database[$table][$column] = array(
'type' => 'integer',
'foreignTable' => $foreign_table,
'foreignReference' => 'id'
);
}
else
{
throw new sfException(sprintf('Unable to resolve foreign table for column "%s"', $column));
}
}
}
else
{
if (!is_array($attributes))
{
// compact type given as single attribute
$this->database[$table][$column] = $this->getAttributesFromCompactType($attributes);
}
else
{
if (isset($attributes['type']))
{
// compact type given as value of the type attribute
$this->database[$table][$column] = array_merge($this->database[$table][$column], $this->getAttributesFromCompactType($attributes['type']));
}
if (isset($attributes['primaryKey']))
{
$has_primary_key = true;
}
}
}
}
if (!$has_primary_key)
{
// convention for tables without primary key
$this->database[$table]['id'] = array(
'type' => 'integer',
'required' => true,
'primaryKey' => true,
'autoincrement' => true
);
}
}
}
protected function getAttributesFromCompactType($type)
{
preg_match('/varchar\(([\d]+)\)/', $type, $matches);
if (isset($matches[1]))
{
return array('type' => 'varchar', 'size' => $matches[1]);
}
else
{
return array('type' => $type);
}
}
protected function setIfNotSet(&$entry, $key, $value)
{
if (!isset($entry[$key]))
{
$entry[$key] = $value;
}
}
protected function findTable($table_name)
{
// find a table from a phpName or a name
$table_match = false;
foreach ($this->getTables() as $tb_name => $table)
{
if ((isset($table['_attributes']['phpName']) && $table['_attributes']['phpName'] == sfInflector::camelize($table_name)) || ($tb_name == $table_name))
{
$table_match = $tb_name;
}
}
return $table_match;
}
protected function getAttributesForColumn($tb_name, $col_name, $column)
{
$attributes_string = '';
if (is_array($column))
{
foreach ($column as $key => $value)
{
if (!in_array($key, array('foreignTable', 'foreignReference', 'onDelete', 'onUpdate', 'index', 'unique')))
{
$attributes_string .= " $key=\"".htmlspecialchars($this->getCorrectValueFor($key, $value))."\"";
}
}
$attributes_string .= " />\n";
}
else
{
throw new sfException('Incorrect settings for column '.$col_name);
}
// conventions for foreign key attributes
if (is_array($column) && isset($column['foreignTable']))
{
$attributes_string .= " <foreign-key foreignTable=\"$column[foreignTable]\"";
if (isset($column['onDelete']))
{
$attributes_string .= " onDelete=\"$column[onDelete]\"";
}
if (isset($column['onUpdate']))
{
$attributes_string .= " onUpdate=\"$column[onUpdate]\"";
}
$attributes_string .= ">\n";
$attributes_string .= " <reference local=\"$col_name\" foreign=\"$column[foreignReference]\" />\n";
$attributes_string .= " </foreign-key>\n";
}
// conventions for index and unique index attributes
if (is_array($column) && isset($column['index']))
{
if ($column['index'] === 'unique')
{
$attributes_string .= " <unique name=\"${tb_name}_${col_name}_unique\">\n";
$attributes_string .= " <unique-column name=\"$col_name\" />\n";
$attributes_string .= " </unique>\n";
}
else
{
$attributes_string .= " <index name=\"${tb_name}_${col_name}_index\">\n";
$attributes_string .= " <index-column name=\"$col_name\" />\n";
$attributes_string .= " </index>\n";
}
}
// conventions for sequence name attributes
// required for databases using sequences for auto-increment columns (e.g. PostgreSQL or Oracle)
if (is_array($column) && isset($column['sequence']))
{
$attributes_string .= " <id-method-parameter value=\"$column[sequence]\" />\n";
}
return $attributes_string;
}
protected function getAttributesFor($tag)
{
if (!isset($tag['_attributes']))
{
return '';
}
$attributes = $tag['_attributes'];
$attributes_string = '';
foreach ($attributes as $key => $value)
{
$attributes_string .= ' '.$key.'="'.htmlspecialchars($this->getCorrectValueFor($key, $value)).'"';
}
return $attributes_string;
}
protected function getCorrectValueFor($key, $value)
{
$booleans = array('required', 'primaryKey', 'autoincrement', 'autoIncrement', 'noXsd', 'isI18N', 'isCulture');
if (in_array($key, $booleans))
{
return $value == 1 ? 'true' : 'false';
}
else
{
return is_null($value) ? 'null' : $value;
}
}
public function getTables()
{
return $this->getChildren($this->database);
}
public function getChildren($hash)
{
foreach ($hash as $key => $value)
{
// ignore special children (starting with _)
if ($key[0] == '_')
{
unset($hash[$key]);
}
}
return $hash;
}
public function loadXML($file)
{
$schema = simplexml_load_file($file);
$database = array();
// database
list($database_name, $database_attributes) = $this->getNameAndAttributes($schema->attributes());
if ($database_name)
{
$this->connection_name = $database_name;
}
else
{
throw new sfException('The database tag misses a name attribute');
}
if ($database_attributes)
{
$database['_attributes'] = $database_attributes;
}
// tables
foreach ($schema as $table)
{
list($table_name, $table_attributes) = $this->getNameAndAttributes($table->attributes());
if ($table_name)
{
$database[$table_name] = array();
}
else
{
throw new sfException('A table tag misses the name attribute');
}
if ($table_attributes)
{
$database[$table_name]['_attributes'] = $table_attributes;
}
// columns
foreach ($table->xpath('column') as $column)
{
list($column_name, $column_attributes) = $this->getNameAndAttributes($column->attributes());
if ($column_name)
{
$database[$table_name][$column_name] = $column_attributes;
}
else
{
throw new sfException('A column tag misses the name attribute');
}
}
// foreign-keys
$database[$table_name]['_foreign_keys'] = array();
foreach ($table->xpath('foreign-key') as $foreign_key)
{
$foreign_key_table = array();
// foreign key attributes
if (isset($foreign_key['foreignTable']))
{
$foreign_key_table['foreign_table'] = (string) $foreign_key['foreignTable'];
}
else
{
throw new sfException('A foreign key misses the foreignTable attribute');
}
if (isset($foreign_key['onDelete']))
{
$foreign_key_table['on_delete'] = (string) $foreign_key['onDelete'];
}
if (isset($foreign_key['onUpdate']))
{
$foreign_key_table['on_update'] = (string) $foreign_key['onUpdate'];
}
// foreign key references
$foreign_key_table['references'] = array();
foreach ($foreign_key->xpath('reference') as $reference)
{
$reference_attributes = array();
foreach ($reference->attributes() as $reference_attribute_name => $reference_attribute_value)
{
$reference_attributes[$reference_attribute_name] = strval($reference_attribute_value);
}
$foreign_key_table['references'][] = $reference_attributes;
}
if (isset($foreign_key['name']))
{
$database[$table_name]['_foreign_keys'][(string)$foreign_key['name']] = $foreign_key_table;
}
else
{
$database[$table_name]['_foreign_keys'][] = $foreign_key_table;
}
}
$this->removeEmptyKey($database[$table_name], '_foreign_keys');
// indexes
$database[$table_name]['_indexes'] = array();
foreach ($table->xpath('index') as $index)
{
$index_keys = array();
foreach ($index->xpath('index-column') as $index_key)
{
$index_keys[] = strval($index_key['name']);
}
$database[$table_name]['_indexes'][strval($index['name'])] = $index_keys;
}
$this->removeEmptyKey($database[$table_name], '_indexes');
// unique indexes
$database[$table_name]['_uniques'] = array();
foreach ($table->xpath('unique') as $index)
{
$unique_keys = array();
foreach ($index->xpath('unique-column') as $unique_key)
{
$unique_keys[] = strval($unique_key['name']);
}
$database[$table_name]['_uniques'][strval($index['name'])] = $unique_keys;
}
$this->removeEmptyKey($database[$table_name], '_uniques');
}
$this->database = $database;
$this->fixXML();
}
public function fixXML()
{
$this->fixXMLForeignKeys();
$this->fixXMLIndexes();
// $this->fixXMLColumns();
}
protected function fixXMLForeignKeys()
{
foreach ($this->getTables() as $table => $columns)
{
if (isset($this->database[$table]['_foreign_keys']))
{
$foreign_keys = $this->database[$table]['_foreign_keys'];
foreach ($foreign_keys as $foreign_key_name => $foreign_key_attributes)
{
// Only single foreign keys can be simplified
if (count($foreign_key_attributes['references']) == 1)
{
$reference = $foreign_key_attributes['references'][0];
// set simple foreign key
$this->database[$table][$reference['local']]['foreignTable'] = $foreign_key_attributes['foreign_table'];
$this->database[$table][$reference['local']]['foreignReference'] = $reference['foreign'];
if (isset($foreign_key_attributes['on_delete']))
{
$this->database[$table][$reference['local']]['onDelete'] = $foreign_key_attributes['on_delete'];
}
if (isset($foreign_key_attributes['on_update']))
{
$this->database[$table][$reference['local']]['onUpdate'] = $foreign_key_attributes['on_update'];
}
// remove complex foreign key
unset($this->database[$table]['_foreign_keys'][$foreign_key_name]);
}
$this->removeEmptyKey($this->database[$table], '_foreign_keys');
}
}
}
}
protected function fixXMLIndexes()
{
foreach ($this->getTables() as $table => $columns)
{
if (isset($this->database[$table]['_indexes']))
{
$indexes = $this->database[$table]['_indexes'];
foreach ($indexes as $index => $references)
{
// Only single indexes can be simplified
if (count($references) == 1 && array_key_exists(substr($index, 0, strlen($index) - 6), $columns))
{
$reference = $references[0];
// set simple index
$this->database[$table][$reference]['index'] = 'true';
// remove complex index
unset($this->database[$table]['_indexes'][$index]);
}
$this->removeEmptyKey($this->database[$table], '_indexes');
}
}
if (isset($this->database[$table]['_uniques']))
{
$uniques = $this->database[$table]['_uniques'];
foreach ($uniques as $index => $references)
{
// Only single unique indexes can be simplified
if (count($references) == 1 && array_key_exists(substr($index, 0, strlen($index) - 7), $columns))
{
$reference = $references[0];
// set simple index
$this->database[$table][$reference]['index'] = 'unique';
// remove complex unique index
unset($this->database[$table]['_uniques'][$index]);
}
$this->removeEmptyKey($this->database[$table], '_uniques');
}
}
}
}
protected function fixXMLColumns()
{
foreach ($this->getTables() as $table => $columns)
{
foreach ($columns as $column => $attributes)
{
if ($column == 'id' && !array_diff($attributes, array('type' => 'integer', 'required' => 'true', 'primaryKey' => 'true', 'autoincrement' => 'true')))
{
// simplify primary keys
$this->database[$table]['id'] = null;
}
if (($column == 'created_at') || ($column == 'updated_at') && !array_diff($attributes, array('type' => 'timestamp')))
{
// simplify timestamps
$this->database[$table][$column] = null;
}
$pos = strpos($column, '_id');
$has_fk_name = $pos > 0 && $pos == strlen($column) - 3;
$is_foreign_key = isset($attributes['type']) && $attributes['type'] == 'integer' && isset($attributes['foreignReference']) && $attributes['foreignReference'] == 'id';
$has_foreign_table = isset($attributes['foreignTable']) && array_key_exists($attributes['foreignTable'], $this->getTables());
$has_other_attribute = isset($attributes['onDelete']);
if ($has_fk_name && $has_foreign_table && $is_foreign_key && !$has_other_attribute)
{
// simplify foreign key
$this->database[$table][$column] = null;
}
}
}
}
public function asYAML()
{
return sfYaml::dump(array($this->connection_name => $this->database));
}
protected function getNameAndAttributes($hash, $name_attribute = 'name')
{
// tag name
$name = '';
if (isset($hash[$name_attribute]))
{
$name = strval($hash[$name_attribute]);
unset($hash[$name_attribute]);
}
// tag attributes
$attributes = array();
foreach ($hash as $attribute => $value)
{
$attributes[$attribute] = strval($value);
}
return array($name, $attributes);
}
protected function removeEmptyKey(&$hash, $key)
{
if (isset($hash[$key]) && !$hash[$key])
{
unset($hash[$key]);
}
}
}

View File

@ -0,0 +1,106 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
*
* @package symfony
* @subpackage util
* @author Nick Lane <nick.lane@internode.on.net>
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfPropelManyToMany.class.php 1931 2006-09-02 17:56:18Z fabien $
*/
class sfPropelManyToMany
{
public static function getColumn($class, $middleClass)
{
// find the related class
$tableMap = call_user_func(array($middleClass.'Peer', 'getTableMap'));
$object_table_name = constant($class.'Peer::TABLE_NAME');
foreach ($tableMap->getColumns() as $column)
{
if ($column->isForeignKey() && $object_table_name == $column->getRelatedTableName())
{
return $column;
}
}
}
public static function getRelatedColumn($class, $middleClass)
{
// find the related class
$tableMap = call_user_func(array($middleClass.'Peer', 'getTableMap'));
$object_table_name = constant($class.'Peer::TABLE_NAME');
foreach ($tableMap->getColumns() as $column)
{
if ($column->isForeignKey() && $object_table_name != $column->getRelatedTableName())
{
return $column;
}
}
}
public static function getRelatedClass($class, $middleClass)
{
$column = self::getRelatedColumn($class, $middleClass);
// we must load all map builder classes
$classes = sfFinder::type('file')->name('*MapBuilder.php')->in(sfLoader::getModelDirs());
foreach ($classes as $class)
{
$class_map_builder = basename($class, '.php');
$map = new $class_map_builder();
$map->doBuild();
}
$tableMap = call_user_func(array($middleClass.'Peer', 'getTableMap'));
return $tableMap->getDatabaseMap()->getTable($column->getRelatedTableName())->getPhpName();
}
public static function getAllObjects($object, $middleClass, $criteria = null)
{
if (null === $criteria)
{
$criteria = new Criteria();
}
$relatedClass = self::getRelatedClass(get_class($object), $middleClass);
return call_user_func(array($relatedClass.'Peer', 'doSelect'), $criteria);
}
/**
* Gets objects related by a many-to-many relationship, with a middle table.
*
* @param $object The object to get related objects for.
* @param $middleClass The middle class used for the many-to-many relationship.
* @param $criteria Criteria to apply to the selection.
*/
public static function getRelatedObjects($object, $middleClass, $criteria = null)
{
if (null === $criteria)
{
$criteria = new Criteria();
}
$relatedClass = self::getRelatedClass(get_class($object), $middleClass);
$relatedObjects = array();
$objectMethod = 'get'.$middleClass.'sJoin'.$relatedClass;
$relatedMethod = 'get'.$relatedClass;
$rels = $object->$objectMethod($criteria);
foreach ($rels as $rel)
{
$relatedObjects[] = $rel->$relatedMethod();
}
return $relatedObjects;
}
}

View File

@ -0,0 +1,138 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* @package symfony
* @subpackage addon
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfPropelPager.class.php 2728 2006-11-17 09:46:01Z chtito $
*/
/**
*
* sfPropelPager class.
*
* @package symfony
* @subpackage addon
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfPropelPager.class.php 2728 2006-11-17 09:46:01Z chtito $
*/
class sfPropelPager extends sfPager
{
protected
$criteria = null,
$peer_method_name = 'doSelect',
$peer_count_method_name = 'doCount';
public function __construct($class, $maxPerPage = 10)
{
parent::__construct($class, $maxPerPage);
$this->setCriteria(new Criteria());
$this->tableName = constant($class.'Peer::TABLE_NAME');
}
public function init()
{
$hasMaxRecordLimit = ($this->getMaxRecordLimit() !== false);
$maxRecordLimit = $this->getMaxRecordLimit();
$cForCount = clone $this->getCriteria();
$cForCount->setOffset(0);
$cForCount->setLimit(0);
$cForCount->clearGroupByColumns();
// require the model class (because autoloading can crash under some conditions)
if (!$classPath = sfCore::getClassPath($this->getClassPeer()))
{
throw new sfException(sprintf('Unable to find path for class "%s".', $this->getClassPeer()));
}
require_once($classPath);
$count = call_user_func(array($this->getClassPeer(), $this->getPeerCountMethod()), $cForCount);
$this->setNbResults($hasMaxRecordLimit ? min($count, $maxRecordLimit) : $count);
$c = $this->getCriteria();
$c->setOffset(0);
$c->setLimit(0);
if (($this->getPage() == 0 || $this->getMaxPerPage() == 0))
{
$this->setLastPage(0);
}
else
{
$this->setLastPage(ceil($this->getNbResults() / $this->getMaxPerPage()));
$offset = ($this->getPage() - 1) * $this->getMaxPerPage();
$c->setOffset($offset);
if ($hasMaxRecordLimit)
{
$maxRecordLimit = $maxRecordLimit - $offset;
if ($maxRecordLimit > $this->getMaxPerPage())
{
$c->setLimit($this->getMaxPerPage());
}
else
{
$c->setLimit($maxRecordLimit);
}
}
else
{
$c->setLimit($this->getMaxPerPage());
}
}
}
protected function retrieveObject($offset)
{
$cForRetrieve = clone $this->getCriteria();
$cForRetrieve->setOffset($offset - 1);
$cForRetrieve->setLimit(1);
$results = call_user_func(array($this->getClassPeer(), $this->getPeerMethod()), $cForRetrieve);
return $results[0];
}
public function getResults()
{
$c = $this->getCriteria();
return call_user_func(array($this->getClassPeer(), $this->getPeerMethod()), $c);
}
public function getPeerMethod()
{
return $this->peer_method_name;
}
public function setPeerMethod($peer_method_name)
{
$this->peer_method_name = $peer_method_name;
}
public function getPeerCountMethod()
{
return $this->peer_count_method_name;
}
public function setPeerCountMethod($peer_count_method_name)
{
$this->peer_count_method_name = $peer_count_method_name;
}
public function getClassPeer()
{
return $this->class.'Peer';
}
}

View File

@ -0,0 +1,98 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfPropelUniqueValidator validates that the uniqueness of a column.
* This validator only works for single column primary key.
*
* <b>Required parameters:</b>
*
* # <b>class</b> - [none] - Propel class name.
* # <b>column</b> - [none] - Propel column name.
*
* <b>Optional parameters:</b>
*
* # <b>unique_error</b> - [Uniqueness error] - An error message to use when
* the value for this column already
* exists in the database.
*
* @package symfony
* @subpackage validator
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Fédéric Coelho <frederic.coelho@symfony-project.com>
* @version SVN: $Id: sfPropelUniqueValidator.class.php 2995 2006-12-09 18:01:32Z fabien $
*/
class sfPropelUniqueValidator extends sfValidator
{
public function execute(&$value, &$error)
{
$className = $this->getParameter('class').'Peer';
$columnName = call_user_func(array($className, 'translateFieldName'), $this->getParameter('column'), BasePeer::TYPE_FIELDNAME, BasePeer::TYPE_COLNAME);
$c = new Criteria();
$c->add($columnName, $value);
$object = call_user_func(array($className, 'doSelectOne'), $c);
if ($object)
{
$tableMap = call_user_func(array($className, 'getTableMap'));
foreach ($tableMap->getColumns() as $column)
{
if (!$column->isPrimaryKey())
{
continue;
}
$method = 'get'.$column->getPhpName();
$primaryKey = call_user_func(array($className, 'translateFieldName'), $column->getPhpName(), BasePeer::TYPE_PHPNAME, BasePeer::TYPE_FIELDNAME);
if ($object->$method() != $this->getContext()->getRequest()->getParameter($primaryKey))
{
$error = $this->getParameter('unique_error');
return false;
}
}
}
return true;
}
/**
* Initialize this validator.
*
* @param sfContext The current application context.
* @param array An associative array of initialization parameters.
*
* @return bool true, if initialization completes successfully, otherwise false.
*/
public function initialize($context, $parameters = null)
{
// initialize parent
parent::initialize($context);
// set defaults
$this->setParameter('unique_error', 'Uniqueness error');
$this->getParameterHolder()->add($parameters);
// check parameters
if (!$this->getParameter('class'))
{
throw new sfValidatorException('The "class" parameter is mandatory for the sfPropelUniqueValidator validator.');
}
if (!$this->getParameter('column'))
{
throw new sfValidatorException('The "column" parameter is mandatory for the sfPropelUniqueValidator validator.');
}
return true;
}
}

View File

@ -0,0 +1,120 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* This class defines the interface for interacting with data, as well
* as default implementations.
*
* @package symfony
* @subpackage addon
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfData.class.php 3382 2007-02-01 07:34:56Z fabien $
*/
abstract class sfData
{
protected
$deleteCurrentData = true,
$object_references = array();
/**
* Sets a flag to indicate if the current data in the database
* should be deleted before new data is loaded.
*
* @param boolean The flag value
*/
public function setDeleteCurrentData($boolean)
{
$this->deleteCurrentData = $boolean;
}
/**
* Gets the current value of the flag that indicates whether
* current data is to be deleted or not.
*
* @returns boolean
*/
public function getDeleteCurrentData()
{
return $this->deleteCurrentData;
}
/**
* Loads data for the database from a YAML file
*
* @param string The path to the YAML file.
*/
protected function doLoadDataFromFile($fixture_file)
{
// import new datas
$data = sfYaml::load($fixture_file);
$this->loadDataFromArray($data);
}
/**
* Manages the insertion of data into the data source
*
* @param array The data to be inserted into the data source
*/
abstract public function loadDataFromArray($data);
/**
* Manages reading all of the fixture data files and
* loading them into the data source
*
* @param array The path names of the YAML data files
*/
protected function doLoadData($fixture_files)
{
$this->object_references = array();
$this->maps = array();
sort($fixture_files);
foreach ($fixture_files as $fixture_file)
{
$this->doLoadDataFromFile($fixture_file);
}
}
/**
* Gets a list of one or more *.yml files and returns the list in an array
*
* @param string A directory or file name; if null, then defaults to 'sf_data_dir'/fixtures
*
* @returns array A list of *.yml files.
*
* @throws sfInitializationException If the directory or file does not exist.
*/
protected function getFiles($directory_or_file = null)
{
// directory or file?
$fixture_files = array();
if (!$directory_or_file)
{
$directory_or_file = sfConfig::get('sf_data_dir').'/fixtures';
}
if (is_file($directory_or_file))
{
$fixture_files[] = $directory_or_file;
}
else if (is_dir($directory_or_file))
{
$fixture_files = sfFinder::type('file')->name('*.yml')->in($directory_or_file);
}
else
{
throw new sfInitializationException('You must give a directory or a file.');
}
return $fixture_files;
}
}

View File

@ -0,0 +1,406 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
*
* sfMail class.
*
* @package symfony
* @subpackage addon
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfMail.class.php 3172 2007-01-05 16:03:15Z fabien $
*/
class sfMail
{
protected $mailer;
public function __construct()
{
require_once(sfConfig::get('sf_symfony_lib_dir').'/vendor/phpmailer/class.phpmailer.php');
require_once(sfConfig::get('sf_symfony_lib_dir').'/vendor/phpmailer/class.smtp.php');
$this->mailer = new PHPMailer();
}
public function initialize()
{
}
public function setCharset($charset)
{
$this->mailer->CharSet = $charset;
}
public function getCharset()
{
return $this->mailer->CharSet;
}
public function setContentType($content_type)
{
$this->mailer->ContentType = $content_type;
}
public function getContentType()
{
return $this->mailer->ContentType;
}
public function setPriority($priority)
{
$this->mailer->Priority = $priority;
}
public function getPriority()
{
return $this->mailer->Priority;
}
public function setEncoding($encoding)
{
$this->mailer->Encoding = $encoding;
}
public function getEncoding()
{
return $this->mailer->Encoding;
}
public function setSubject($subject)
{
$this->mailer->Subject = $subject;
}
public function getSubject()
{
return $this->mailer->Subject;
}
public function setBody($body)
{
$this->mailer->Body = $body;
}
public function getBody()
{
return $this->mailer->Body;
}
public function setMailer($type = 'mail', $options = array())
{
switch ($type)
{
case 'smtp':
$this->mailer->IsSMTP();
if (isset($options['keep_alive'])) $this->mailer->SMTPKeepAlive = true;
break;
case 'sendmail':
$this->mailer->IsSendmail();
break;
default:
$this->mailer->IsMail();
break;
}
}
public function getMailer()
{
return $this->mailer->Mailer;
}
public function setSender($address, $name = null)
{
if (!$address)
{
return;
}
if ($name == null)
{
list($address, $name) = $this->splitAddress($address);
}
$this->mailer->Sender = $address;
}
public function getSender()
{
return $this->mailer->Sender;
}
public function setFrom($address, $name = null)
{
if (!$address)
{
return;
}
if ($name == null)
{
list($address, $name) = $this->splitAddress($address);
}
$this->mailer->From = $address;
$this->mailer->FromName = $name;
}
public function getFrom()
{
return $this->mailer->From;
}
/*
* $recipents:
* test@example.com
* Example email <test@example.com>
* array('test@example.com', 'test1@example.com')
* array('Example email <test@example.com>', 'test1@example.com')
*/
public function addAddresses($addresses)
{
if (!$addresses)
{
return;
}
if (is_array($addresses))
{
foreach ($addresses as $address)
{
list($address, $name) = $this->splitAddress($address);
$this->mailer->AddAddress($address, $name);
}
}
else
{
list($address, $name) = $this->splitAddress($addresses);
$this->mailer->AddAddress($address, $name);
}
}
private function splitAddress($address)
{
if (preg_match('/^(.+)\s<(.+?)>$/', $address, $matches))
{
return array($matches[2], $matches[1]);
}
else
{
return array($address, '');
}
}
public function addAddress($address, $name = null)
{
if ($name == null)
{
list($address, $name) = $this->splitAddress($address);
}
$this->mailer->AddAddress($address, $name);
}
public function addCc($address, $name = null)
{
if ($name == null)
{
list($address, $name) = $this->splitAddress($address);
}
$this->mailer->AddCc($address, $name);
}
public function addBcc($address, $name = null)
{
if ($name == null)
{
list($address, $name) = $this->splitAddress($address);
}
$this->mailer->AddBcc($address, $name);
}
public function addReplyTo($address, $name = null)
{
if (!$address)
{
return;
}
if ($name == null)
{
list($address, $name) = $this->splitAddress($address);
}
$this->mailer->AddReplyTo($address, $name);
}
public function clearAddresses()
{
$this->mailer->ClearAddresses();
}
public function clearCcs()
{
$this->mailer->ClearCcs();
}
public function clearBccs()
{
$this->mailer->ClearBccs();
}
public function clearReplyTos()
{
$this->mailer->ClearReplyTos();
}
public function clearAllRecipients()
{
$this->mailer->ClearAllRecipients();
}
public function addAttachment($path, $name = '', $encoding = 'base64', $type = 'application/octet-stream')
{
$this->mailer->AddAttachment($path, $name, $encoding, $type);
}
public function addStringAttachment($string, $filename, $encoding = 'base64', $type = 'application/octet-stream')
{
$this->mailer->AddStringAttachment($string, $filename, $encoding, $type);
}
public function addEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = 'application/octet-stream')
{
$this->mailer->AddEmbeddedImage($path, $cid, $name, $encoding, $type);
}
public function setAttachments($attachments)
{
if ($attachments instanceof sfMailAttachments)
{
$this->mailer->setAttachments($attachments->getAttachments());
}
}
public function clearAttachments()
{
$this->mailer->ClearAttachments();
}
function addCustomHeader($name, $value)
{
$this->mailer->AddCustomHeader("$name: $value");
}
function clearCustomHeaders()
{
$this->mailer->ClearCustomHeaders();
}
public function prepare()
{
// Set whether the message is multipart/alternative
if (!empty($this->mailer->AltBody))
{
$this->mailer->ContentType = "multipart/alternative";
}
$this->mailer->SetMessageType();
}
public function send()
{
if (!$this->mailer->Send())
{
throw new sfException($this->mailer->ErrorInfo);
}
}
public function smtpClose()
{
$this->mailer->SmtpClose();
}
public function getRawHeader()
{
return $this->mailer->CreateHeader();
}
public function getRawBody()
{
return $this->mailer->CreateBody();
}
public function setDomain($hostname)
{
$this->mailer->Hostname = $hostname;
}
public function getDomain()
{
return $this->mailer->Hostname;
}
public function setHostname($hostname)
{
$this->mailer->Host = $hostname;
}
public function getHostname()
{
return $this->mailer->Host;
}
public function setPort($port)
{
$this->mailer->Port = $port;
}
public function getPort()
{
return $this->mailer->Port;
}
public function setUsername($username)
{
$this->mailer->Username = $username;
$this->mailer->SMTPAuth = $username ? true : false;
}
public function getUsername()
{
return $this->mailer->Username;
}
public function setPassword($password)
{
$this->mailer->Password = $password;
}
public function getPassword()
{
return $this->mailer->Password;
}
public function setWordWrap($wordWrap)
{
$this->mailer->WordWrap = $wordWrap;
}
public function getWordWrap()
{
return $this->mailer->WordWrap;
}
public function setAltBody($text)
{
$this->mailer->AltBody = $text;
}
public function getAltBody()
{
return $this->mailer->AltBody;
}
}

View File

@ -0,0 +1,307 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* @package symfony
* @subpackage addon
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfPager.class.php 3099 2006-12-20 08:16:15Z fabien $
*/
/**
*
* sfPager class.
*
* @package symfony
* @subpackage addon
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfPager.class.php 3099 2006-12-20 08:16:15Z fabien $
*/
abstract class sfPager
{
protected
$page = 1,
$maxPerPage = 0,
$lastPage = 1,
$nbResults = 0,
$class = '',
$tableName = '',
$objects = null,
$cursor = 1,
$parameters = array(),
$currentMaxLink = 1,
$parameterHolder = null,
$maxRecordLimit = false;
public function __construct($class, $maxPerPage = 10)
{
$this->setClass($class);
$this->setMaxPerPage($maxPerPage);
$this->setPage(1);
$this->parameterHolder = new sfParameterHolder();
}
// function to be called after parameters have been set
abstract public function init();
// main method: returns an array of result on the given page
abstract public function getResults();
// used internally by getCurrent()
abstract protected function retrieveObject($offset);
public function getCurrentMaxLink()
{
return $this->currentMaxLink;
}
public function getMaxRecordLimit()
{
return $this->maxRecordLimit;
}
public function setMaxRecordLimit($limit)
{
$this->maxRecordLimit = $limit;
}
public function getLinks($nb_links = 5)
{
$links = array();
$tmp = $this->page - floor($nb_links / 2);
$check = $this->lastPage - $nb_links + 1;
$limit = ($check > 0) ? $check : 1;
$begin = ($tmp > 0) ? (($tmp > $limit) ? $limit : $tmp) : 1;
$i = $begin;
while (($i < $begin + $nb_links) && ($i <= $this->lastPage))
{
$links[] = $i++;
}
$this->currentMaxLink = $links[count($links) - 1];
return $links;
}
public function haveToPaginate()
{
return (($this->getPage() != 0) && ($this->getNbResults() > $this->getMaxPerPage()));
}
public function getCursor()
{
return $this->cursor;
}
public function setCursor($pos)
{
if ($pos < 1)
{
$this->cursor = 1;
}
else if ($pos > $this->nbResults)
{
$this->cursor = $this->nbResults;
}
else
{
$this->cursor = $pos;
}
}
public function getObjectByCursor($pos)
{
$this->setCursor($pos);
return $this->getCurrent();
}
public function getCurrent()
{
return $this->retrieveObject($this->cursor);
}
public function getNext()
{
if (($this->cursor + 1) > $this->nbResults)
{
return null;
}
else
{
return $this->retrieveObject($this->cursor + 1);
}
}
public function getPrevious()
{
if (($this->cursor - 1) < 1)
{
return null;
}
else
{
return $this->retrieveObject($this->cursor - 1);
}
}
public function getFirstIndice()
{
if ($this->page == 0)
{
return 1;
}
else
{
return ($this->page - 1) * $this->maxPerPage + 1;
}
}
public function getLastIndice()
{
if ($this->page == 0)
{
return $this->nbResults;
}
else
{
if (($this->page * $this->maxPerPage) >= $this->nbResults)
{
return $this->nbResults;
}
else
{
return ($this->page * $this->maxPerPage);
}
}
}
public function getCriteria()
{
return $this->criteria;
}
public function setCriteria($c)
{
$this->criteria = $c;
}
public function getClass()
{
return $this->class;
}
public function setClass($class)
{
$this->class = $class;
}
public function getNbResults()
{
return $this->nbResults;
}
protected function setNbResults($nb)
{
$this->nbResults = $nb;
}
public function getFirstPage()
{
return 1;
}
public function getLastPage()
{
return $this->lastPage;
}
protected function setLastPage($page)
{
$this->lastPage = $page;
if ($this->getPage() > $page)
{
$this->setPage($page);
}
}
public function getPage()
{
return $this->page;
}
public function getNextPage()
{
return min($this->getPage() + 1, $this->getLastPage());
}
public function getPreviousPage()
{
return max($this->getPage() - 1, $this->getFirstPage());
}
public function setPage($page)
{
$page = intval($page);
$this->page = ($page <= 0) ? 1 : $page;
}
public function getMaxPerPage()
{
return $this->maxPerPage;
}
public function setMaxPerPage($max)
{
if ($max > 0)
{
$this->maxPerPage = $max;
if ($this->page == 0)
{
$this->page = 1;
}
}
else if ($max == 0)
{
$this->maxPerPage = 0;
$this->page = 0;
}
else
{
$this->maxPerPage = 1;
if ($this->page == 0)
{
$this->page = 1;
}
}
}
public function getParameterHolder()
{
return $this->parameterHolder;
}
public function getParameter($name, $default = null, $ns = null)
{
return $this->parameterHolder->get($name, $default, $ns);
}
public function hasParameter($name, $ns = null)
{
return $this->parameterHolder->has($name, $ns);
}
public function setParameter($name, $value, $ns = null)
{
return $this->parameterHolder->set($name, $value, $ns);
}
}

118
lib/symfony/cache/sfCache.class.php vendored Executable file
View File

@ -0,0 +1,118 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfCache is an abstract class for all cache classes in symfony.
*
* @package symfony
* @subpackage cache
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Fabien Marty <fab@php.net>
* @version SVN: $Id: sfCache.class.php 3198 2007-01-08 20:36:20Z fabien $
*/
abstract class sfCache
{
/**
* Cache lifetime (in seconds)
*
* @var int $lifeTime
*/
protected $lifeTime = 86400;
/**
* Timestamp of the last valid cache
*
* @var int $refreshTime
*/
protected $refreshTime;
/**
* Gets the cache content for a given id and namespace.
*
* @param string The cache id
* @param string The name of the cache namespace
* @param boolean If set to true, the cache validity won't be tested
*
* @return string The data of the cache (or null if no cache available)
*/
abstract public function get($id, $namespace = self::DEFAULT_NAMESPACE, $doNotTestCacheValidity = false);
/**
* Returns true if there is a cache for the given id and namespace.
*
* @param string The cache id
* @param string The name of the cache namespace
* @param boolean If set to true, the cache validity won't be tested
*
* @return boolean true if the cache exists, false otherwise
*/
abstract public function has($id, $namespace = self::DEFAULT_NAMESPACE, $doNotTestCacheValidity = false);
/**
* Saves some data in the cache.
*
* @param string The cache id
* @param string The name of the cache namespace
* @param string The data to put in cache
*
* @return boolean true if no problem
*/
abstract public function set($id, $namespace = self::DEFAULT_NAMESPACE, $data);
/**
* Removes a content from the cache.
*
* @param string The cache id
* @param string The name of the cache namespace
*
* @return boolean true if no problem
*/
abstract public function remove($id, $namespace = self::DEFAULT_NAMESPACE);
/**
* Cleans the cache.
*
* If no namespace is specified all cache content will be destroyed
* else only cache contents of the specified namespace will be destroyed.
*
* @param string The name of the cache namespace
*
* @return boolean true if no problem
*/
abstract public function clean($namespace = null, $mode = 'all');
/**
* Sets a new life time.
*
* @param int The new life time (in seconds)
*/
public function setLifeTime($newLifeTime)
{
$this->lifeTime = $newLifeTime;
$this->refreshTime = time() - $newLifeTime;
}
/**
* Returns the current life time.
*
* @return int The current life time (in seconds)
*/
public function getLifeTime()
{
return $this->lifeTime;
}
/**
* Returns the cache last modification time.
*
* @return int The last modification time
*/
abstract public function lastModified($id, $namespace = self::DEFAULT_NAMESPACE);
}

601
lib/symfony/cache/sfFileCache.class.php vendored Executable file
View File

@ -0,0 +1,601 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Cache class that stores content in files.
*
* This class is based on the PEAR_Cache_Lite class.
* All cache files are stored in files in the [sf_root_dir].'/cache/'.[sf_app].'/template' directory.
* To disable all caching, you can set to false [sf_cache] setting.
*
* @package symfony
* @subpackage cache
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Fabien Marty <fab@php.net>
* @version SVN: $Id: sfFileCache.class.php 5308 2007-09-29 06:51:43Z fabien $
*/
class sfFileCache extends sfCache
{
const DEFAULT_NAMESPACE = '';
/**
* Directory where to put the cache files
*/
protected $cacheDir = '';
/**
* Enable / disable fileLocking (can avoid cache corruption under bad circumstances)
* @var boolean $fileLocking
*/
protected $fileLocking = true;
/**
* Enable / disable write control (the cache is read just after writing to detect corrupt entries)
*
* Enable write control will lightly slow the cache writing but not the cache reading
* Write control can detect some corrupt cache files but maybe it's not a perfect control
*/
protected $writeControl = false;
/**
* Enable / disable read control
*
* If enabled, a control key is embeded in cache file and this key is compared with the one calculated after the reading.
*/
protected $readControl = false;
/**
* File Name protection
*
* if set to true, you can use any cache id or namespace name
* if set to false, it can be faster but cache ids and namespace names
* will be used directly in cache file names so be carefull with
* special characters...
*/
protected $fileNameProtection = false;
/**
* Disable / Tune the automatic cleaning process
*
* The automatic cleaning process destroy too old (for the given life time)
* cache files when a new cache file is written.
* 0 => no automatic cache cleaning
* 1 => systematic cache cleaning
* x (integer) > 1 => automatic cleaning randomly 1 times on x cache write
*/
protected $automaticCleaningFactor = 500;
/**
* Nested directory level
*/
protected $hashedDirectoryLevel = 0;
/**
* Cache suffix
*/
protected
$suffix = '.cache';
/**
* Constructor.
*
* @param string The cache root directory
*/
public function __construct($cacheDir = null)
{
$this->setCacheDir($cacheDir);
}
/**
* Initializes the cache.
*
* @param array An array of options
* Available options:
* - cacheDir: cache root directory
* - fileLocking: enable / disable file locking (boolean)
* - writeControl: enable / disable write control (boolean)
* - readControl: enable / disable read control (boolean)
* - fileNameProtection: enable / disable automatic file name protection (boolean)
* - automaticCleaningFactor: disable / tune automatic cleaning process (int)
* - hashedDirectoryLevel: level of the hashed directory system (int)
* - lifeTime: default life time
*
*/
public function initialize($options = array())
{
if (isset($options['cacheDir']))
{
$this->setCacheDir($options['cacheDir']);
unset($options['cacheDir']);
}
$availableOptions = array('fileLocking', 'writeControl', 'readControl', 'fileNameProtection', 'automaticCleaningFactor', 'hashedDirectoryLevel', 'lifeTime');
foreach ($options as $key => $value)
{
if (!in_array($key, $availableOptions) && sfConfig::get('sf_logging_enabled'))
{
sfLogger::getInstance()->err(sprintf('sfFileCache cannot take "%s" as an option', $key));
}
$this->$key = $value;
}
}
/**
* Sets the suffix for cache files.
*
* @param string The suffix name (with the leading .)
*/
public function setSuffix($suffix)
{
$this->suffix = $suffix;
}
/**
* Enables / disables write control.
*
* @param boolean
*/
public function setWriteControl($boolean)
{
$this->writeControl = $boolean;
}
/**
* Gets the value of the writeControl option.
*
* @return boolean
*/
public function getWriteControl()
{
return $this->writeControl;
}
/**
* Enables / disables file locking.
*
* @param boolean
*/
public function setFileLocking($boolean)
{
$this->fileLocking = $boolean;
}
/**
* Gets the value of the fileLocking option.
*
* @return boolean
*/
public function getFileLocking()
{
return $this->fileLocking;
}
/**
* Sets the cache root directory.
*
* @param string The directory where to put the cache files
*/
public function setCacheDir($cacheDir)
{
// remove last DIRECTORY_SEPARATOR
if (DIRECTORY_SEPARATOR == substr($cacheDir, -1))
{
$cacheDir = substr($cacheDir, 0, -1);
}
// create cache dir if needed
if (!is_dir($cacheDir))
{
$current_umask = umask(0000);
@mkdir($cacheDir, 0777, true);
umask($current_umask);
}
$this->cacheDir = $cacheDir;
}
public function getCacheDir()
{
return $this->cacheDir;
}
/**
* Tests if a cache is available and (if yes) returns it.
*
* @param string The cache id
* @param string The name of the cache namespace
* @param boolean If set to true, the cache validity won't be tested
*
* @return string Data of the cache (or null if no cache available)
*
* @see sfCache
*/
public function get($id, $namespace = self::DEFAULT_NAMESPACE, $doNotTestCacheValidity = false)
{
$data = null;
list($path, $file) = $this->getFileName($id, $namespace);
if ($doNotTestCacheValidity)
{
if (file_exists($path.$file))
{
$data = $this->read($path, $file);
}
}
else
{
if ((file_exists($path.$file)) && (@filemtime($path.$file) > $this->refreshTime))
{
$data = $this->read($path, $file);
}
}
return $data ? $data : null;
}
/**
* Returns true if there is a cache for the given id and namespace.
*
* @param string The cache id
* @param string The name of the cache namespace
* @param boolean If set to true, the cache validity won't be tested
*
* @return boolean true if the cache exists, false otherwise
*
* @see sfCache
*/
public function has($id, $namespace = self::DEFAULT_NAMESPACE, $doNotTestCacheValidity = false)
{
list($path, $file) = $this->getFileName($id, $namespace);
if ($doNotTestCacheValidity)
{
if (file_exists($path.$file))
{
return true;
}
}
else
{
if ((file_exists($path.$file)) && (@filemtime($path.$file) > $this->refreshTime))
{
return true;
}
}
return false;
}
/**
* Saves some data in a cache file.
*
* @param string The cache id
* @param string The name of the cache namespace
* @param string The data to put in cache
*
* @return boolean true if no problem
*
* @see sfCache
*/
public function set($id, $namespace = self::DEFAULT_NAMESPACE, $data)
{
list($path, $file) = $this->getFileName($id, $namespace);
if ($this->automaticCleaningFactor > 0)
{
$rand = rand(1, $this->automaticCleaningFactor);
if ($rand == 1)
{
$this->clean(false, 'old');
}
}
if ($this->writeControl)
{
return $this->writeAndControl($path, $file, $data);
}
else
{
return $this->write($path, $file, $data);
}
}
/**
* Removes a cache file.
*
* @param string The cache id
* @param string The name of the cache namespace
*
* @return boolean true if no problem
*/
public function remove($id, $namespace = self::DEFAULT_NAMESPACE)
{
list($path, $file) = $this->getFileName($id, $namespace);
return $this->unlink($path.$file);
}
/**
* Cleans the cache.
*
* If no namespace is specified all cache files will be destroyed
* else only cache files of the specified namespace will be destroyed.
*
* @param string The name of the cache namespace
*
* @return boolean true if no problem
*/
public function clean($namespace = null, $mode = 'all')
{
$namespace = str_replace('/', DIRECTORY_SEPARATOR, $namespace);
$dir = $this->cacheDir.DIRECTORY_SEPARATOR.$namespace;
if (!file_exists($dir))
{
return true;
}
return $this->cleanDir($dir, $mode);
}
/**
* Returns the cache last modification time.
*
* @return int The last modification time
*/
public function lastModified($id, $namespace = self::DEFAULT_NAMESPACE)
{
list($path, $file) = $this->getFileName($id, $namespace);
return (file_exists($path.$file) ? filemtime($path.$file) : 0);
}
/**
* Makes a file name (with path).
*
* @param string The cache id
* @param string The name of the namespace
*
* @return array An array containing the path and the file name
*/
protected function getFileName($id, $namespace)
{
$file = ($this->fileNameProtection) ? md5($id).$this->suffix : $id.$this->suffix;
if ($namespace)
{
$namespace = str_replace('/', DIRECTORY_SEPARATOR, $namespace);
$path = $this->cacheDir.DIRECTORY_SEPARATOR.$namespace.DIRECTORY_SEPARATOR;
}
else
{
$path = $this->cacheDir.DIRECTORY_SEPARATOR;
}
if ($this->hashedDirectoryLevel > 0)
{
$hash = md5($file);
for ($i = 0; $i < $this->hashedDirectoryLevel; $i++)
{
$path = $path.substr($hash, 0, $i + 1).DIRECTORY_SEPARATOR;
}
}
return array($path, $file);
}
/**
* Removes a file.
*
* @param string The complete file path and name
*
* @return boolean true if no problem
*/
protected function unlink($file)
{
return @unlink($file) ? true : false;
}
/**
* Recursive function for cleaning cache file in the given directory.
*
* @param string The directory complete path
* @param string The name of the cache namespace
* @param string The flush cache mode : 'old', 'all'
*
* @return boolean true if no problem
*
* @throws sfCacheException
*/
protected function cleanDir($dir, $mode)
{
if (!($dh = opendir($dir)))
{
throw new sfCacheException('Unable to open cache directory "'.$dir.'"');
}
$result = true;
while ($file = readdir($dh))
{
if (($file != '.') && ($file != '..'))
{
$file2 = $dir.DIRECTORY_SEPARATOR.$file;
if (is_file($file2))
{
$unlink = 1;
if ($mode == 'old')
{
// files older than lifeTime get deleted from cache
if ((time() - filemtime($file2)) < $this->lifeTime)
{
$unlink = 0;
}
}
if ($unlink)
{
$result = ($result and ($this->unlink($file2)));
}
}
else if (is_dir($file2))
{
$result = ($result and ($this->cleanDir($file2.DIRECTORY_SEPARATOR, $mode)));
}
}
}
return $result;
}
/**
* Reads the cache file and returns the content.
*
* @param string The file path
* @param string The file name
*
* @return string The content of the cache file.
*
* @throws sfCacheException
*/
protected function read($path, $file)
{
$fp = @fopen($path.$file, "rb");
if ($this->fileLocking)
{
@flock($fp, LOCK_SH);
}
if ($fp)
{
clearstatcache(); // because the filesize can be cached by PHP itself...
$length = @filesize($path.$file);
$mqr = get_magic_quotes_runtime();
set_magic_quotes_runtime(0);
if ($this->readControl)
{
$hashControl = @fread($fp, 32);
$length = $length - 32;
}
$data = ($length) ? @fread($fp, $length) : '';
set_magic_quotes_runtime($mqr);
if ($this->fileLocking)
{
@flock($fp, LOCK_UN);
}
@fclose($fp);
if ($this->readControl)
{
$hashData = $this->hash($data);
if ($hashData != $hashControl)
{
@touch($path.$file, time() - 2 * abs($this->lifeTime));
return false;
}
}
return $data;
}
throw new sfCacheException('Unable to read cache file "'.$path.$file.'"');
}
/**
* Writes the given data in the cache file.
*
* @param string The file path
* @param string The file name
* @param string The data to put in cache
*
* @return boolean true if ok
*
* @throws sfCacheException
*/
protected function write($path, $file, $data)
{
$try = 1;
while ($try <= 2)
{
$fp = @fopen($path.$file, 'wb');
if ($fp)
{
if ($this->fileLocking)
{
@flock($fp, LOCK_EX);
}
if ($this->readControl)
{
@fwrite($fp, $this->hash($data), 32);
}
@fwrite($fp, $data);
if ($this->fileLocking)
{
@flock($fp, LOCK_UN);
}
@fclose($fp);
// change file mode
$current_umask = umask();
umask(0000);
chmod($path.$file, 0666);
umask($current_umask);
return true;
}
else
{
if ($try == 1 && !is_dir($path))
{
// create directory structure if needed
$current_umask = umask(0000);
mkdir($path, 0777, true);
umask($current_umask);
$try = 2;
}
else
{
$try = 999;
}
}
}
throw new sfCacheException('Unable to write cache file "'.$path.$file.'"');
}
/**
* Writes the given data in the cache file and controls it just after to avoid corrupted cache entries.
*
* @param string The file path
* @param string The file name
* @param string The data to put in cache
*
* @return boolean true if the test is ok
*/
protected function writeAndControl($path, $file, $data)
{
$this->write($path, $file, $data);
$dataRead = $this->read($path, $file);
return ($dataRead == $data);
}
/**
* Makes a control key with the string containing datas.
*
* @param string $data data
*
* @return string control key
*/
protected function hash($data)
{
return sprintf('% 32d', crc32($data));
}
}

102
lib/symfony/cache/sfFunctionCache.class.php vendored Executable file
View File

@ -0,0 +1,102 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* This class can be used to cache the result and output of functions/methods.
*
* This class is based on the PEAR_Cache_Lite class.
* All cache files are stored in files in the [sf_root_dir].'/cache/'.[sf_app].'/function' directory.
* To disable all caching, you can set to false [sf_cache] constant.
*
* @package symfony
* @subpackage cache
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Fabien Marty <fab@php.net>
* @version SVN: $Id: sfFunctionCache.class.php 3452 2007-02-14 15:03:08Z francois $
*/
class sfFunctionCache extends sfFileCache
{
/**
* Calls a cacheable function or method (or not if there is already a cache for it).
*
* Arguments of this method are read with func_get_args. So it doesn't appear in the function definition. Synopsis :
* call('functionName', $arg1, $arg2, ...)
* (arg1, arg2... are arguments of 'functionName')
*
* @return mixed The result of the function/method
*/
public function call()
{
$arguments = func_get_args();
// Generate a cache id
$id = md5(serialize($arguments));
$data = $this->get($id);
if ($data !== null)
{
$array = unserialize($data);
$output = $array['output'];
$result = $array['result'];
}
else
{
$target = array_shift($arguments);
ob_start();
ob_implicit_flush(false);
if (is_string($target) && strstr($target, '::'))
{
// classname::staticMethod
list($class, $method) = explode('::', $target);
try
{
$result = call_user_func_array(array($class, $method), $arguments);
}
catch (Exception $e)
{
ob_end_clean();
throw $e;
}
}
else if (is_string($target) && strstr($target, '->'))
{
// object->method
// use a stupid name ($objet_123456789 because) of problems when the object
// name is the same as this var name
list($object_123456789, $method) = explode('->', $target);
global $$object_123456789;
try
{
$result = call_user_func_array(array($$object_123456789, $method), $arguments);
}
catch (Exception $e)
{
ob_end_clean();
throw $e;
}
}
else
{
// function
$result = call_user_func_array($target, $arguments);
}
$output = ob_get_contents();
ob_end_clean();
$array['output'] = $output;
$array['result'] = $result;
$this->set($id, '', serialize($array));
}
echo($output);
return $result;
}
}

171
lib/symfony/cache/sfProcessCache.class.php vendored Executable file
View File

@ -0,0 +1,171 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfProcessCache stores content in memory if you run a PHP accelerator.
*
* Current PHP accelerator supported: APC, XCache and Eaccelerator.
*
* @package symfony
* @subpackage cache
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id$
*/
class sfProcessCache
{
/**
* Gets the cache engine name or false if no PHP accelerator is enabled.
*
* @return string The cache engine name
*/
public static function cacher()
{
static $cacher = null;
if (null === $cacher)
{
if (!sfConfig::get('sf_use_process_cache'))
{
$cacher = false;
}
elseif (function_exists('apc_store'))
{
$cacher = 'apc';
}
elseif (function_exists('xcache_set'))
{
$cacher = 'xcache';
}
elseif (function_exists('ecacher_put'))
{
$cacher = 'eaccelerator';
}
else
{
$cacher = false;
}
}
return $cacher;
}
/**
* Gets the prefix to use for all key name.
*
* @return string The prefix string
*/
public static function getPrefix()
{
static $prefix = null;
if (!$prefix)
{
$prefix = md5(sfConfig::get('sf_app_dir')).'_';
}
return $prefix;
}
/**
* Sets a value in the cache for the specified key.
*
* @param string The key name
* @param string The content to put in cache
* @param int The life time to keep the content in the cache
*
* @return boolean true if ok
*/
public static function set($key, $value, $lifeTime = 0)
{
switch (self::cacher())
{
case 'apc':
return apc_store(self::getPrefix().$key, $value, $lifeTime);
case 'xcache':
return xcache_set(self::getPrefix().$key, $value, $lifeTime);
case 'eaccelerator':
return eaccelerator_put(self::getPrefix().$key, serialize($value), $lifeTime);
}
return false;
}
/**
* Gets a value in the cache for the specified key.
*
* @param string The key name
*
* @return mixed The content associated with the key or null if the key does not exist
*/
public static function get($key)
{
switch (self::cacher())
{
case 'apc':
$value = apc_fetch(self::getPrefix().$key);
return false === $value ? null : $value;
case 'xcache':
return xcache_isset(self::getPrefix().$key) ? xcache_get(self::getPrefix().$key) : null;
case 'eaccelerator':
return unserialize(eaccelerator_get(self::getPrefix().$key));
}
return null;
}
/**
* Returns true if a given key exists in the cache, false otherwise.
*
* @param string The key name
*
* @return boolean true if the key exists, false otherwise
*/
public static function has($key)
{
switch (self::cacher())
{
case 'apc':
return false === apc_fetch(self::getPrefix().$key) ? false : true;
case 'xcache':
return xcache_isset(self::getPrefix().$key);
case 'eaccelerator':
return null === eaccelerator_get(self::getPrefix().$key) ? false : true;
}
return false;
}
/**
* Clears the cache.
*
* @return boolean true if ok, false otherwise
*/
public static function clear()
{
switch (self::cacher())
{
case 'apc':
return apc_clear_cache('user');
case 'xcache':
for ($i = 0, $max = xcache_count(XC_TYPE_VAR); $i < $max; $i++)
{
if (!xcache_clear_cache(XC_TYPE_VAR, $i))
{
return false;
}
}
return true;
case 'eaccelerator':
eaccelerator_clean();
}
return false;
}
}

317
lib/symfony/cache/sfSQLiteCache.class.php vendored Executable file
View File

@ -0,0 +1,317 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Cache class that stores content in a sqlite database.
*
* @package symfony
* @subpackage cache
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfSQLiteCache.class.php 3935 2007-05-06 10:07:08Z fabien $
*/
class sfSQLiteCache extends sfCache
{
const DEFAULT_NAMESPACE = '';
protected $conn = null;
/**
* File where to put the cache database (or :memory: to store cache in memory)
*/
protected $database = '';
/**
* Disable / Tune the automatic cleaning process
*
* The automatic cleaning process destroy too old (for the given life time)
* cache files when a new cache file is written.
* 0 => no automatic cache cleaning
* 1 => systematic cache cleaning
* x (integer) > 1 => automatic cleaning randomly 1 times on x cache write
*/
protected $automaticCleaningFactor = 500;
/**
* Constructor.
*
* @param string The database name
*/
public function __construct($database = null)
{
if (!extension_loaded('sqlite'))
{
throw new sfConfigurationException('sfSQLiteCache class needs "sqlite" extension');
}
$this->setDatabase($database);
}
/**
* Initializes the cache.
*
* @param array An array of options
* Available options:
* - database: database name
* - automaticCleaningFactor: disable / tune automatic cleaning process (int)
*
*/
public function initialize($options = array())
{
if (isset($options['database']))
{
$this->setDatabase($options['database']);
unset($options['database']);
}
$availableOptions = array('automaticCleaningFactor');
foreach ($options as $key => $value)
{
if (!in_array($key, $availableOptions) && sfConfig::get('sf_logging_enabled'))
{
sfLogger::getInstance()->err(sprintf('sfSQLiteCache cannot take "%s" as an option', $key));
}
$this->$key = $value;
}
}
/**
* Sets the database name.
*
* @param string The database name where to store the cache
*/
public function setDatabase($database)
{
if (!$database)
{
return;
}
$this->database = $database;
$new = false;
if (':memory:' == $database)
{
$new = true;
}
elseif (!is_file($database))
{
$new = true;
// create cache dir if needed
$dir = dirname($database);
$current_umask = umask(0000);
if (!is_dir($dir))
{
@mkdir($dir, 0777, true);
}
touch($database);
umask($current_umask);
}
if (!($this->conn = @sqlite_open($this->database, 0644, $errmsg)))
{
throw new sfException(sprintf("Unable to connect to SQLite database: %s", $errmsg));
}
if ($new)
{
$this->createSchema();
}
}
/**
* Creates the database schema.
*
* @throws sfException
*/
protected function createSchema()
{
$statements = array(
"CREATE TABLE [cache] (
[id] VARCHAR(255),
[namespace] VARCHAR(255),
[data] LONGVARCHAR,
[created_at] TIMESTAMP
)",
"CREATE UNIQUE INDEX [cache_unique] ON [cache] ([namespace], [id])",
);
foreach ($statements as $statement)
{
if (!sqlite_query($statement, $this->conn))
{
throw new sfException(sqlite_error_string(sqlite_last_error($this->database)));
}
}
}
/**
* Destructor.
*/
public function __destruct()
{
sqlite_close($this->conn);
}
/**
* Gets the database name.
*
* @return string The database name
*/
public function getDatabase()
{
return $this->database;
}
/**
* Tests if a cache is available and (if yes) returns it.
*
* @param string The cache id
* @param string The name of the cache namespace
* @param boolean If set to true, the cache validity won't be tested
*
* @return string The data in the cache (or null if no cache available)
*
* @see sfCache
*/
public function get($id, $namespace = self::DEFAULT_NAMESPACE, $doNotTestCacheValidity = false)
{
$statement = sprintf("SELECT data FROM cache WHERE id = '%s' AND namespace = '%s'", sqlite_escape_string($id), sqlite_escape_string($namespace));
if (!$doNotTestCacheValidity)
{
$statement .= sprintf(" AND created_at > '%s'", sqlite_escape_string($this->refreshTime));
}
$rs = sqlite_query($statement, $this->conn);
return sqlite_num_rows($rs) ? sqlite_fetch_single($rs) : null;
}
/**
* Returns true if there is a cache for the given id and namespace.
*
* @param string The cache id
* @param string The name of the cache namespace
* @param boolean If set to true, the cache validity won't be tested
*
* @return boolean true if the cache exists, false otherwise
*
* @see sfCache
*/
public function has($id, $namespace = self::DEFAULT_NAMESPACE, $doNotTestCacheValidity = false)
{
$statement = sprintf("SELECT id FROM cache WHERE id = '%s' AND namespace = '%s'", sqlite_escape_string($id), sqlite_escape_string($namespace));
if (!$doNotTestCacheValidity)
{
$statement .= sprintf(" AND created_at > '%s'", sqlite_escape_string($this->refreshTime));
}
return sqlite_num_rows(sqlite_query($statement, $this->conn)) ? true : false;
}
/**
* Saves some data in the cache.
*
* @param string The cache id
* @param string The name of the cache namespace
* @param string The data to put in cache
*
* @return boolean true if no problem
*
* @see sfCache
*/
public function set($id, $namespace = self::DEFAULT_NAMESPACE, $data)
{
if ($this->automaticCleaningFactor > 0)
{
$rand = rand(1, $this->automaticCleaningFactor);
if ($rand == 1)
{
$this->clean(false, 'old');
}
}
if (!$this->has($id, $namespace, true))
{
$statement = sprintf("INSERT INTO cache (id, namespace, data, created_at) VALUES ('%s', '%s', '%s', %d)", sqlite_escape_string($id), sqlite_escape_string($namespace), sqlite_escape_string($data), time());
}
else
{
$statement = sprintf("UPDATE cache SET data = '%s', created_at = %s WHERE id = '%s' AND namespace = '%s'", sqlite_escape_string($data), time(), sqlite_escape_string($id), sqlite_escape_string($namespace));
}
if (sqlite_query($statement, $this->conn))
{
return true;
}
return false;
}
/**
* Removes an element from the cache.
*
* @param string The cache id
* @param string The name of the cache namespace
*
* @return boolean true if no problem
*
* @see sfCache
*/
public function remove($id, $namespace = self::DEFAULT_NAMESPACE)
{
$statement = sprintf("DELETE FROM cache WHERE id = '%s' AND namespace = '%s'", sqlite_escape_string($id), sqlite_escape_string($namespace));
if (sqlite_query($statement, $this->conn))
{
return true;
}
return false;
}
/**
* Cleans the cache.
*
* If no namespace is specified all cache files will be destroyed
* else only cache files of the specified namespace will be destroyed.
*
* @param string The name of the cache namespace
*
* @return boolean true if no problem
*/
public function clean($namespace = null, $mode = 'all')
{
if (!$namespace)
{
$statement = "DELETE FROM cache";
}
else
{
$statement = sprintf("DELETE FROM cache WHERE namespace LIKE '%s%%'", $namespace);
}
if ('old' == $mode)
{
$statement .= sprintf(" %s created_at < '%s'", $namespace ? 'AND' : 'WHERE', sqlite_escape_string($this->refreshTime));
}
return sqlite_num_rows(sqlite_query($statement, $this->conn)) ? true : false;
}
public function lastModified($id, $namespace = self::DEFAULT_NAMESPACE)
{
$statement = sprintf("SELECT created_at FROM cache WHERE id = '%s' AND namespace = '%s'", sqlite_escape_string($id), sqlite_escape_string($namespace));
$rs = sqlite_query($statement, $this->conn);
return sqlite_num_rows($rs) ? intval(sqlite_fetch_single($rs)) : 0;
}
}

View File

@ -0,0 +1,130 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
*
* @package symfony
* @subpackage config
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfAutoloadConfigHandler.class.php 3256 2007-01-13 08:39:10Z fabien $
*/
class sfAutoloadConfigHandler extends sfYamlConfigHandler
{
/**
* Executes this configuration handler.
*
* @param array An array of absolute filesystem path to a configuration file
*
* @return string Data to be written to a cache file
*
* @throws sfConfigurationException If a requested configuration file does not exist or is not readable
* @throws sfParseException If a requested configuration file is improperly formatted
*/
public function execute($configFiles)
{
// set our required categories list and initialize our handler
$categories = array('required_categories' => array('autoload'));
$this->initialize($categories);
// parse the yaml
$myConfig = $this->parseYamls($configFiles);
// init our data array
$data = array();
// let's do our fancy work
foreach ($myConfig['autoload'] as $name => $entry)
{
if (isset($entry['name']))
{
$data[] = sprintf("\n// %s", $entry['name']);
}
// file mapping or directory mapping?
if (isset($entry['files']))
{
// file mapping
foreach ($entry['files'] as $class => $path)
{
$path = $this->replaceConstants($path);
$data[] = sprintf("'%s' => '%s',", $class, $path);
}
}
else
{
// directory mapping
$ext = isset($entry['ext']) ? $entry['ext'] : '.php';
$path = $entry['path'];
$path = $this->replaceConstants($path);
$path = $this->replacePath($path);
// we automatically add our php classes
require_once(sfConfig::get('sf_symfony_lib_dir').'/util/sfFinder.class.php');
$finder = sfFinder::type('file')->ignore_version_control()->name('*'.$ext);
// recursive mapping?
$recursive = ((isset($entry['recursive'])) ? $entry['recursive'] : false);
if (!$recursive)
{
$finder->maxdepth(1);
}
// exclude files or directories?
if (isset($entry['exclude']) && is_array($entry['exclude']))
{
$finder->prune($entry['exclude'])->discard($entry['exclude']);
}
if ($matches = glob($path))
{
$files = $finder->in($matches);
}
else
{
$files = array();
}
$regex = '~^\s*(?:abstract\s+|final\s+)?(?:class|interface)\s+(\w+)~mi';
foreach ($files as $file)
{
preg_match_all($regex, file_get_contents($file), $classes);
foreach ($classes[1] as $class)
{
$prefix = '';
if (isset($entry['prefix']))
{
// FIXME: does not work for plugins installed with a symlink
preg_match('~^'.str_replace('\*', '(.+?)', preg_quote(str_replace('/', DIRECTORY_SEPARATOR, $path), '~')).'~', $file, $match);
if (isset($match[$entry['prefix']]))
{
$prefix = $match[$entry['prefix']].'/';
}
}
$data[] = sprintf("'%s%s' => '%s',", $prefix, $class, $file);
}
}
}
}
// compile data
$retval = sprintf("<?php\n".
"// auto-generated by sfAutoloadConfigHandler\n".
"// date: %s\nreturn array(\n%s\n);\n",
date('Y/m/d H:i:s'), implode("\n", $data));
return $retval;
}
}

View File

@ -0,0 +1,119 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfCacheConfigHandler allows you to configure cache.
*
* @package symfony
* @subpackage config
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfCacheConfigHandler.class.php 3203 2007-01-09 18:32:54Z fabien $
*/
class sfCacheConfigHandler extends sfYamlConfigHandler
{
protected
$cacheConfig = array();
/**
* Executes this configuration handler.
*
* @param array An array of absolute filesystem path to a configuration file
*
* @return string Data to be written to a cache file
*
* @throws <b>sfConfigurationException</b> If a requested configuration file does not exist or is not readable
* @throws <b>sfParseException</b> If a requested configuration file is improperly formatted
* @throws <b>sfInitializationException</b> If a cache.yml key check fails
*/
public function execute($configFiles)
{
// set our required categories list and initialize our handler
$categories = array('required_categories' => array());
$this->initialize($categories);
// parse the yaml
$myConfig = $this->parseYamls($configFiles);
$myConfig['all'] = sfToolkit::arrayDeepMerge(
isset($myConfig['default']) && is_array($myConfig['default']) ? $myConfig['default'] : array(),
isset($myConfig['all']) && is_array($myConfig['all']) ? $myConfig['all'] : array()
);
unset($myConfig['default']);
$this->yamlConfig = $myConfig;
// iterate through all action names
$data = array();
$first = true;
foreach ($this->yamlConfig as $actionName => $values)
{
if ($actionName == 'all')
{
continue;
}
$data[] = $this->addCache($actionName);
$first = false;
}
// general cache configuration
$data[] = $this->addCache('DEFAULT');
// compile data
$retval = sprintf("<?php\n".
"// auto-generated by sfCacheConfigHandler\n".
"// date: %s\n%s\n",
date('Y/m/d H:i:s'), implode('', $data));
return $retval;
}
/**
* Returns a single addCache statement.
*
* @param string The action name
*
* @return string PHP code for the addCache statement
*/
protected function addCache($actionName = '')
{
$data = array();
// enabled?
$enabled = $this->getConfigValue('enabled', $actionName);
// cache with or without loayout
$withLayout = $this->getConfigValue('with_layout', $actionName) ? 'true' : 'false';
// lifetime
$lifeTime = !$enabled ? '0' : $this->getConfigValue('lifetime', $actionName, '0');
// client_lifetime
$clientLifetime = !$enabled ? '0' : $this->getConfigValue('client_lifetime', $actionName, $lifeTime, '0');
// contextual
$contextual = $this->getConfigValue('contextual', $actionName) ? 'true' : 'false';
// vary
$vary = $this->getConfigValue('vary', $actionName, array());
if (!is_array($vary))
{
$vary = array($vary);
}
// add cache information to cache manager
$data[] = sprintf("\$this->addCache(\$moduleName, '%s', array('withLayout' => %s, 'lifeTime' => %s, 'clientLifeTime' => %s, 'contextual' => %s, 'vary' => %s));\n",
$actionName, $withLayout, $lifeTime, $clientLifetime, $contextual, str_replace("\n", '', var_export($vary, true)));
return implode("\n", $data);
}
}

View File

@ -0,0 +1,113 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfCompileConfigHandler gathers multiple files and puts them into a single file.
* Upon creation of the new file, all comments and blank lines are removed.
*
* @package symfony
* @subpackage config
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfCompileConfigHandler.class.php 5061 2007-09-13 06:49:52Z fabien $
*/
class sfCompileConfigHandler extends sfYamlConfigHandler
{
/**
* Executes this configuration handler.
*
* @param array An array of absolute filesystem path to a configuration file
*
* @return string Data to be written to a cache file
*
* @throws sfConfigurationException If a requested configuration file does not exist or is not readable
* @throws sfParseException If a requested configuration file is improperly formatted
*/
public function execute($configFiles)
{
// parse the yaml
$config = array();
foreach ($configFiles as $configFile)
{
$config = array_merge($config, $this->parseYaml($configFile));
}
// init our data
$data = '';
// let's do our fancy work
foreach ($config as $file)
{
$file = $this->replaceConstants($file);
$file = $this->replacePath($file);
if (!is_readable($file))
{
// file doesn't exist
$error = sprintf('Configuration file "%s" specifies nonexistent or unreadable file "%s"', $configFiles[0], $file);
throw new sfParseException($error);
}
$contents = file_get_contents($file);
// strip comments (not in debug mode)
if (!sfConfig::get('sf_debug'))
{
$contents = sfToolkit::stripComments($contents);
}
// insert configuration files
$contents = preg_replace_callback(array('#(require|include)(_once)?\((sfConfigCache::getInstance\(\)|\$configCache)->checkConfig\([^_]+sf_app_config_dir_name[^\.]*\.\'/([^\']+)\'\)\);#m',
'#()()(sfConfigCache::getInstance\(\)|\$configCache)->import\(.sf_app_config_dir_name\.\'/([^\']+)\'(, false)?\);#m'),
array($this, 'insertConfigFileCallback'), $contents);
// strip php tags
$contents = sfToolkit::pregtr($contents, array('/^\s*<\?(php)?/m' => '',
'/^\s*\?>/m' => ''));
// replace windows and mac format with unix format
$contents = str_replace("\r", "\n", $contents);
// replace multiple new lines with a single newline
$contents = preg_replace(array('/\s+$/Sm', '/\n+/S'), "\n", $contents);
// append file data
$data .= "\n".$contents;
}
// compile data
$retval = sprintf("<?php\n".
"// auto-generated by sfCompileConfigHandler\n".
"// date: %s\n%s\n",
date('Y/m/d H:i:s'), $data);
// save current symfony release
file_put_contents(sfConfig::get('sf_config_cache_dir').'/VERSION', file_get_contents(sfConfig::get('sf_symfony_lib_dir').'/VERSION'));
return $retval;
}
/**
* Callback for configuration file insertion in the cache.
*
*/
protected function insertConfigFileCallback($matches)
{
$configFile = sfConfig::get('sf_app_config_dir_name').'/'.$matches[4];
sfConfigCache::getInstance()->checkConfig($configFile);
$config = "// '$configFile' config file\n".
file_get_contents(sfConfigCache::getInstance()->getCacheName($configFile));
return $config;
}
}

View File

@ -0,0 +1,93 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfConfig stores all configuration information for a symfony application.
*
* @package symfony
* @subpackage config
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfConfig.class.php 3203 2007-01-09 18:32:54Z fabien $
*/
class sfConfig
{
protected static
$config = array();
/**
* Retrieves a config parameter.
*
* @param string A config parameter name
* @param mixed A default config parameter value
*
* @return mixed A config parameter value, if the config parameter exists, otherwise null
*/
public static function get($name, $default = null)
{
return isset(self::$config[$name]) ? self::$config[$name] : $default;
}
/**
* Indicates whether or not a config parameter exists.
*
* @param string A config parameter name
*
* @return bool true, if the config parameter exists, otherwise false
*/
public static function has($name)
{
return array_key_exists($name, self::$config);
}
/**
* Sets a config parameter.
*
* If a config parameter with the name already exists the value will be overridden.
*
* @param string A config parameter name
* @param mixed A config parameter value
*/
public static function set($name, $value)
{
self::$config[$name] = $value;
}
/**
* Sets an array of config parameters.
*
* If an existing config parameter name matches any of the keys in the supplied
* array, the associated value will be overridden.
*
* @param array An associative array of config parameters and their associated values
*/
public static function add($parameters = array())
{
self::$config = array_merge(self::$config, $parameters);
}
/**
* Retrieves all configuration parameters.
*
* @return array An associative array of configuration parameters.
*/
public static function getAll()
{
return self::$config;
}
/**
* Clears all current config parameters.
*/
public static function clear()
{
self::$config = null;
self::$config = array();
}
}

View File

@ -0,0 +1,342 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfConfigCache allows you to customize the format of a configuration file to
* make it easy-to-use, yet still provide a PHP formatted result for direct
* inclusion into your modules.
*
* @package symfony
* @subpackage config
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfConfigCache.class.php 3503 2007-02-18 19:08:26Z fabien $
*/
class sfConfigCache
{
protected
$handlers = array();
protected static
$instance = null;
/**
* Retrieves the singleton instance of this class.
*
* @return sfConfigCache A sfConfigCache instance
*/
public static function getInstance()
{
if (!self::$instance)
{
self::$instance = new sfConfigCache();
}
return self::$instance;
}
/**
* Loads a configuration handler.
*
* @param string The handler to use when parsing a configuration file
* @param array An array of absolute filesystem paths to configuration files
* @param string An absolute filesystem path to the cache file that will be written
*
* @throws <b>sfConfigurationException</b> If a requested configuration file does not have an associated configuration handler
*/
protected function callHandler($handler, $configs, $cache)
{
if (count($this->handlers) == 0)
{
// we need to load the handlers first
$this->loadConfigHandlers();
}
// handler to call for this configuration file
$handlerToCall = null;
$handler = str_replace(DIRECTORY_SEPARATOR, '/', $handler);
// grab the base name of the handler
$basename = basename($handler);
if (isset($this->handlers[$handler]))
{
// we have a handler associated with the full configuration path
$handlerToCall = $this->handlers[$handler];
}
else if (isset($this->handlers[$basename]))
{
// we have a handler associated with the configuration base name
$handlerToCall = $this->handlers[$basename];
}
else
{
// let's see if we have any wildcard handlers registered that match
// this basename
foreach ($this->handlers as $key => $handlerInstance)
{
// replace wildcard chars in the configuration
$pattern = strtr($key, array('.' => '\.', '*' => '.*?'));
// create pattern from config
if (preg_match('#'.$pattern.'#', $handler))
{
// we found a match!
$handlerToCall = $this->handlers[$key];
break;
}
}
}
if ($handlerToCall)
{
// call the handler and retrieve the cache data
$data = $handlerToCall->execute($configs);
$this->writeCacheFile($handler, $cache, $data);
}
else
{
// we do not have a registered handler for this file
$error = sprintf('Configuration file "%s" does not have a registered handler', implode(', ', $configs));
throw new sfConfigurationException($error);
}
}
/**
* Checks to see if a configuration file has been modified and if so
* recompile the cache file associated with it.
*
* The recompilation only occurs in a non debug environment.
*
* If the configuration file path is relative, symfony will look in directories
* defined in the sfLoader::getConfigPaths() method.
*
* @param string A filesystem path to a configuration file
*
* @return string An absolute filesystem path to the cache filename associated with this specified configuration file
*
* @throws <b>sfConfigurationException</b> If a requested configuration file does not exist
*
* @see sfLoader::getConfigPaths()
*/
public function checkConfig($configPath, $optional = false)
{
static $process_cache_cleared = false;
if (sfConfig::get('sf_debug') && sfConfig::get('sf_logging_enabled'))
{
$timer = sfTimerManager::getTimer('Configuration');
}
// the cache filename we'll be using
$cache = $this->getCacheName($configPath);
if (sfConfig::get('sf_in_bootstrap') && is_readable($cache))
{
if (sfConfig::get('sf_debug') && sfConfig::get('sf_logging_enabled'))
{
$timer->addTime();
}
return $cache;
}
if (!sfToolkit::isPathAbsolute($configPath))
{
$files = sfLoader::getConfigPaths($configPath);
}
else
{
$files = is_readable($configPath) ? array($configPath) : array();
}
if (!isset($files[0]))
{
if ($optional)
{
return null;
}
// configuration does not exist
$error = sprintf('Configuration "%s" does not exist or is unreadable', $configPath);
throw new sfConfigurationException($error);
}
// find the more recent configuration file last modification time
$mtime = 0;
foreach ($files as $file)
{
if (filemtime($file) > $mtime)
{
$mtime = filemtime($file);
}
}
if (!is_readable($cache) || $mtime > filemtime($cache))
{
// configuration has changed so we need to reparse it
$this->callHandler($configPath, $files, $cache);
// clear process cache
if ('config/config_handlers.yml' != $configPath && sfConfig::has('sf_use_process_cache') && !$process_cache_cleared)
{
sfProcessCache::clear();
$process_cache_cleared = true;
}
}
if (sfConfig::get('sf_debug') && sfConfig::get('sf_logging_enabled'))
{
$timer->addTime();
}
return $cache;
}
/**
* Clears all configuration cache files.
*/
public function clear()
{
sfToolkit::clearDirectory(sfConfig::get('sf_config_cache_dir'));
}
/**
* Converts a normal filename into a cache filename.
*
* @param string A normal filename
*
* @return string An absolute filesystem path to a cache filename
*/
public function getCacheName($config)
{
if (strlen($config) > 3 && ctype_alpha($config[0]) && $config[1] == ':' && ($config[2] == '\\' || $config[2] == '/'))
{
// file is a windows absolute path, strip off the drive letter
$config = substr($config, 3);
}
// replace unfriendly filename characters with an underscore
$config = str_replace(array('\\', '/', ' '), '_', $config);
$config .= '.php';
return sfConfig::get('sf_config_cache_dir').'/'.$config;
}
/**
* Imports a configuration file.
*
* @param string A filesystem path to a configuration file
* @param bool Only allow this configuration file to be included once per request?
*
* @see checkConfig()
*/
public function import($config, $once = true, $optional = false)
{
$cache = $this->checkConfig($config, $optional);
if ($optional && !$cache)
{
return;
}
// include cache file
if ($once)
{
include_once($cache);
}
else
{
include($cache);
}
}
/**
* Loads all configuration application and module level handlers.
*
* @throws <b>sfConfigurationException</b> If a configuration related error occurs.
*/
protected function loadConfigHandlers()
{
// manually create our config_handlers.yml handler
$this->handlers['config_handlers.yml'] = new sfRootConfigHandler();
$this->handlers['config_handlers.yml']->initialize();
// application configuration handlers
require_once($this->checkConfig(sfConfig::get('sf_app_config_dir_name').'/config_handlers.yml'));
// module level configuration handlers
// make sure our modules directory exists
if (is_readable($sf_app_module_dir = sfConfig::get('sf_app_module_dir')))
{
// ignore names
$ignore = array('.', '..', 'CVS', '.svn');
// create a file pointer to the module dir
$fp = opendir($sf_app_module_dir);
// loop through the directory and grab the modules
while (($directory = readdir($fp)) !== false)
{
if (!in_array($directory, $ignore))
{
$configPath = $sf_app_module_dir.'/'.$directory.'/'.sfConfig::get('sf_app_module_config_dir_name').'/config_handlers.yml';
if (is_readable($configPath))
{
// initialize the root configuration handler with this module name
$params = array('module_level' => true, 'module_name' => $directory);
$this->handlers['config_handlers.yml']->initialize($params);
// replace module dir path with a special keyword that
// checkConfig knows how to use
$configPath = sfConfig::get('sf_app_module_dir_name').'/'.$directory.'/'.sfConfig::get('sf_app_module_config_dir_name').'/config_handlers.yml';
require_once($this->checkConfig($configPath));
}
}
}
// close file pointer
fclose($fp);
}
else
{
// module directory doesn't exist or isn't readable
$error = sprintf('Module directory "%s" does not exist or is not readable',
sfConfig::get('sf_app_module_dir'));
throw new sfConfigurationException($error);
}
}
/**
* Writes a cache file.
*
* @param string An absolute filesystem path to a configuration file
* @param string An absolute filesystem path to the cache file that will be written
* @param string Data to be written to the cache file
*
* @throws sfCacheException If the cache file cannot be written
*/
protected function writeCacheFile($config, $cache, &$data)
{
$fileCache = new sfFileCache(dirname($cache));
$fileCache->setSuffix('');
$fileCache->set(basename($cache), '', $data);
}
}

View File

@ -0,0 +1,105 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfConfigHandler allows a developer to create a custom formatted configuration
* file pertaining to any information they like and still have it auto-generate
* PHP code.
*
* @package symfony
* @subpackage config
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfConfigHandler.class.php 3203 2007-01-09 18:32:54Z fabien $
*/
abstract class sfConfigHandler
{
protected
$parameterHolder = null;
/**
* Executes this configuration handler
*
* @param array An array of filesystem path to a configuration file
*
* @return string Data to be written to a cache file
*
* @throws <b>sfConfigurationException</b> If a requested configuration file does not exist or is not readable
* @throws <b>sfParseException</b> If a requested configuration file is improperly formatted
*/
abstract public function execute($configFiles);
/**
* Initializes this configuration handler.
*
* @param array An associative array of initialization parameters
*
* @return bool true, if initialization completes successfully, otherwise false
*
* @throws <b>sfInitializationException</b> If an error occurs while initializing this ConfigHandler
*/
public function initialize($parameters = null)
{
$this->parameterHolder = new sfParameterHolder();
$this->parameterHolder->add($parameters);
}
/**
* Replaces constant identifiers in a value.
*
* If the value is an array replacements are made recursively.
*
* @param mixed The value on which to run the replacement procedure
*
* @return string The new value
*/
public static function replaceConstants($value)
{
if (is_array($value))
{
array_walk_recursive($value, create_function('&$value', '$value = sfToolkit::replaceConstants($value);'));
}
else
{
$value = sfToolkit::replaceConstants($value);
}
return $value;
}
/**
* Replaces a relative filesystem path with an absolute one.
*
* @param string A relative filesystem path
*
* @return string The new path
*/
public static function replacePath($path)
{
if (!sfToolkit::isPathAbsolute($path))
{
// not an absolute path so we'll prepend to it
$path = sfConfig::get('sf_app_dir').'/'.$path;
}
return $path;
}
/**
* Gets the parameter holder for this configuration handler.
*
* @return sfParameterHolder A sfParameterHolder instance
*/
public function getParameterHolder()
{
return $this->parameterHolder;
}
}

View File

@ -0,0 +1,120 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfDatabaseConfigHandler allows you to setup database connections in a
* configuration file that will be created for you automatically upon first
* request.
*
* @package symfony
* @subpackage config
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfDatabaseConfigHandler.class.php 3254 2007-01-13 07:52:26Z fabien $
*/
class sfDatabaseConfigHandler extends sfYamlConfigHandler
{
/**
* Executes this configuration handler.
*
* @param array An array of absolute filesystem path to a configuration file
*
* @return string Data to be written to a cache file
*
* @throws sfConfigurationException If a requested configuration file does not exist or is not readable
* @throws sfParseException If a requested configuration file is improperly formatted
*/
public function execute($configFiles)
{
// parse the yaml
$myConfig = $this->parseYamls($configFiles);
$myConfig = sfToolkit::arrayDeepMerge(
isset($myConfig['default']) && is_array($myConfig['default']) ? $myConfig['default'] : array(),
isset($myConfig['all']) && is_array($myConfig['all']) ? $myConfig['all'] : array(),
isset($myConfig[sfConfig::get('sf_environment')]) && is_array($myConfig[sfConfig::get('sf_environment')]) ? $myConfig[sfConfig::get('sf_environment')] : array()
);
// init our data and includes arrays
$data = array();
$databases = array();
$includes = array();
// get a list of database connections
foreach ($myConfig as $key => $dbConfig)
{
// is this category already registered?
if (in_array($key, $databases))
{
// this category is already registered
$error = sprintf('Configuration file "%s" specifies previously registered category "%s"', $configFiles[0], $key);
throw new sfParseException($error);
}
// add this database
$databases[] = $key;
// let's do our fancy work
if (!isset($dbConfig['class']))
{
// missing class key
$error = sprintf('Configuration file "%s" specifies category "%s" with missing class key', $configFiles[0], $key);
throw new sfParseException($error);
}
if (isset($dbConfig['file']))
{
// we have a file to include
$file = $this->replaceConstants($dbConfig['file']);
$file = $this->replacePath($file);
if (!is_readable($file))
{
// database file doesn't exist
$error = sprintf('Configuration file "%s" specifies class "%s" with nonexistent or unreadable file "%s"', $configFiles[0], $dbConfig['class'], $file);
throw new sfParseException($error);
}
// append our data
$includes[] = sprintf("require_once('%s');", $file);
}
// parse parameters
if (isset($dbConfig['param']))
{
foreach ($dbConfig['param'] as &$value)
{
$value = $this->replaceConstants($value);
}
$parameters = var_export($dbConfig['param'], true);
}
else
{
$parameters = 'null';
}
// append new data
$data[] = sprintf("\n\$database = new %s();\n".
"\$database->initialize(%s, '%s');\n".
"\$this->databases['%s'] = \$database;",
$dbConfig['class'], $parameters, $key, $key);
}
// compile data
$retval = sprintf("<?php\n".
"// auto-generated by sfDatabaseConfigHandler\n".
"// date: %s%s\n%s\n",
date('Y/m/d H:i:s'), implode("\n", $includes), implode("\n", $data));
return $retval;
}
}

View File

@ -0,0 +1,159 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
*
* @package symfony
* @subpackage config
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfDefineEnvironmentConfigHandler.class.php 3254 2007-01-13 07:52:26Z fabien $
*/
class sfDefineEnvironmentConfigHandler extends sfYamlConfigHandler
{
/**
* Executes this configuration handler.
*
* @param string An absolute filesystem path to a configuration file
*
* @return string Data to be written to a cache file
*
* @throws sfConfigurationException If a requested configuration file does not exist or is not readable
* @throws sfParseException If a requested configuration file is improperly formatted
*/
public function execute($configFiles)
{
// get our prefix
$prefix = strtolower($this->getParameterHolder()->get('prefix', ''));
// add dynamic prefix if needed
if ($this->getParameterHolder()->get('module', false))
{
$prefix .= "'.strtolower(\$moduleName).'_";
}
// parse the yaml
$myConfig = $this->mergeEnvironment($this->parseYamls($configFiles));
$values = array();
foreach ($myConfig as $category => $keys)
{
$values = array_merge($values, $this->getValues($prefix, $category, $keys));
}
$data = '';
foreach ($values as $key => $value)
{
$data .= sprintf(" '%s' => %s,\n", $key, var_export($value, true));
}
// compile data
$retval = '';
if ($values)
{
$retval = "<?php\n".
"// auto-generated by sfDefineEnvironmentConfigHandler\n".
"// date: %s\nsfConfig::add(array(\n%s));\n";
$retval = sprintf($retval, date('Y/m/d H:i:s'), $data);
}
return $retval;
}
/**
* Gets values from the configuration array.
*
* @param string The prefix name
* @param string The category name
* @param mixed The key/value array
*
* @param array The new key/value array
*/
protected function getValues($prefix, $category, $keys)
{
if (!is_array($keys))
{
list($key, $value) = $this->fixCategoryValue($prefix.strtolower($category), '', $keys);
return array($key => $value);
}
$values = array();
$category = $this->fixCategoryName($category, $prefix);
// loop through all key/value pairs
foreach ($keys as $key => $value)
{
list($key, $value) = $this->fixCategoryValue($category, $key, $value);
$values[$key] = $value;
}
return $values;
}
/**
* Fixes the category name and replaces constants in the value.
*
* @param string The category name
* @param string The key name
* @param string The value
*
* @param string Return the new key and value
*/
protected function fixCategoryValue($category, $key, $value)
{
// prefix the key
$key = $category.$key;
// replace constant values
$value = $this->replaceConstants($value);
return array($key, $value);
}
/**
* Fixes the category name.
*
* @param string The category name
* @param string The prefix
*
* @return string The fixed category name
*/
protected function fixCategoryName($category, $prefix)
{
// categories starting without a period will be prepended to the key
if ($category[0] != '.')
{
$category = $prefix.$category.'_';
}
else
{
$category = $prefix;
}
return $category;
}
/**
* Merges default, all and current environment configurations.
*
* @param array The main configuratino array
*
* @param array The merged configuration
*/
protected function mergeEnvironment($config)
{
return sfToolkit::arrayDeepMerge(
isset($config['default']) && is_array($config['default']) ? $config['default'] : array(),
isset($config['all']) && is_array($config['all']) ? $config['all'] : array(),
isset($config[sfConfig::get('sf_environment')]) && is_array($config[sfConfig::get('sf_environment')]) ? $config[sfConfig::get('sf_environment')] : array()
);
}
}

View File

@ -0,0 +1,162 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfFactoryConfigHandler allows you to specify which factory implementation the
* system will use.
*
* @package symfony
* @subpackage config
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfFactoryConfigHandler.class.php 3203 2007-01-09 18:32:54Z fabien $
*/
class sfFactoryConfigHandler extends sfYamlConfigHandler
{
/**
* Executes this configuration handler.
*
* @param array An array of absolute filesystem path to a configuration file
*
* @return string Data to be written to a cache file
*
* @throws <b>sfConfigurationException</b> If a requested configuration file does not exist or is not readable
* @throws <b>sfParseException</b> If a requested configuration file is improperly formatted
*/
public function execute($configFiles)
{
// parse the yaml
$myConfig = $this->parseYamls($configFiles);
$myConfig = sfToolkit::arrayDeepMerge(
isset($myConfig['default']) && is_array($myConfig['default']) ? $myConfig['default'] : array(),
isset($myConfig['all']) && is_array($myConfig['all']) ? $myConfig['all'] : array(),
isset($myConfig[sfConfig::get('sf_environment')]) && is_array($myConfig[sfConfig::get('sf_environment')]) ? $myConfig[sfConfig::get('sf_environment')] : array()
);
// init our data and includes arrays
$includes = array();
$inits = array();
$instances = array();
// available list of factories
$factories = array('controller', 'request', 'response', 'storage', 'user', 'view_cache');
// let's do our fancy work
foreach ($factories as $factory)
{
// see if the factory exists for this controller
$keys = $myConfig[$factory];
if (!isset($keys['class']))
{
// missing class key
$error = sprintf('Configuration file "%s" specifies category "%s" with missing class key', $configFiles[0], $factory);
throw new sfParseException($error);
}
$class = $keys['class'];
if (isset($keys['file']))
{
// we have a file to include
$file = $this->replaceConstants($keys['file']);
$file = $this->replacePath($file);
if (!is_readable($file))
{
// factory file doesn't exist
$error = sprintf('Configuration file "%s" specifies class "%s" with nonexistent or unreadable file "%s"', $configFiles[0], $class, $file);
throw new sfParseException($error);
}
// append our data
$includes[] = sprintf("require_once('%s');", $file);
}
// parse parameters
if (isset($keys['param']))
{
$parameters = array();
foreach ($keys['param'] as $key => $value)
{
$parameters[$key] = $this->replaceConstants($value);
}
}
else
{
$parameters = null;
}
$parameters = var_export($parameters, true);
// append new data
switch ($factory)
{
case 'controller':
// append instance creation
$instances[] = sprintf(" \$this->controller = sfController::newInstance(sfConfig::get('sf_factory_controller', '%s'));", $class);
// append instance initialization
$inits[] = " \$this->controller->initialize(\$this);";
break;
case 'request':
// append instance creation
$instances[] = sprintf(" \$this->request = sfRequest::newInstance(sfConfig::get('sf_factory_request', '%s'));", $class);
// append instance initialization
$inits[] = sprintf(" \$this->request->initialize(\$this, sfConfig::get('sf_factory_request_parameters', %s), sfConfig::get('sf_factory_request_attributes', array()));", $parameters);
break;
case 'response':
// append instance creation
$instances[] = sprintf(" \$this->response = sfResponse::newInstance(sfConfig::get('sf_factory_response', '%s'));", $class);
// append instance initialization
$inits[] = sprintf(" \$this->response->initialize(\$this, sfConfig::get('sf_factory_response_parameters', %s));", $parameters);
break;
case 'storage':
// append instance creation
$instances[] = sprintf(" \$this->storage = sfStorage::newInstance(sfConfig::get('sf_factory_storage', '%s'));", $class);
// append instance initialization
$inits[] = sprintf(" \$this->storage->initialize(\$this, sfConfig::get('sf_factory_storage_parameters', %s));", $parameters);
break;
case 'user':
// append instance creation
$instances[] = sprintf(" \$this->user = sfUser::newInstance(sfConfig::get('sf_factory_user', '%s'));", $class);
// append instance initialization
$inits[] = sprintf(" \$this->user->initialize(\$this, sfConfig::get('sf_factory_user_parameters', %s));", $parameters);
break;
case 'view_cache':
// append view cache class name
$inits[] = sprintf("\n if (sfConfig::get('sf_cache'))\n {\n".
" \$this->viewCacheManager = new sfViewCacheManager();\n".
" \$this->viewCacheManager->initialize(\$this, sfConfig::get('sf_factory_view_cache', '%s'), sfConfig::get('sf_factory_view_cache_parameters', %s));\n".
" }\n",
$class, $parameters);
break;
}
}
// compile data
$retval = sprintf("<?php\n".
"// auto-generated by sfFactoryConfigHandler\n".
"// date: %s\n%s\n%s\n%s\n",
date('Y/m/d H:i:s'), implode("\n", $includes),
implode("\n", $instances), implode("\n", $inits));
return $retval;
}
}

View File

@ -0,0 +1,206 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfFilterConfigHandler allows you to register filters with the system.
*
* @package symfony
* @subpackage config
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfFilterConfigHandler.class.php 3258 2007-01-13 12:12:22Z fabien $
*/
class sfFilterConfigHandler extends sfYamlConfigHandler
{
/**
* Executes this configuration handler
*
* @param array An array of absolute filesystem path to a configuration file
*
* @return string Data to be written to a cache file
*
* @throws sfConfigurationException If a requested configuration file does not exist or is not readable
* @throws sfParseException If a requested configuration file is improperly formatted
*/
public function execute($configFiles)
{
// parse the yaml
$config = $this->parseYaml($configFiles[0]);
foreach (array_slice($configFiles, 1) as $i => $configFile)
{
// we get the order of the new file and merge with the previous configurations
$previous = $config;
$config = array();
foreach ($this->parseYaml($configFile) as $key => $value)
{
$value = (array) $value;
$config[$key] = isset($previous[$key]) ? sfToolkit::arrayDeepMerge($previous[$key], $value) : $value;
}
// check that every key in previous array is still present (to avoid problem when upgrading)
foreach (array_keys($previous) as $key)
{
if (!isset($config[$key]))
{
throw new sfConfigurationException(sprintf('The filter name "%s" is defined in "%s" but not present in "%s" file. To disable a filter, add a "enabled" key with a false value', $key, $configFiles[$i], $configFile));
}
}
}
// init our data and includes arrays
$data = array();
$includes = array();
$execution = false;
$rendering = false;
// let's do our fancy work
foreach ($config as $category => $keys)
{
if (isset($keys['enabled']) && !$keys['enabled'])
{
continue;
}
if (!isset($keys['class']))
{
// missing class key
$error = 'Configuration file "%s" specifies category "%s" with missing class key';
$error = sprintf($error, $configFiles[0], $category);
throw new sfParseException($error);
}
$class = $keys['class'];
if (isset($keys['file']))
{
// we have a file to include
$file = $this->replaceConstants($keys['file']);
$file = $this->replacePath($file);
if (!is_readable($file))
{
// filter file doesn't exist
$error = sprintf('Configuration file "%s" specifies class "%s" with nonexistent or unreadable file "%s"', $configFiles[0], $class, $file);
throw new sfParseException($error);
}
// append our data
$includes[] = sprintf("require_once('%s');\n", $file);
}
$condition = true;
if (isset($keys['param']['condition']))
{
$condition = $this->replaceConstants($keys['param']['condition']);
unset($keys['param']['condition']);
}
$type = isset($keys['param']['type']) ? $keys['param']['type'] : null;
unset($keys['param']['type']);
if ($condition)
{
// parse parameters
$parameters = isset($keys['param']) ? var_export($keys['param'], true) : 'null';
// append new data
if ('security' == $type)
{
$data[] = $this->addSecurityFilter($category, $class, $parameters);
}
else
{
$data[] = $this->addFilter($category, $class, $parameters);
}
if ('rendering' == $type)
{
$rendering = true;
}
if ('execution' == $type)
{
$execution = true;
}
}
}
if (!$rendering)
{
$error = sprintf('Configuration file "%s" must register a filter of type "rendering"', $configFiles[0]);
throw new sfParseException($error);
}
if (!$execution)
{
$error = sprintf('Configuration file "%s" must register a filter of type "execution"', $configFiles[0]);
throw new sfParseException($error);
}
// compile data
$retval = sprintf("<?php\n".
"// auto-generated by sfFilterConfigHandler\n".
"// date: %s%s\n%s\n\n", date('Y/m/d H:i:s'),
implode("\n", $includes), implode("\n", $data));
return $retval;
}
/**
* Adds a filter statement to the data.
*
* @param string The category name
* @param string The filter class name
* @param array Filter default parameters
*
* @return string The PHP statement
*/
protected function addFilter($category, $class, $parameters)
{
return sprintf("\nlist(\$class, \$parameters) = (array) sfConfig::get('sf_%s_filter', array('%s', %s));\n".
"\$filter = new \$class();\n".
"\$filter->initialize(\$this->context, \$parameters);\n".
"\$filterChain->register(\$filter);",
$category, $class, $parameters);
}
/**
* Adds a security filter statement to the data.
*
* @param string The category name
* @param string The filter class name
* @param array Filter default parameters
*
* @return string The PHP statement
*/
protected function addSecurityFilter($category, $class, $parameters)
{
return <<<EOF
// does this action require security?
if (\$actionInstance->isSecure())
{
if (!in_array('sfSecurityUser', class_implements(\$this->context->getUser())))
{
\$error = 'Security is enabled, but your sfUser implementation does not implement sfSecurityUser interface';
throw new sfSecurityException(\$error);
}
{$this->addFilter($category, $class, $parameters)}
}
EOF;
}
}

View File

@ -0,0 +1,82 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfGeneratorConfigHandler.
*
* @package symfony
* @subpackage config
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfGeneratorConfigHandler.class.php 3203 2007-01-09 18:32:54Z fabien $
*/
class sfGeneratorConfigHandler extends sfYamlConfigHandler
{
/**
* Executes this configuration handler.
*
* @param array An array of absolute filesystem path to a configuration file
*
* @return string Data to be written to a cache file
*
* @throws sfConfigurationException If a requested configuration file does not exist or is not readable
* @throws sfParseException If a requested configuration file is improperly formatted
* @throws sfInitializationException If a generator.yml key check fails
*/
public function execute($configFiles)
{
// parse the yaml
$config = $this->parseYamls($configFiles);
if (!$config)
{
return '';
}
if (!isset($config['generator']))
{
throw new sfParseException(sprintf('Configuration file "%s" must specify a generator section', $configFiles[1] ? $configFiles[1] : $configFiles[0]));
}
$config = $config['generator'];
if (!isset($config['class']))
{
throw new sfParseException(sprintf('Configuration file "%s" must specify a generator class section under the generator section', $configFiles[1] ? $configFiles[1] : $configFiles[0]));
}
foreach (array('fields', 'list', 'edit') as $section)
{
if (isset($config[$section]))
{
throw new sfParseException(sprintf('Configuration file "%s" can specify a "%s" section but only under the param section', $configFiles[1] ? $configFiles[1] : $configFiles[0], $section));
}
}
// generate class and add a reference to it
$generatorManager = new sfGeneratorManager();
$generatorManager->initialize();
// generator parameters
$generatorParam = (isset($config['param']) ? $config['param'] : array());
// hack to find the module name
preg_match('#'.sfConfig::get('sf_app_module_dir_name').'/([^/]+)/#', $configFiles[1], $match);
$generatorParam['moduleName'] = $match[1];
$data = $generatorManager->generate($config['class'], $generatorParam);
// compile data
$retval = "<?php\n".
"// auto-generated by sfGeneratorConfigHandler\n".
"// date: %s\n%s\n";
$retval = sprintf($retval, date('Y/m/d H:i:s'), $data);
return $retval;
}
}

View File

@ -0,0 +1,373 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfLoader is a class which contains the logic to look for files/classes in symfony.
*
* @package symfony
* @subpackage util
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfLoader.class.php 4277 2007-06-20 10:12:35Z fabien $
*/
class sfLoader
{
/**
* Gets directories where model classes are stored.
*
* @return array An array of directories
*/
static public function getModelDirs()
{
$dirs = array(sfConfig::get('sf_lib_dir').'/model' ? sfConfig::get('sf_lib_dir').'/model' : 'lib/model'); // project
if ($pluginDirs = glob(sfConfig::get('sf_plugins_dir').'/*/lib/model'))
{
$dirs = array_merge($dirs, $pluginDirs); // plugins
}
return $dirs;
}
/**
* Gets directories where controller classes are stored for a given module.
*
* @param string The module name
*
* @return array An array of directories
*/
static public function getControllerDirs($moduleName)
{
$suffix = $moduleName.'/'.sfConfig::get('sf_app_module_action_dir_name');
$dirs = array();
foreach (sfConfig::get('sf_module_dirs', array()) as $key => $value)
{
$dirs[$key.'/'.$suffix] = $value;
}
$dirs[sfConfig::get('sf_app_module_dir').'/'.$suffix] = false; // application
if ($pluginDirs = glob(sfConfig::get('sf_plugins_dir').'/*/modules/'.$suffix))
{
$dirs = array_merge($dirs, array_combine($pluginDirs, array_fill(0, count($pluginDirs), true))); // plugins
}
$dirs[sfConfig::get('sf_symfony_data_dir').'/modules/'.$suffix] = true; // core modules
return $dirs;
}
/**
* Gets directories where template files are stored for a given module.
*
* @param string The module name
*
* @return array An array of directories
*/
static public function getTemplateDirs($moduleName)
{
$suffix = $moduleName.'/'.sfConfig::get('sf_app_module_template_dir_name');
$dirs = array();
foreach (sfConfig::get('sf_module_dirs', array()) as $key => $value)
{
$dirs[] = $key.'/'.$suffix;
}
$dirs[] = sfConfig::get('sf_app_module_dir').'/'.$suffix; // application
if ($pluginDirs = glob(sfConfig::get('sf_plugins_dir').'/*/modules/'.$suffix))
{
$dirs = array_merge($dirs, $pluginDirs); // plugins
}
$dirs[] = sfConfig::get('sf_symfony_data_dir').'/modules/'.$suffix; // core modules
$dirs[] = sfConfig::get('sf_module_cache_dir').'/auto'.ucfirst($suffix); // generated templates in cache
return $dirs;
}
/**
* Gets the template directory to use for a given module and template file.
*
* @param string The module name
* @param string The template file
*
* @return string A template directory
*/
static public function getTemplateDir($moduleName, $templateFile)
{
$dirs = self::getTemplateDirs($moduleName);
foreach ($dirs as $dir)
{
if (is_readable($dir.'/'.$templateFile))
{
return $dir;
}
}
return null;
}
/**
* Gets the template to use for a given module and template file.
*
* @param string The module name
* @param string The template file
*
* @return string A template path
*/
static public function getTemplatePath($moduleName, $templateFile)
{
$dir = self::getTemplateDir($moduleName, $templateFile);
return $dir ? $dir.'/'.$templateFile : null;
}
/**
* Gets the i18n directory to use for a given module.
*
* @param string The module name
*
* @return string An i18n directory
*/
static public function getI18NDir($moduleName)
{
$suffix = $moduleName.'/'.sfConfig::get('sf_app_module_i18n_dir_name');
// application
$dir = sfConfig::get('sf_app_module_dir').'/'.$suffix;
if (is_dir($dir))
{
return $dir;
}
// plugins
$dirs = glob(sfConfig::get('sf_plugins_dir').'/*/modules/'.$suffix);
if (isset($dirs[0]))
{
return $dirs[0];
}
}
/**
* Gets directories where template files are stored for a generator class and a specific theme.
*
* @param string The generator class name
* @param string The theme name
*
* @return array An array of directories
*/
static public function getGeneratorTemplateDirs($class, $theme)
{
$dirs = array(sfConfig::get('sf_data_dir').'/generator/'.$class.'/'.$theme.'/template'); // project
if ($pluginDirs = glob(sfConfig::get('sf_plugins_dir').'/*/data/generator/'.$class.'/'.$theme.'/template'))
{
$dirs = array_merge($dirs, $pluginDirs); // plugin
}
$dirs[] = sfConfig::get('sf_symfony_data_dir').'/generator/'.$class.'/default/template'; // default theme
return $dirs;
}
/**
* Gets directories where the skeleton is stored for a generator class and a specific theme.
*
* @param string The generator class name
* @param string The theme name
*
* @return array An array of directories
*/
static public function getGeneratorSkeletonDirs($class, $theme)
{
$dirs = array(sfConfig::get('sf_data_dir').'/generator/'.$class.'/'.$theme.'/skeleton'); // project
if ($pluginDirs = glob(sfConfig::get('sf_plugins_dir').'/*/data/generator/'.$class.'/'.$theme.'/skeleton'))
{
$dirs = array_merge($dirs, $pluginDirs); // plugin
}
$dirs[] = sfConfig::get('sf_symfony_data_dir').'/generator/'.$class.'/default/skeleton'; // default theme
return $dirs;
}
/**
* Gets the template to use for a generator class.
*
* @param string The generator class name
* @param string The theme name
* @param string The template path
*
* @return string A template path
*
* @throws sfException
*/
static public function getGeneratorTemplate($class, $theme, $path)
{
$dirs = self::getGeneratorTemplateDirs($class, $theme);
foreach ($dirs as $dir)
{
if (is_readable($dir.'/'.$path))
{
return $dir.'/'.$path;
}
}
throw new sfException(sprintf('Unable to load "%s" generator template in: %s', $path, implode(', ', $dirs)));
}
/**
* Gets the configuration file paths for a given relative configuration path.
*
* @param string The configuration path
*
* @return array An array of paths
*/
static public function getConfigPaths($configPath)
{
$globalConfigPath = basename(dirname($configPath)).'/'.basename($configPath);
$files = array(
sfConfig::get('sf_symfony_data_dir').'/'.$globalConfigPath, // symfony
sfConfig::get('sf_symfony_data_dir').'/'.$configPath, // core modules
);
if ($pluginDirs = glob(sfConfig::get('sf_plugins_dir').'/*/'.$globalConfigPath))
{
$files = array_merge($files, $pluginDirs); // plugins
}
$files = array_merge($files, array(
sfConfig::get('sf_root_dir').'/'.$globalConfigPath, // project
sfConfig::get('sf_root_dir').'/'.$configPath, // project
sfConfig::get('sf_app_dir').'/'.$globalConfigPath, // application
sfConfig::get('sf_cache_dir').'/'.$configPath, // generated modules
));
if ($pluginDirs = glob(sfConfig::get('sf_plugins_dir').'/*/'.$configPath))
{
$files = array_merge($files, $pluginDirs); // plugins
}
$files[] = sfConfig::get('sf_app_dir').'/'.$configPath; // module
$configs = array();
foreach (array_unique($files) as $file)
{
if (is_readable($file))
{
$configs[] = $file;
}
}
return $configs;
}
/**
* Gets the helper directories for a given module name.
*
* @param string The module name
*
* @return array An array of directories
*/
static public function getHelperDirs($moduleName = '')
{
$dirs = array();
if ($moduleName)
{
$dirs[] = sfConfig::get('sf_app_module_dir').'/'.$moduleName.'/'.sfConfig::get('sf_app_module_lib_dir_name').'/helper'; // module
if ($pluginDirs = glob(sfConfig::get('sf_plugins_dir').'/*/modules/'.$moduleName.'/lib/helper'))
{
$dirs = array_merge($dirs, $pluginDirs); // module plugins
}
}
$dirs[] = sfConfig::get('sf_app_lib_dir').'/helper'; // application
$dirs[] = sfConfig::get('sf_lib_dir').'/helper'; // project
if ($pluginDirs = glob(sfConfig::get('sf_plugins_dir').'/*/lib/helper'))
{
$dirs = array_merge($dirs, $pluginDirs); // plugins
}
$dirs[] = sfConfig::get('sf_symfony_lib_dir').'/helper'; // global
return $dirs;
}
/**
* Loads helpers.
*
* @param array An array of helpers to load
* @param string A module name (optional)
*
* @throws sfViewException
*/
static public function loadHelpers($helpers, $moduleName = '')
{
static $loaded = array();
$dirs = self::getHelperDirs($moduleName);
foreach ((array) $helpers as $helperName)
{
if (isset($loaded[$helperName]))
{
continue;
}
$fileName = $helperName.'Helper.php';
foreach ($dirs as $dir)
{
$included = false;
if (is_readable($dir.'/'.$fileName))
{
include($dir.'/'.$fileName);
$included = true;
break;
}
}
if (!$included)
{
// search in the include path
if ((@include('helper/'.$fileName)) != 1)
{
$dirs = array_merge($dirs, explode(PATH_SEPARATOR, get_include_path()));
// remove sf_root_dir from dirs
foreach ($dirs as &$dir)
{
$dir = str_replace('%SF_ROOT_DIR%', sfConfig::get('sf_root_dir'), $dir);
}
throw new sfViewException(sprintf('Unable to load "%sHelper.php" helper in: %s', $helperName, implode(', ', $dirs)));
}
}
$loaded[$helperName] = true;
}
}
static public function loadPluginConfig()
{
if ($pluginConfigs = glob(sfConfig::get('sf_plugins_dir').'/*/config/config.php'))
{
foreach ($pluginConfigs as $config)
{
include($config);
}
}
}
}

View File

@ -0,0 +1,93 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfLoggingConfigHandler allows you to configure logging and register loggers with the system.
*
* @package symfony
* @subpackage config
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfLoggingConfigHandler.class.php 3258 2007-01-13 12:12:22Z fabien $
*/
class sfLoggingConfigHandler extends sfDefineEnvironmentConfigHandler
{
protected
$enabled = true,
$loggers = array();
/**
* Executes this configuration handler.
*
* @param array An array of absolute filesystem path to a configuration file
*
* @return string Data to be written to a cache file
*/
public function execute($configFiles)
{
$data = parent::execute($configFiles);
if ($this->enabled)
{
$data .= "\n\$logger = sfLogger::getInstance();\n";
// log level
$data .= "\$logger->setLogLevel(constant('SF_LOG_'.strtoupper(sfConfig::get('sf_logging_level'))));\n";
// register loggers defined in the logging.yml configuration file
foreach ($this->loggers as $name => $keys)
{
if (isset($keys['enabled']) && !$keys['enabled'])
{
continue;
}
if (!isset($keys['class']))
{
// missing class key
throw new sfParseException(sprintf('Configuration file "%s" specifies filter "%s" with missing class key', $configFiles[0], $name));
}
$condition = true;
if (isset($keys['param']['condition']))
{
$condition = $this->replaceConstants($keys['param']['condition']);
unset($keys['param']['condition']);
}
if ($condition)
{
// parse parameters
$parameters = isset($keys['param']) ? var_export($keys['param'], true) : '';
// create logger instance
$data .= sprintf("\n\$log = new %s();\n\$log->initialize(%s);\n\$logger->registerLogger(\$log);\n", $keys['class'], $parameters);
}
}
}
return $data;
}
protected function getValues($prefix, $category, $keys)
{
if ('enabled' == $category)
{
$this->enabled = $this->replaceConstants($keys);
}
else if ('loggers' == $category)
{
$this->loggers = $this->replaceConstants($keys);
return array();
}
return parent::getValues($prefix, $category, $keys);
}
}

View File

@ -0,0 +1,154 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfPhpConfigHandler allows you to override php.ini configuration at runtime.
*
* @package symfony
* @subpackage config
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfPhpConfigHandler.class.php 3203 2007-01-09 18:32:54Z fabien $
*/
class sfPhpConfigHandler extends sfYamlConfigHandler
{
/**
* Executes this configuration handler
*
* @param array An array of absolute filesystem path to a configuration file
*
* @return string Data to be written to a cache file
*
* @throws <b>sfConfigurationException</b> If a requested configuration file does not exist or is not readable
* @throws <b>sfParseException</b> If a requested configuration file is improperly formatted
* @throws <b>sfInitializationException</b> If a php.yml key check fails
*/
public function execute($configFiles)
{
$this->initialize();
// parse the yaml
$config = $this->parseYamls($configFiles);
// init our data array
$data = array();
// get all php.ini configuration
$configs = ini_get_all();
// set some php.ini keys
if (isset($config['set']))
{
foreach ($config['set'] as $key => $value)
{
$key = strtolower($key);
// key exists?
if (!array_key_exists($key, $configs))
{
$error = sprintf('Configuration file "%s" specifies key "%s" which is not a php.ini directive', $configFiles[0], $key);
throw new sfParseException($error);
}
// key is overridable?
if ($configs[$key]['access'] != 7)
{
$error = sprintf('Configuration file "%s" specifies key "%s" which cannot be overrided', $configFiles[0], $key);
throw new sfParseException($error);
}
// escape value
$value = str_replace("'", "\\'", $value);
$data[] = sprintf("ini_set('%s', '%s');", $key, $value);
}
}
// check some php.ini settings
if (isset($config['check']))
{
foreach ($config['check'] as $key => $value)
{
$key = strtolower($key);
// key exists?
if (!array_key_exists($key, $configs))
{
$error = sprintf('Configuration file "%s" specifies key "%s" which is not a php.ini directive [err0002]', $configFiles[0], $key);
throw new sfParseException($error);
}
if (ini_get($key) != $value)
{
$error = sprintf('Configuration file "%s" specifies that php.ini "%s" key must be set to "%s". The current value is "%s" (%s). [err0001]', $configFiles[0], $key, var_export($value, true), var_export(ini_get($key), true), $this->get_ini_path());
throw new sfInitializationException($error);
}
}
}
// warn about some php.ini settings
if (isset($config['warn']))
{
foreach ($config['warn'] as $key => $value)
{
$key = strtolower($key);
// key exists?
if (!array_key_exists($key, $configs))
{
$error = sprintf('Configuration file "%s" specifies key "%s" which is not a php.ini directive [err0002]', $configFiles[0], $key);
throw new sfParseException($error);
}
$warning = sprintf('{sfPhpConfigHandler} php.ini "%s" key is better set to "%s" (current value is "%s" - %s)', $key, var_export($value, true), var_export(ini_get($key), true), $this->get_ini_path());
$data[] = sprintf("if (ini_get('%s') != %s)\n{\n sfLogger::getInstance()->warning('%s');\n}\n", $key, var_export($value, true), str_replace("'", "\\'", $warning));
}
}
// check for some extensions
if (isset($config['extensions']))
{
foreach ($config['extensions'] as $extension_name)
{
if (!extension_loaded($extension_name))
{
$error = sprintf('Configuration file "%s" specifies that the PHP extension "%s" should be loaded. (%s)', $configFiles[0], $extension_name, $this->get_ini_path());
throw new sfInitializationException($error);
}
}
}
// compile data
$retval = sprintf("<?php\n".
"// auto-generated by sfPhpConfigHandler\n".
"// date: %s\n%s\n", date('Y/m/d H:i:s'), implode("\n", $data));
return $retval;
}
/**
* Gets the php.ini path used by PHP.
*
* @return string the php.ini path
*/
protected function get_ini_path()
{
$cfg_path = get_cfg_var('cfg_file_path');
if ($cfg_path == '')
{
$ini_path = 'WARNING: system is not using a php.ini file';
}
else
{
$ini_path = sprintf('php.ini location: "%s"', $cfg_path);
}
return $ini_path;
}
}

View File

@ -0,0 +1,104 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfRootConfigHandler allows you to specify configuration handlers for the
* application or on a module level.
*
* @package symfony
* @subpackage config
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfRootConfigHandler.class.php 3203 2007-01-09 18:32:54Z fabien $
*/
class sfRootConfigHandler extends sfYamlConfigHandler
{
/**
* Executes this configuration handler
*
* @param array An array of absolute filesystem path to a configuration file
*
* @return string Data to be written to a cache file
*
* @throws sfConfigurationException If a requested configuration file does not exist or is not readable
* @throws sfParseException If a requested configuration file is improperly formatted
*/
public function execute($configFiles)
{
// parse the yaml
$config = $this->parseYamls($configFiles);
// determine if we're loading the system config_handlers.yml or a module config_handlers.yml
$moduleLevel = ($this->getParameterHolder()->get('module_level') === true) ? true : false;
if ($moduleLevel)
{
// get the current module name
$moduleName = $this->getParameterHolder()->get('module_name');
}
// init our data and includes arrays
$data = array();
$includes = array();
// let's do our fancy work
foreach ($config as $category => $keys)
{
if ($moduleLevel)
{
// module-level registration, so we must prepend the module
// root to the category
$category = 'modules/'.$moduleName.'/'.$category;
}
if (!isset($keys['class']))
{
// missing class key
$error = sprintf('Configuration file "%s" specifies category "%s" with missing class key', $configFiles[0], $category);
throw new sfParseException($error);
}
$class = $keys['class'];
if (isset($keys['file']))
{
// we have a file to include
$file = $this->replaceConstants($keys['file']);
$file = $this->replacePath($file);
if (!is_readable($file))
{
// handler file doesn't exist
$error = sprintf('Configuration file "%s" specifies class "%s" with nonexistent or unreadable file "%s"', $configFiles[0], $class, $file);
throw new sfParseException($error);
}
// append our data
$includes[] = sprintf("require_once('%s');", $file);
}
// parse parameters
$parameters = (isset($keys['param']) ? var_export($keys['param'], true) : null);
// append new data
$data[] = sprintf("\$this->handlers['%s'] = new %s();", $category, $class);
// initialize the handler with parameters
$data[] = sprintf("\$this->handlers['%s']->initialize(%s);", $category, $parameters);
}
// compile data
$retval = sprintf("<?php\n" .
"// auto-generated by sfRootConfigHandler\n".
"// date: %s\n%s\n%s\n",
date('Y/m/d H:i:s'), implode("\n", $includes), implode("\n", $data));
return $retval;
}
}

View File

@ -0,0 +1,54 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* @package symfony
* @subpackage config
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfRoutingConfigHandler.class.php 3203 2007-01-09 18:32:54Z fabien $
*/
class sfRoutingConfigHandler extends sfYamlConfigHandler
{
/**
* Executes this configuration handler.
*
* @param array An array of absolute filesystem path to a configuration file
*
* @return string Data to be written to a cache file
*
* @throws sfConfigurationException If a requested configuration file does not exist or is not readable
* @throws sfParseException If a requested configuration file is improperly formatted
*/
public function execute($configFiles)
{
// parse the yaml
$config = $this->parseYamls($configFiles);
// connect routes
$routes = sfRouting::getInstance();
foreach ($config as $name => $params)
{
$routes->connect(
$name,
($params['url'] ? $params['url'] : '/'),
(isset($params['param']) ? $params['param'] : array()),
(isset($params['requirements']) ? $params['requirements'] : array())
);
}
// compile data
$retval = sprintf("<?php\n".
"// auto-generated by sfRoutingConfigHandler\n".
"// date: %s\n\$routes = sfRouting::getInstance();\n\$routes->setRoutes(\n%s\n);\n",
date('Y/m/d H:i:s'), var_export($routes->getRoutes(), 1));
return $retval;
}
}

View File

@ -0,0 +1,55 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfSecurityConfigHandler allows you to configure action security.
*
* @package symfony
* @subpackage config
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfSecurityConfigHandler.class.php 3624 2007-03-17 10:57:03Z fabien $
*/
class sfSecurityConfigHandler extends sfYamlConfigHandler
{
/**
* Executes this configuration handler.
*
* @param array An array of absolute filesystem path to a configuration file
*
* @return string Data to be written to a cache file
*
* @throws <b>sfConfigurationException</b> If a requested configuration file does not exist or is not readable
* @throws <b>sfParseException</b> If a requested configuration file is improperly formatted
* @throws <b>sfInitializationException</b> If a view.yml key check fails
*/
public function execute($configFiles)
{
// parse the yaml
$myConfig = $this->parseYamls($configFiles);
$myConfig['all'] = sfToolkit::arrayDeepMerge(
isset($myConfig['default']) && is_array($myConfig['default']) ? $myConfig['default'] : array(),
isset($myConfig['all']) && is_array($myConfig['all']) ? $myConfig['all'] : array()
);
unset($myConfig['default']);
// change all of the keys to lowercase
$myConfig = array_change_key_case($myConfig);
// compile data
$retval = sprintf("<?php\n".
"// auto-generated by sfSecurityConfigHandler\n".
"// date: %s\n\$this->security = %s;\n",
date('Y/m/d H:i:s'), var_export($myConfig, true));
return $retval;
}
}

View File

@ -0,0 +1,40 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfSimpleYamlConfigHandler allows you to load simple configuration files formatted as YAML.
*
* @package symfony
* @subpackage config
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfSimpleYamlConfigHandler.class.php 3203 2007-01-09 18:32:54Z fabien $
*/
class sfSimpleYamlConfigHandler extends sfYamlConfigHandler
{
/**
* Executes this configuration handler.
*
* @param array An array of absolute filesystem path to a configuration file
*
* @return string Data to be written to a cache file
*/
public function execute($configFiles)
{
$config = $this->parseYamls($configFiles);
// compile data
$retval = "<?php\n".
"// auto-generated by %s\n".
"// date: %s\nreturn %s;\n";
$retval = sprintf($retval, __CLASS__, date('Y/m/d H:i:s'), var_export($config, true));
return $retval;
}
}

View File

@ -0,0 +1,555 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfValidatorConfigHandler allows you to register validators with the system.
*
* @package symfony
* @subpackage config
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfValidatorConfigHandler.class.php 3410 2007-02-06 08:11:38Z fabien $
*/
class sfValidatorConfigHandler extends sfYamlConfigHandler
{
/**
* Executes this configuration handler.
*
* @param array An array of absolute filesystem path to a configuration file
*
* @return string Data to be written to a cache file
*
* @throws sfConfigurationException If a requested configuration file does not exist or is not readable
* @throws sfParseException If a requested configuration file is improperly formatted
*/
public function execute($configFiles)
{
// parse the yaml
$config = $this->parseYamls($configFiles);
// alternate format?
if (isset($config['fields']))
{
$this->convertAlternate2Standard($config);
}
foreach (array('methods', 'names') as $category)
{
if (!isset($config[$category]))
{
throw new sfParseException(sprintf('Configuration file "%s" is missing "%s" category', $configFiles[0], $category));
}
}
// init our data, includes, methods, names and validators arrays
$data = array();
$includes = array();
$methods = array();
$names = array();
$validators = array();
// get a list of methods and their registered files/parameters
foreach ($config['methods'] as $method => $list)
{
$method = strtoupper($method);
if (!isset($methods[$method]))
{
// make sure that this method is GET or POST
if ($method != 'GET' && $method != 'POST')
{
// unsupported request method
$error = sprintf('Configuration file "%s" specifies unsupported request method "%s"', $configFiles[0], $method);
throw new sfParseException($error);
}
// create our method
$methods[$method] = array();
}
if (!count($list))
{
// we have an empty list of names
continue;
}
// load name list
$this->loadNames($configFiles, $method, $methods, $names, $config, $list);
}
// load attribute list
$this->loadAttributes($configFiles, $methods, $names, $validators, $config, $list);
// fill-in filter configuration
$fillin = var_export(isset($config['fillin']) ? $config['fillin'] : array(), true);
// generate GET file/parameter data
$data[] = "if (\$_SERVER['REQUEST_METHOD'] == 'GET')";
$data[] = "{";
$ret = $this->generateRegistration('GET', $data, $methods, $names, $validators);
if ($ret)
{
$data[] = sprintf(" \$context->getRequest()->setAttribute('fillin', %s, 'symfony/filter');", $fillin);
}
// generate POST file/parameter data
$data[] = "}";
$data[] = "else if (\$_SERVER['REQUEST_METHOD'] == 'POST')";
$data[] = "{";
$ret = $this->generateRegistration('POST', $data, $methods, $names, $validators);
if ($ret)
{
$data[] = sprintf(" \$context->getRequest()->setAttribute('fillin', %s, 'symfony/filter');", $fillin);
}
$data[] = "}";
// compile data
$retval = sprintf("<?php\n".
"// auto-generated by sfValidatorConfigHandler\n".
"// date: %s\n%s\n%s\n", date('Y/m/d H:i:s'),
implode("\n", $includes), implode("\n", $data));
return $retval;
}
/**
* Generates raw cache data.
*
* @param string A request method
* @param array The data array where our cache code will be appended
* @param array An associative array of request method data
* @param array An associative array of file/parameter data
* @param array A validators array
*
* @return boolean Returns true if there is some validators for this file/parameter
*/
protected function generateRegistration($method, &$data, &$methods, &$names, &$validators)
{
// setup validator array
$data[] = " \$validators = array();";
if (!isset($methods[$method]))
{
$methods[$method] = array();
}
// determine which validators we need to create for this request method
foreach ($methods[$method] as $name)
{
if (preg_match('/^([a-z0-9_-]+)\{([a-z0-9\s_-]+)\}$/i', $name, $match))
{
// this file/parameter has a parent
$subname = $match[2];
$parent = $match[1];
$valList = $names[$parent][$subname]['validators'];
}
else
{
// no parent
$valList = $names[$name]['validators'];
}
if ($valList == null)
{
// no validator list for this file/parameter
continue;
}
foreach ($valList as $valName)
{
if (isset($validators[$valName]) && !isset($validators[$valName][$method]))
{
// retrieve this validator's info
$validator =& $validators[$valName];
$data[] = sprintf(" \$validators['%s'] = new %s();\n".
" \$validators['%s']->initialize(%s, %s);",
$valName, $validator['class'], $valName, '$context', $validator['parameters']);
// mark this validator as created for this request method
$validators[$valName][$method] = true;
}
}
}
foreach ($methods[$method] as $name)
{
if (preg_match('/^([a-z0-9_-]+)\{([a-z0-9\s_-]+)\}$/i', $name, $match))
{
// this file/parameter has a parent
$subname = $match[2];
$parent = $match[1];
$name = $match[2];
$attributes = $names[$parent][$subname];
}
else
{
// no parent
$attributes = $names[$name];
}
// register file/parameter
$data[] = sprintf(" \$validatorManager->registerName('%s', %s, %s, %s, %s, %s);",
$name, $attributes['required'] ? 1 : 0,
isset($attributes['required_msg']) ? $attributes['required_msg'] : "''",
$attributes['parent'], $attributes['group'],
$attributes['file']);
// register validators for this file/parameter
foreach ($attributes['validators'] as &$validator)
{
$data[] = sprintf(" \$validatorManager->registerValidator('%s', %s, %s);", $name,
"\$validators['$validator']",
$attributes['parent']);
}
}
return count($methods[$method]) ? true : false;
}
/**
* Loads the linear list of attributes from the [names] category.
*
* @param string The configuration file name (for exception usage)
* @param array An associative array of request method data
* @param array An associative array of file/parameter names in which to store loaded information
* @param array An associative array of validator data
* @param array The loaded ini configuration that we'll use for verification purposes
* @param string A comma delimited list of file/parameter names
*/
protected function loadAttributes(&$configFiles, &$methods, &$names, &$validators, &$config, &$list)
{
foreach ($config['names'] as $name => $attributes)
{
// get a reference to the name entry
if (preg_match('/^([a-z0-9_-]+)\{([a-z0-9\s_-]+)\}$/i', $name, $match))
{
// this name entry has a parent
$subname = $match[2];
$parent = $match[1];
if (!isset($names[$parent][$subname]))
{
// unknown parent or subname
$error = sprintf('Configuration file "%s" specifies unregistered parent "%s" or subname "%s"', $configFiles[0], $parent, $subname);
throw new sfParseException($error);
}
$entry =& $names[$parent][$subname];
}
else
{
// no parent
if (!isset($names[$name]))
{
// unknown name
$error = sprintf('Configuration file "%s" specifies unregistered name "%s"', $configFiles[0], $name);
throw new sfParseException($error);
}
$entry =& $names[$name];
}
foreach ($attributes as $attribute => $value)
{
if ($attribute == 'validators')
{
// load validators for this file/parameter name
$this->loadValidators($configFiles, $validators, $config, $value, $entry);
}
else if ($attribute == 'type')
{
// name type
$lvalue = strtolower($value);
$entry['file'] = ($lvalue == 'file' ? 'true' : 'false');
}
else
{
// just a normal attribute
$entry[$attribute] = sfToolkit::literalize($value, true);
}
}
}
}
/**
* Loads all request methods and the file/parameter names that will be
* validated from the [methods] category.
*
* @param string The configuration file name (for exception usage)
* @param string A request method
* @param array An associative array of request method data
* @param array An associative array of file/parameter names in which to store loaded information
* @param array The loaded ini configuration that we'll use for verification purposes
* @param string A comma delimited list of file/parameter names
*/
protected function loadNames(&$configFiles, &$method, &$methods, &$names, &$config, &$list)
{
// explode the list of names
$array = $list;
// loop through the names
foreach ($array as $name)
{
// make sure we have the required status of this file or parameter
if (!isset($config['names'][$name]['required']))
{
// missing 'required' attribute
$error = sprintf('Configuration file "%s" specifies file or parameter "%s", but it is missing the "required" attribute', $configFiles[0], $name);
throw new sfParseException($error);
}
// determine parent status
if (preg_match('/^([a-z0-9_-]+)\{([a-z0-9\s_-]+)\}$/i', $name, $match))
{
// this name has a parent
$subname = $match[2];
$parent = $match[1];
if (!isset($names[$parent]) || !isset($names[$parent][$name]))
{
if (!isset($names[$parent]))
{
// create our parent
$names[$parent] = array('_is_parent' => true);
}
// create our new name entry
$entry = array();
$entry['file'] = 'false';
$entry['group'] = 'null';
$entry['parent'] = "'$parent'";
$entry['required'] = 'true';
$entry['required_msg'] = "'Required'";
$entry['validators'] = array();
// add our name entry
$names[$parent][$subname] = $entry;
}
}
else if (strpos($name, '{') !== false || strpos($name, '}') !== false)
{
// name contains an invalid character
// this is most likely a typo where the user forgot to add a brace
$error = sprintf('Configuration file "%s" specifies method "%s" with invalid file/parameter name "%s"', $configFiles[0], $method, $name);
throw new sfParseException($error);
}
else
{
// no parent
if (!isset($names[$name]))
{
// create our new name entry
$entry = array();
$entry['file'] = 'false';
$entry['group'] = 'null';
$entry['parent'] = 'null';
$entry['required'] = 'true';
$entry['required_msg'] = "'Required'";
$entry['type'] = 'parameter';
$entry['validators'] = array();
// add our name entry
$names[$name] = $entry;
}
}
// add this name to the current request method
$methods[$method][] = $name;
}
}
/**
* Loads a list of validators.
*
* @param string The configuration file name (for exception usage)
* @param array An associative array of validator data
* @param array The loaded ini configuration that we'll use for verification purposes
* @param string A comma delimited list of validator names
* @param array A file/parameter name entry
*/
protected function loadValidators(&$configFiles, &$validators, &$config, &$list, &$entry)
{
// create our empty entry validator array
$entry['validators'] = array();
if (!$list || (!is_array($list) && trim($list) == ''))
{
// skip the empty list
return;
}
// get our validator array
$array = is_array($list) ? $list : explode(',', $list);
foreach ($array as $validator)
{
$validator = trim($validator);
// add this validator name to our entry
$entry['validators'][] = $validator;
// make sure the specified validator exists
if (!isset($config[$validator]))
{
// validator hasn't been registered
$error = sprintf('Configuration file "%s" specifies unregistered validator "%s"', $configFiles[0], $validator);
throw new sfParseException($error);
}
// has it already been registered?
if (isset($validators[$validator]))
{
continue;
}
if (!isset($config[$validator]['class']))
{
// missing class key
$error = sprintf('Configuration file "%s" specifies category "%s" with missing class key', $configFiles[0], $validator);
throw new sfParseException($error);
}
// create our validator
$validators[$validator] = array();
$validators[$validator]['class'] = $config[$validator]['class'];
$validators[$validator]['file'] = null;
$validators[$validator]['parameters'] = null;
if (isset($config[$validator]['file']))
{
// we have a file for this validator
$file = $config[$validator]['file'];
// keyword replacement
$file = $this->replaceConstants($file);
$file = $this->replacePath($file);
if (!is_readable($file))
{
// file doesn't exist
$error = sprintf('Configuration file "%s" specifies category "%s" with nonexistent or unreadable file "%s"', $configFiles[0], $validator, $file);
throw new sfParseException($error);
}
$validators[$validator]['file'] = $file;
}
// parse parameters
$parameters = (isset($config[$validator]['param']) ? var_export($config[$validator]['param'], true) : 'null');
$validators[$validator]['parameters'] = $parameters;
}
}
/**
* Converts alternate format to standard format.
*
* @param array Configuration data
*/
protected function convertAlternate2Standard(&$config)
{
$defaultMethods = isset($config['methods']) ? $config['methods'] : array('post');
$config['methods'] = array();
// validators
if (isset($config['validators']))
{
foreach ((array) $config['validators'] as $validator => $params)
{
$config[$validator] = $params;
}
unset($config['validators']);
}
// names
$config['names'] = $config['fields'];
unset($config['fields']);
foreach ($config['names'] as $name => $values)
{
// validators
$validators = array();
foreach ($values as $validator => $params)
{
if (in_array($validator, array('required', 'group', 'group_msg', 'parent', 'file', 'methods')))
{
continue;
}
// class or validator
if (!isset($config[$validator]))
{
$config[$validator] = array('class' => $validator);
}
$validatorName = $validator;
if ($params)
{
// create a new validator
$validatorName = $validator.'_'.$name;
$config[$validatorName] = $config[$validator];
$config[$validatorName]['param'] = array_merge(isset($config[$validator]['param']) ? (array) $config[$validator]['param'] : array(), $params);
}
$validators[] = $validatorName;
unset($values[$validator]);
}
$values['validators'] = $validators;
// group
if (isset($values['group']) && isset($values['group_msg']))
{
$values['required_msg'] = $values['group_msg'];
}
// required
if (isset($values['required']))
{
$values['required_msg'] = $values['required']['msg'];
$values['required'] = true;
}
else
{
$values['required'] = false;
}
// methods
if (isset($values['methods']))
{
$methods = (array) $values['methods'];
unset($values['methods']);
}
else
{
$methods = $defaultMethods;
}
foreach ($methods as $method)
{
$config['methods'][$method][] = $name;
}
$config['names'][$name] = $values;
}
}
}

View File

@ -0,0 +1,343 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfViewConfigHandler allows you to configure views.
*
* @package symfony
* @subpackage config
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfViewConfigHandler.class.php 3289 2007-01-15 21:28:51Z fabien $
*/
class sfViewConfigHandler extends sfYamlConfigHandler
{
/**
* Executes this configuration handler.
*
* @param array An array of absolute filesystem path to a configuration file
*
* @return string Data to be written to a cache file
*
* @throws <b>sfConfigurationException</b> If a requested configuration file does not exist or is not readable
* @throws <b>sfParseException</b> If a requested configuration file is improperly formatted
* @throws <b>sfInitializationException</b> If a view.yml key check fails
*/
public function execute($configFiles)
{
// set our required categories list and initialize our handler
$categories = array('required_categories' => array());
$this->initialize($categories);
// parse the yaml
$this->mergeConfig($this->parseYamls($configFiles));
// init our data array
$data = array();
$data[] = "\$context = \$this->getContext();\n";
$data[] = "\$response = \$context->getResponse();\n\n";
// first pass: iterate through all view names to determine the real view name
$first = true;
foreach ($this->yamlConfig as $viewName => $values)
{
if ($viewName == 'all')
{
continue;
}
$data[] = ($first ? '' : 'else ')."if (\$this->actionName.\$this->viewName == '$viewName')\n".
"{\n";
$data[] = $this->addTemplate($viewName);
$data[] = "}\n";
$first = false;
}
// general view configuration
$data[] = ($first ? '' : "else\n{")."\n";
$data[] = $this->addTemplate($viewName);
$data[] = ($first ? '' : "}")."\n\n";
// second pass: iterate through all real view names
$first = true;
foreach ($this->yamlConfig as $viewName => $values)
{
if ($viewName == 'all')
{
continue;
}
$data[] = ($first ? '' : 'else ')."if (\$templateName.\$this->viewName == '$viewName')\n".
"{\n";
$data[] = $this->addLayout($viewName);
$data[] = $this->addComponentSlots($viewName);
$data[] = $this->addHtmlHead($viewName);
$data[] = $this->addEscaping($viewName);
$data[] = $this->addHtmlAsset($viewName);
$data[] = "}\n";
$first = false;
}
// general view configuration
$data[] = ($first ? '' : "else\n{")."\n";
$data[] = $this->addLayout();
$data[] = $this->addComponentSlots();
$data[] = $this->addHtmlHead();
$data[] = $this->addEscaping();
$data[] = $this->addHtmlAsset();
$data[] = ($first ? '' : "}")."\n";
// compile data
$retval = sprintf("<?php\n".
"// auto-generated by sfViewConfigHandler\n".
"// date: %s\n%s\n",
date('Y/m/d H:i:s'), implode('', $data));
return $retval;
}
/**
* Merges assets and environement configuration.
*
* @param array A configuration array
*/
protected function mergeConfig($myConfig)
{
// merge javascripts and stylesheets
$myConfig['all']['stylesheets'] = array_merge(isset($myConfig['default']['stylesheets']) && is_array($myConfig['default']['stylesheets']) ? $myConfig['default']['stylesheets'] : array(), isset($myConfig['all']['stylesheets']) && is_array($myConfig['all']['stylesheets']) ? $myConfig['all']['stylesheets'] : array());
unset($myConfig['default']['stylesheets']);
$myConfig['all']['javascripts'] = array_merge(isset($myConfig['default']['javascripts']) && is_array($myConfig['default']['javascripts']) ? $myConfig['default']['javascripts'] : array(), isset($myConfig['all']['javascripts']) && is_array($myConfig['all']['javascripts']) ? $myConfig['all']['javascripts'] : array());
unset($myConfig['default']['javascripts']);
// merge default and all
$myConfig['all'] = sfToolkit::arrayDeepMerge(
isset($myConfig['default']) && is_array($myConfig['default']) ? $myConfig['default'] : array(),
isset($myConfig['all']) && is_array($myConfig['all']) ? $myConfig['all'] : array()
);
unset($myConfig['default']);
$this->yamlConfig = $myConfig;
}
/**
* Adds a component slot statement to the data.
*
* @param string The view name
*
* @return string The PHP statement
*/
protected function addComponentSlots($viewName = '')
{
$data = '';
$components = $this->mergeConfigValue('components', $viewName);
foreach ($components as $name => $component)
{
if (!is_array($component) || count($component) < 1)
{
$component = array(null, null);
}
$data .= " \$this->setComponentSlot('$name', '{$component[0]}', '{$component[1]}');\n";
$data .= " if (sfConfig::get('sf_logging_enabled')) \$context->getLogger()->info('{sfViewConfig} set component \"$name\" ({$component[0]}/{$component[1]})');\n";
}
return $data;
}
/**
* Adds a template setting statement to the data.
*
* @param string The view name
*
* @return string The PHP statement
*/
protected function addTemplate($viewName = '')
{
$data = '';
$templateName = $this->getConfigValue('template', $viewName);
$defaultTemplateName = $templateName ? "'$templateName'" : '$this->actionName';
$data .= " \$templateName = \$response->getParameter(\$this->moduleName.'_'.\$this->actionName.'_template', $defaultTemplateName, 'symfony/action/view');\n";
$data .= " \$this->setTemplate(\$templateName.\$this->viewName.\$this->getExtension());\n";
return $data;
}
/**
* Adds a layour statement statement to the data.
*
* @param string The view name
*
* @return string The PHP statement
*/
protected function addLayout($viewName = '')
{
$data = '';
if ($this->getConfigValue('has_layout', $viewName) && false !== $layout = $this->getConfigValue('layout', $viewName))
{
$data = " \$this->setDecoratorTemplate('$layout'.\$this->getExtension());\n";
}
// For XMLHttpRequest, we want no layout by default
// So, we check if the user requested has_layout: true or if he gave a layout: name for this particular action
$localLayout = isset($this->yamlConfig[$viewName]['layout']) || isset($this->yamlConfig[$viewName]['has_layout']);
if (!$localLayout && $data)
{
$data = " if (!\$context->getRequest()->isXmlHttpRequest())\n {\n $data }\n";
}
return $data;
}
/**
* Adds http metas and metas statements to the data.
*
* @param string The view name
*
* @return string The PHP statement
*/
protected function addHtmlHead($viewName = '')
{
$data = array();
foreach ($this->mergeConfigValue('http_metas', $viewName) as $httpequiv => $content)
{
$data[] = sprintf(" \$response->addHttpMeta('%s', '%s', false);", $httpequiv, str_replace('\'', '\\\'', $content));
}
foreach ($this->mergeConfigValue('metas', $viewName) as $name => $content)
{
$data[] = sprintf(" \$response->addMeta('%s', '%s', false, false);", $name, str_replace('\'', '\\\'', preg_replace('/&amp;(?=\w+;)/', '&', htmlentities($content, ENT_QUOTES, sfConfig::get('sf_charset')))));
}
return implode("\n", $data)."\n";
}
/**
* Adds stylesheets and javascripts statements to the data.
*
* @param string The view name
*
* @return string The PHP statement
*/
protected function addHtmlAsset($viewName = '')
{
$data = array();
$omit = array();
$delete = array();
$delete_all = false;
// Merge the current view's stylesheets with the app's default stylesheets
$stylesheets = $this->mergeConfigValue('stylesheets', $viewName);
$tmp = array();
foreach ((array) $stylesheets as $css)
{
$position = '';
if (is_array($css))
{
$key = key($css);
$options = $css[$key];
if (isset($options['position']))
{
$position = $options['position'];
unset($options['position']);
}
}
else
{
$key = $css;
$options = array();
}
$key = $this->replaceConstants($key);
if ('-*' == $key)
{
$tmp = array();
}
else if ('-' == $key[0])
{
unset($tmp[substr($key, 1)]);
}
else
{
$tmp[$key] = sprintf(" \$response->addStylesheet('%s', '%s', %s);", $key, $position, str_replace("\n", '', var_export($options, true)));
}
}
$data = array_merge($data, array_values($tmp));
$omit = array();
$delete_all = false;
// Populate $javascripts with the values from ONLY the current view
$javascripts = $this->mergeConfigValue('javascripts', $viewName);
$tmp = array();
foreach ((array) $javascripts as $js)
{
$js = $this->replaceConstants($js);
if ('-*' == $js)
{
$tmp = array();
}
else if ('-' == $js[0])
{
unset($tmp[substr($js, 1)]);
}
else
{
$tmp[$js] = sprintf(" \$response->addJavascript('%s');", $js);
}
}
$data = array_merge($data, array_values($tmp));
return implode("\n", $data)."\n";
}
/**
* Adds an escaping statement to the data.
*
* @param string The view name
*
* @return string The PHP statement
*/
protected function addEscaping($viewName = '')
{
$data = array();
$escaping = $this->getConfigValue('escaping', $viewName);
if (isset($escaping['strategy']))
{
$data[] = sprintf(" \$this->setEscaping(%s);", var_export($escaping['strategy'], true));
}
if (isset($escaping['method']))
{
$data[] = sprintf(" \$this->setEscapingMethod(%s);", var_export($escaping['method'], true));
}
return implode("\n", $data)."\n";
}
}

View File

@ -0,0 +1,134 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfYamlConfigHandler is a base class for YAML (.yml) configuration handlers. This class
* provides a central location for parsing YAML files and detecting required categories.
*
* @package symfony
* @subpackage config
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfYamlConfigHandler.class.php 3203 2007-01-09 18:32:54Z fabien $
*/
abstract class sfYamlConfigHandler extends sfConfigHandler
{
protected
$yamlConfig = null;
/**
* Parses an array of YAMLs files and merges them in one configuration array.
*
* @param array An array of configuration file paths
*
* @param array A merged configuration array
*/
protected function parseYamls($configFiles)
{
$config = array();
foreach ($configFiles as $configFile)
{
$config = sfToolkit::arrayDeepMerge($config, $this->parseYaml($configFile));
}
return $config;
}
/**
* Parses a YAML (.yml) configuration file.
*
* @param string An absolute filesystem path to a configuration file
*
* @return string A parsed .yml configuration
*
* @throws sfConfigurationException If a requested configuration file does not exist or is not readable
* @throws sfParseException If a requested configuration file is improperly formatted
*/
protected function parseYaml($configFile)
{
if (!is_readable($configFile))
{
// can't read the configuration
$error = sprintf('Configuration file "%s" does not exist or is not readable', $configFile);
throw new sfConfigurationException($error);
}
// parse our config
$config = sfYaml::load($configFile);
if ($config === false || $config === null)
{
// configuration couldn't be parsed
$error = sprintf('Configuration file "%s" could not be parsed', $configFile);
throw new sfParseException($error);
}
// get a list of the required categories
$categories = $this->getParameterHolder()->get('required_categories', array());
foreach ($categories as $category)
{
if (!isset($config[$category]))
{
$error = sprintf('Configuration file "%s" is missing "%s" category', $configFile, $category);
throw new sfParseException($error);
}
}
return $config;
}
/**
* Merges configuration values for a given key and category.
*
* @param string The key name
* @param string The category name
*
* @return string The value associated with this key name and category
*/
protected function mergeConfigValue($keyName, $category)
{
$values = array();
if (isset($this->yamlConfig['all'][$keyName]) && is_array($this->yamlConfig['all'][$keyName]))
{
$values = $this->yamlConfig['all'][$keyName];
}
if ($category && isset($this->yamlConfig[$category][$keyName]) && is_array($this->yamlConfig[$category][$keyName]))
{
$values = array_merge($values, $this->yamlConfig[$category][$keyName]);
}
return $values;
}
/**
* Gets a configuration value for a given key and category.
*
* @param string The key name
* @param string The category name
* @param string The default value
*
* @return string The value associated with this key name and category
*/
protected function getConfigValue($keyName, $category, $defaultValue = null)
{
if (isset($this->yamlConfig[$category][$keyName]))
{
return $this->yamlConfig[$category][$keyName];
}
else if (isset($this->yamlConfig['all'][$keyName]))
{
return $this->yamlConfig['all'][$keyName];
}
return $defaultValue;
}
}

View File

@ -0,0 +1,47 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* @package symfony
* @subpackage controller
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfConsoleController.class.php 3204 2007-01-09 18:50:08Z fabien $
*/
class sfConsoleController extends sfController
{
/**
* Dispatches a request.
*
* @param string A module name
* @param string An action name
* @param array An associative array of parameters to be set
*/
public function dispatch($moduleName, $actionName, $parameters = array())
{
try
{
// set parameters
$this->getContext()->getRequest()->getParameterHolder()->add($parameters);
// make the first request
$this->forward($moduleName, $actionName);
}
catch (sfException $e)
{
$e->printStackTrace();
}
catch (Exception $e)
{
// wrap non symfony exceptions
$sfException = new sfException();
$sfException->printStackTrace($e);
}
}
}

View File

@ -0,0 +1,644 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfController directs application flow.
*
* @package symfony
* @subpackage controller
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfController.class.php 3221 2007-01-11 07:33:23Z fabien $
*/
abstract class sfController
{
protected
$context = null,
$controllerClasses = array(),
$maxForwards = 5,
$renderMode = sfView::RENDER_CLIENT,
$viewCacheClassName = null;
/**
* Indicates whether or not a module has a specific component.
*
* @param string A module name
* @param string An component name
*
* @return bool true, if the component exists, otherwise false
*/
public function componentExists($moduleName, $componentName)
{
return $this->controllerExists($moduleName, $componentName, 'component', false);
}
/**
* Indicates whether or not a module has a specific action.
*
* @param string A module name
* @param string An action name
*
* @return bool true, if the action exists, otherwise false
*/
public function actionExists($moduleName, $actionName)
{
return $this->controllerExists($moduleName, $actionName, 'action', false);
}
/**
* Looks for a controller and optionally throw exceptions if existence is required (i.e.
* in the case of {@link getController()}).
*
* @param string The name of the module
* @param string The name of the controller within the module
* @param string Either 'action' or 'component' depending on the type of controller to look for
* @param boolean Whether to throw exceptions if the controller doesn't exist
*
* @throws sfConfigurationException thrown if the module is not enabled
* @throws sfControllerException thrown if the controller doesn't exist and the $throwExceptions parameter is set to true
*
* @return boolean true if the controller exists, false otherwise
*/
protected function controllerExists($moduleName, $controllerName, $extension, $throwExceptions)
{
$dirs = sfLoader::getControllerDirs($moduleName);
foreach ($dirs as $dir => $checkEnabled)
{
// plugin module enabled?
if ($checkEnabled && !in_array($moduleName, sfConfig::get('sf_enabled_modules')) && is_readable($dir))
{
$error = 'The module "%s" is not enabled.';
$error = sprintf($error, $moduleName);
throw new sfConfigurationException($error);
}
// one action per file or one file for all actions
$classFile = strtolower($extension);
$classSuffix = ucfirst(strtolower($extension));
$file = $dir.'/'.$controllerName.$classSuffix.'.class.php';
if (is_readable($file))
{
// action class exists
require_once($file);
$this->controllerClasses[$moduleName.'_'.$controllerName.'_'.$classSuffix] = $controllerName.$classSuffix;
return true;
}
$module_file = $dir.'/'.$classFile.'s.class.php';
if (is_readable($module_file))
{
// module class exists
require_once($module_file);
if (!class_exists($moduleName.$classSuffix.'s', false))
{
if ($throwExceptions)
{
throw new sfControllerException(sprintf('There is no "%s" class in your action file "%s".', $moduleName.$classSuffix.'s', $module_file));
}
return false;
}
// action is defined in this class?
if (!in_array('execute'.ucfirst($controllerName), get_class_methods($moduleName.$classSuffix.'s')))
{
if ($throwExceptions)
{
throw new sfControllerException(sprintf('There is no "%s" method in your action class "%s"', 'execute'.ucfirst($controllerName), $moduleName.$classSuffix.'s'));
}
return false;
}
$this->controllerClasses[$moduleName.'_'.$controllerName.'_'.$classSuffix] = $moduleName.$classSuffix.'s';
return true;
}
}
// send an exception if debug
if ($throwExceptions && sfConfig::get('sf_debug'))
{
$dirs = array_keys($dirs);
// remove sf_root_dir from dirs
foreach ($dirs as &$dir)
{
$dir = str_replace(sfConfig::get('sf_root_dir'), '%SF_ROOT_DIR%', $dir);
}
throw new sfControllerException(sprintf('{sfController} controller "%s/%s" does not exist in: %s', $moduleName, $controllerName, implode(', ', $dirs)));
}
return false;
}
/**
* Forwards the request to another action.
*
* @param string A module name
* @param string An action name
*
* @throws <b>sfConfigurationException</b> If an invalid configuration setting has been found
* @throws <b>sfForwardException</b> If an error occurs while forwarding the request
* @throws <b>sfInitializationException</b> If the action could not be initialized
* @throws <b>sfSecurityException</b> If the action requires security but the user implementation is not of type sfSecurityUser
*/
public function forward($moduleName, $actionName)
{
// replace unwanted characters
$moduleName = preg_replace('/[^a-z0-9\-_]+/i', '', $moduleName);
$actionName = preg_replace('/[^a-z0-9\-_]+/i', '', $actionName);
if ($this->getActionStack()->getSize() >= $this->maxForwards)
{
// let's kill this party before it turns into cpu cycle hell
$error = 'Too many forwards have been detected for this request (> %d)';
$error = sprintf($error, $this->maxForwards);
throw new sfForwardException($error);
}
$rootDir = sfConfig::get('sf_root_dir');
$app = sfConfig::get('sf_app');
$env = sfConfig::get('sf_environment');
if (!sfConfig::get('sf_available') || sfToolkit::hasLockFile($rootDir.'/'.$app.'_'.$env.'.clilock'))
{
// application is unavailable
$moduleName = sfConfig::get('sf_unavailable_module');
$actionName = sfConfig::get('sf_unavailable_action');
if (!$this->actionExists($moduleName, $actionName))
{
// cannot find unavailable module/action
$error = 'Invalid configuration settings: [sf_unavailable_module] "%s", [sf_unavailable_action] "%s"';
$error = sprintf($error, $moduleName, $actionName);
throw new sfConfigurationException($error);
}
}
// check for a module generator config file
sfConfigCache::getInstance()->import(sfConfig::get('sf_app_module_dir_name').'/'.$moduleName.'/'.sfConfig::get('sf_app_module_config_dir_name').'/generator.yml', true, true);
if (!$this->actionExists($moduleName, $actionName))
{
// the requested action doesn't exist
if (sfConfig::get('sf_logging_enabled'))
{
$this->getContext()->getLogger()->info('{sfController} action does not exist');
}
// track the requested module so we have access to the data in the error 404 page
$this->context->getRequest()->setAttribute('requested_action', $actionName);
$this->context->getRequest()->setAttribute('requested_module', $moduleName);
// switch to error 404 action
$moduleName = sfConfig::get('sf_error_404_module');
$actionName = sfConfig::get('sf_error_404_action');
if (!$this->actionExists($moduleName, $actionName))
{
// cannot find unavailable module/action
$error = 'Invalid configuration settings: [sf_error_404_module] "%s", [sf_error_404_action] "%s"';
$error = sprintf($error, $moduleName, $actionName);
throw new sfConfigurationException($error);
}
}
// create an instance of the action
$actionInstance = $this->getAction($moduleName, $actionName);
// add a new action stack entry
$this->getActionStack()->addEntry($moduleName, $actionName, $actionInstance);
// include module configuration
require(sfConfigCache::getInstance()->checkConfig(sfConfig::get('sf_app_module_dir_name').'/'.$moduleName.'/'.sfConfig::get('sf_app_module_config_dir_name').'/module.yml'));
// check if this module is internal
if ($this->getActionStack()->getSize() == 1 && sfConfig::get('mod_'.strtolower($moduleName).'_is_internal') && !sfConfig::get('sf_test'))
{
$error = 'Action "%s" from module "%s" cannot be called directly';
$error = sprintf($error, $actionName, $moduleName);
throw new sfConfigurationException($error);
}
if (sfConfig::get('mod_'.strtolower($moduleName).'_enabled'))
{
// module is enabled
// check for a module config.php
$moduleConfig = sfConfig::get('sf_app_module_dir').'/'.$moduleName.'/'.sfConfig::get('sf_app_module_config_dir_name').'/config.php';
if (is_readable($moduleConfig))
{
require_once($moduleConfig);
}
// initialize the action
if ($actionInstance->initialize($this->context))
{
// create a new filter chain
$filterChain = new sfFilterChain();
$this->loadFilters($filterChain, $actionInstance);
if ($moduleName == sfConfig::get('sf_error_404_module') && $actionName == sfConfig::get('sf_error_404_action'))
{
$this->getContext()->getResponse()->setStatusCode(404);
$this->getContext()->getResponse()->setHttpHeader('Status', '404 Not Found');
foreach (sfMixer::getCallables('sfController:forward:error404') as $callable)
{
call_user_func($callable, $this, $moduleName, $actionName);
}
}
// change i18n message source directory to our module
if (sfConfig::get('sf_i18n'))
{
$this->context->getI18N()->setMessageSourceDir(sfLoader::getI18NDir($moduleName), $this->context->getUser()->getCulture());
}
// process the filter chain
$filterChain->execute();
}
else
{
// action failed to initialize
$error = 'Action initialization failed for module "%s", action "%s"';
$error = sprintf($error, $moduleName, $actionName);
throw new sfInitializationException($error);
}
}
else
{
// module is disabled
$moduleName = sfConfig::get('sf_module_disabled_module');
$actionName = sfConfig::get('sf_module_disabled_action');
if (!$this->actionExists($moduleName, $actionName))
{
// cannot find mod disabled module/action
$error = 'Invalid configuration settings: [sf_module_disabled_module] "%s", [sf_module_disabled_action] "%s"';
$error = sprintf($error, $moduleName, $actionName);
throw new sfConfigurationException($error);
}
$this->forward($moduleName, $actionName);
}
}
/**
* Retrieves an sfAction implementation instance.
*
* @param string A module name
* @param string An action name
*
* @return sfAction An sfAction implementation instance, if the action exists, otherwise null
*/
public function getAction($moduleName, $actionName)
{
return $this->getController($moduleName, $actionName, 'action');
}
/**
* Retrieves a sfComponent implementation instance.
*
* @param string A module name
* @param string A component name
*
* @return sfComponent A sfComponent implementation instance, if the component exists, otherwise null
*/
public function getComponent($moduleName, $componentName)
{
return $this->getController($moduleName, $componentName, 'component');
}
/**
* Retrieves a controller implementation instance.
*
* @param string A module name
* @param string A component name
* @param string Either 'action' or 'component' depending on the type of controller to look for
*
* @return object A controller implementation instance, if the controller exists, otherwise null
*
* @see getComponent(), getAction()
*/
protected function getController($moduleName, $controllerName, $extension)
{
$classSuffix = ucfirst(strtolower($extension));
if (!isset($this->controllerClasses[$moduleName.'_'.$controllerName.'_'.$classSuffix]))
{
$this->controllerExists($moduleName, $controllerName, $extension, true);
}
$class = $this->controllerClasses[$moduleName.'_'.$controllerName.'_'.$classSuffix];
// fix for same name classes
$moduleClass = $moduleName.'_'.$class;
if (class_exists($moduleClass, false))
{
$class = $moduleClass;
}
return new $class();
}
/**
* Retrieves the action stack.
*
* @return sfActionStack An sfActionStack instance, if the action stack is enabled, otherwise null
*/
public function getActionStack()
{
return $this->context->getActionStack();
}
/**
* Retrieves the current application context.
*
* @return sfContext A sfContext instance
*/
public function getContext()
{
return $this->context;
}
/**
* Retrieves the presentation rendering mode.
*
* @return int One of the following:
* - sfView::RENDER_CLIENT
* - sfView::RENDER_VAR
*/
public function getRenderMode()
{
return $this->renderMode;
}
/**
* Retrieves a sfView implementation instance.
*
* @param string A module name
* @param string An action name
* @param string A view name
*
* @return sfView A sfView implementation instance, if the view exists, otherwise null
*/
public function getView($moduleName, $actionName, $viewName)
{
// user view exists?
$file = sfConfig::get('sf_app_module_dir').'/'.$moduleName.'/'.sfConfig::get('sf_app_module_view_dir_name').'/'.$actionName.$viewName.'View.class.php';
if (is_readable($file))
{
require_once($file);
$class = $actionName.$viewName.'View';
// fix for same name classes
$moduleClass = $moduleName.'_'.$class;
if (class_exists($moduleClass, false))
{
$class = $moduleClass;
}
}
else
{
// view class (as configured in module.yml or defined in action)
$viewName = $this->getContext()->getRequest()->getAttribute($moduleName.'_'.$actionName.'_view_name', sfConfig::get('mod_'.strtolower($moduleName).'_view_class'), 'symfony/action/view');
$class = sfCore::getClassPath($viewName.'View') ? $viewName.'View' : 'sfPHPView';
}
return new $class();
}
/**
* Initializes this controller.
*
* @param sfContext A sfContext implementation instance
*/
public function initialize($context)
{
$this->context = $context;
if (sfConfig::get('sf_logging_enabled'))
{
$this->context->getLogger()->info('{sfController} initialization');
}
// set max forwards
$this->maxForwards = sfConfig::get('sf_max_forwards');
}
/**
* Retrieves a new sfController implementation instance.
*
* @param string A sfController class name
*
* @return sfController A sfController implementation instance
*
* @throws sfFactoryException If a new controller implementation instance cannot be created
*/
public static function newInstance($class)
{
try
{
// the class exists
$object = new $class();
if (!($object instanceof sfController))
{
// the class name is of the wrong type
$error = 'Class "%s" is not of the type sfController';
$error = sprintf($error, $class);
throw new sfFactoryException($error);
}
return $object;
}
catch (sfException $e)
{
$e->printStackTrace();
}
}
/**
* Sends and email from the current action.
*
* This methods calls a module/action with the sfMailView class.
*
* @param string A module name
* @param string An action name
*
* @return string The generated mail content
*
* @see sfMailView, getPresentationFor(), sfController
*/
public function sendEmail($module, $action)
{
return $this->getPresentationFor($module, $action, 'sfMail');
}
/**
* Returns the rendered view presentation of a given module/action.
*
* @param string A module name
* @param string An action name
* @param string A View class name
*
* @return string The generated content
*/
public function getPresentationFor($module, $action, $viewName = null)
{
if (sfConfig::get('sf_logging_enabled'))
{
$this->getContext()->getLogger()->info('{sfController} get presentation for action "'.$module.'/'.$action.'" (view class: "'.$viewName.'")');
}
// get original render mode
$renderMode = $this->getRenderMode();
// set render mode to var
$this->setRenderMode(sfView::RENDER_VAR);
// grab the action stack
$actionStack = $this->getActionStack();
// grab this next forward's action stack index
$index = $actionStack->getSize();
// set viewName if needed
if ($viewName)
{
$this->getContext()->getRequest()->setAttribute($module.'_'.$action.'_view_name', $viewName, 'symfony/action/view');
}
// forward to the mail action
$this->forward($module, $action);
// grab the action entry from this forward
$actionEntry = $actionStack->getEntry($index);
// get raw email content
$presentation =& $actionEntry->getPresentation();
// put render mode back
$this->setRenderMode($renderMode);
// remove the action entry
$nb = $actionStack->getSize() - $index;
while ($nb-- > 0)
{
$actionEntry = $actionStack->popEntry();
if ($actionEntry->getModuleName() == sfConfig::get('sf_login_module') && $actionEntry->getActionName() == sfConfig::get('sf_login_action'))
{
$error = 'Your mail action is secured but the user is not authenticated.';
throw new sfException($error);
}
else if ($actionEntry->getModuleName() == sfConfig::get('sf_secure_module') && $actionEntry->getActionName() == sfConfig::get('sf_secure_action'))
{
$error = 'Your mail action is secured but the user does not have access.';
throw new sfException($error);
}
}
// remove viewName
if ($viewName)
{
$this->getContext()->getRequest()->getAttributeHolder()->remove($module.'_'.$action.'_view_name', 'symfony/action/view');
}
return $presentation;
}
/**
* Sets the presentation rendering mode.
*
* @param int A rendering mode
*
* @throws sfRenderException If an invalid render mode has been set
*/
public function setRenderMode($mode)
{
if ($mode == sfView::RENDER_CLIENT || $mode == sfView::RENDER_VAR || $mode == sfView::RENDER_NONE)
{
$this->renderMode = $mode;
return;
}
// invalid rendering mode type
$error = 'Invalid rendering mode: %s';
$error = sprintf($error, $mode);
throw new sfRenderException($error);
}
/**
* Indicates whether or not we were called using the CLI version of PHP.
*
* @return bool true, if using cli, otherwise false.
*/
public function inCLI()
{
return 0 == strncasecmp(PHP_SAPI, 'cli', 3);
}
/**
* Loads application nad module filters.
*
* @param sfFilterChain A sfFilterChain instance
* @param sfAction A sfAction instance
*/
public function loadFilters($filterChain, $actionInstance)
{
$moduleName = $this->context->getModuleName();
require(sfConfigCache::getInstance()->checkConfig(sfConfig::get('sf_app_module_dir_name').'/'.$moduleName.'/'.sfConfig::get('sf_app_module_config_dir_name').'/filters.yml'));
}
/**
* Calls methods defined via the sfMixer class.
*
* @param string The method name
* @param array The method arguments
*
* @return mixed The returned value of the called method
*
* @see sfMixer
*/
public function __call($method, $arguments)
{
if (!$callable = sfMixer::getCallable('sfController:'.$method))
{
throw new sfException(sprintf('Call to undefined method sfController::%s', $method));
}
array_unshift($arguments, $this);
return call_user_func_array($callable, $arguments);
}
}

View File

@ -0,0 +1,78 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfFrontWebController allows you to centralize your entry point in your web
* application, but at the same time allow for any module and action combination
* to be requested.
*
* @package symfony
* @subpackage controller
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfFrontWebController.class.php 3502 2007-02-18 18:28:28Z fabien $
*/
class sfFrontWebController extends sfWebController
{
/**
* Dispatches a request.
*
* This will determine which module and action to use by request parameters specified by the user.
*/
public function dispatch()
{
try
{
if (sfConfig::get('sf_logging_enabled'))
{
$this->getContext()->getLogger()->info('{sfController} dispatch request');
}
// reinitialize filters (needed for unit and functional tests)
sfFilter::$filterCalled = array();
// determine our module and action
$request = $this->getContext()->getRequest();
$moduleName = $request->getParameter('module');
$actionName = $request->getParameter('action');
// make the first request
$this->forward($moduleName, $actionName);
}
catch (sfException $e)
{
if (sfConfig::get('sf_test'))
{
throw $e;
}
$e->printStackTrace();
}
catch (Exception $e)
{
if (sfConfig::get('sf_test'))
{
throw $e;
}
try
{
// wrap non symfony exceptions
$sfException = new sfException();
$sfException->printStackTrace($e);
}
catch (Exception $e)
{
header('HTTP/1.0 500 Internal Server Error');
}
}
}
}

View File

@ -0,0 +1,633 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfRouting class controls the creation of URLs and parses URLs. It maps an array of parameters to URLs definition.
* Each map is called a route.
* It implements the Singleton pattern.
*
* Routing can be disabled when [sf_routing] is set to false.
*
* This class is based on the Routes class of Cake framework.
*
* @package symfony
* @subpackage controller
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfRouting.class.php 4228 2007-06-15 13:43:24Z francois $
*/
class sfRouting
{
protected static
$instance = null;
protected
$current_route_name = '',
$routes = array();
/**
* Retrieve the singleton instance of this class.
*
* @return sfRouting The sfRouting implementation instance
*/
public static function getInstance()
{
if (!isset(self::$instance))
{
self::$instance = new sfRouting();
}
return self::$instance;
}
/**
* Sets the current route name.
*
* @param string The route name
*/
protected function setCurrentRouteName($name)
{
$this->current_route_name = $name;
}
/**
* Gets the current route name.
*
* @return string The route name
*/
public function getCurrentRouteName()
{
return $this->current_route_name;
}
/**
* Gets the internal URI for the current request.
*
* @param boolean Whether to give an internal URI with the route name (@route)
* or with the module/action pair
*
* @return string The current internal URI
*/
public function getCurrentInternalUri($with_route_name = false)
{
if ($this->current_route_name)
{
list($url, $regexp, $names, $names_hash, $defaults, $requirements, $suffix) = $this->routes[$this->current_route_name];
$request = sfContext::getInstance()->getRequest();
if ($with_route_name)
{
$internal_uri = '@'.$this->current_route_name;
}
else
{
$internal_uri = $request->getParameter('module', isset($defaults['module']) ? $defaults['module'] : '').'/'.$request->getParameter('action', isset($defaults['action']) ? $defaults['action'] : '');
}
$params = array();
// add parameters
foreach ($names as $name)
{
if ($name == 'module' || $name == 'action') continue;
$params[] = $name.'='.$request->getParameter($name, isset($defaults[$name]) ? $defaults[$name] : '');
}
// add * parameters if needed
if (strpos($url, '*'))
{
foreach ($request->getParameterHolder()->getAll() as $key => $value)
{
if ($key == 'module' || $key == 'action' || in_array($key, $names))
{
continue;
}
$params[] = $key.'='.$value;
}
}
// sort to guaranty unicity
sort($params);
return $internal_uri.($params ? '?'.implode('&', $params) : '');
}
}
/**
* Gets the current compiled route array.
*
* @return array The route array
*/
public function getRoutes()
{
return $this->routes;
}
/**
* Sets the compiled route array.
*
* @param array The route array
*
* @return array The route array
*/
public function setRoutes($routes)
{
return $this->routes = $routes;
}
/**
* Returns true if this instance has some routes.
*
* @return boolean
*/
public function hasRoutes()
{
return count($this->routes) ? true : false;
}
/**
* Returns true if the route name given is defined.
*
* @param string The route name
*
* @return boolean
*/
public function hasRouteName($name)
{
return isset($this->routes[$name]) ? true : false;
}
/**
* Gets a route by its name.
*
* @param string The route name
*
* @return array A route array
*/
public function getRouteByName($name)
{
if ($name[0] == '@')
{
$name = substr($name, 1);
}
if (!isset($this->routes[$name]))
{
$error = 'The route "%s" does not exist';
$error = sprintf($error, $name);
throw new sfConfigurationException($error);
}
return $this->routes[$name];
}
/**
* Clears all current routes.
*/
public function clearRoutes()
{
if (sfConfig::get('sf_logging_enabled'))
{
sfLogger::getInstance()->info('{sfRouting} clear all current routes');
}
$this->routes = array();
}
/**
* Adds a new route at the beginning of the current list of routes.
*
* @see connect
*/
public function prependRoute($name, $route, $default = array(), $requirements = array())
{
$routes = $this->routes;
$this->routes = array();
$newroutes = $this->connect($name, $route, $default, $requirements);
$this->routes = array_merge($newroutes, $routes);
return $this->routes;
}
/**
* Adds a new route.
*
* Alias for the connect method.
*
* @see connect
*/
public function appendRoute($name, $route, $default = array(), $requirements = array())
{
return $this->connect($name, $route, $default, $requirements);
}
/**
* Adds a new route at the end of the current list of routes.
*
* A route string is a string with 2 special constructions:
* - :string: :string denotes a named paramater (available later as $request->getParameter('string'))
* - *: * match an indefinite number of parameters in a route
*
* Here is a very common rule in a symfony project:
*
* <code>
* $r->connect('/:module/:action/*');
* </code>
*
* @param string The route name
* @param string The route string
* @param array The default parameter values
* @param array The regexps parameters must match
*
* @return array current routes
*/
public function connect($name, $route, $default = array(), $requirements = array())
{
// route already exists?
if (isset($this->routes[$name]))
{
$error = 'This named route already exists ("%s").';
$error = sprintf($error, $name);
throw new sfConfigurationException($error);
}
$parsed = array();
$names = array();
$suffix = (($sf_suffix = sfConfig::get('sf_suffix')) == '.') ? '' : $sf_suffix;
// used for performance reasons
$names_hash = array();
$r = null;
if (($route == '') || ($route == '/'))
{
$regexp = '/^[\/]*$/';
$this->routes[$name] = array($route, $regexp, array(), array(), $default, $requirements, $suffix);
}
else
{
$elements = array();
foreach (explode('/', $route) as $element)
{
if (trim($element))
{
$elements[] = $element;
}
}
if (!isset($elements[0]))
{
return false;
}
// specific suffix for this route?
// or /$ directory
if (preg_match('/^(.+)(\.\w*)$/i', $elements[count($elements) - 1], $matches))
{
$suffix = ($matches[2] == '.') ? '' : $matches[2];
$elements[count($elements) - 1] = $matches[1];
$route = '/'.implode('/', $elements);
}
else if ($route{strlen($route) - 1} == '/')
{
$suffix = '/';
}
$regexp_suffix = preg_quote($suffix);
foreach ($elements as $element)
{
if (preg_match('/^:(.+)$/', $element, $r))
{
$element = $r[1];
// regex is [^\/]+ or the requirement regex
if (isset($requirements[$element]))
{
$regex = $requirements[$element];
if (0 === strpos($regex, '^'))
{
$regex = substr($regex, 1);
}
if (strlen($regex) - 1 === strpos($regex, '$'))
{
$regex = substr($regex, 0, -1);
}
}
else
{
$regex = '[^\/]+';
}
$parsed[] = '(?:\/('.$regex.'))?';
$names[] = $element;
$names_hash[$element] = 1;
}
elseif (preg_match('/^\*$/', $element, $r))
{
$parsed[] = '(?:\/(.*))?';
}
else
{
$parsed[] = '/'.$element;
}
}
$regexp = '#^'.join('', $parsed).$regexp_suffix.'$#';
$this->routes[$name] = array($route, $regexp, $names, $names_hash, $default, $requirements, $suffix);
}
if (sfConfig::get('sf_logging_enabled'))
{
sfLogger::getInstance()->info('{sfRouting} connect "'.$route.'"'.($suffix ? ' ("'.$suffix.'" suffix)' : ''));
}
return $this->routes;
}
/**
* Generates a valid URLs for parameters.
*
* @param array The parameter values
* @param string The divider between key/value pairs
* @param string The equal sign to use between key and value
*
* @return string The generated URL
*/
public function generate($name, $params, $querydiv = '/', $divider = '/', $equals = '/')
{
$global_defaults = sfConfig::get('sf_routing_defaults', null);
// named route?
if ($name)
{
if (!isset($this->routes[$name]))
{
$error = 'The route "%s" does not exist.';
$error = sprintf($error, $name);
throw new sfConfigurationException($error);
}
list($url, $regexp, $names, $names_hash, $defaults, $requirements, $suffix) = $this->routes[$name];
if ($global_defaults !== null)
{
$defaults = array_merge($defaults, $global_defaults);
}
// all params must be given
foreach ($names as $tmp)
{
if (!isset($params[$tmp]) && !isset($defaults[$tmp]))
{
throw new sfException(sprintf('Route named "%s" have a mandatory "%s" parameter', $name, $tmp));
}
}
}
else
{
// find a matching route
$found = false;
foreach ($this->routes as $name => $route)
{
list($url, $regexp, $names, $names_hash, $defaults, $requirements, $suffix) = $route;
if ($global_defaults !== null)
{
$defaults = array_merge($defaults, $global_defaults);
}
$tparams = array_merge($defaults, $params);
// we must match all names (all $names keys must be in $params array)
foreach ($names as $key)
{
if (!isset($tparams[$key])) continue 2;
}
// we must match all defaults with value except if present in names
foreach ($defaults as $key => $value)
{
if (isset($names_hash[$key])) continue;
if (!isset($tparams[$key]) || $tparams[$key] != $value) continue 2;
}
// we must match all requirements for rule
foreach ($requirements as $req_param => $req_regexp)
{
if (!preg_match('/'.str_replace('/', '\\/', $req_regexp).'/', $tparams[$req_param]))
{
continue 2;
}
}
// we must have consumed all $params keys if there is no * in route
if (!strpos($url, '*'))
{
if (count(array_diff(array_keys($tparams), $names, array_keys($defaults))))
{
continue;
}
}
// match found
$found = true;
break;
}
if (!$found)
{
$error = 'Unable to find a matching routing rule to generate url for params "%s".';
$error = sprintf($error, var_export($params));
throw new sfConfigurationException($error);
}
}
$params = array_merge($defaults, $params);
$real_url = preg_replace('/\:([^\/]+)/e', 'urlencode($params["\\1"])', $url);
// we add all other params if *
if (strpos($real_url, '*'))
{
$tmp = array();
foreach ($params as $key => $value)
{
if (isset($names_hash[$key]) || isset($defaults[$key])) continue;
if (is_array($value))
{
foreach ($value as $v)
{
$tmp[] = $key.$equals.urlencode($v);
}
}
else
{
$tmp[] = urlencode($key).$equals.urlencode($value);
}
}
$tmp = implode($divider, $tmp);
if (strlen($tmp) > 0)
{
$tmp = $querydiv.$tmp;
}
$real_url = preg_replace('/\/\*(\/|$)/', "$tmp$1", $real_url);
}
// strip off last divider character
if (strlen($real_url) > 1)
{
$real_url = rtrim($real_url, $divider);
}
if ($real_url != '/')
{
$real_url .= $suffix;
}
return $real_url;
}
/**
* Parses a URL to find a matching route.
*
* Returns null if no route match the URL.
*
* @param string URL to be parsed
*
* @return array An array of parameters
*/
public function parse($url)
{
// an URL should start with a '/', mod_rewrite doesn't respect that, but no-mod_rewrite version does.
if ($url && ('/' != $url[0]))
{
$url = '/'.$url;
}
// we remove the query string
if ($pos = strpos($url, '?'))
{
$url = substr($url, 0, $pos);
}
// we remove multiple /
$url = preg_replace('#/+#', '/', $url);
foreach ($this->routes as $route_name => $route)
{
$out = array();
$r = null;
list($route, $regexp, $names, $names_hash, $defaults, $requirements, $suffix) = $route;
$break = false;
if (preg_match($regexp, $url, $r))
{
$break = true;
// remove the first element, which is the url
array_shift($r);
// hack, pre-fill the default route names
foreach ($names as $name)
{
$out[$name] = null;
}
// defaults
foreach ($defaults as $name => $value)
{
if (preg_match('#[a-z_\-]#i', $name))
{
$out[$name] = urldecode($value);
}
else
{
$out[$value] = true;
}
}
$pos = 0;
foreach ($r as $found)
{
// if $found is a named url element (i.e. ':action')
if (isset($names[$pos]))
{
$out[$names[$pos]] = urldecode($found);
}
// unnamed elements go in as 'pass'
else
{
$pass = explode('/', $found);
$found = '';
for ($i = 0, $max = count($pass); $i < $max; $i += 2)
{
if (!isset($pass[$i + 1])) continue;
$found .= $pass[$i].'='.$pass[$i + 1].'&';
}
parse_str($found, $pass);
foreach ($pass as $key => $value)
{
// we add this parameters if not in conflict with named url element (i.e. ':action')
if (!isset($names_hash[$key]))
{
$out[$key] = $value;
}
}
}
$pos++;
}
// we must have found all :var stuffs in url? except if default values exists
foreach ($names as $name)
{
if ($out[$name] == null)
{
$break = false;
}
}
if ($break)
{
// we store route name
$this->setCurrentRouteName($route_name);
if (sfConfig::get('sf_logging_enabled'))
{
sfLogger::getInstance()->info('{sfRouting} match route ['.$route_name.'] "'.$route.'"');
}
break;
}
}
}
// no route found
if (!$break)
{
if (sfConfig::get('sf_logging_enabled'))
{
sfLogger::getInstance()->info('{sfRouting} no matching route found');
}
return null;
}
return $out;
}
}

View File

@ -0,0 +1,227 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfWebController provides web specific methods to sfController such as, url redirection.
*
* @package symfony
* @subpackage controller
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfWebController.class.php 4763 2007-07-31 11:52:49Z fabien $
*/
abstract class sfWebController extends sfController
{
/**
* Generates an URL from an array of parameters.
*
* @param mixed An associative array of URL parameters or an internal URI as a string.
* @param boolean Whether to generate an absolute URL
*
* @return string A URL to a symfony resource
*/
public function genUrl($parameters = array(), $absolute = false)
{
// absolute URL or symfony URL?
if (!is_array($parameters) && preg_match('#^[a-z]+\://#', $parameters))
{
return $parameters;
}
if (!is_array($parameters) && $parameters == '#')
{
return $parameters;
}
$url = '';
if (!sfConfig::get('sf_no_script_name'))
{
$url = $this->getContext()->getRequest()->getScriptName();
}
else if ($sf_relative_url_root = $this->getContext()->getRequest()->getRelativeUrlRoot())
{
$url = $sf_relative_url_root;
}
$route_name = '';
$fragment = '';
if (!is_array($parameters))
{
// strip fragment
if (false !== ($pos = strpos($parameters, '#')))
{
$fragment = substr($parameters, $pos + 1);
$parameters = substr($parameters, 0, $pos);
}
list($route_name, $parameters) = $this->convertUrlStringToParameters($parameters);
}
if (sfConfig::get('sf_url_format') == 'PATH')
{
// use PATH format
$divider = '/';
$equals = '/';
$querydiv = '/';
}
else
{
// use GET format
$divider = ini_get('arg_separator.output');
$equals = '=';
$querydiv = '?';
}
// default module
if (!isset($parameters['module']))
{
$parameters['module'] = sfConfig::get('sf_default_module');
}
// default action
if (!isset($parameters['action']))
{
$parameters['action'] = sfConfig::get('sf_default_action');
}
$r = sfRouting::getInstance();
if ($r->hasRoutes() && $generated_url = $r->generate($route_name, $parameters, $querydiv, $divider, $equals))
{
$url .= $generated_url;
}
else
{
$query = http_build_query($parameters);
if (sfConfig::get('sf_url_format') == 'PATH')
{
$query = strtr($query, ini_get('arg_separator.output').'=', '/');
}
$url .= $query;
}
if ($absolute)
{
$request = $this->getContext()->getRequest();
$url = 'http'.($request->isSecure() ? 's' : '').'://'.$request->getHost().$url;
}
if ($fragment)
{
$url .= '#'.$fragment;
}
return $url;
}
/**
* Converts an internal URI string to an array of parameters.
*
* @param string An internal URI
*
* @return array An array of parameters
*/
public function convertUrlStringToParameters($url)
{
$params = array();
$query_string = '';
$route_name = '';
// empty url?
if (!$url)
{
$url = '/';
}
// we get the query string out of the url
if ($pos = strpos($url, '?'))
{
$query_string = substr($url, $pos + 1);
$url = substr($url, 0, $pos);
}
// 2 url forms
// @route_name?key1=value1&key2=value2...
// module/action?key1=value1&key2=value2...
// first slash optional
if ($url[0] == '/')
{
$url = substr($url, 1);
}
// route_name?
if ($url[0] == '@')
{
$route_name = substr($url, 1);
}
else
{
$tmp = explode('/', $url);
$params['module'] = $tmp[0];
$params['action'] = isset($tmp[1]) ? $tmp[1] : sfConfig::get('sf_default_action');
}
// split the query string
if ($query_string)
{
$matched = preg_match_all('/
([^&=]+) # key
= # =
(.*?) # value
(?:
(?=&[^&=]+=) | $ # followed by another key= or the end of the string
)
/x', $query_string, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE);
foreach ($matches as $match)
{
$params[$match[1][0]] = $match[2][0];
}
// check that all string is matched
if (!$matched)
{
throw new sfParseException(sprintf('Unable to parse query string "%s".', $query_string));
}
}
return array($route_name, $params);
}
/**
* Redirects the request to another URL.
*
* @param string An existing URL
* @param int A delay in seconds before redirecting. This is only needed on
* browsers that do not support HTTP headers
* @param int The status code
*/
public function redirect($url, $delay = 0, $statusCode = 302)
{
$response = $this->getContext()->getResponse();
// redirect
$response->clearHttpHeaders();
$response->setStatusCode($statusCode);
$response->setHttpHeader('Location', $url);
$response->setContent(sprintf('<html><head><meta http-equiv="refresh" content="%d;url=%s"/></head></html>', $delay, htmlentities($url, ENT_QUOTES, sfConfig::get('sf_charset'))));
if (!sfConfig::get('sf_test'))
{
$response->sendHttpHeaders();
}
$response->sendContent();
}
}

View File

@ -0,0 +1,163 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfDatabase is a base abstraction class that allows you to setup any type of
* database connection via a configuration file.
*
* @package symfony
* @subpackage database
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfDatabase.class.php 3210 2007-01-10 20:28:16Z fabien $
*/
abstract class sfDatabase
{
protected
$connection = null,
$parameterHolder = null,
$resource = null;
/**
* Connects to the database.
*
* @throws <b>sfDatabaseException</b> If a connection could not be created
*/
abstract function connect();
/**
* Retrieves the database connection associated with this sfDatabase implementation.
*
* When this is executed on a Database implementation that isn't an
* abstraction layer, a copy of the resource will be returned.
*
* @return mixed A database connection
*
* @throws <b>sfDatabaseException</b> If a connection could not be retrieved
*/
public function getConnection()
{
if ($this->connection == null)
{
$this->connect();
}
return $this->connection;
}
/**
* Retrieves a raw database resource associated with this sfDatabase implementation.
*
* @return mixed A database resource
*
* @throws <b>sfDatabaseException</b> If a resource could not be retrieved
*/
public function getResource()
{
if ($this->resource == null)
{
$this->connect();
}
return $this->resource;
}
/**
* Initializes this sfDatabase object.
*
* @param array An associative array of initialization parameters
*
* @return bool true, if initialization completes successfully, otherwise false
*
* @throws <b>sfInitializationException</b> If an error occurs while initializing this sfDatabase object
*/
public function initialize($parameters = array())
{
$this->parameterHolder = new sfParameterHolder();
$this->parameterHolder->add($parameters);
}
/**
* Gets the parameter holder for this object.
*
* @return sfParameterHolder A sfParameterHolder instance
*/
public function getParameterHolder()
{
return $this->parameterHolder;
}
/**
* Gets the parameter associated with the given key.
*
* This is a shortcut for:
*
* <code>$this->getParameterHolder()->get()</code>
*
* @param string The key name
* @param string The default value
* @param string The namespace to use
*
* @return string The value associated with the key
*
* @see sfParameterHolder
*/
public function getParameter($name, $default = null, $ns = null)
{
return $this->parameterHolder->get($name, $default, $ns);
}
/**
* Returns true if the given key exists in the parameter holder.
*
* This is a shortcut for:
*
* <code>$this->getParameterHolder()->has()</code>
*
* @param string The key name
* @param string The namespace to use
*
* @return boolean true if the given key exists, false otherwise
*
* @see sfParameterHolder
*/
public function hasParameter($name, $ns = null)
{
return $this->parameterHolder->has($name, $ns);
}
/**
* Sets the value for the given key.
*
* This is a shortcut for:
*
* <code>$this->getParameterHolder()->set()</code>
*
* @param string The key name
* @param string The value
* @param string The namespace to use
*
* @see sfParameterHolder
*/
public function setParameter($name, $value, $ns = null)
{
$this->parameterHolder->set($name, $value, $ns);
}
/**
* Executes the shutdown procedure.
*
* @return void
*
* @throws <b>sfDatabaseException</b> If an error occurs while shutting down this database
*/
abstract function shutdown();
}

View File

@ -0,0 +1,79 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfDatabaseManager allows you to setup your database connectivity before the
* request is handled. This eliminates the need for a filter to manage database
* connections.
*
* @package symfony
* @subpackage database
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfDatabaseManager.class.php 3210 2007-01-10 20:28:16Z fabien $
*/
class sfDatabaseManager
{
protected
$databases = array();
/**
* Retrieves the database connection associated with this sfDatabase implementation.
*
* @param string A database name
*
* @return mixed A Database instance
*
* @throws <b>sfDatabaseException</b> If the requested database name does not exist
*/
public function getDatabase($name = 'default')
{
if (isset($this->databases[$name]))
{
return $this->databases[$name];
}
// nonexistent database name
$error = 'Database "%s" does not exist';
$error = sprintf($error, $name);
throw new sfDatabaseException($error);
}
/**
* Initializes this sfDatabaseManager object
*
* @return bool true, if initialization completes successfully, otherwise false
*
* @throws <b>sfInitializationException</b> If an error occurs while initializing this sfDatabaseManager object
*/
public function initialize()
{
// load database configuration
require(sfConfigCache::getInstance()->checkConfig(sfConfig::get('sf_app_config_dir_name').'/databases.yml'));
}
/**
* Executes the shutdown procedure
*
* @return void
*
* @throws <b>sfDatabaseException</b> If an error occurs while shutting down this DatabaseManager
*/
public function shutdown()
{
// loop through databases and shutdown connections
foreach ($this->databases as $database)
{
$database->shutdown();
}
}
}

View File

@ -0,0 +1,166 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfMySQLDatabase provides connectivity for the MySQL brand database.
*
* <b>Optional parameters:</b>
*
* # <b>database</b> - [none] - The database name.
* # <b>host</b> - [localhost] - The database host.
* # <b>method</b> - [normal] - How to read connection parameters.
* Possible values are normal, server, and
* env. The normal method reads them from
* the specified values. server reads them
* from $_SERVER where the keys to retrieve
* the values are what you specify the value
* as in the settings. env reads them from
* $_ENV and works like $_SERVER.
* # <b>password</b> - [none] - The database password.
* # <b>persistent</b> - [No] - Indicates that the connection should be
* persistent.
* # <b>username</b> - [none] - The database username.
*
* @package symfony
* @subpackage database
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfMySQLDatabase.class.php 3329 2007-01-23 08:29:34Z fabien $
*/
class sfMySQLDatabase extends sfDatabase
{
/**
* Connects to the database.
*
* @throws <b>sfDatabaseException</b> If a connection could not be created
*/
public function connect()
{
// determine how to get our
$method = $this->getParameter('method', 'normal');
switch ($method)
{
case 'normal':
// get parameters normally
$database = $this->getParameter('database');
$host = $this->getParameter('host', 'localhost');
$password = $this->getParameter('password');
$username = $this->getParameter('username');
break;
case 'server':
// construct a connection string from existing $_SERVER values
// and extract them to local scope
$parameters =& $this->loadParameters($_SERVER);
extract($parameters);
break;
case 'env':
// construct a connection string from existing $_ENV values
// and extract them to local scope
$string =& $this->loadParameters($_ENV);
extract($parameters);
break;
default:
// who knows what the user wants...
$error = 'Invalid MySQLDatabase parameter retrieval method "%s"';
$error = sprintf($error, $method);
throw new sfDatabaseException($error);
}
// let's see if we need a persistent connection
$persistent = $this->getParameter('persistent', false);
$connect = ($persistent) ? 'mysql_pconnect' : 'mysql_connect';
if ($password == null)
{
if ($username == null)
{
$this->connection = @$connect($host);
}
else
{
$this->connection = @$connect($host, $username);
}
}
else
{
$this->connection = @$connect($host, $username, $password);
}
// make sure the connection went through
if ($this->connection === false)
{
// the connection's foobar'd
$error = 'Failed to create a MySQLDatabase connection';
throw new sfDatabaseException($error);
}
// select our database
if ($database != null && !@mysql_select_db($database, $this->connection))
{
// can't select the database
$error = 'Failed to select MySQLDatabase "%s"';
$error = sprintf($error, $database);
throw new sfDatabaseException($error);
}
// since we're not an abstraction layer, we copy the connection
// to the resource
$this->resource = $this->connection;
}
/**
* Loads connection parameters from an existing array.
*
* @return array An associative array of connection parameters
*/
protected function & loadParameters(&$array)
{
// list of available parameters
$available = array('database', 'host', 'password', 'user');
$parameters = array();
foreach ($available as $parameter)
{
$$parameter = $this->getParameter($parameter);
$parameters[$parameter] = ($$parameter != null) ? $array[$$parameter] : null;
}
return $parameters;
}
/**
* Execute the shutdown procedure
*
* @return void
*
* @throws <b>sfDatabaseException</b> If an error occurs while shutting down this database
*/
public function shutdown()
{
if ($this->connection != null)
{
@mysql_close($this->connection);
}
}
}

View File

@ -0,0 +1,88 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfPDODatabase provides connectivity for the PDO database abstraction layer.
*
* @package symfony
* @subpackage database
* @author Daniel Swarbrick (daniel@pressure.net.nz)
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfPDODatabase.class.php 3210 2007-01-10 20:28:16Z fabien $
*/
class sfPDODatabase extends sfDatabase
{
/**
* Connects to the database.
*
* @throws <b>sfDatabaseException</b> If a connection could not be created
*/
public function connect()
{
// determine how to get our parameters
$method = $this->getParameter('method', 'dsn');
// get parameters
switch ($method)
{
case 'dsn':
$dsn = $this->getParameter('dsn');
if ($dsn == null)
{
// missing required dsn parameter
$error = 'Database configuration specifies method "dsn", but is missing dsn parameter';
throw new sfDatabaseException($error);
}
break;
}
try
{
$pdo_username = $this->getParameter('username');
$pdo_password = $this->getParameter('password');
$this->connection = new PDO($dsn, $pdo_username, $pdo_password);
}
catch (PDOException $e)
{
throw new sfDatabaseException($e->getMessage());
}
// lets generate exceptions instead of silent failures
if (defined('PDO::ATTR_ERRMODE'))
{
$this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
else
{
$this->connection->setAttribute(PDO_ATTR_ERRMODE, PDO_ERRMODE_EXCEPTION);
}
}
/**
* Executes the shutdown procedure.
*
* @return void
*
* @throws <b>sfDatabaseException</b> If an error occurs while shutting down this database
*/
public function shutdown()
{
if ($this->connection !== null)
{
$this->connection = null;
}
}
}

View File

@ -0,0 +1,147 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfPostgreSQLDatabase provides connectivity for the PostgreSQL brand database.
*
* <b>Optional parameters:</b>
*
* # <b>database</b> - [none] - The database name.
* # <b>host</b> - [localhost] - The database host.
* # <b>method</b> - [normal] - How to read connection parameters.
* Possible values are normal, server, and
* env. The normal method reads them from
* the specified values. server reads them
* from $_SERVER where the keys to retrieve
* the values are what you specify the value
* as in the settings. env reads them from
* $_ENV and works like $_SERVER.
* # <b>password</b> - [none] - The database password.
* # <b>persistent</b> - [No] - Indicates that the connection should be
* persistent.
* # <b>port</b> - [none] - TCP/IP port on which PostgreSQL is
* listening.
* # <b>username</b> - [none] - The database username.
*
* @package symfony
* @subpackage database
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfPostgreSQLDatabase.class.php 3210 2007-01-10 20:28:16Z fabien $
*/
class sfPostgreSQLDatabase extends sfDatabase
{
/**
* Connects to the database.
*
* @throws <b>sfDatabaseException</b> If a connection could not be created
*/
public function connect()
{
// determine how to get our parameters
$method = $this->getParameter('method', 'normal');
// get parameters
switch ($method)
{
case 'normal':
// get parameters normally
$database = $this->getParameter('database');
$host = $this->getParameter('host');
$password = $this->getParameter('password');
$port = $this->getParameter('port');
$username = $this->getParameter('username');
// construct connection string
$string = ($database != null ? (' dbname=' .$database) : '').
($host != null ? (' host=' .$host) : '').
($password != null ? (' password=' .$password) : '').
($port != null ? (' port=' .$port) : '').
($username != null ? (' user=' .$username) : '');
break;
case 'server':
// construct a connection string from existing $_SERVER values
$string = $this->loadParameters($_SERVER);
break;
case 'env':
// construct a connection string from existing $_ENV values
$string = $this->loadParameters($_ENV);
break;
default:
// who knows what the user wants...
$error = 'Invalid PostgreSQLDatabase parameter retrieval method "%s"';
$error = sprintf($error, $method);
throw new sfDatabaseException($error);
}
// let's see if we need a persistent connection
$persistent = $this->getParameter('persistent', false);
$connect = $persistent ? 'pg_pconnect' : 'pg_connect';
$this->connection = @$connect($string);
// make sure the connection went through
if ($this->connection === false)
{
// the connection's foobar'd
$error = 'Failed to create a PostgreSQLDatabase connection';
throw new sfDatabaseException($error);
}
// since we're not an abstraction layer, we copy the connection
// to the resource
$this->resource = $this->connection;
}
/**
* Loads connection parameters from an existing array.
*
* @return string A connection string
*/
protected function loadParameters(&$array)
{
$database = $this->getParameter('database');
$host = $this->getParameter('host');
$password = $this->getParameter('password');
$port = $this->getParameter('port');
$username = $this->getParameter('username');
// construct connection string
$string = ($database != null ? (' dbname=' .$array[$database]) : '').
($host != null ? (' host=' .$array[$host]) : '').
($password != null ? (' password='.$array[$password]) : '').
($port != null ? (' port=' .$array[$port]) : '').
($username != null ? (' user=' .$array[$username]) : '');
return $string;
}
/**
* Executes the shutdown procedure.
*
* @throws <b>sfDatabaseException</b> If an error occurs while shutting down this database
*/
public function shutdown()
{
if ($this->connection != null)
{
@pg_close($this->connection);
}
}
}

View File

@ -0,0 +1,168 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfDebug provides some method to help debugging a symfony application.
*
* @package symfony
* @subpackage debug
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfDebug.class.php 3785 2007-04-13 17:26:08Z fabien $
*/
class sfDebug
{
/**
* Returns PHP information as an array.
*
* @return array An array of php information
*/
public static function phpInfoAsArray()
{
$values = array(
'php' => phpversion(),
'os' => php_uname(),
'extensions' => get_loaded_extensions(),
);
return $values;
}
/**
* Returns PHP globals variables as a sorted array.
*
* @return array PHP globals
*/
public static function globalsAsArray()
{
$values = array();
foreach (array('cookie', 'server', 'get', 'post', 'files', 'env', 'session') as $name)
{
if (!isset($GLOBALS['_'.strtoupper($name)]))
{
continue;
}
$values[$name] = array();
foreach ($GLOBALS['_'.strtoupper($name)] as $key => $value)
{
$values[$name][$key] = $value;
}
ksort($values[$name]);
}
ksort($values);
return $values;
}
/**
* Returns sfConfig variables as a sorted array.
*
* @return array sfConfig variables
*/
public static function settingsAsArray()
{
$config = sfConfig::getAll();
ksort($config);
return $config;
}
/**
* Returns request parameter holders as an array.
*
* @param sfRequest A sfRequest instance
*
* @return array The request parameter holders
*/
public static function requestAsArray($request)
{
if ($request)
{
$values = array(
'parameterHolder' => self::flattenParameterHolder($request->getParameterHolder()),
'attributeHolder' => self::flattenParameterHolder($request->getAttributeHolder()),
);
}
else
{
$values = array('parameterHolder' => array(), 'attributeHolder' => array());
}
return $values;
}
/**
* Returns response parameters as an array.
*
* @param sfResponse A sfResponse instance
*
* @return array The response parameters
*/
public static function responseAsArray($response)
{
if ($response)
{
$values = array(
'cookies' => array(),
'httpHeaders' => array(),
'parameterHolder' => self::flattenParameterHolder($response->getParameterHolder()),
);
if (method_exists($response, 'getHttpHeaders'))
{
foreach ($response->getHttpHeaders() as $key => $value)
{
$values['httpHeaders'][$key] = $value;
}
}
if (method_exists($response, 'getCookies'))
{
$cookies = array();
foreach ($response->getCookies() as $key => $value)
{
$values['cookies'][$key] = $value;
}
}
}
else
{
$values = array('cookies' => array(), 'httpHeaders' => array(), 'parameterHolder' => array());
}
return $values;
}
/**
* Returns a parameter holder as an array.
*
* @param sfParameterHolder A sfParameterHolder instance
*
* @return array The parameter holder as an array
*/
public static function flattenParameterHolder($parameterHolder)
{
$values = array();
foreach ($parameterHolder->getNamespaces() as $ns)
{
$values[$ns] = array();
foreach ($parameterHolder->getAll($ns) as $key => $value)
{
$values[$ns][$key] = $value;
}
ksort($values[$ns]);
}
ksort($values);
return $values;
}
}

View File

@ -0,0 +1,84 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfTimer class allows to time some PHP code.
*
* @package symfony
* @subpackage util
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfTimer.class.php 3411 2007-02-06 08:17:38Z fabien $
*/
class sfTimer
{
protected
$startTime = null,
$totalTime = null,
$name = '',
$calls = 0;
/**
* Creates a new sfTimer instance.
*
* @param string The name of the timer
*/
public function __construct($name = '')
{
$this->name = $name;
$this->startTimer();
}
/**
* Starts the timer.
*/
public function startTimer()
{
$this->startTime = microtime(true);
}
/**
* Stops the timer and add the amount of time since the start to the total time.
*
* @return integer Time spend for the last call
*/
public function addTime()
{
$spend = microtime(true) - $this->startTime;
$this->totalTime += $spend;
++$this->calls;
return $spend;
}
/**
* Gets the number of calls this timer has been called to time code.
*
* @return integer Number of calls
*/
public function getCalls()
{
return $this->calls;
}
/**
* Gets the total time elapsed for all calls of this timer.
*
* @return integer Time in milliseconds
*/
public function getElapsedTime()
{
if (null === $this->totalTime)
{
$this->addTime();
}
return $this->totalTime;
}
}

View File

@ -0,0 +1,61 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfTimerManager is a container for sfTimer objects.
*
* @package symfony
* @subpackage util
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfTimerManager.class.php 3211 2007-01-10 20:51:39Z fabien $
*/
class sfTimerManager
{
static public $timers = array();
/**
* Gets a sfTimer instance.
*
* It returns the timer named $name or create a new one if it does not exist.
*
* @param string The name of the timer
*
* @return sfTimer The timer instance
*/
public static function getTimer($name)
{
if (!isset(self::$timers[$name]))
{
self::$timers[$name] = new sfTimer($name);
}
self::$timers[$name]->startTimer();
return self::$timers[$name];
}
/**
* Gets all sfTimer instances stored in sfTimerManager.
*
* @return array An array of all sfTimer instances
*/
public static function getTimers()
{
return self::$timers;
}
/**
* Clears all sfTimer instances stored in sfTimerManager.
*/
public static function clearTimers()
{
self::$timers = array();
}
}

View File

@ -0,0 +1,471 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfWebDebug creates debug information for easy debugging in the browser.
*
* @package symfony
* @subpackage debug
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfWebDebug.class.php 4641 2007-07-17 11:19:54Z fabien $
*/
class sfWebDebug
{
protected
$log = array(),
$short_log = array(),
$max_priority = 1000,
$types = array(),
$last_time_log = -1;
protected static
$instance = null;
public function initialize()
{
}
/**
* Retrieves the singleton instance of this class.
*
* @return sfWebDebug A sfWebDebug implementation instance
*/
public static function getInstance()
{
if (!isset(self::$instance))
{
$class = __CLASS__;
self::$instance = new $class();
self::$instance->initialize();
}
return self::$instance;
}
/**
* Registers javascripts and stylesheets needed for the web debug toolbar.
*/
public function registerAssets()
{
$response = sfContext::getInstance()->getResponse();
// register our css and js
$response->addJavascript(sfConfig::get('sf_web_debug_web_dir').'/js/main');
$response->addStylesheet(sfConfig::get('sf_web_debug_web_dir').'/css/main');
}
/**
* Logs a short message to be displayed in the web debug toolbar.
*
* @param string The message string
*/
public function logShortMessage($message)
{
$this->short_log[] = $message;
}
/**
* Logs a message to the web debug toolbar.
*
* @param array An array of parameter
*
* @see sfWebDebugLogger
*/
public function log($logEntry)
{
// elapsed time
if ($this->last_time_log == -1)
{
$this->last_time_log = sfConfig::get('sf_timer_start');
}
$this->last_time_log = microtime(true);
// update max priority
if ($logEntry['priority'] < $this->max_priority)
{
$this->max_priority = $logEntry['priority'];
}
// update types
if (!isset($this->types[$logEntry['type']]))
{
$this->types[$logEntry['type']] = 1;
}
else
{
++$this->types[$logEntry['type']];
}
$this->log[] = $logEntry;
}
/**
* Loads helpers needed for the web debug toolbar.
*/
protected function loadHelpers()
{
sfLoader::loadHelpers(array('Helper', 'Url', 'Asset', 'Tag'));
}
/**
* Formats a log line.
*
* @param string The log line to format
*
* @return string The formatted log lin
*/
protected function formatLogLine($log_line)
{
static $constants;
if (!$constants)
{
foreach (array('sf_app_dir', 'sf_root_dir', 'sf_symfony_lib_dir', 'sf_symfony_data_dir') as $constant)
{
$constants[realpath(sfConfig::get($constant)).DIRECTORY_SEPARATOR] = $constant.DIRECTORY_SEPARATOR;
}
}
// escape HTML
$log_line = htmlentities($log_line, ENT_QUOTES, sfConfig::get('sf_charset'));
// replace constants value with constant name
$log_line = str_replace(array_keys($constants), array_values($constants), $log_line);
$log_line = sfToolkit::pregtr($log_line, array('/&quot;(.+?)&quot;/s' => '"<span class="sfWebDebugLogInfo">\\1</span>"',
'/^(.+?)\(\)\:/S' => '<span class="sfWebDebugLogInfo">\\1()</span>:',
'/line (\d+)$/' => 'line <span class="sfWebDebugLogInfo">\\1</span>'));
// special formatting for SQL lines
$log_line = preg_replace('/\b(SELECT|FROM|AS|LIMIT|ASC|COUNT|DESC|WHERE|LEFT JOIN|INNER JOIN|RIGHT JOIN|ORDER BY|GROUP BY|IN|LIKE|DISTINCT|DELETE|INSERT|INTO|VALUES)\b/', '<span class="sfWebDebugLogInfo">\\1</span>', $log_line);
// remove username/password from DSN
if (strpos($log_line, 'DSN') !== false)
{
$log_line = preg_replace("/=&gt;\s+'?[^'\s,]+'?/", "=&gt; '****'", $log_line);
}
return $log_line;
}
/**
* Returns the web debug toolbar as HTML.
*
* @return string The web debug toolbar HTML
*/
public function getResults()
{
if (!sfConfig::get('sf_web_debug'))
{
return '';
}
$this->loadHelpers();
$result = '';
// max priority
$max_priority = '';
if (sfConfig::get('sf_logging_enabled'))
{
$max_priority = $this->getPriority($this->max_priority);
}
$logs = '';
$sql_logs = array();
if (sfConfig::get('sf_logging_enabled'))
{
$logs = '<table class="sfWebDebugLogs">
<tr>
<th>#</th>
<th>type</th>
<th>message</th>
</tr>'."\n";
$line_nb = 0;
foreach ($this->log as $logEntry)
{
$log = $logEntry['message'];
$priority = $this->getPriority($logEntry['priority']);
if (strpos($type = $logEntry['type'], 'sf') === 0)
{
$type = substr($type, 2);
}
// xdebug information
$debug_info = '';
if ($logEntry['debugStack'])
{
$debug_info .= '&nbsp;<a href="#" onclick="sfWebDebugToggle(\'debug_'.$line_nb.'\'); return false;">'.image_tag(sfConfig::get('sf_web_debug_web_dir').'/images/toggle.gif').'</a><div class="sfWebDebugDebugInfo" id="debug_'.$line_nb.'" style="display:none">';
foreach ($logEntry['debugStack'] as $i => $log_line)
{
$debug_info .= '#'.$i.' &raquo; '.$this->formatLogLine($log_line).'<br/>';
}
$debug_info .= "</div>\n";
}
// format log
$log = $this->formatLogLine($log);
// sql queries log
if (preg_match('/execute(?:Query|Update).+?\:\s+(.+)$/', $log, $match))
{
$sql_logs[] .= $match[1];
}
++$line_nb;
$logs .= sprintf("<tr class='sfWebDebugLogLine sfWebDebug%s %s'><td class=\"sfWebDebugLogNumber\">%s</td><td class=\"sfWebDebugLogType\">%s&nbsp;%s</td><td>%s%s</td></tr>\n",
ucfirst($priority),
$logEntry['type'],
$line_nb,
image_tag(sfConfig::get('sf_web_debug_web_dir').'/images/'.$priority.'.png'),
$type,
$log,
$debug_info
);
}
$logs .= '</table>';
ksort($this->types);
$types = array();
foreach ($this->types as $type => $nb)
{
$types[] = '<a href="#" onclick="sfWebDebugToggleMessages(\''.$type.'\'); return false;">'.$type.'</a>';
}
}
// ignore cache link
$cacheLink = '';
if (sfConfig::get('sf_debug') && sfConfig::get('sf_cache'))
{
$self_url = $_SERVER['PHP_SELF'].((strpos($_SERVER['PHP_SELF'], '_sf_ignore_cache') === false) ? '?_sf_ignore_cache=1' : '');
$cacheLink = '<li><a href="'.$self_url.'" title="reload and ignore cache">'.image_tag(sfConfig::get('sf_web_debug_web_dir').'/images/reload.png').'</a></li>';
}
// logging information
$logLink = '';
if (sfConfig::get('sf_logging_enabled'))
{
$logLink = '<li><a href="#" onclick="sfWebDebugShowDetailsFor(\'sfWebDebugLog\'); return false;">'.image_tag(sfConfig::get('sf_web_debug_web_dir').'/images/comment.png').' logs &amp; msgs</a></li>';
}
// database information
$dbInfo = '';
$dbInfoDetails = '';
if ($sql_logs)
{
$dbInfo = '<li><a href="#" onclick="sfWebDebugShowDetailsFor(\'sfWebDebugDatabaseDetails\'); return false;">'.image_tag(sfConfig::get('sf_web_debug_web_dir').'/images/database.png').' '.count($sql_logs).'</a></li>';
$dbInfoDetails = '
<div id="sfWebDebugDatabaseLogs">
<ol><li>'.implode("</li>\n<li>", $sql_logs).'</li></ol>
</div>
';
}
// memory used
$memoryInfo = '';
if (sfConfig::get('sf_debug') && function_exists('memory_get_usage'))
{
$total_memory = sprintf('%.1f', (memory_get_usage() / 1024));
$memoryInfo = '<li>'.image_tag(sfConfig::get('sf_web_debug_web_dir').'/images/memory.png').' '.$total_memory.' KB</li>';
}
// total time elapsed
$timeInfo = '';
if (sfConfig::get('sf_debug'))
{
$total_time = (microtime(true) - sfConfig::get('sf_timer_start')) * 1000;
$total_time = sprintf(($total_time <= 1) ? '%.2f' : '%.0f', $total_time);
$timeInfo = '<li class="last"><a href="#" onclick="sfWebDebugShowDetailsFor(\'sfWebDebugTimeDetails\'); return false;">'.image_tag(sfConfig::get('sf_web_debug_web_dir').'/images/time.png').' '.$total_time.' ms</a></li>';
}
// timers
$timeInfoDetails = '<table class="sfWebDebugLogs" style="width: 300px"><tr><th>type</th><th>calls</th><th>time (ms)</th></tr>';
foreach (sfTimerManager::getTimers() as $name => $timer)
{
$timeInfoDetails .= sprintf('<tr><td class="sfWebDebugLogType">%s</td><td class="sfWebDebugLogNumber" style="text-align: right">%d</td><td style="text-align: right">%.2f</td></tr>', $name, $timer->getCalls(), $timer->getElapsedTime() * 1000);
}
$timeInfoDetails .= '</table>';
// short log messages
$short_messages = '';
if ($this->short_log)
{
$short_messages = '<ul id="sfWebDebugShortMessages"><li>&raquo;&nbsp;'.implode('</li><li>&raquo&nbsp;', $this->short_log).'</li></ul>';
}
// logs
$logInfo = '';
if (sfConfig::get('sf_logging_enabled'))
{
$logInfo .= $short_messages.'
<ul id="sfWebDebugLogMenu">
<li><a href="#" onclick="sfWebDebugToggleAllLogLines(true, \'sfWebDebugLogLine\'); return false;">[all]</a></li>
<li><a href="#" onclick="sfWebDebugToggleAllLogLines(false, \'sfWebDebugLogLine\'); return false;">[none]</a></li>
<li><a href="#" onclick="sfWebDebugShowOnlyLogLines(\'info\'); return false;">'.image_tag(sfConfig::get('sf_web_debug_web_dir').'/images/info.png').'</a></li>
<li><a href="#" onclick="sfWebDebugShowOnlyLogLines(\'warning\'); return false;">'.image_tag(sfConfig::get('sf_web_debug_web_dir').'/images/warning.png').'</a></li>
<li><a href="#" onclick="sfWebDebugShowOnlyLogLines(\'error\'); return false;">'.image_tag(sfConfig::get('sf_web_debug_web_dir').'/images/error.png').'</a></li>
<li>'.implode("</li>\n<li>", $types).'</li>
</ul>
<div id="sfWebDebugLogLines">'.$logs.'</div>
';
}
$result .= '
<div id="sfWebDebug">
<div id="sfWebDebugBar" class="sfWebDebug'.ucfirst($max_priority).'">
<a href="#" onclick="sfWebDebugToggleMenu(); return false;">'.image_tag(sfConfig::get('sf_web_debug_web_dir').'/images/sf.png').'</a>
<ul id="sfWebDebugDetails" class="menu">
<li>'.file_get_contents(sfConfig::get('sf_symfony_lib_dir').'/VERSION').'</li>
<li><a href="#" onclick="sfWebDebugShowDetailsFor(\'sfWebDebugConfig\'); return false;">'.image_tag(sfConfig::get('sf_web_debug_web_dir').'/images/config.png').' vars &amp; config</a></li>
'.$cacheLink.'
'.$logLink.'
'.$dbInfo.'
'.$memoryInfo.'
'.$timeInfo.'
</ul>
<a href="#" onclick="document.getElementById(\'sfWebDebug\').style.display=\'none\'; return false;">'.image_tag(sfConfig::get('sf_web_debug_web_dir').'/images/close.png').'</a>
</div>
<div id="sfWebDebugLog" class="sfWebDebugTop" style="display: none"><h1>Log and debug messages</h1>'.$logInfo.'</div>
<div id="sfWebDebugConfig" class="sfWebDebugTop" style="display: none"><h1>Configuration and request variables</h1>'.$this->getCurrentConfigAsHtml().'</div>
<div id="sfWebDebugDatabaseDetails" class="sfWebDebugTop" style="display: none"><h1>SQL queries</h1>'.$dbInfoDetails.'</div>
<div id="sfWebDebugTimeDetails" class="sfWebDebugTop" style="display: none"><h1>Timers</h1>'.$timeInfoDetails.'</div>
</div>
';
return $result;
}
/**
* Returns the current configuration as HTML.
*
* @return string The current configuration as HTML
*/
protected function getCurrentConfigAsHtml()
{
$config = array(
'debug' => sfConfig::get('sf_debug') ? 'on' : 'off',
'xdebug' => (extension_loaded('xdebug')) ? 'on' : 'off',
'logging' => sfConfig::get('sf_logging_enabled') ? 'on' : 'off',
'cache' => sfConfig::get('sf_cache') ? 'on' : 'off',
'eaccelerator' => (extension_loaded('eaccelerator') && ini_get('eaccelerator.enable')) ? 'on' : 'off',
'apc' => (extension_loaded('apc') && ini_get('apc.enabled')) ? 'on' : 'off',
'xcache' => (extension_loaded('xcache') && ini_get('xcache.cacher')) ? 'on' : 'off',
'compression' => sfConfig::get('sf_compressed') ? 'on' : 'off',
'syck' => (extension_loaded('syck')) ? 'on' : 'off',
);
$result = '<ul id="sfWebDebugConfigSummary">';
foreach ($config as $key => $value)
{
$result .= '<li class="is'.$value.''.($key == 'syck' ? ' last' : '').'">'.$key.'</li>';
}
$result .= '</ul>';
$context = sfContext::getInstance();
$result .= $this->formatArrayAsHtml('request', sfDebug::requestAsArray($context->getRequest()));
$result .= $this->formatArrayAsHtml('response', sfDebug::responseAsArray($context->getResponse()));
$result .= $this->formatArrayAsHtml('settings', sfDebug::settingsAsArray());
$result .= $this->formatArrayAsHtml('globals', sfDebug::globalsAsArray());
$result .= $this->formatArrayAsHtml('php', sfDebug::phpInfoAsArray());
return $result;
}
/**
* Converts an array to HTML.
*
* @param string The identifier to use
* @param array The array of values
*
* @return string An HTML string
*/
protected function formatArrayAsHtml($id, $values)
{
$id = ucfirst(strtolower($id));
$content = '
<h2>'.$id.' <a href="#" onclick="sfWebDebugToggle(\'sfWebDebug'.$id.'\'); return false;">'.image_tag(sfConfig::get('sf_web_debug_web_dir').'/images/toggle.gif').'</a></h2>
<div id="sfWebDebug'.$id.'" style="display: none"><pre>'.htmlentities(@sfYaml::Dump($values), ENT_QUOTES, sfConfig::get('sf_charset')).'</pre></div>
';
return $content;
}
/**
* Decorates a chunk of HTML with cache information.
*
* @param string The internalUri representing the content
* @param string The HTML content
* @param boolean true if the content is new in the cache, false otherwise
*
* @return string The decorated HTML string
*/
public function decorateContentWithDebug($internalUri, $content, $new = false)
{
$context = sfContext::getInstance();
// don't decorate if not html or if content is null
if (!sfConfig::get('sf_web_debug') || !$content || false === strpos($context->getResponse()->getContentType(), 'html'))
{
return $content;
}
$cache = $context->getViewCacheManager();
$this->loadHelpers();
$bg_color = $new ? '#9ff' : '#ff9';
$last_modified = $cache->lastModified($internalUri);
$id = md5($internalUri);
$content = '
<div id="main_'.$id.'" class="sfWebDebugActionCache" style="border: 1px solid #f00">
<div id="sub_main_'.$id.'" class="sfWebDebugCache" style="background-color: '.$bg_color.'; border-right: 1px solid #f00; border-bottom: 1px solid #f00;">
<div style="height: 16px; padding: 2px"><a href="#" onclick="sfWebDebugToggle(\''.$id.'\'); return false;"><strong>cache information</strong></a>&nbsp;<a href="#" onclick="sfWebDebugToggle(\'sub_main_'.$id.'\'); document.getElementById(\'main_'.$id.'\').style.border = \'none\'; return false;">'.image_tag(sfConfig::get('sf_web_debug_web_dir').'/images/close.png').'</a>&nbsp;</div>
<div style="padding: 2px; display: none" id="'.$id.'">
[uri]&nbsp;'.$internalUri.'<br />
[life&nbsp;time]&nbsp;'.$cache->getLifeTime($internalUri).'&nbsp;seconds<br />
[last&nbsp;modified]&nbsp;'.(time() - $last_modified).'&nbsp;seconds<br />
&nbsp;<br />&nbsp;
</div>
</div><div>
'.$content.'
</div></div>
';
return $content;
}
/**
* Converts a proprity value to a string.
*
* @param integer The priority value
*
* @return string The priority as a string
*/
protected function getPriority($value)
{
if ($value >= 6)
{
return 'info';
}
else if ($value >= 4)
{
return 'warning';
}
else
{
return 'error';
}
}
}

View File

@ -0,0 +1,34 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfActionException is thrown when an error occurs in an action.
*
* @package symfony
* @subpackage exception
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfActionException.class.php 3243 2007-01-12 14:22:50Z fabien $
*/
class sfActionException extends sfException
{
/**
* Class constructor.
*
* @param string The error message
* @param int The error code
*/
public function __construct($message = null, $code = 0)
{
$this->setName('sfActionException');
parent::__construct($message, $code);
}
}

View File

@ -0,0 +1,34 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfAutoloadException is thrown when a class that has been required cannot be loaded.
*
* @package symfony
* @subpackage exception
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfAutoloadException.class.php 3243 2007-01-12 14:22:50Z fabien $
*/
class sfAutoloadException extends sfException
{
/**
* Class constructor.
*
* @param string The error message
* @param int The error code
*/
public function __construct($message = null, $code = 0)
{
$this->setName('sfAutoloadException');
parent::__construct($message, $code);
}
}

View File

@ -0,0 +1,34 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfCacheException is thrown when ConfigCache fails to execute properly.
*
* @package symfony
* @subpackage exception
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfCacheException.class.php 3243 2007-01-12 14:22:50Z fabien $
*/
class sfCacheException extends sfException
{
/**
* Class constructor.
*
* @param string The error message
* @param int The error code
*/
public function __construct($message = null, $code = 0)
{
$this->setName('sfCacheException');
parent::__construct($message, $code);
}
}

View File

@ -0,0 +1,35 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfConfigurationException is thrown when the framework finds an error in a
* configuration setting.
*
* @package symfony
* @subpackage exception
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfConfigurationException.class.php 3243 2007-01-12 14:22:50Z fabien $
*/
class sfConfigurationException extends sfException
{
/**
* Class constructor.
*
* @param string The error message
* @param int The error code
*/
public function __construct($message = null, $code = 0)
{
$this->setName('sfConfigurationException');
parent::__construct($message, $code);
}
}

View File

@ -0,0 +1,33 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfContextException is thrown when an instance of the context has not been created.
*
* @package symfony
* @subpackage exception
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfContextException.class.php 3243 2007-01-12 14:22:50Z fabien $
*/
class sfContextException extends sfException
{
/**
* Class constructor.
*
* @param string The error message
* @param int The error code
*/
public function __construct($message = null, $code = 0)
{
parent::__construct($message, $code);
$this->setName('sfContextException');
}
}

View File

@ -0,0 +1,35 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfControllerException is thrown when a requested Controller implementation
* doesn't exist.
*
* @package symfony
* @subpackage exception
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfControllerException.class.php 3243 2007-01-12 14:22:50Z fabien $
*/
class sfControllerException extends sfException
{
/**
* Class constructor.
*
* @param string The error message
* @param int The error code
*/
public function __construct($message = null, $code = 0)
{
$this->setName('sfControllerException');
parent::__construct($message, $code);
}
}

View File

@ -0,0 +1,34 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfDatabaseException is thrown when a database related error occurs.
*
* @package symfony
* @subpackage exception
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfDatabaseException.class.php 3243 2007-01-12 14:22:50Z fabien $
*/
class sfDatabaseException extends sfException
{
/**
* Class constructor.
*
* @param string The error message
* @param int The error code
*/
public function __construct($message = null, $code = 0)
{
$this->setName('sfDatabaseException');
parent::__construct($message, $code);
}
}

View File

@ -0,0 +1,42 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfError404Exception is thrown when a 404 error occurs in an action.
*
* @package symfony
* @subpackage exception
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfError404Exception.class.php 3243 2007-01-12 14:22:50Z fabien $
*/
class sfError404Exception extends sfException
{
/**
* Class constructor.
*
* @param string The error message
* @param int The error code
*/
public function __construct($message = null, $code = 0)
{
$this->setName('sfError404Exception');
parent::__construct($message, $code);
}
/**
* Forwards to the 404 action.
*
* @param Exception An Exception implementation instance
*/
public function printStackTrace($exception = null)
{
sfContext::getInstance()->getController()->forward(sfConfig::get('sf_error_404_module'), sfConfig::get('sf_error_404_action'));
}
}

View File

@ -0,0 +1,295 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfException is the base class for all symfony related exceptions and
* provides an additional method for printing up a detailed view of an
* exception.
*
* @package symfony
* @subpackage exception
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfException.class.php 3243 2007-01-12 14:22:50Z fabien $
*/
class sfException extends Exception
{
protected
$name = null;
/**
* Class constructor.
*
* @param string The error message
* @param int The error code
*/
public function __construct($message = null, $code = 0)
{
if ($this->getName() === null)
{
$this->setName('sfException');
}
parent::__construct($message, $code);
if (sfConfig::get('sf_logging_enabled') && $this->getName() != 'sfStopException')
{
sfLogger::getInstance()->err('{'.$this->getName().'} '.$message);
}
}
/**
* Retrieves the name of this exception.
*
* @return string This exception's name
*/
public function getName()
{
return $this->name;
}
/**
* Prints the stack trace for this exception.
*
* @param Exception An Exception implementation instance
*/
public function printStackTrace($exception = null)
{
if (!$exception)
{
$exception = $this;
}
// don't print message if it is an sfStopException exception
if (method_exists($exception, 'getName') && $exception->getName() == 'sfStopException')
{
if (!sfConfig::get('sf_test'))
{
exit(1);
}
return;
}
if (class_exists('sfMixer', false))
{
foreach (sfMixer::getCallables('sfException:printStackTrace:printStackTrace') as $callable)
{
$ret = call_user_func($callable, $this, $exception);
if ($ret)
{
if (!sfConfig::get('sf_test'))
{
exit(1);
}
return;
}
}
}
if (!sfConfig::get('sf_test'))
{
header('HTTP/1.0 500 Internal Server Error');
// clean current output buffer
while (@ob_end_clean());
ob_start(sfConfig::get('sf_compressed') ? 'ob_gzhandler' : '');
}
// send an error 500 if not in debug mode
if (!sfConfig::get('sf_debug'))
{
error_log($exception->getMessage());
$file = sfConfig::get('sf_web_dir').'/errors/error500.php';
include(is_readable($file) ? $file : sfConfig::get('sf_symfony_data_dir').'/web/errors/error500.php');
if (!sfConfig::get('sf_test'))
{
exit(1);
}
return;
}
$message = null !== $exception->getMessage() ? $exception->getMessage() : 'n/a';
$name = get_class($exception);
$format = 0 == strncasecmp(PHP_SAPI, 'cli', 3) ? 'plain' : 'html';
$traces = $this->getTraces($exception, $format);
// extract error reference from message
$error_reference = '';
if (preg_match('/\[(err\d+)\]/', $message, $matches))
{
$error_reference = $matches[1];
}
// dump main objects values
$sf_settings = '';
$settingsTable = $requestTable = $responseTable = $globalsTable = '';
if (class_exists('sfContext', false) && sfContext::hasInstance())
{
$context = sfContext::getInstance();
$settingsTable = $this->formatArrayAsHtml(sfDebug::settingsAsArray());
$requestTable = $this->formatArrayAsHtml(sfDebug::requestAsArray($context->getRequest()));
$responseTable = $this->formatArrayAsHtml(sfDebug::responseAsArray($context->getResponse()));
$globalsTable = $this->formatArrayAsHtml(sfDebug::globalsAsArray());
}
include(sfConfig::get('sf_symfony_data_dir').'/data/exception.'.($format == 'html' ? 'php' : 'txt'));
// if test, do not exit
if (!sfConfig::get('sf_test'))
{
exit(1);
}
}
/**
* Returns an array of exception traces.
*
* @param Exception An Exception implementation instance
* @param string The trace format (plain or html)
*
* @return array An array of traces
*/
public function getTraces($exception, $format = 'plain')
{
$traceData = $exception->getTrace();
array_unshift($traceData, array(
'function' => '',
'file' => $exception->getFile() != null ? $exception->getFile() : 'n/a',
'line' => $exception->getLine() != null ? $exception->getLine() : 'n/a',
'args' => array(),
));
$traces = array();
if ($format == 'html')
{
$lineFormat = 'at <strong>%s%s%s</strong>(%s)<br />in <em>%s</em> line %s <a href="#" onclick="toggle(\'%s\'); return false;">...</a><br /><ul id="%s" style="display: %s">%s</ul>';
}
else
{
$lineFormat = 'at %s%s%s(%s) in %s line %s';
}
for ($i = 0, $count = count($traceData); $i < $count; $i++)
{
$line = isset($traceData[$i]['line']) ? $traceData[$i]['line'] : 'n/a';
$file = isset($traceData[$i]['file']) ? $traceData[$i]['file'] : 'n/a';
$shortFile = preg_replace(array('#^'.preg_quote(sfConfig::get('sf_root_dir')).'#', '#^'.preg_quote(realpath(sfConfig::get('sf_symfony_lib_dir'))).'#'), array('SF_ROOT_DIR', 'SF_SYMFONY_LIB_DIR'), $file);
$args = isset($traceData[$i]['args']) ? $traceData[$i]['args'] : array();
$traces[] = sprintf($lineFormat,
(isset($traceData[$i]['class']) ? $traceData[$i]['class'] : ''),
(isset($traceData[$i]['type']) ? $traceData[$i]['type'] : ''),
$traceData[$i]['function'],
$this->formatArgs($args, false, $format),
$shortFile,
$line,
'trace_'.$i,
'trace_'.$i,
$i == 0 ? 'block' : 'none',
$this->fileExcerpt($file, $line)
);
}
return $traces;
}
/**
* Returns an HTML version of an array as YAML.
*
* @param array The values array
*
* @return string An HTML string
*/
protected function formatArrayAsHtml($values)
{
return '<pre>'.@sfYaml::Dump($values).'</pre>';
}
/**
* Returns an excerpt of a code file around the given line number.
*
* @param string A file path
* @param int The selected line number
*
* @return string An HTML string
*/
protected function fileExcerpt($file, $line)
{
if (is_readable($file))
{
$content = preg_split('#<br />#', highlight_file($file, true));
$lines = array();
for ($i = max($line - 3, 1), $max = min($line + 3, count($content)); $i <= $max; $i++)
{
$lines[] = '<li'.($i == $line ? ' class="selected"' : '').'>'.$content[$i - 1].'</li>';
}
return '<ol start="'.max($line - 3, 1).'">'.implode("\n", $lines).'</ol>';
}
}
/**
* Formats an array as a string.
*
* @param array The argument array
* @param boolean
* @param string The format string (html or plain)
*
* @return string
*/
protected function formatArgs($args, $single = false, $format = 'html')
{
$result = array();
$single and $args = array($args);
foreach ($args as $key => $value)
{
if (is_object($value))
{
$result[] = ($format == 'html' ? '<em>object</em>' : 'object').'(\''.get_class($value).'\')';
}
else if (is_array($value))
{
$result[] = ($format == 'html' ? '<em>array</em>' : 'array').'('.self::formatArgs($value).')';
}
else if ($value === null)
{
$result[] = '<em>null</em>';
}
else if (!is_int($key))
{
$result[] = "'$key' =&gt; '$value'";
}
else
{
$result[] = "'".$value."'";
}
}
return implode(', ', $result);
}
/**
* Sets the name of this exception.
*
* @param string An exception name
*/
protected function setName($name)
{
$this->name = $name;
}
}

View File

@ -0,0 +1,35 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfFactoryException is thrown when an error occurs while attempting to create
* a new factory implementation instance.
*
* @package symfony
* @subpackage exception
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfFactoryException.class.php 3243 2007-01-12 14:22:50Z fabien $
*/
class sfFactoryException extends sfException
{
/**
* Class constructor.
*
* @param string The error message
* @param int The error code
*/
public function __construct($message = null, $code = 0)
{
$this->setName('sfFactoryException');
parent::__construct($message, $code);
}
}

View File

@ -0,0 +1,34 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfFileException is thrown when an error occurs while moving an uploaded file.
*
* @package symfony
* @subpackage exception
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfFileException.class.php 3243 2007-01-12 14:22:50Z fabien $
*/
class sfFileException extends sfException
{
/**
* Class constructor.
*
* @param string The error message
* @param int The error code
*/
public function __construct($message = null, $code = 0)
{
$this->setName('sfFileException');
parent::__construct($message, $code);
}
}

View File

@ -0,0 +1,35 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfFilterException is thrown when an error occurs while attempting to initialize
* or execute a filter.
*
* @package symfony
* @subpackage exception
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfFilterException.class.php 3243 2007-01-12 14:22:50Z fabien $
*/
class sfFilterException extends sfException
{
/**
* Class constructor.
*
* @param string The error message
* @param int The error code
*/
public function __construct($message = null, $code = 0)
{
$this->setName('sfFilterException');
parent::__construct($message, $code);
}
}

View File

@ -0,0 +1,35 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfForwardException is thrown when an error occurs while attempting to forward
* the request.
*
* @package symfony
* @subpackage exception
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfForwardException.class.php 3243 2007-01-12 14:22:50Z fabien $
*/
class sfForwardException extends sfException
{
/**
* Class constructor.
*
* @param string The error message
* @param int The error code
*/
public function __construct($message = null, $code = 0)
{
$this->setName('sfForwardException');
parent::__construct($message, $code);
}
}

View File

@ -0,0 +1,34 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfInitializationException is thrown when an initialization procedure fails.
*
* @package symfony
* @subpackage exception
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfInitializationException.class.php 3243 2007-01-12 14:22:50Z fabien $
*/
class sfInitializationException extends sfException
{
/**
* Class constructor.
*
* @param string The error message
* @param int The error code
*/
public function __construct($message = null, $code = 0)
{
$this->setName('sfInitializationException');
parent::__construct($message, $code);
}
}

View File

@ -0,0 +1,35 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfParseException is thrown when a parsing procedure fails to complete
* successfully.
*
* @package symfony
* @subpackage exception
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfParseException.class.php 3243 2007-01-12 14:22:50Z fabien $
*/
class sfParseException extends sfException
{
/**
* Class constructor.
*
* @param string The error message
* @param int The error code
*/
public function __construct($message = null, $code = 0)
{
$this->setName('sfParseException');
parent::__construct($message, $code);
}
}

View File

@ -0,0 +1,34 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfRenderException is thrown when a view's pre-render check fails.
*
* @package symfony
* @subpackage exception
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfRenderException.class.php 3243 2007-01-12 14:22:50Z fabien $
*/
class sfRenderException extends sfException
{
/**
* Class constructor.
*
* @param string The error message
* @param int The error code
*/
public function __construct($message = null, $code = 0)
{
$this->setName('sfRenderException');
parent::__construct($message, $code);
}
}

View File

@ -0,0 +1,34 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfSecurityException is thrown when a security related error occurs.
*
* @package symfony
* @subpackage exception
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfSecurityException.class.php 3243 2007-01-12 14:22:50Z fabien $
*/
class sfSecurityException extends sfException
{
/**
* Class constructor.
*
* @param string The error message
* @param int The error code
*/
public function __construct($message = null, $code = 0)
{
$this->setName('sfSecurityException');
parent::__construct($message, $code);
}
}

View File

@ -0,0 +1,46 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfStopException is thrown when you want to stop action flow.
*
* @package symfony
* @subpackage exception
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfStopException.class.php 3243 2007-01-12 14:22:50Z fabien $
*/
class sfStopException extends sfException
{
/**
* Class constructor.
*
* @param string The error message
* @param int The error code
*/
public function __construct($message = null, $code = 0)
{
$this->setName('sfStopException');
// disable xdebug to avoid backtrace in error log
if (function_exists('xdebug_disable'))
{
xdebug_disable();
}
parent::__construct($message, $code);
}
/**
* Stops the current action.
*/
public function printStackTrace($exception = null)
{
}
}

View File

@ -0,0 +1,35 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfStorageException is thrown when a requested sfStorage implementation doesn't
* exist or data cannot be read from or written to the storage.
*
* @package symfony
* @subpackage exception
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfStorageException.class.php 3243 2007-01-12 14:22:50Z fabien $
*/
class sfStorageException extends sfException
{
/**
* Class constructor.
*
* @param string The error message
* @param int The error code
*/
public function __construct($message = null, $code = 0)
{
$this->setName('sfStorageException');
parent::__construct($message, $code);
}
}

View File

@ -0,0 +1,34 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfValidatorException is thrown when an error occurs in a validator.
*
* @package symfony
* @subpackage exception
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfValidatorException.class.php 3243 2007-01-12 14:22:50Z fabien $
*/
class sfValidatorException extends sfException
{
/**
* Class constructor.
*
* @param string The error message
* @param int The error code
*/
public function __construct($message = null, $code = 0)
{
$this->setName('sfValidatorException');
parent::__construct($message, $code);
}
}

View File

@ -0,0 +1,34 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfViewException is thrown when an error occurs in a view.
*
* @package symfony
* @subpackage exception
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfViewException.class.php 3243 2007-01-12 14:22:50Z fabien $
*/
class sfViewException extends sfException
{
/**
* Class constructor.
*
* @param string The error message
* @param int The error code
*/
public function __construct($message = null, $code = 0)
{
$this->setName('sfViewException');
parent::__construct($message, $code);
}
}

View File

@ -0,0 +1,87 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfBasicSecurityFilter checks security by calling the getCredential() method
* of the action. Once the credential has been acquired, sfBasicSecurityFilter
* verifies the user has the same credential by calling the hasCredential()
* method of SecurityUser.
*
* @package symfony
* @subpackage filter
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfBasicSecurityFilter.class.php 5001 2007-09-08 08:34:34Z fabien $
*/
class sfBasicSecurityFilter extends sfSecurityFilter
{
/**
* Executes this filter.
*
* @param sfFilterChain A sfFilterChain instance
*/
public function execute($filterChain)
{
// get the cool stuff
$context = $this->getContext();
$controller = $context->getController();
$user = $context->getUser();
// get the current action instance
$actionEntry = $controller->getActionStack()->getLastEntry();
$actionInstance = $actionEntry->getActionInstance();
// disable security on [sf_login_module] / [sf_login_action]
if (
(sfConfig::get('sf_login_module') == $context->getModuleName()) && (sfConfig::get('sf_login_action') == $context->getActionName())
||
(sfConfig::get('sf_secure_module') == $context->getModuleName()) && (sfConfig::get('sf_secure_action') == $context->getActionName())
)
{
$filterChain->execute();
return;
}
// get the credential required for this action
$credential = $actionInstance->getCredential();
// for this filter, the credentials are a simple privilege array
// where the first index is the privilege name and the second index
// is the privilege namespace
//
// NOTE: the nice thing about the Action class is that getCredential()
// is vague enough to describe any level of security and can be
// used to retrieve such data and should never have to be altered
if ($user->isAuthenticated())
{
// the user is authenticated
if ($credential === null || $user->hasCredential($credential))
{
// the user has access, continue
$filterChain->execute();
}
else
{
// the user doesn't have access, exit stage left
$controller->forward(sfConfig::get('sf_secure_module'), sfConfig::get('sf_secure_action'));
throw new sfStopException();
}
}
else
{
// the user is not authenticated
$controller->forward(sfConfig::get('sf_login_module'), sfConfig::get('sf_login_action'));
throw new sfStopException();
}
}
}

View File

@ -0,0 +1,290 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfCacheFilter deals with page caching and action caching.
*
* @package symfony
* @subpackage filter
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfCacheFilter.class.php 5145 2007-09-16 14:59:51Z fabien $
*/
class sfCacheFilter extends sfFilter
{
protected
$cacheManager = null,
$request = null,
$response = null,
$cache = array();
/**
* Initializes this Filter.
*
* @param sfContext The current application context
* @param array An associative array of initialization parameters
*
* @return bool true, if initialization completes successfully, otherwise false
*
* @throws <b>sfInitializationException</b> If an error occurs while initializing this Filter
*/
public function initialize($context, $parameters = array())
{
parent::initialize($context, $parameters);
$this->cacheManager = $context->getViewCacheManager();
$this->request = $context->getRequest();
$this->response = $context->getResponse();
}
/**
* Executes this filter.
*
* @param sfFilterChain A sfFilterChain instance
*/
public function execute($filterChain)
{
// execute this filter only once, if cache is set and no GET or POST parameters
if (!sfConfig::get('sf_cache') || count($_GET) || count($_POST))
{
$filterChain->execute();
return;
}
if ($this->executeBeforeExecution())
{
$filterChain->execute();
}
$this->executeBeforeRendering();
}
public function executeBeforeExecution()
{
// register our cache configuration
$this->cacheManager->registerConfiguration($this->getContext()->getModuleName());
$uri = sfRouting::getInstance()->getCurrentInternalUri();
// page cache
$this->cache[$uri] = array('page' => false, 'action' => false);
$cacheable = $this->cacheManager->isCacheable($uri);
if ($cacheable)
{
if ($this->cacheManager->withLayout($uri))
{
$inCache = $this->getPageCache($uri);
$this->cache[$uri]['page'] = !$inCache;
if ($inCache)
{
// page is in cache, so no need to run execution filter
return false;
}
}
else
{
$inCache = $this->getActionCache($uri);
$this->cache[$uri]['action'] = !$inCache;
}
}
return true;
}
/**
* Executes this filter.
*
* @param sfFilterChain A sfFilterChain instance.
*/
public function executeBeforeRendering()
{
// cache only 200 HTTP status
if (200 != $this->response->getStatusCode())
{
return;
}
$uri = sfRouting::getInstance()->getCurrentInternalUri();
// save page in cache
if ($this->cache[$uri]['page'])
{
// set some headers that deals with cache
$lifetime = $this->cacheManager->getClientLifeTime($uri, 'page');
$this->response->setHttpHeader('Last-Modified', $this->response->getDate(time()), false);
$this->response->setHttpHeader('Expires', $this->response->getDate(time() + $lifetime), false);
$this->response->addCacheControlHttpHeader('max-age', $lifetime);
// set Vary headers
foreach ($this->cacheManager->getVary($uri, 'page') as $vary)
{
$this->response->addVaryHttpHeader($vary);
}
$this->setPageCache($uri);
}
else if ($this->cache[$uri]['action'])
{
// save action in cache
$this->setActionCache($uri);
}
// remove PHP automatic Cache-Control and Expires headers if not overwritten by application or cache
if ($this->response->hasHttpHeader('Last-Modified') || sfConfig::get('sf_etag'))
{
// FIXME: these headers are set by PHP sessions (see session_cache_limiter())
$this->response->setHttpHeader('Cache-Control', null, false);
$this->response->setHttpHeader('Expires', null, false);
$this->response->setHttpHeader('Pragma', null, false);
}
// Etag support
if (sfConfig::get('sf_etag'))
{
$etag = md5($this->response->getContent());
$this->response->setHttpHeader('ETag', '"'.$etag.'"');
if ($this->request->getHttpHeader('IF_NONE_MATCH') == $etag)
{
$this->response->setStatusCode(304);
$this->response->setHeaderOnly(true);
if (sfConfig::get('sf_logging_enabled'))
{
$this->getContext()->getLogger()->info('{sfFilter} ETag matches If-None-Match (send 304)');
}
}
}
// conditional GET support
// never in debug mode
if ($this->response->hasHttpHeader('Last-Modified') && !sfConfig::get('sf_debug'))
{
$last_modified = $this->response->getHttpHeader('Last-Modified');
$last_modified = $last_modified[0];
if ($this->request->getHttpHeader('IF_MODIFIED_SINCE') == $last_modified)
{
$this->response->setStatusCode(304);
$this->response->setHeaderOnly(true);
if (sfConfig::get('sf_logging_enabled'))
{
$this->getContext()->getLogger()->info('{sfFilter} Last-Modified matches If-Modified-Since (send 304)');
}
}
}
}
/**
* Sets a page template in the cache.
*
* @param string The internal URI
*/
protected function setPageCache($uri)
{
if ($this->getContext()->getController()->getRenderMode() != sfView::RENDER_CLIENT)
{
return;
}
// save content in cache
$this->cacheManager->set(serialize($this->response), $uri);
if (sfConfig::get('sf_web_debug'))
{
$content = sfWebDebug::getInstance()->decorateContentWithDebug($uri, $this->response->getContent(), true);
$this->response->setContent($content);
}
}
/**
* Gets a page template from the cache.
*
* @param string The internal URI
*/
protected function getPageCache($uri)
{
$context = $this->getContext();
// get the current action information
$moduleName = $context->getModuleName();
$actionName = $context->getActionName();
$retval = $this->cacheManager->get($uri);
if ($retval === null)
{
return false;
}
$cachedResponse = unserialize($retval);
$cachedResponse->setContext($context);
$controller = $context->getController();
if ($controller->getRenderMode() == sfView::RENDER_VAR)
{
$controller->getActionStack()->getLastEntry()->setPresentation($cachedResponse->getContent());
$this->response->setContent('');
}
else
{
$context->setResponse($cachedResponse);
$this->response = $this->getContext()->getResponse();
if (sfConfig::get('sf_web_debug'))
{
$content = sfWebDebug::getInstance()->decorateContentWithDebug($uri, $this->response->getContent(), false);
$this->response->setContent($content);
}
}
return true;
}
/**
* Sets an action template in the cache.
*
* @param string The internal URI
*/
protected function setActionCache($uri)
{
$content = $this->response->getParameter($uri.'_action', null, 'symfony/cache');
if ($content !== null)
{
$this->cacheManager->set($content, $uri);
}
}
/**
* Gets an action template from the cache.
*
* @param string The internal URI
*/
protected function getActionCache($uri)
{
// retrieve content from cache
$retval = $this->cacheManager->get($uri);
if ($retval && sfConfig::get('sf_web_debug'))
{
$cache = unserialize($retval);
$this->response->mergeProperties($cache['response']);
$cache['content'] = sfWebDebug::getInstance()->decorateContentWithDebug($uri, $cache['content'], false);
$retval = serialize($cache);
}
$this->response->setParameter('current_key', $uri.'_action', 'symfony/cache/current');
$this->response->setParameter($uri.'_action', $retval, 'symfony/cache');
return $retval ? true : false;
}
}

View File

@ -0,0 +1,58 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfCommonFilter automatically adds javascripts and stylesheets information in the sfResponse content.
*
* @package symfony
* @subpackage filter
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfCommonFilter.class.php 3244 2007-01-12 14:46:11Z fabien $
*/
class sfCommonFilter extends sfFilter
{
/**
* Executes this filter.
*
* @param sfFilterChain A sfFilterChain instance
*/
public function execute($filterChain)
{
// execute next filter
$filterChain->execute();
// execute this filter only once
$response = $this->getContext()->getResponse();
// include javascripts and stylesheets
$content = $response->getContent();
if (false !== ($pos = strpos($content, '</head>')))
{
sfLoader::loadHelpers(array('Tag', 'Asset'));
$html = '';
if (!$response->getParameter('javascripts_included', false, 'symfony/view/asset'))
{
$html .= get_javascripts($response);
}
if (!$response->getParameter('stylesheets_included', false, 'symfony/view/asset'))
{
$html .= get_stylesheets($response);
}
if ($html)
{
$response->setContent(substr($content, 0, $pos).$html.substr($content, $pos));
}
}
$response->setParameter('javascripts_included', false, 'symfony/view/asset');
$response->setParameter('stylesheets_included', false, 'symfony/view/asset');
}
}

View File

@ -0,0 +1,204 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfExecutionFilter is the last filter registered for each filter chain. This
* filter does all action and view execution.
*
* @package symfony
* @subpackage filter
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfExecutionFilter.class.php 3244 2007-01-12 14:46:11Z fabien $
*/
class sfExecutionFilter extends sfFilter
{
/**
* Executes this filter.
*
* @param sfFilterChain The filter chain
*
* @throws <b>sfInitializeException</b> If an error occurs during view initialization.
* @throws <b>sfViewException</b> If an error occurs while executing the view.
*/
public function execute($filterChain)
{
// get the context and controller
$context = $this->getContext();
$controller = $context->getController();
// get the current action instance
$actionEntry = $controller->getActionStack()->getLastEntry();
$actionInstance = $actionEntry->getActionInstance();
// get the current action information
$moduleName = $context->getModuleName();
$actionName = $context->getActionName();
// get the request method
$method = $context->getRequest()->getMethod();
$viewName = null;
if (sfConfig::get('sf_cache'))
{
$uri = sfRouting::getInstance()->getCurrentInternalUri();
if (null !== $context->getResponse()->getParameter($uri.'_action', null, 'symfony/cache'))
{
// action in cache, so go to the view
$viewName = sfView::SUCCESS;
}
}
if (!$viewName)
{
if (($actionInstance->getRequestMethods() & $method) != $method)
{
// this action will skip validation/execution for this method
// get the default view
$viewName = $actionInstance->getDefaultView();
}
else
{
// set default validated status
$validated = true;
// get the current action validation configuration
$validationConfig = $moduleName.'/'.sfConfig::get('sf_app_module_validate_dir_name').'/'.$actionName.'.yml';
// load validation configuration
// do NOT use require_once
if (null !== $validateFile = sfConfigCache::getInstance()->checkConfig(sfConfig::get('sf_app_module_dir_name').'/'.$validationConfig, true))
{
// create validator manager
$validatorManager = new sfValidatorManager();
$validatorManager->initialize($context);
require($validateFile);
// process validators
$validated = $validatorManager->execute();
}
// process manual validation
$validateToRun = 'validate'.ucfirst($actionName);
$manualValidated = method_exists($actionInstance, $validateToRun) ? $actionInstance->$validateToRun() : $actionInstance->validate();
// action is validated if:
// - all validation methods (manual and automatic) return true
// - or automatic validation returns false but errors have been 'removed' by manual validation
$validated = ($manualValidated && $validated) || ($manualValidated && !$validated && !$context->getRequest()->hasErrors());
// register fill-in filter
if (null !== ($parameters = $context->getRequest()->getAttribute('fillin', null, 'symfony/filter')))
{
$this->registerFillInFilter($filterChain, $parameters);
}
if ($validated)
{
if (sfConfig::get('sf_debug') && sfConfig::get('sf_logging_enabled'))
{
$timer = sfTimerManager::getTimer(sprintf('Action "%s/%s"', $moduleName, $actionName));
}
// execute the action
$actionInstance->preExecute();
$viewName = $actionInstance->execute();
if ($viewName == '')
{
$viewName = sfView::SUCCESS;
}
$actionInstance->postExecute();
if (sfConfig::get('sf_debug') && sfConfig::get('sf_logging_enabled'))
{
$timer->addTime();
}
}
else
{
if (sfConfig::get('sf_logging_enabled'))
{
$this->context->getLogger()->info('{sfFilter} action validation failed');
}
// validation failed
$handleErrorToRun = 'handleError'.ucfirst($actionName);
$viewName = method_exists($actionInstance, $handleErrorToRun) ? $actionInstance->$handleErrorToRun() : $actionInstance->handleError();
if ($viewName == '')
{
$viewName = sfView::ERROR;
}
}
}
}
if ($viewName == sfView::HEADER_ONLY)
{
$context->getResponse()->setHeaderOnly(true);
// execute next filter
$filterChain->execute();
}
else if ($viewName != sfView::NONE)
{
if (sfConfig::get('sf_debug') && sfConfig::get('sf_logging_enabled'))
{
$timer = sfTimerManager::getTimer(sprintf('View "%s" for "%s/%s"', $viewName, $moduleName, $actionName));
}
// get the view instance
$viewInstance = $controller->getView($moduleName, $actionName, $viewName);
$viewInstance->initialize($context, $moduleName, $actionName, $viewName);
$viewInstance->execute();
// render the view and if data is returned, stick it in the
// action entry which was retrieved from the execution chain
$viewData = $viewInstance->render();
if (sfConfig::get('sf_debug') && sfConfig::get('sf_logging_enabled'))
{
$timer->addTime();
}
if ($controller->getRenderMode() == sfView::RENDER_VAR)
{
$actionEntry->setPresentation($viewData);
}
else
{
// execute next filter
$filterChain->execute();
}
}
}
/**
* Registers the fill in filter in the filter chain.
*
* @param sfFilterChain A sfFilterChain implementation instance
* @param array An array of parameters to pass to the fill in filter.
*/
protected function registerFillInFilter($filterChain, $parameters)
{
// automatically register the fill in filter if it is not already loaded in the chain
if (isset($parameters['enabled']) && $parameters['enabled'] && !$filterChain->hasFilter('sfFillInFormFilter'))
{
// register the fill in form filter
$fillInFormFilter = new sfFillInFormFilter();
$fillInFormFilter->initialize($this->context, isset($parameters['param']) ? $parameters['param'] : array());
$filterChain->register($fillInFormFilter);
}
}
}

View File

@ -0,0 +1,67 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfFillInFormFilter fills in forms.
*
* @package symfony
* @subpackage filter
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfFillInFormFilter.class.php 3244 2007-01-12 14:46:11Z fabien $
*/
class sfFillInFormFilter extends sfFilter
{
/**
* Executes this filter.
*
* @param sfFilterChain A sfFilterChain instance
*/
public function execute($filterChain)
{
// execute next filter
$filterChain->execute();
$context = $this->getContext();
$response = $context->getResponse();
$request = $context->getRequest();
$fillInForm = new sfFillInForm();
// converters
foreach ($this->getParameter('converters', array()) as $functionName => $fields)
{
$fillInForm->addConverter($functionName, $fields);
}
// skip fields
$fillInForm->setSkipFields((array) $this->getParameter('skip_fields', array()));
// types
$excludeTypes = (array) $this->getParameter('exclude_types', array('hidden', 'password'));
$checkTypes = (array) $this->getParameter('check_types', array('text', 'checkbox', 'radio', 'password', 'hidden'));
$fillInForm->setTypes(array_diff($checkTypes, $excludeTypes));
// fill in
$method = 'fillIn'.ucfirst(strtolower($this->getParameter('content_type', 'Html')));
try
{
$content = $fillInForm->$method($response->getContent(), $this->getParameter('name'), $this->getParameter('id'), $request->getParameterHolder()->getAll());
$response->setContent($content);
}
catch (sfException $e)
{
if (sfConfig::get('sf_logging_enabled'))
{
$this->getContext()->getLogger()->err(sprintf('{sfFilter} %s', $e->getMessage()));
}
}
}
}

View File

@ -0,0 +1,146 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
* (c) 2004-2006 Sean Kerr.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* sfFilter provides a way for you to intercept incoming requests or outgoing responses.
*
* @package symfony
* @subpackage filter
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Sean Kerr <skerr@mojavi.org>
* @version SVN: $Id: sfFilter.class.php 3502 2007-02-18 18:28:28Z fabien $
*/
abstract class sfFilter
{
protected
$parameterHolder = null,
$context = null;
public static
$filterCalled = array();
/**
* Returns true if this is the first call to the sfFilter instance.
*
* @return boolean true if this is the first call to the sfFilter instance, false otherwise
*/
protected function isFirstCall()
{
$class = get_class($this);
if (isset(self::$filterCalled[$class]))
{
return false;
}
else
{
self::$filterCalled[$class] = true;
return true;
}
}
/**
* Retrieves the current application context.
*
* @return sfContext The current sfContext instance
*/
public final function getContext()
{
return $this->context;
}
/**
* Initializes this Filter.
*
* @param sfContext The current application context
* @param array An associative array of initialization parameters
*
* @return boolean true, if initialization completes successfully, otherwise false
*
* @throws <b>sfInitializationException</b> If an error occurs while initializing this Filter
*/
public function initialize($context, $parameters = array())
{
$this->context = $context;
$this->parameterHolder = new sfParameterHolder();
$this->parameterHolder->add($parameters);
return true;
}
/**
* Gets the parameter holder for this object.
*
* @return sfParameterHolder A sfParameterHolder instance
*/
public function getParameterHolder()
{
return $this->parameterHolder;
}
/**
* Gets the parameter associated with the given key.
*
* This is a shortcut for:
*
* <code>$this->getParameterHolder()->get()</code>
*
* @param string The key name
* @param string The default value
* @param string The namespace to use
*
* @return string The value associated with the key
*
* @see sfParameterHolder
*/
public function getParameter($name, $default = null, $ns = null)
{
return $this->parameterHolder->get($name, $default, $ns);
}
/**
* Returns true if the given key exists in the parameter holder.
*
* This is a shortcut for:
*
* <code>$this->getParameterHolder()->has()</code>
*
* @param string The key name
* @param string The namespace to use
*
* @return boolean true if the given key exists, false otherwise
*
* @see sfParameterHolder
*/
public function hasParameter($name, $ns = null)
{
return $this->parameterHolder->has($name, $ns);
}
/**
* Sets the value for the given key.
*
* This is a shortcut for:
*
* <code>$this->getParameterHolder()->set()</code>
*
* @param string The key name
* @param string The value
* @param string The namespace to use
*
* @see sfParameterHolder
*/
public function setParameter($name, $value, $ns = null)
{
return $this->parameterHolder->set($name, $value, $ns);
}
}

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