src/bitExpert/Disco/Proxy/Configuration/ConfigurationGenerator.php
public function generate(ReflectionClass $originalClass, ClassGenerator $classGenerator)
    {
        CanProxyAssertion::assertClassCanBeProxied($originalClass, false);

        $annotation = null;
        $forceLazyInitProperty = new ForceLazyInitProperty();
        $sessionBeansProperty = new SessionBeansProperty();
        $postProcessorsProperty = new BeanPostProcessorsProperty();
        $parameterValuesProperty = new ParameterValuesProperty();
        $beanFactoryConfigurationProperty = new BeanFactoryConfigurationProperty();
        $aliasesProperty = new AliasesProperty();
        $getParameterMethod = new GetParameter($parameterValuesProperty);
        $wrapBeanAsLazyMethod = new WrapBeanAsLazy($beanFactoryConfigurationProperty);

        try {
            $reader = new AnnotationReader();
            $annotation = $reader->getClassAnnotation($originalClass, Configuration::class);
        } catch (Exception $e) {
            throw new InvalidProxiedClassException($e->getMessage(), $e->getCode(), $e);
        }

        if (null === $annotation) {
            throw new InvalidProxiedClassException(
                sprintf(
                    '"%s" seems not to be a valid configuration class. @Configuration annotation missing!',
                    $originalClass->name
                )
            );
        }

        $classGenerator->setExtendedClass($originalClass->getName());
        $classGenerator->setImplementedInterfaces([AliasContainerInterface::class]);
        $classGenerator->addPropertyFromGenerator($forceLazyInitProperty);
        $classGenerator->addPropertyFromGenerator($sessionBeansProperty);
        $classGenerator->addPropertyFromGenerator($postProcessorsProperty);
        $classGenerator->addPropertyFromGenerator($parameterValuesProperty);
        $classGenerator->addPropertyFromGenerator($beanFactoryConfigurationProperty);
        $classGenerator->addPropertyFromGenerator($aliasesProperty);

        $postProcessorMethods = [];
        $parentAliases = [];
        $localAliases = [];
        $methods = $originalClass->getMethods(ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_PROTECTED);
        foreach ($methods as $method) {
            $methodReflection = new MethodReflection(
                $method->class,
                $method->name
            );

            /** @var \bitExpert\Disco\Annotations\Bean|null $beanAnnotation */
            $beanAnnotation = $reader->getMethodAnnotation($method, Bean::class);
            if (null === $beanAnnotation) {
                /** @var \bitExpert\Disco\Annotations\BeanPostProcessor $beanAnnotation */
                $beanAnnotation = $reader->getMethodAnnotation($method, BeanPostProcessor::class);
                if ($beanAnnotation instanceof BeanPostProcessor) {
                    $postProcessorMethods[] = $method->name;

                    $proxyMethod = BeanPostProcessorMethod::generateMethod(
                        $methodReflection,
                        $beanAnnotation,
                        $getParameterMethod
                    );
                    $classGenerator->addMethodFromGenerator($proxyMethod);
                    continue;
                }

                if ($method->isProtected()) {
                    continue;
                }

                // every method needs either @Bean or @PostPostprocessor annotation
                throw new InvalidProxiedClassException(
                    sprintf(
                        'Method "%s" on "%s" is missing the @Bean annotation!',
                        $method->name,
                        $originalClass->name
                    )
                );
            }

            foreach ($beanAnnotation->getAliases() as $beanAlias) {
                $alias = $beanAlias->isTypeAlias() ? (string) $method->getReturnType() : $beanAlias->getName();
                if (empty($alias)) {
                    continue;
                }

                $hasAlias = '';
                if ($method->getDeclaringClass()->name === $originalClass->name) {
                    $hasAlias = $localAliases[$alias] ?? '';
                } else {
                    $hasAlias= $parentAliases[$alias] ?? '';
                }

                if ($hasAlias !== '') {
                    throw new InvalidProxiedClassException(
                        sprintf(
                            'Alias "%s" of method "%s" on "%s" is already used by method "%s" of another Bean!'
                            . ' Did you use a type alias twice?',
                            $alias,
                            $method->name,
                            $originalClass->name,
                            $hasAlias
                        )
                    );
                }

                if ($method->getDeclaringClass()->name === $originalClass->name) {
                    $localAliases[$alias] = $method->name;
                } else {
                    $parentAliases[$alias] = $method->name;
                }
            }

            $proxyMethod = BeanMethod::generateMethod(
                $methodReflection,
                $beanAnnotation,
                $method->getReturnType(),
                $forceLazyInitProperty,
                $sessionBeansProperty,
                $postProcessorsProperty,
                $beanFactoryConfigurationProperty,
                $getParameterMethod,
                $wrapBeanAsLazyMethod
            );

            $classGenerator->addMethodFromGenerator($proxyMethod);
        }

        $aliasesProperty->setDefaultValue($parentAliases + $localAliases);

        $classGenerator->addMethodFromGenerator(
            new Constructor(
                $parameterValuesProperty,
                $sessionBeansProperty,
                $beanFactoryConfigurationProperty,
                $postProcessorsProperty,
                $postProcessorMethods
            )
        );
        $classGenerator->addMethodFromGenerator($wrapBeanAsLazyMethod);
        $classGenerator->addMethodFromGenerator($getParameterMethod);
        $classGenerator->addMethodFromGenerator(
            new MagicSleep(
                $originalClass,
                $sessionBeansProperty
            )
        );
        $classGenerator->addMethodFromGenerator(
            new GetAlias($aliasesProperty)
        );
        $classGenerator->addMethodFromGenerator(
            new HasAlias($aliasesProperty)
        );
    }
public function generate(ReflectionClass $originalClass, ClassGenerator $classGenerator)
    {
        CanProxyAssertion::assertClassCanBeProxied($originalClass, false);

        $annotation = null;
        $forceLazyInitProperty = new ForceLazyInitProperty();
        $sessionBeansProperty = new SessionBeansProperty();
        $postProcessorsProperty = new BeanPostProcessorsProperty();
        $parameterValuesProperty = new ParameterValuesProperty();
        $beanFactoryConfigurationProperty = new BeanFactoryConfigurationProperty();
        $aliasesProperty = new AliasesProperty();
        $getParameterMethod = new GetParameter($parameterValuesProperty);
        $wrapBeanAsLazyMethod = new WrapBeanAsLazy($beanFactoryConfigurationProperty);

        try {
            $reader = new AnnotationReader();
            $annotation = $reader->getClassAnnotation($originalClass, Configuration::class);
        } catch (Exception $e) {
            throw new InvalidProxiedClassException($e->getMessage(), $e->getCode(), $e);
        }

        if (null === $annotation) {
            throw new InvalidProxiedClassException(
                sprintf(
                    '"%s" seems not to be a valid configuration class. @Configuration annotation missing!',
                    $originalClass->name
                )
            );
        }

        $classGenerator->setExtendedClass($originalClass->getName());
        $classGenerator->setImplementedInterfaces([AliasContainerInterface::class]);
        $classGenerator->addPropertyFromGenerator($forceLazyInitProperty);
        $classGenerator->addPropertyFromGenerator($sessionBeansProperty);
        $classGenerator->addPropertyFromGenerator($postProcessorsProperty);
        $classGenerator->addPropertyFromGenerator($parameterValuesProperty);
        $classGenerator->addPropertyFromGenerator($beanFactoryConfigurationProperty);
        $classGenerator->addPropertyFromGenerator($aliasesProperty);

        $postProcessorMethods = [];
        $parentAliases = [];
        $localAliases = [];
        $methods = $originalClass->getMethods(ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_PROTECTED);
        foreach ($methods as $method) {
            $methodReflection = new MethodReflection(
                $method->class,
                $method->name
            );

            /** @var \bitExpert\Disco\Annotations\Bean|null $beanAnnotation */
            $beanAnnotation = $reader->getMethodAnnotation($method, Bean::class);
            if (null === $beanAnnotation) {
                /** @var \bitExpert\Disco\Annotations\BeanPostProcessor $beanAnnotation */
                $beanAnnotation = $reader->getMethodAnnotation($method, BeanPostProcessor::class);
                if ($beanAnnotation instanceof BeanPostProcessor) {
                    $postProcessorMethods[] = $method->name;

                    $proxyMethod = BeanPostProcessorMethod::generateMethod(
                        $methodReflection,
                        $beanAnnotation,
                        $getParameterMethod
                    );
                    $classGenerator->addMethodFromGenerator($proxyMethod);
                    continue;
                }

                if ($method->isProtected()) {
                    continue;
                }

                // every method needs either @Bean or @PostPostprocessor annotation
                throw new InvalidProxiedClassException(
                    sprintf(
                        'Method "%s" on "%s" is missing the @Bean annotation!',
                        $method->name,
                        $originalClass->name
                    )
                );
            }

            foreach ($beanAnnotation->getAliases() as $beanAlias) {
                $alias = $beanAlias->isTypeAlias() ? (string) $method->getReturnType() : $beanAlias->getName();
                if (empty($alias)) {
                    continue;
                }

                $hasAlias = '';
                if ($method->getDeclaringClass()->name === $originalClass->name) {
                    $hasAlias = $localAliases[$alias] ?? '';
                } else {
                    $hasAlias= $parentAliases[$alias] ?? '';
                }

                if ($hasAlias !== '') {
                    throw new InvalidProxiedClassException(
                        sprintf(
                            'Alias "%s" of method "%s" on "%s" is already used by method "%s" of another Bean!'
                            . ' Did you use a type alias twice?',
                            $alias,
                            $method->name,
                            $originalClass->name,
                            $hasAlias
                        )
                    );
                }

                if ($method->getDeclaringClass()->name === $originalClass->name) {
                    $localAliases[$alias] = $method->name;
                } else {
                    $parentAliases[$alias] = $method->name;
                }
            }

            $proxyMethod = BeanMethod::generateMethod(
                $methodReflection,
                $beanAnnotation,
                $method->getReturnType(),
                $forceLazyInitProperty,
                $sessionBeansProperty,
                $postProcessorsProperty,
                $beanFactoryConfigurationProperty,
                $getParameterMethod,
                $wrapBeanAsLazyMethod
            );

            $classGenerator->addMethodFromGenerator($proxyMethod);
        }

        $aliasesProperty->setDefaultValue($parentAliases + $localAliases);

        $classGenerator->addMethodFromGenerator(
            new Constructor(
                $parameterValuesProperty,
                $sessionBeansProperty,
                $beanFactoryConfigurationProperty,
                $postProcessorsProperty,
                $postProcessorMethods
            )
        );
        $classGenerator->addMethodFromGenerator($wrapBeanAsLazyMethod);
        $classGenerator->addMethodFromGenerator($getParameterMethod);
        $classGenerator->addMethodFromGenerator(
            new MagicSleep(
                $originalClass,
                $sessionBeansProperty
            )
        );
        $classGenerator->addMethodFromGenerator(
            new GetAlias($aliasesProperty)
        );
        $classGenerator->addMethodFromGenerator(
            new HasAlias($aliasesProperty)
        );
    }
{@inheritDoc}
@throws InvalidProxiedClassException
@throws InvalidArgumentException
@throws \ReflectionException