samsonos/php_config

View on GitHub
src/Scheme.php

Summary

Maintainability
A
25 mins
Test Coverage
<?php
namespace samsonos\config;

use samson\core\Event;

/**
 * Generic SamsonPHP core configuration system
 * @author Vitaly Egorov <egorov@samsonos.com>
 * @copyright 2014 SamsonOS
 */
class Scheme
{
    /** Global/Default scheme marker */
    const BASE = 'global';

    /** Entity configuration file pattern */
    const ENTITY_PATTERN = '*Config.php';

    /** @var array Collection of file path -> class loaded */
    protected static $classes = array();

    /** @var string Current configuration environment */
    protected $environment;

    /** @var array Configuration folder path array */
    protected $path = array();

    /** @var array Collection of module identifier => configurator class */
    public $entities = array();

    /**
     * Create configuration instance.
     *
     * All module configurators must be stored within configuration base path,
     * by default this is stored in __SAMSON_CONFIG_PATH constant.
     *
     * Every environment configuration must be stored in sub-folder with the name of this
     * environment within base configuration folder.
     *
     * Configurators located at base root configuration folder considered as generic
     * module configurators.
     *
     * @param string $path    Base path to configuration root folder
     * @param string $environment Configuration environment name
     */
    public function __construct($path, $environment)
    {
        // Store current configuration environment
        $this->environment = $environment;

        // Check scheme folder existence
        if (file_exists($path)) {
            // Load scheme entities
            $this->load($path);
        }
    }

    /**
     * Load entity configuration classes for this scheme.
     * Function scans all required classes and matches them by
     * specified scheme path.
     */
    public function load($path = null)
    {
        // Build path to environment configuration folder
        $this->path[] = $path;

        // Iterate all loaded classes matching class name pattern
        foreach (preg_grep(Entity::CLASS_PATTERN, get_declared_classes()) as $class) {
            // If this is a entity configuration class ancestor
            if (in_array(__NAMESPACE__.'\Entity', class_parents($class))) {
                // Get class reflection object
                $reflector = new \ReflectionClass($class);

                // If path to class file is in scheme paths collection
                if (in_array(dirname($reflector->getFileName()), $this->path)) {
                    // Store module identifier - entity configuration object
                    $this->entities[$this->identifier($class)] = new $class();
                }
            }
        }
    }

    /**
     * Convert entity configuration or object class name to identifier
     * @param string $class Entity configuration class name
     * @return string Entity real class name
     */
    public function identifier($class)
    {
        // If namespace is present
        if (($classNamePos = strrpos($class, '\\')) !== false) {
            $class = substr($class, $classNamePos+1);
        }

        // Remove only last occurrence of pattern
        return preg_replace(Entity::CLASS_PATTERN, '', strtolower($class));
    }

    /**
     * Retrieve entity configuration by identifier.
     * If entity configuration not found null will be
     * returned.
     *
     * @param string $identifier Entity identifier
     * @param mixed $entity Return found entity configuration pointer
     * @return Entity|boolean Entity configuration pointer or bool
     */
    public function & entity($identifier, & $entity = null)
    {
        // Convert identifier of entity configuration name is passed
        $pointer = & $this->entities[$this->identifier($identifier)];

        // PHP bugs =) We cannot assign referenced value pointer to array element
        $entity = $pointer;

        // Prepare return value - pointer or bool
        $return = (func_num_args() == 2) ? isset($pointer) : $pointer;

        // Also PHP bugs - we cannot return reference from ternary operator
        return $return;
    }

    /**
     * Perform object configuration with specific entity
     * @param mixed $object Object instance pointer
     * @param Entity $entity Entity configuration pointer
     * @param mixed $params Collection of parameters
     * @return bool True if everything went fine, otherwise false
     */
    protected function handleConfigure(& $object, Entity & $entity, $params = null)
    {
        // If this class knows how to configure it self
        if (method_exists($object, 'configure')) {
            // Call custom configuration implementation
            return $object->configure($entity);
        } else { // Generic logic - implement entity configuration to object
            return $entity->configure($object, $params);
        }
    }

    /**
     * Configure object with configuration entity parameters.
     *
     * If now $identifier is passed - automatic identifier generation
     * will take place from object class name.
     *
     * If additional parameters key=>value collection is passed, they
     * will be used to configure object instead of entity configuration
     * class.
     *
     * @param mixed $object Object for configuration with entity
     * @param string $identifier Configuration entity name
     * @param array|null $params Collection of configuration parameters
     *
     * @return boolean True if we have successfully configured object
     */
    public function configure(& $object, $identifier = null, $params = null)
    {
        /** @var Entity $pointer Pointer to entity instance */
        $pointer = null;

        // If we have found this entity configuration, If no entity identifier is passed get it from object class
        if ($this->entity(isset($identifier) ? $identifier : get_class($object), $pointer)) {
            return $this->handleConfigure($object, $pointer, $params);
        } else { // Signal error
            Event::fire(
                'error',
                array(
                    $this,
                    'Cannot configure entity[' . $identifier . '] - Entity configuration does not exists'
                )
            );

            // We have failed
            return false;
        }
    }
}