Creates the property shortcuts.

@param array           $property
@param ClassDefinition $classDefinition

@throws CompilerException
323294
protected function processShortcuts(array $property, ClassDefinition $classDefinition)
    {
        foreach ($property['shortcuts'] as $shortcut) {
            if ('_' == substr($property['name'], 0, 1)) {
                $name = substr($property['name'], 1);
            } else {
                $name = $property['name'];
            }

            $docBlock = null;
            if (isset($shortcut['docblock'])) {
                $docBlock = $shortcut['docblock'];
            } elseif (isset($property['docblock'])) {
                $docBlock = $property['docblock'];
            }

            $returnsType = [];

            if ($docBlock) {
                $docBlockParser = new DocblockParser('/'.$docBlock.'/');
                $docBlockParsed = $docBlockParser->parse();

                if ($annotations = $docBlockParsed->getAnnotationsByType('var')) {
                    $returnsType = array_map(function ($type) {
                        return 'mixed' == ($type = trim($type)) ? 'variable' : $type;
                    }, (array) explode('|', $annotations[0]->getString()));
                }

                // Clear annotations
                $docBlockParsed->setAnnotations([]);
                $docBlock = $docBlockParsed->generate();
            }

            switch ($shortcut['name']) {
                case 'get':
                    $classDefinition->addMethod(new ClassMethod(
                        $classDefinition,
                        ['public'],
                        'get'.camelize($name),
                        null,
                        new StatementsBlock([
                            [
                                'type' => 'return',
                                'expr' => [
                                    'type' => 'property-access',
                                    'left' => [
                                        'type' => 'variable',
                                        'value' => 'this',
                                    ],
                                    'right' => [
                                        'type' => 'variable',
                                        'value' => $property['name'],
                                    ],
                                ],
                            ],
                        ]),
                        $docBlock,
                        $this->createReturnsType($returnsType, true),
                        $shortcut
                    ), $shortcut);
                    break;

                case 'set':
                    $classDefinition->addMethod(new ClassMethod(
                        $classDefinition,
                        ['public'],
                        'set'.camelize($name),
                        new ClassMethodParameters([
                            [
                                'type' => 'parameter',
                                'name' => $name,
                                'const' => 0,
                                'data-type' => 1 == \count($returnsType) ? $returnsType[0] : 'variable',
                                'mandatory' => 0,
                            ],
                        ]),
                        new StatementsBlock([
                            [
                                'type' => 'let',
                                'assignments' => [
                                    [
                                        'assign-type' => 'object-property',
                                        'operator' => 'assign',
                                        'variable' => 'this',
                                        'property' => $property['name'],
                                        'expr' => [
                                            'type' => 'variable',
                                            'value' => $name,
                                            'file' => $property['file'],
                                            'line' => $property['line'],
                                            'char' => $property['char'],
                                        ],
                                        'file' => $property['file'],
                                        'line' => $property['line'],
                                        'char' => $property['char'],
                                    ],
                                ],
                            ],
                            [
                                'type' => 'return',
                                'expr' => [
                                    'type' => 'variable',
                                    'value' => 'this',
                                    'file' => $property['file'],
                                    'line' => $property['line'],
                                    'char' => $property['char'],
                                ],
                            ],
                        ]),
                        $docBlock,
                        null,
                        $shortcut
                    ), $shortcut);
                    break;

                case 'toString':
                case '__toString':
                    $classDefinition->addMethod(new ClassMethod(
                        $classDefinition,
                        ['public'],
                        '__toString',
                        null,
                        new StatementsBlock([
                            [
                                'type' => 'return',
                                'expr' => [
                                    'type' => 'property-access',
                                    'left' => [
                                        'type' => 'variable',
                                        'value' => 'this',
                                    ],
                                    'right' => [
                                        'type' => 'variable',
                                        'value' => $property['name'],
                                    ],
                                ],
                            ],
                        ]),
                        $docBlock,
                        $this->createReturnsType(['string']),
                        $shortcut
                    ), $shortcut);
                    break;

                default:
                    throw new CompilerException("Unknown shortcut '".$shortcut['name']."'", $shortcut);
            }
        }
    }
760768
protected function invokeGetter(ReflectionProperty $property)
    {
        $methodName = $this->generateGetterName($property->getName());
        if ($this->hasInternalMethod($methodName)) {
            return $this->$methodName();
        }

        throw new UndefinedPropertyException(sprintf(
            'No "%s"() method available for property "%s"', $methodName,
            $property->getName()
        ));
    }
936682
protected function defineEntity(ClassDefinition $class)
    {
        $class->property($this->driverName)->asString();

        $class->property($this->options)->asObject(FormObject::class);
    }
321822
private function implementGetResult(ContextInterface $context, ClassGenerator $class, Property $property)
    {
        $useAssembler = new UseAssembler($this->wrapperClass ?: ResultInterface::class);
        if ($useAssembler->canAssemble($context)) {
            $useAssembler->assemble($context);
        }

        $methodName = 'getResult';
        $class->removeMethod($methodName);
        $class->addMethodFromGenerator(
            MethodGenerator::fromArray([
                'name' => $methodName,
                'parameters' => [],
                'visibility' => MethodGenerator::VISIBILITY_PUBLIC,
                'returntype' => ResultInterface::class,
                'body' => $this->generateGetResultBody($property),
                'docblock' => DocBlockGeneratorFactory::fromArray([
                    'tags' => [
                        [
                            'name' => 'return',
                            'description' => $this->generateGetResultReturnTag($property)
                        ]
                    ]
                ])
            ])
        );
    }
231277
protected function buildClass(ClassDefinition $class, $indent)
    {
        $source = <<<EOF
<?php

namespace {$class->getNamespace()};


EOF;

        $source .= (new DocBlock($class->getDocBlock(), ''))."\n";

        if ($class->isFinal()) {
            $source .= 'final ';
        } elseif ($class->isAbstract()) {
            $source .= 'abstract ';
        }

        $source .= $class->getType().' '.$class->getName();

        if ($class->getExtendsClass()) {
            $extendsClassDefinition = $class->getExtendsClassDefinition();
            if (!$extendsClassDefinition) {
                throw new \RuntimeException('Class "'.$class->getName().'" does not have a extendsClassDefinition');
            }

            $source .= ' extends '.($extendsClassDefinition->isBundled() ? '' : '\\').trim($extendsClassDefinition->getCompleteName(), '\\');
        }

        if ($implementedInterfaces = $class->getImplementedInterfaces()) {
            $interfaces = array_map(function ($val) {
                return '\\'.trim($val, '\\');
            }, $implementedInterfaces);

            $keyword = 'interface' == $class->getType() ? ' extends ' : ' implements ';
            $source .= $keyword.implode(', ', $interfaces);
        }

        $source .= PHP_EOL.'{'.PHP_EOL;

        foreach ($class->getConstants() as $constant) {
            $source .= $this->buildConstant($constant, $indent).PHP_EOL.PHP_EOL;
        }

        foreach ($class->getProperties() as $property) {
            $source .= $this->buildProperty($property, $indent).PHP_EOL.PHP_EOL;
        }

        $source .= PHP_EOL;

        foreach ($class->getMethods() as $method) {
            if ($method->isInternal()) {
                continue;
            }

            $source .= $this->buildMethod($method, 'interface' === $class->getType(), $indent)."\n\n";
        }

        return $source.'}'.PHP_EOL;
    }
167160
final protected function defineClass(ClassDefinition $class)
    {
        $class->property($this->object)->asObject($this->getObjectType());
        $class->property($this->dataSource)->asObject(IObjectSet::class);

        $this->defineClassStructure($class);
    }
1027162
protected function define(ClassDefinition $class)
    {
        $class->property($this->name)->asString();

        $class->property($this->image)->asObject(Image::class);

        $class->property($this->altText)->nullable()->asString();
    }
33095
public static function fromProperty(
        string $class,
        string $property
    ): array
    {
        try {

            $property = new \ReflectionProperty($class, $property);
        }
        catch (\ReflectionException $e) {

            throw new Exception(
                "Property '{$class}::{$property}' not found.",
                Exception::PROPERTY_NOT_FOUND
            );
        }

        $docComment = $property->getDocComment();

        unset($property);

        if ($docComment === false) {

            return [];
        }

        return Parser::parseDocComment($docComment);
    }
1302694
private function implementGetIterator(ClassGenerator $class, Property $firstProperty)
    {
        $methodName = 'getIterator';
        $class->removeMethod($methodName);
        $class->addMethodFromGenerator(
            MethodGenerator::fromArray([
                'name' => $methodName,
                'parameters' => [],
                'visibility' => MethodGenerator::VISIBILITY_PUBLIC,
                'body' => sprintf(
                    'return new \\ArrayIterator(is_array($this->%1$s) ? $this->%1$s : []);',
                    $firstProperty->getName()
                ),
                'docblock' => DocBlockGeneratorFactory::fromArray([
                    'tags' => [
                        [
                            'name' => 'return',
                            'description' => '\\ArrayIterator'
                        ]
                    ]
                ])
            ])
        );
    }
1056201
public function finalize(FinalizedClassDefinition $class = null) : FinalizedFormObjectDefinition
    {
        return new FinalizedFormObjectDefinition(
                $class ?: $this->class->finalize(),
                $this->propertyFieldMap,
                $this->build()
        );
    }
85151
protected function defineEntity(ClassDefinition $class)
    {
        $class->property($this->author)->asObject(BlogAuthor::class);

        $class->property($this->category)->nullable()->asObject(BlogCategory::class);

        $class->property($this->title)->asString();

        $class->property($this->subTitle)->asString();

        $class->property($this->slug)->asString();

        $class->property($this->extract)->asString();

        $class->property($this->featuredImage)->nullable()->asObject(Image::class);

        $class->property($this->date)->asObject(Date::class);

        $class->property($this->articleContent)->asObject(Html::class);

        $class->property($this->comments)->asType(BlogArticleComment::collectionType());

        $class->property($this->allowSharing)->asBool();

        $class->property($this->allowCommenting)->asBool();

        $class->property($this->published)->asBool();

        $class->property($this->createdAt)->asObject(DateTime::class);

        $class->property($this->updatedAt)->asObject(DateTime::class);

        $this->defineMetadata($class);
    }
921332
protected function defineEntity(ClassDefinition $class)
    {
        $class->property($this->namespace)->asString();

        $class->property($this->name)->asString();
        
        $class->property($this->orderIndex)->asInt();

        $class->property($this->htmlContentAreas)->asType(HtmlContentArea::collectionType());

        $class->property($this->imageContentAreas)->asType(ImageContentArea::collectionType());

        $class->property($this->textContentAreas)->asType(TextContentArea::collectionType());

        $class->property($this->fileContentAreas)->asType(FileContentArea::collectionType());

        $class->property($this->metadata)->asType(ContentMetadata::collectionType());

        $class->property($this->nestedArrayContentGroups)->asType(ContentGroup::collectionType());

        $class->property($this->updatedAt)->asObject(DateTime::class);
    }
922642
private function isClassCacheable($classDefinition)
    {
        if ($classDefinition instanceof ClassDefinition) {
            return true;
        }
        if ($classDefinition instanceof \ReflectionClass) {
            if ($classDefinition->isInternal() && $classDefinition->isInstantiable()) {
                $extension = $classDefinition->getExtension();
                switch ($extension->getName()) {
                    case 'Reflection':
                    case 'Core':
                    case 'SPL':
                        return true;
                }
            }
        }

        return false;
    }
615664
protected function define(ClassDefinition $class)
    {
        $class->property($this->colour)->asObject(Colour::class);

        $class->property($this->alpha)->asFloat();
    }
612228
protected function define(ClassDefinition $class)
    {
        $class->property($this->key)->asString();

        $class->property($this->value)->asMixed();
    }
272640
private function getDocBlockFromProperty($class, $property)
    {
        // Use a ReflectionProperty instead of $class to get the parent class if applicable
        try {
            $reflectionProperty = new \ReflectionProperty($class, $property);
        } catch (\ReflectionException $e) {
            return;
        }

        return $this->docBlockFactory->create($reflectionProperty, $this->contextFactory->createFromReflector($reflectionProperty->getDeclaringClass()));
    }
112438
public function checkInterfaceImplements(self $classDefinition, self $interfaceDefinition)
    {
        foreach ($interfaceDefinition->getMethods() as $method) {
            if (!$classDefinition->hasMethod($method->getName())) {
                throw new CompilerException(
                    sprintf(
                        'Class %s must implement a method called: "%s" as requirement of interface: "%s"',
                        $classDefinition->getCompleteName(),
                        $method->getName(),
                        $interfaceDefinition->getCompleteName()
                    )
                );
            }

            if (!$method->hasParameters()) {
                continue;
            }

            $implementedMethod = $classDefinition->getMethod($method->getName());
            if ($implementedMethod->getNumberOfRequiredParameters() > $method->getNumberOfRequiredParameters() ||
                $implementedMethod->getNumberOfParameters() < $method->getNumberOfParameters()
            ) {
                throw new CompilerException(
                    sprintf(
                        'Method %s::%s() does not have the same number of required parameters in interface: "%s"',
                        $classDefinition->getCompleteName(),
                        $method->getName(),
                        $interfaceDefinition->getCompleteName()
                    )
                );
            }
        }
    }