Location: PHPKode > projects > Spiral > ametaireau-spiral-272a2b1/framework/di/classes/definition/FluentSchemaFacade.php
<?php

namespace spiral\framework\di\definition;

use \spiral\framework\di\definition\builder\FluentBuilder;

/**
 * Default implementation of SchemaFluent interface
 *
 * Facade for the schema supporting fluent interface
 * 
 * So, you can view it as a facility to manipulate the schema classes. 
 *
 * <code>
 * $fluentSchema
 * ->addService('test', 'spiral\tests\ToInject')
 * ->addService('test2', 'spiral\tests\ToInject')
 *		->construct()->with('arg1', 'arg2')
 *		->call('method')->withService('service')
 *		->etc.
 * </code>
 * 
 * @author		Alexis Métaireau <hide@address.com>
 * @copyright	2009 Spiral-project.org <http://www.spiral-project.org>
 * @license		GNU General Public License <http://www.gnu.org/licenses/gpl.html>
 */
class FluentSchemaFacade
{
	/**
	 * Array of active services
	 *
	 * @var array
	 */
	protected $_activeServices = array();
	
	/**
	 * Array of active method
	 * 
	 * @var array
	 */
	protected $_activeMethods = array();
	
	/**
	 * Resolver for the schema classes
	 *
	 * @var	SchemaResolver
	 */
	protected $_resolver = null;
	
	/**
	 * The schema object
	 *
	 * @var	Schema
	 */
	protected $_schema = null;
	
	/**
	 * add the last method call type
	 *
	 * @var	string
	 */
	protected $_lastCall = 'service';
	
	/**
	 * By default, if no resolver is set, the resolver is set to the default 
	 * SchemaResolver implementation
	 *
	 * @param	SchemaResolver	$resolver
	 * @return	void
	 */
	public function __construct(SchemaResolver $resolver = null)
	{
		if ($resolver == null)
		{
			$resolver = new DefaultSchemaResolver();
		}
		
		$this->_resolver = $resolver;
		
		// create the schema object and store it
		$schemaClass = $this->_resolver->resolveSchema();
		$this->_schema = new $schemaClass();
	}
	
	/**
	 * Return all active services for now, in an array, or null if no active 
	 * service is registred
	 *
	 * @return  array|null
	 */
	protected function _getActiveServices()
	{
		// if we have a single object to return, build an array with it
		if (!is_array($this->_activeServices) && !empty($this->_activeServices))
		{
			$services = array($this->_activeServices);
		
		// otherwise, just return the array ..
		}
		elseif(is_array($this->_activeServices))
		{
			$services = $this->_activeServices;
		
		// or nothin'
		}
		else 
		{
			$services = null;
		}
		
		return $services;
	}
	
	/**
	 * Check out if a service with the given name is already registred and 
	 * return it when possible.
	 *
	 * If not, create a new one, store it and return it
	 *
	 * @param	string  $serviceName	name of the wanted service
	 * @param	string  $className  	classname of the service
     * @param   bool    $isSingleton
	 * @return  Service
	 */
	protected function _getService($serviceName, $className, $isSingleton = false)
	{
		if ($this->_lastCall != 'service')
		{
			$this->_activeServices = array();
		}
		
		// if the service is registred, just return the one already registred
		if (isset($this->_schema[$serviceName]))
		{
			$service = $this->_schema->getService($serviceName);
		} 
		// if service is not registred, create a new one, and add it to the active object
		else 
		{
			$serviceClass = $this->_resolver->resolveService();
			$service = new $serviceClass($serviceName, $className, $isSingleton);
			$this->_schema->addService($service);
		}
		
		// add it to the active services
		$this->_activeServices[] = $service;
		$this->_lastCall = 'service';
				
		// and return it
		return $service;
	}
	
	/**
	 * Add the given method, and add it to the activeMethod list
	 * 
	 * @param	Method	$method
	 * @return	void
	 */
	protected function _addMethod(Method $method)
	{
		if ($this->_lastCall != 'method')
		{
			$this->_activeMethods = array();
		}

		foreach($this->_activeServices as $service)
		{
			$service->addMethod($method);
		}
		
		$this->_activeMethods[] = $method;
		$this->_lastCall = 'method';
	}
	
	/**
	 * Add a service, set it as the active object
	 *
	 * @param   string  $key
	 * @param   string  $className
     * @param   bool    $isSingleton
	 * @return  FluentBuilder
	 */
	public function addService($key, $className, $isSingleton=true)
	{
		$this->_getService($key, $className, $isSingleton);
		return $this;
	}	

	/**
	 * Create a new method to call, add it to the schema
	 * and add it to the active methods
	 *
	 * @param   string  $methodName
	 * @return  FluentBuilder
	 */
	public function call($methodName)
	{
		$methodClass = $this->_resolver->resolveMethod();
		$method = new $methodClass($methodName);
		$this->_addMethod($method); 
		return $this;
	}
	
	/**
	 * Set a static method call
	 *
	 * @param   string  $className
	 * @param   string  $methodName
	 * @return  FluentBuilder
	 */
	public function callStatic($className, $methodName)
	{
		$methodClass = $this->_resolver->resolveMethod();
		$method = new $methodClass($methodName, $className);
		$this->_addMethod($method); 
		return $this;
	}
	
	/**
	 * Alias for 'call' for a constructor.
	 *
	 * @return  FluentBuilder
	 */
	public function construct()
	{
		$this->call('__construct');
		return $this;
	}
	
	/**
	 * Use all given params as param for active method objects
	 *
	 * @param   mixed
	 * @return  FluentBuilder
	 */
	public function with()
	{
		return $this->setArguments(func_get_args());
	}
	
	/**
	 * Use array $parameters as param for active method objects
	 *
	 * @param   array   $parameters
	 * @param   bool	$asService  Specify if the given parameters has to be used as services
	 * @return  FluentBuilder
	 */
	public function setArguments($parameters, $asService = false)
	{
		foreach($parameters as $parameter)
		{
			$this->addArgument($parameter, $asService);
		}
		return $this;
	}
	
	/**
	 * Call the selected method(s) with given parameter
	 *
	 * @param   string  $value
	 * @return  FluentBuilder
	 */
	public function addArgument($value, $asService = false)
	{
		if ($asService === true)
		{
			$parameter = new ServiceReferenceArgument($value);
		} 
		else
		{
			$parameter = new DefaultArgument($value);
		}
		
		foreach($this->_activeMethods as $method)
		{
			$method->addArgument($parameter);
		}
		//$service->addMethod($method);
		$this->_lastCall = 'argument';
		return $this;
	}

	/**
	 * Same as with, for services.
	 *
	 * @param   mixed
	 * @return  FluentBuilder
	 */
	public function withServices()
	{
		return $this->setArguments(func_get_args(), true);
	}
	
	/**
	 * Same as setArguments, for services
	 *
	 * @param   array   $parameters
	 * @return  FluentBuilder
	 */
	public function setArgumentsAsServices($parameters)
	{
		return $this->setArguments($parameters, true);
	}
	
	/**
	 * Same as addArgument, for services
	 *
	 * @param   string   $parameter
	 * @return  FluentBuilder
	 */
	public function addArgumentAsService($parameter)
	{
		return $this->addArgument($parameters, true);
	}
	
	/**
	 * Return the schema object
	 *
	 * @return	Schema
	 */
	public function getSchema()
	{
		return $this->_schema;
	}
}
Return current item: Spiral