<commit_before><?php

/**
 * This file is part of the Miny framework.
 * (c) <NAME> <<EMAIL>>
 *
 * For licensing information see the LICENSE file.
 */

namespace Modules\Annotation;

use Modules\Annotation\Annotations\Attribute;
use Modules\Annotation\Annotations\Target;
use Modules\Annotation\Exceptions\AnnotationException;

class AnnotationContainer
{
    /**
     * @var AnnotationMetadata[]
     */
    private $annotations;

    /**
     * @var AnnotationReader
     */
    private $reader;

    /**
     * @var \ReflectionClass[]
     */
    private $reflectors = array();

    public function __construct(AnnotationReader $reader)
    {
        $this->reader = $reader;

        $this->annotations = array(
            'Modules\\Annotation\\Annotations\\Attribute' => AnnotationMetadata::create(
                    array(
                        'defaultAttribute' => 'name',
                        'attributes'       => array(
                            'name'     => array(
                                'required' => true,
                                'type'     => 'string'
                            ),
                            'setter'   => array(
                                'required' => false,
                                'type'     => 'string'
                            ),
                            'type'     => array(
                                'required' => false,
                                'type'     => 'mixed'
                            ),
                            'nullable' => array(
                                'required' => false,
                                'type'     => 'bool'
                            ),
                            'required' => array(
                                'required' => false,
                                'type'     => 'bool'
                            )
                        ),
                        'target'           => Target::TARGET_CLASS
                    )
                ),
            'Modules\\Annotation\\Annotations\\Enum'      => AnnotationMetadata::create(
                    array(
                        'defaultAttribute' => 'values',
                        'attributes'       => array(
                            'values' => array(
                                'required' => true,
                                'type'     => array()
                            )
                        ),
                        'target'           => Target::TARGET_ANNOTATION
                    )
                ),
            'Modules\\Annotation\\Annotations\\Target'    => AnnotationMetadata::create(
                    array(
                        'defaultAttribute' => 'target',
                        'constructor'      => array(
                            'target'
                        ),
                        'attributes'       => array(
                            'target' => array(
                                'required' => true,
                                'type'     => 'mixed'
                            )
                        ),
                        'target'           => Target::TARGET_CLASS
                    )
                )
        );
    }

    public function registerAnnotation($class, array $metadata)
    {
        $this->annotations[$class] = AnnotationMetadata::create($metadata);
    }

    /**
     * @param $class
     * @return \ReflectionClass
     */
    public function getClassReflector($class)
    {
        if (!isset($this->reflectors[$class])) {
            $this->reflectors[$class] = new \ReflectionClass($class);
        }

        return $this->reflectors[$class];
    }

    /**
     * @param      $class
     * @param bool $isParent
     *
     * @throws AnnotationException
     *
     * @return AnnotationMetadata
     */
    private function readClassMetadata($class, $isParent = false)
    {
        if (!isset($this->annotations[$class])) {
            $reflector = $this->getClassReflector($class);

            $parent = $reflector->getParentClass();
            if ($parent) {
                $this->reflectors[$parent->getName()] = $parent;

                $metadata = $this->readClassMetadata($parent->getName(), true);
            } else {
                $metadata = new AnnotationMetadata();
            }

            $comment = $this->reader->readClass($class);
            if (!$comment->has('Annotation')) {
                if ($isParent) {
                    return $metadata;
                }
                throw new AnnotationException("Class {$class} has not been marked with @Annotation");
            }

            //get constructor info
            $constructor  = $reflector->getConstructor();
            $markRequired = array();
            if ($constructor !== null && $constructor->getNumberOfParameters() > 0) {
                $metadata->constructor = array();
                foreach ($constructor->getParameters() as $parameter) {
                    $metadata->constructor[] = $parameter->getName();
                    if (!$parameter->allowsNull() && !$parameter->isDefaultValueAvailable()) {
                        $markRequired[] = $parameter->getName();
                    }
                }
            }

            //@Attribute annotations
            $attributeClassName = 'Modules\\Annotation\\Annotations\\Attribute';
            if ($comment->hasAnnotationType($attributeClassName)) {
                foreach ($comment->getAnnotationType($attributeClassName) as $annotation) {
                    /** @var $annotation Attribute */
                    $metadata->attributes[$annotation->name] = $annotation->toArray();
                }
            }

            foreach ($markRequired as $attribute) {
                if (!isset($metadata->attributes[$attribute])) {
                    $metadata->attributes[$attribute] = array();
                }
                $metadata->attributes[$attribute]['required'] = true;
            }

            //@Target
            $targetClassName = 'Modules\\Annotation\\Annotations\\Target';
            if ($comment->hasAnnotationType($targetClassName)) {
                $metadata->target = 0;
                foreach ($comment->getAnnotationType($targetClassName) as $annotation) {
                    /** @var $annotation Target */
                    $metadata->target |= $annotation->target;
                }
            }

            //@DefaultAttribute
            if ($comment->has('DefaultAttribute')) {
                $metadata->defaultAttribute = $comment->get('DefaultAttribute');
            }
            $this->annotations[$class] = $metadata;<commit_msg>Constructor attributes are automatically created and marked as required when needed.<commit_after><?php

/**
 * This file is part of the Miny framework.
 * (c) <NAME> <<EMAIL>>
 *
 * For licensing information see the LICENSE file.
 */

namespace Modules\Annotation;

use Modules\Annotation\Annotations\Attribute;
use Modules\Annotation\Annotations\Target;
use Modules\Annotation\Exceptions\AnnotationException;

class AnnotationContainer
{
    /**
     * @var AnnotationMetadata[]
     */
    private $annotations;

    /**
     * @var AnnotationReader
     */
    private $reader;

    /**
     * @var \ReflectionClass[]
     */
    private $reflectors = array();

    public function __construct(AnnotationReader $reader)
    {
        $this->reader = $reader;

        $this->annotations = array(
            'Modules\\Annotation\\Annotations\\Attribute' => AnnotationMetadata::create(
                    array(
                        'defaultAttribute' => 'name',
                        'attributes'       => array(
                            'name'     => array(
                                'required' => true,
                                'type'     => 'string'
                            ),
                            'setter'   => array(
                                'required' => false,
                                'type'     => 'string'
                            ),
                            'type'     => array(
                                'required' => false,
                                'type'     => 'mixed'
                            ),
                            'nullable' => array(
                                'required' => false,
                                'type'     => 'bool'
                            ),
                            'required' => array(
                                'required' => false,
                                'type'     => 'bool'
                            )
                        ),
                        'target'           => Target::TARGET_CLASS
                    )
                ),
            'Modules\\Annotation\\Annotations\\Enum'      => AnnotationMetadata::create(
                    array(
                        'defaultAttribute' => 'values',
                        'attributes'       => array(
                            'values' => array(
                                'required' => true,
                                'type'     => array()
                            )
                        ),
                        'target'           => Target::TARGET_ANNOTATION
                    )
                ),
            'Modules\\Annotation\\Annotations\\Target'    => AnnotationMetadata::create(
                    array(
                        'defaultAttribute' => 'target',
                        'constructor'      => array(
                            'target'
                        ),
                        'attributes'       => array(
                            'target' => array(
                                'required' => true,
                                'type'     => 'mixed'
                            )
                        ),
                        'target'           => Target::TARGET_CLASS
                    )
                )
        );
    }

    public function registerAnnotation($class, array $metadata)
    {
        $this->annotations[$class] = AnnotationMetadata::create($metadata);
    }

    /**
     * @param $class
     * @return \ReflectionClass
     */
    public function getClassReflector($class)
    {
        if (!isset($this->reflectors[$class])) {
            $this->reflectors[$class] = new \ReflectionClass($class);
        }

        return $this->reflectors[$class];
    }

    /**
     * @param      $class
     * @param bool $isParent
     *
     * @throws AnnotationException
     *
     * @return AnnotationMetadata
     */
    private function readClassMetadata($class, $isParent = false)
    {
        if (!isset($this->annotations[$class])) {
            $reflector = $this->getClassReflector($class);

            $parent = $reflector->getParentClass();
            if ($parent) {
                $this->reflectors[$parent->getName()] = $parent;

                $metadata = $this->readClassMetadata($parent->getName(), true);
            } else {
                $metadata = new AnnotationMetadata();
            }

            $comment = $this->reader->readClass($class);
            if (!$comment->has('Annotation')) {
                if ($isParent) {
                    return $metadata;
                }
                throw new AnnotationException("Class {$class} has not been marked with @Annotation");
            }

            //@Attribute annotations
            $attributeClassName = 'Modules\\Annotation\\Annotations\\Attribute';
            if ($comment->hasAnnotationType($attributeClassName)) {
                foreach ($comment->getAnnotationType($attributeClassName) as $annotation) {
                    /** @var $annotation Attribute */
                    $metadata->attributes[$annotation->name] = $annotation->toArray();
                }
            }

            //@Target
            $targetClassName = 'Modules\\Annotation\\Annotations\\Target';
            if ($comment->hasAnnotationType($targetClassName)) {
                $metadata->target = 0;
                foreach ($comment->getAnnotationType($targetClassName) as $annotation) {
                    /** @var $annotation Target */
                    $metadata->target |= $annotation->target;
                }
            }

            //@DefaultAttribute
            if ($comment->has('DefaultAttribute')) {
                $metadata->defaultAttribute = $comment->get('DefaultAttribute');
            }

            //get constructor info
            $constructor = $reflector->getConstructor();
            if ($constructor !== null && $constructor->getNumberOfParameters() > 0) {
                $metadata->constructor = array();
                foreach ($constructor->getParameters() as $parameter) {
                    $name = $parameter->getName();
                    if (!isset($metadata->attributes[$name])) {
                        $metadata->attributes[$name] = array(
                            'required' => false,
                            'type'     => 'mixed',
                            'setter'   => null,
                            'nullable' => false
                        );
                    }

                    $metadata->constructor[] = $name;
                    if (!$parameter->allowsNull() && !$parameter->isDefaultValueAvailable()) {
                        $metadata->attributes[$name]['required'] = true;
                    }
                }
            }
            $this->annotations[$class] = $metadata;
{'fraction_non_alphanumeric': 0.12004136810223831, 'fraction_numerical': 0.0002954864445593558, 'mean_word_length': 1.127947186419365, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 166, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7560129', 'n_tokens_mistral': 3026, 'n_tokens_neox': 2876, 'n_words': 541}