Location: PHPKode > scripts > SilverSmith > unclecheese-SilverSmith-c6bab03/code/SilverSmithSpec.php
<?php



/**
 * A wrapper class for accessing the specifications for the SilverSmith project configuration file.
 * Used primarily for validating the project yaml.
 *
 * @package SilverSmith
 * @author Aaron Carlino <hide@address.com>
 */
class SilverSmithSpec {



	/**
	 * @var BedrockYAML A cached object representing the spec.yml 
	 */
    protected static $settings_list;
    
    
    
    /**
     * Loads the YAML into a {@link BedrockYAML} object given a file path
     *
     * @param string the path to the YAML file
     */
    public static function load($path) {
        self::$settings_list = new BedrockYAML($path);
    }
    
    
    
    /**
     * Gets a given setting from the spec
     *
     * @param string The dot-separated path to the setting
     * @return BedrockNode
     */
    public static function get($setting) {
        return self::$settings_list->get($setting);
    }
    
    
    
    
    /**
     * Gets a translatable list of a given setting
     * Future-proofing for a GUI
     *
     * @param string The dot-separated path to the setting
     * @return 
     */
    public static function get_i18n_map($path) {
        $map = array();
        if ($result = self::get($path)) {
            foreach ($result as $name => $setting) {
                $map[$name] = _t('ProjectBuilder.' . strtoupper($name), $setting->getLabel());
            }
        }
        return $map;
    }
    
    
    
    
    /**
     * Future-proofing for a GUI. Provide translatable entities for the spec
     *
     * @return array
     */
    public function provideI18nEntities() {
        $entities   = array();
        $paths      = array(
            'Field.AvailableNodes.DBField',
            'Component.AvailableNodes.Type',
            'Interface'
        );
        $candidates = array();
        foreach ($paths as $path) {
            if ($dropdownValues = self::get($path . '.DropdownValues')) {
                foreach ($dropdownValues as $name => $value) {
                    $entities["ProjectBuilder." . strtoupper($name)] = $value->getLabel();
                }
            }
        }
        return $entities;
    }
    
    
    
}




/**
 * A class that validates a given project configuration file based on the spec.yml	
 *
 * @package SivlerSmith
 * @author Aaron Carlino <hide@address.com>
 */
class SilverSmithSpec_Validator {



	/**
	 * @var array A list of errors in the YAML
	 */
    protected $errors = array();
    
    
    /**
     * @var BedrockYAML The object representing the YAML input to be validated	
     */
    protected $yml;
    
    
    
    /**
     * Create a new instances of the validator
     *
     * @param string The path to the YAML file to validate
     */
    public function __construct($path) {
        $this->yml = new BedrockYAML($path);
        $this->validate();
    }
    
    
    
    
    /**
     * Get all of the errors in the project YAML file
     *
     * @return array
     */
    public function getErrors() {
        return $this->errors;
    }
    
    
    
    
    /**
     * Validate the YAML file based on the spec.yml
     *
     */
    public function validate()
    {
        if (!$this->yml)
            return $this->$errors;
        $keys = array_keys($this->yml->getConfiguration());
        foreach ($keys as $key) {
            $setting = $this->yml->get($key);
            if ($setting instanceof BedrockNode) {
                $this->doValidation($setting);
            }
        }
    }
    
    
    
    
    /**
     * A recursive function that validates the project YAML based on the spec.yml
     *
     * @param BedrockNode The node to validate
     * @param string The name of the parent node	
     */
    protected function doValidation($setting, $parent_class = null) {
        foreach ($setting as $name => $result) {
            $value      = $setting->get($name);
            $is_setting = $value instanceof BedrockNode;
            $class      = $result->getBaseClass();
            $validator  = SilverSmithSpec::get($name);
            if (!$validator) {
                $validator = SilverSmithSpec::get($class);
            }
            if (!$validator) {
                $validator = SilverSmithSpec::get($class . ".AvailableNodes.{$name}");
            }
            if (!$validator && $parent_class) {
                $validator = SilverSmithSpec::get($parent_class . ".AvailableNodes.{$name}");
            }
            
            if (!$validator) {
                continue;
            }
            // If the setting came back as an object
            if ($is_setting) {
                // Check to make sure all nodes in the tree are allowed.
                if (!$validator->getUserDefined() && ($allowed_nodes = $validator->getAvailableNodes())) {
                    $allowed = array_keys($allowed_nodes->toArray());
                    foreach ($value as $node => $config) {
                        if (!in_array($node, $allowed)) {
                            $this->errors[] = sprintf(_t('Bedrock.NODENOTALLOWED', 'The node %s is not allowed in %s'), $node, $name);
                        }
                    }
                }
                // If this is a user-defined node (e.g. Fields), make sure there are no reserved nodes floating around.
                elseif ($validator->getUserDefined()) {
                    foreach ($value as $node => $config) {
                        if (class_exists("Bedrock" . $node)) {
                            $this->errors[] = sprintf(_t('Bedrock.NODENOTALLOWED', 'The node %s is note allowed in %s'), $node, $name);
                        }
                    }
                }
                // Make sure any required nodes are present.
                if ($required = $validator->getRequiredNodes()) {
                    if ($is_setting) {
                        foreach ($required as $node) {
                            if (!$value->get($node)) {
                                $this->errors[] = sprintf(_t('Bedrock.NODEISREQUIRED', 'The node %s is required in %s'), $node, $name);
                            }
                        }
                    }
                }
            }
            // If the setting came back as a string.
            else {
                // Make sure it's not supposed to be an object
                if ($type = $validator->getDataType()) {
                    if ($type == "setting") {
                        $this->errors[] = sprintf(_t('Bedrock.MUSTBESETTING', 'The node "%s" should be a collection of nodes, not a plain value.'), $name);
                    } else {
                        $this->validateDataType($value, $type, $name);
                    }
                }
                if ($vals = $validator->getPossibleValues()) {
                    $this->validatePossibleValues($value, $vals, $name);
                }
                
            }
            
            
            if ($is_setting) {
                $this->doValidation($value, $result->getBaseClass());
            }
        }
    }
    
    
    
    
    /**
     * Validates a node to make sure it is the right data type
     *
     * @param mixed The value to validate
     * @param string The type of data that the value is required to be
     * @param string The name of the node being validated
     */
    protected function validateDataType($value, $type, $name) {
        if ($type == "string" && !is_string($value))
            $this->errors[] = sprintf(_t('Bedrock.VALUEMUSTBESTRING', 'The value of %s must be a string. Right now it is %s'), $name, $value);
        elseif ($type == "integer") {
            $i = (int) $value;
            if (!is_numeric($value) || !is_int($i)) {
                $this->errors[] = sprintf(_t('Bedrock.VALUEMUSTBEINT', 'The value of %s must be an integer. Right now it is %s'), $name, $value);
            }
        } elseif ($type == "boolean" && (!in_array($value, array(
            'true',
            'false'
        )) && !is_bool($value)))
            $this->errors[] = sprintf(_t('Bedrock.VALUEMUSTBEBOOLEAN', 'The value of %s must be a boolean. Right now it is %s.'), $name, $value);
        
    }
    
    
    
    
    
    /**
     * Validates a node to make sure its value is within the list of allowed values
     *
     * @param mixed The value of the node
     * @param array The list of allowed values
     * @param string The name of the node
     */
    protected function validatePossibleValues($value, $allowed, $n) {
        $valid = false;
        foreach ($allowed as $a) {
            if (preg_match('/^' . $a . '$/', $value)) {
                $valid = true;
                break;
            }
        }
        if (!$valid) {
            $this->errors[] = sprintf(_t('Bedrock.VALUENOTALLOWED', '"%s" is not a valid value for %s. Allowed values are %s'), $value, $n, implode(', ', $allowed));
        }
        
    }
    
}
Return current item: SilverSmith