Seditio Source
Root |
./othercms/croogo-4.0.7/vendor/cakephp/bake/src/View/Helper/DocBlockHelper.php
<?php
namespace Bake\View\Helper;

use
Cake\Collection\Collection;
use
Cake\Core\App;
use
Cake\Database\Type;
use
Cake\ORM\Association;
use
Cake\Utility\Inflector;
use
Cake\View\Helper;

/**
 * DocBlock helper
 */
class DocBlockHelper extends Helper
{
   
/**
     * @var bool Whether to add a blank line between different class annotations
     */
   
protected $_annotationSpacing = true;

   
/**
     * Writes the DocBlock header for a class which includes the property and method declarations. Annotations are
     * sorted and grouped by type and value. Groups of annotations are separated by blank lines.
     *
     * @param string $className The class this comment block is for.
     * @param string $classType The type of class (example, Entity)
     * @param array $annotations An array of PHP comment block annotations.
     * @return string The DocBlock for a class header.
     */
   
public function classDescription($className, $classType, array $annotations)
    {
       
$lines = [];
        if (
$className && $classType) {
           
$lines[] = "{$className} {$classType}";
        }

        if (
$annotations && $lines) {
           
$lines[] = '';
        }

       
$previous = false;
        foreach (
$annotations as $annotation) {
            if (
strlen($annotation) > 1 && $annotation[0] === '@' && strpos($annotation, ' ') > 0) {
               
$type = substr($annotation, 0, strpos($annotation, ' '));
                if (
                   
$this->_annotationSpacing &&
                   
$previous !== false &&
                   
$previous !== $type
               
) {
                   
$lines[] = '';
                }
               
$previous = $type;
            }
           
$lines[] = $annotation;
        }

       
$lines = array_merge(["/**"], (new Collection($lines))->map(function ($line) {
            return
rtrim(" * {$line}");
        })->
toArray(), [" */"]);

        return
implode("\n", $lines);
    }

   
/**
     * Converts an entity class type to its DocBlock hint type counterpart.
     *
     * @param string $type The entity class type (a fully qualified class name).
     * @param \Cake\ORM\Association $association The association related to the entity class.
     * @return string The DocBlock type
     */
   
public function associatedEntityTypeToHintType($type, Association $association)
    {
       
$annotationType = $association->type();
        if (
           
$annotationType === Association::MANY_TO_MANY ||
           
$annotationType === Association::ONE_TO_MANY
       
) {
            return
$type . '[]';
        }

        return
$type;
    }

   
/**
     * Builds a map of entity columns as DocBlock types for use
     * in generating `@property` hints.
     *
     * This method expects a property schema as generated by
     * `\Bake\Shell\Task\ModelTask::getEntityPropertySchema()`.
     *
     * The generated map has the format of
     *
     * ```
     * [
     *     'property-name' => 'doc-block-type',
     *     ...
     * ]
     * ```
     *
     * @see \Bake\Shell\Task\ModelTask::getEntityPropertySchema
     *
     * @param array $propertySchema The property schema to use for generating the type map.
     * @return array The property DocType map.
     */
   
public function buildEntityPropertyHintTypeMap(array $propertySchema)
    {
       
$properties = [];
        foreach (
$propertySchema as $property => $info) {
            if (
$info['kind'] === 'column') {
               
$type = $this->columnTypeToHintType($info['type']);
                if (!empty(
$info['null'])) {
                   
$type .= '|null';
                }

               
$properties[$property] = $type;
            }
        }

        return
$properties;
    }

   
/**
     * Builds a map of entity associations as DocBlock types for use
     * in generating `@property` hints.
     *
     * This method expects a property schema as generated by
     * `\Bake\Shell\Task\ModelTask::getEntityPropertySchema()`.
     *
     * The generated map has the format of
     *
     * ```
     * [
     *     'property-name' => 'doc-block-type',
     *     ...
     * ]
     * ```
     *
     * @see \Bake\Shell\Task\ModelTask::getEntityPropertySchema
     *
     * @param array $propertySchema The property schema to use for generating the type map.
     * @return array The property DocType map.
     */
   
public function buildEntityAssociationHintTypeMap(array $propertySchema)
    {
       
$properties = [];
        foreach (
$propertySchema as $property => $info) {
            if (
$info['kind'] === 'association') {
               
$type = $this->associatedEntityTypeToHintType($info['type'], $info['association']);
                if (
$info['association']->type() === Association::MANY_TO_ONE) {
                   
$properties = $this->_insertAfter(
                       
$properties,
                       
$info['association']->getForeignKey(),
                        [
$property => $type]
                    );
                } else {
                   
$properties[$property] = $type;
                }
            }
        }

        return
$properties;
    }

   
/**
     * Converts a column type to its DocBlock type counterpart.
     *
     * This method only supports the default CakePHP column types,
     * custom column/database types will be ignored.
     *
     * @see \Cake\Database\Type
     *
     * @param string $type The column type.
     * @return null|string The DocBlock type, or `null` for unsupported column types.
     */
   
public function columnTypeToHintType($type)
    {
        switch (
$type) {
            case
'string':
            case
'text':
            case
'uuid':
                return
'string';

            case
'integer':
            case
'biginteger':
            case
'smallinteger':
            case
'tinyinteger':
                return
'int';

            case
'float':
            case
'decimal':
                return
'float';

            case
'boolean':
                return
'bool';

            case
'array':
            case
'json':
                return
'array';

            case
'binary':
                return
'string|resource';

            case
'date':
            case
'datetime':
            case
'time':
            case
'timestamp':
               
$dbType = Type::build($type);
                if (
method_exists($dbType, 'getDateTimeClassName')) {
                    return
'\\' . Type::build($type)->getDateTimeClassName();
                }

                return
'\Cake\I18n\Time';
        }

        return
null;
    }

   
/**
     * Renders a map of DocBlock property types as an array of
     * `@property` hints.
     *
     * @param array $properties A key value pair where key is the name of a property and the value is the type.
     * @return array
     */
   
public function propertyHints(array $properties)
    {
       
$lines = [];
        foreach (
$properties as $property => $type) {
           
$type = $type ? $type . ' ' : '';
           
$lines[] = "@property {$type}\${$property}";
        }

        return
$lines;
    }

   
/**
     * Build property, method, mixing annotations for table class.
     *
     * @param array $associations Associations list.
     * @param array $associationInfo Association info.
     * @param array $behaviors Behaviors list.
     * @param string $entity Entity name.
     * @param string $namespace Namespace.
     * @return array
     */
   
public function buildTableAnnotations($associations, $associationInfo, $behaviors, $entity, $namespace)
    {
       
$annotations = [];
        foreach (
$associations as $type => $assocs) {
            foreach (
$assocs as $assoc) {
               
$typeStr = Inflector::camelize($type);
               
$tableFqn = $associationInfo[$assoc['alias']]['targetFqn'];
               
$annotations[] = "@property {$tableFqn}&\Cake\ORM\Association\\{$typeStr} \${$assoc['alias']}";
            }
        }
       
$annotations[] = "@method \\{$namespace}\\Model\\Entity\\{$entity} get(\$primaryKey, \$options = [])";
       
$annotations[] = "@method \\{$namespace}\\Model\\Entity\\{$entity} newEntity(\$data = null, array \$options = [])";
       
$annotations[] = "@method \\{$namespace}\\Model\\Entity\\{$entity}[] newEntities(array \$data, array \$options = [])";
       
$annotations[] = "@method \\{$namespace}\\Model\\Entity\\{$entity}|false save(\\Cake\\Datasource\\EntityInterface \$entity, \$options = [])";
       
$annotations[] = "@method \\{$namespace}\\Model\\Entity\\{$entity} saveOrFail(\\Cake\\Datasource\\EntityInterface \$entity, \$options = [])";
       
$annotations[] = "@method \\{$namespace}\\Model\\Entity\\{$entity} patchEntity(\\Cake\\Datasource\\EntityInterface \$entity, array \$data, array \$options = [])";
       
$annotations[] = "@method \\{$namespace}\\Model\\Entity\\{$entity}[] patchEntities(\$entities, array \$data, array \$options = [])";
       
$annotations[] = "@method \\{$namespace}\\Model\\Entity\\{$entity} findOrCreate(\$search, callable \$callback = null, \$options = [])";
        foreach (
$behaviors as $behavior => $behaviorData) {
           
$className = App::className($behavior, 'Model/Behavior', 'Behavior');
            if (
$className === false) {
               
$className = "Cake\ORM\Behavior\\{$behavior}Behavior";
            }

           
$annotations[] = '@mixin \\' . $className;
        }

        return
$annotations;
    }

   
/**
     * Inserts a value after a specific key in an associative array.
     *
     * In case the given key cannot be found, the value will be appended.
     *
     * @param array $target The array in which to insert the new value.
     * @param string $key The array key after which to insert the new value.
     * @param mixed $value The entry to insert.
     * @return array The array with the new value inserted.
     */
   
protected function _insertAfter(array $target, $key, $value)
    {
       
$index = array_search($key, array_keys($target));
        if (
$index !== false) {
           
$target = array_merge(
               
array_slice($target, 0, $index + 1),
               
$value,
               
array_slice($target, $index + 1, null)
            );
        } else {
           
$target += (array)$value;
        }

        return
$target;
    }
}