/**
  * {@inheritdoc}
  */
 public function generate(ReflectionClass $originalClass, ClassGenerator $classGenerator)
 {
     CanProxyAssertion::assertClassCanBeProxied($originalClass);
     $classGenerator->setExtendedClass($originalClass->getName());
     $additionalInterfaces = ['OpenClassrooms\\ServiceProxy\\ServiceProxyInterface'];
     $additionalProperties['proxy_realSubject'] = new PropertyGenerator('proxy_realSubject', null, PropertyGenerator::FLAG_PRIVATE);
     $additionalMethods['setProxy_realSubject'] = new MethodGenerator('setProxy_realSubject', [['name' => 'realSubject']], MethodGenerator::FLAG_PUBLIC, '$this->proxy_realSubject = $realSubject;');
     $methods = $originalClass->getMethods(\ReflectionMethod::IS_PUBLIC);
     foreach ($methods as $method) {
         $preSource = '';
         $postSource = '';
         $exceptionSource = '';
         $methodAnnotations = $this->annotationReader->getMethodAnnotations($method);
         foreach ($methodAnnotations as $methodAnnotation) {
             if ($methodAnnotation instanceof Cache) {
                 $this->addCacheAnnotation($classGenerator);
                 $additionalInterfaces['cache'] = 'OpenClassrooms\\ServiceProxy\\ServiceProxyCacheInterface';
                 $response = $this->cacheStrategy->execute($this->serviceProxyStrategyRequestBuilder->create()->withAnnotation($methodAnnotation)->withClass($originalClass)->withMethod($method)->build());
                 foreach ($response->getMethods() as $methodToAdd) {
                     $additionalMethods[$methodToAdd->getName()] = $methodToAdd;
                 }
                 foreach ($response->getProperties() as $propertyToAdd) {
                     $additionalProperties[$propertyToAdd->getName()] = $propertyToAdd;
                 }
                 $preSource .= $response->getPreSource();
                 $postSource .= $response->getPostSource();
                 $exceptionSource .= $response->getExceptionSource();
             }
         }
         $classGenerator->addMethodFromGenerator($this->generateProxyMethod($method, $preSource, $postSource, $exceptionSource));
     }
     $classGenerator->setImplementedInterfaces($additionalInterfaces);
     $classGenerator->addProperties($additionalProperties);
     $classGenerator->addMethods($additionalMethods);
 }
 /**
  * {@inheritDoc}
  */
 public function generate(ReflectionClass $originalClass, ClassGenerator $classGenerator)
 {
     CanProxyAssertion::assertClassCanBeProxied($originalClass, false);
     $classGenerator->setExtendedClass($originalClass->getName());
     $classGenerator->setImplementedInterfaces([AccessInterceptorInterface::class]);
     $classGenerator->addPropertyFromGenerator($prefixInterceptors = new MethodPrefixInterceptors());
     $classGenerator->addPropertyFromGenerator($suffixInterceptors = new MethodSuffixInterceptors());
     array_map(function (MethodGenerator $generatedMethod) use($originalClass, $classGenerator) {
         ClassGeneratorUtils::addMethodIfNotFinal($originalClass, $classGenerator, $generatedMethod);
     }, array_merge(array_map($this->buildMethodInterceptor($prefixInterceptors, $suffixInterceptors), ProxiedMethodsFilter::getProxiedMethods($originalClass, ['__get', '__set', '__isset', '__unset', '__clone', '__sleep'])), [new StaticProxyConstructor($originalClass, $prefixInterceptors, $suffixInterceptors), new BindProxyProperties($originalClass, $prefixInterceptors, $suffixInterceptors), new SetMethodPrefixInterceptor($prefixInterceptors), new SetMethodSuffixInterceptor($suffixInterceptors), new MagicGet($originalClass, $prefixInterceptors, $suffixInterceptors), new MagicSet($originalClass, $prefixInterceptors, $suffixInterceptors), new MagicIsset($originalClass, $prefixInterceptors, $suffixInterceptors), new MagicUnset($originalClass, $prefixInterceptors, $suffixInterceptors), new MagicSleep($originalClass, $prefixInterceptors, $suffixInterceptors), new MagicClone($originalClass, $prefixInterceptors, $suffixInterceptors)]));
 }
 /**
  * {@inheritDoc}
  */
 public function generate(ReflectionClass $originalClass, ClassGenerator $classGenerator)
 {
     CanProxyAssertion::assertClassCanBeProxied($originalClass);
     $interfaces = array('ProxyManager\\Proxy\\NullObjectInterface');
     if ($originalClass->isInterface()) {
         $interfaces[] = $originalClass->getName();
     }
     $classGenerator->setImplementedInterfaces($interfaces);
     foreach (ProxiedMethodsFilter::getProxiedMethods($originalClass) as $method) {
         $classGenerator->addMethodFromGenerator(NullObjectMethodInterceptor::generateMethod(new MethodReflection($method->getDeclaringClass()->getName(), $method->getName())));
     }
     ClassGeneratorUtils::addMethodIfNotFinal($originalClass, $classGenerator, new Constructor($originalClass));
 }
 /**
  * {@inheritDoc}
  */
 public function generate(ReflectionClass $originalClass, ClassGenerator $classGenerator)
 {
     CanProxyAssertion::assertClassCanBeProxied($originalClass, false);
     $classGenerator->setExtendedClass($originalClass->getName());
     $classGenerator->setImplementedInterfaces(array('ProxyManager\\Proxy\\AccessInterceptorInterface'));
     $classGenerator->addPropertyFromGenerator($prefixInterceptors = new MethodPrefixInterceptors());
     $classGenerator->addPropertyFromGenerator($suffixInterceptors = new MethodPrefixInterceptors());
     array_map(function (MethodGenerator $generatedMethod) use($originalClass, $classGenerator) {
         ClassGeneratorUtils::addMethodIfNotFinal($originalClass, $classGenerator, $generatedMethod);
     }, array_merge(array_map(function (ReflectionMethod $method) use($prefixInterceptors, $suffixInterceptors) {
         return InterceptedMethod::generateMethod(new MethodReflection($method->getDeclaringClass()->getName(), $method->getName()), $prefixInterceptors, $suffixInterceptors);
     }, ProxiedMethodsFilter::getProxiedMethods($originalClass, array('__get', '__set', '__isset', '__unset', '__clone', '__sleep'))), array(new Constructor($originalClass, $prefixInterceptors, $suffixInterceptors), new SetMethodPrefixInterceptor($prefixInterceptors), new SetMethodSuffixInterceptor($suffixInterceptors), new MagicGet($originalClass, $prefixInterceptors, $suffixInterceptors), new MagicSet($originalClass, $prefixInterceptors, $suffixInterceptors), new MagicIsset($originalClass, $prefixInterceptors, $suffixInterceptors), new MagicUnset($originalClass, $prefixInterceptors, $suffixInterceptors), new MagicSleep($originalClass, $prefixInterceptors, $suffixInterceptors), new MagicClone($originalClass, $prefixInterceptors, $suffixInterceptors))));
 }
 /**
  * {@inheritDoc}
  */
 public function generate(ReflectionClass $originalClass, ClassGenerator $classGenerator)
 {
     CanProxyAssertion::assertClassCanBeProxied($originalClass);
     $interfaces = [RemoteObjectInterface::class];
     if ($originalClass->isInterface()) {
         $interfaces[] = $originalClass->getName();
     } else {
         $classGenerator->setExtendedClass($originalClass->getName());
     }
     $classGenerator->setImplementedInterfaces($interfaces);
     $classGenerator->addPropertyFromGenerator($adapter = new AdapterProperty());
     array_map(function (MethodGenerator $generatedMethod) use($originalClass, $classGenerator) {
         ClassGeneratorUtils::addMethodIfNotFinal($originalClass, $classGenerator, $generatedMethod);
     }, array_merge(array_map(function (ReflectionMethod $method) use($adapter, $originalClass) : RemoteObjectMethod {
         return RemoteObjectMethod::generateMethod(new MethodReflection($method->getDeclaringClass()->getName(), $method->getName()), $adapter, $originalClass);
     }, ProxiedMethodsFilter::getProxiedMethods($originalClass, ['__get', '__set', '__isset', '__unset'])), [new StaticProxyConstructor($originalClass, $adapter), new MagicGet($originalClass, $adapter), new MagicSet($originalClass, $adapter), new MagicIsset($originalClass, $adapter), new MagicUnset($originalClass, $adapter)]));
 }
 /**
  * {@inheritDoc}
  */
 public function generate(ReflectionClass $originalClass, ClassGenerator $classGenerator)
 {
     CanProxyAssertion::assertClassCanBeProxied($originalClass);
     $interfaces = [VirtualProxyInterface::class];
     $publicProperties = new PublicPropertiesMap(Properties::fromReflectionClass($originalClass));
     if ($originalClass->isInterface()) {
         $interfaces[] = $originalClass->getName();
     } else {
         $classGenerator->setExtendedClass($originalClass->getName());
     }
     $classGenerator->setImplementedInterfaces($interfaces);
     $classGenerator->addPropertyFromGenerator($valueHolder = new ValueHolderProperty());
     $classGenerator->addPropertyFromGenerator($initializer = new InitializerProperty());
     $classGenerator->addPropertyFromGenerator($publicProperties);
     array_map(function (MethodGenerator $generatedMethod) use($originalClass, $classGenerator) {
         ClassGeneratorUtils::addMethodIfNotFinal($originalClass, $classGenerator, $generatedMethod);
     }, array_merge(array_map($this->buildLazyLoadingMethodInterceptor($initializer, $valueHolder), ProxiedMethodsFilter::getProxiedMethods($originalClass)), [new StaticProxyConstructor($initializer, Properties::fromReflectionClass($originalClass)), Constructor::generateMethod($originalClass, $valueHolder), new MagicGet($originalClass, $initializer, $valueHolder, $publicProperties), new MagicSet($originalClass, $initializer, $valueHolder, $publicProperties), new MagicIsset($originalClass, $initializer, $valueHolder, $publicProperties), new MagicUnset($originalClass, $initializer, $valueHolder, $publicProperties), new MagicClone($originalClass, $initializer, $valueHolder), new MagicSleep($originalClass, $initializer, $valueHolder), new MagicWakeup($originalClass), new SetProxyInitializer($initializer), new GetProxyInitializer($initializer), new InitializeProxy($initializer, $valueHolder), new IsProxyInitialized($valueHolder), new GetWrappedValueHolderValue($valueHolder)]));
 }
 /**
  * {@inheritDoc}
  */
 public function generate(ReflectionClass $originalClass, ClassGenerator $classGenerator, array $proxyOptions = [])
 {
     CanProxyAssertion::assertClassCanBeProxied($originalClass, false);
     $filteredProperties = Properties::fromReflectionClass($originalClass)->filter(isset($proxyOptions['skippedProperties']) ? $proxyOptions['skippedProperties'] : []);
     $publicProperties = new PublicPropertiesMap($filteredProperties);
     $privateProperties = new PrivatePropertiesMap($filteredProperties);
     $protectedProperties = new ProtectedPropertiesMap($filteredProperties);
     $classGenerator->setExtendedClass($originalClass->getName());
     $classGenerator->setImplementedInterfaces([GhostObjectInterface::class]);
     $classGenerator->addPropertyFromGenerator($initializer = new InitializerProperty());
     $classGenerator->addPropertyFromGenerator($initializationTracker = new InitializationTracker());
     $classGenerator->addPropertyFromGenerator($publicProperties);
     $classGenerator->addPropertyFromGenerator($privateProperties);
     $classGenerator->addPropertyFromGenerator($protectedProperties);
     $init = new CallInitializer($initializer, $initializationTracker, $filteredProperties);
     array_map(function (MethodGenerator $generatedMethod) use($originalClass, $classGenerator) {
         ClassGeneratorUtils::addMethodIfNotFinal($originalClass, $classGenerator, $generatedMethod);
     }, array_merge($this->getAbstractProxiedMethods($originalClass), [$init, new StaticProxyConstructor($initializer, $filteredProperties), new MagicGet($originalClass, $initializer, $init, $publicProperties, $protectedProperties, $privateProperties, $initializationTracker), new MagicSet($originalClass, $initializer, $init, $publicProperties, $protectedProperties, $privateProperties), new MagicIsset($originalClass, $initializer, $init, $publicProperties, $protectedProperties, $privateProperties), new MagicUnset($originalClass, $initializer, $init, $publicProperties, $protectedProperties, $privateProperties), new MagicClone($originalClass, $initializer, $init, $publicProperties), new MagicSleep($originalClass, $initializer, $init, $publicProperties), new SetProxyInitializer($initializer), new GetProxyInitializer($initializer), new InitializeProxy($initializer, $init), new IsProxyInitialized($initializer)]));
 }
 /**
  * {@inheritDoc}
  */
 public function generate(ReflectionClass $originalClass, ClassGenerator $classGenerator)
 {
     CanProxyAssertion::assertClassCanBeProxied($originalClass);
     $interfaces = array('ProxyManager\\Proxy\\VirtualProxyInterface');
     $publicProperties = new PublicPropertiesMap($originalClass);
     if ($originalClass->isInterface()) {
         $interfaces[] = $originalClass->getName();
     } else {
         $classGenerator->setExtendedClass($originalClass->getName());
     }
     $classGenerator->setImplementedInterfaces($interfaces);
     $classGenerator->addPropertyFromGenerator($valueHolder = new ValueHolderProperty());
     $classGenerator->addPropertyFromGenerator($initializer = new InitializerProperty());
     $classGenerator->addPropertyFromGenerator($publicProperties);
     array_map(function (MethodGenerator $generatedMethod) use($originalClass, $classGenerator) {
         ClassGeneratorUtils::addMethodIfNotFinal($originalClass, $classGenerator, $generatedMethod);
     }, array_merge(array_map(function (ReflectionMethod $method) use($initializer, $valueHolder) {
         return LazyLoadingMethodInterceptor::generateMethod(new MethodReflection($method->getDeclaringClass()->getName(), $method->getName()), $initializer, $valueHolder);
     }, ProxiedMethodsFilter::getProxiedMethods($originalClass)), array(new Constructor($originalClass, $initializer), new MagicGet($originalClass, $initializer, $valueHolder, $publicProperties), new MagicSet($originalClass, $initializer, $valueHolder, $publicProperties), new MagicIsset($originalClass, $initializer, $valueHolder, $publicProperties), new MagicUnset($originalClass, $initializer, $valueHolder, $publicProperties), new MagicClone($originalClass, $initializer, $valueHolder), new MagicSleep($originalClass, $initializer, $valueHolder), new MagicWakeup($originalClass), new SetProxyInitializer($initializer), new GetProxyInitializer($initializer), new InitializeProxy($initializer, $valueHolder), new IsProxyInitialized($valueHolder), new GetWrappedValueHolderValue($valueHolder))));
 }
 /**
  * {@inheritDoc}
  */
 public function generate(ReflectionClass $originalClass, ClassGenerator $classGenerator)
 {
     CanProxyAssertion::assertClassCanBeProxied($originalClass);
     $publicProperties = new PublicPropertiesMap(Properties::fromReflectionClass($originalClass));
     $interfaces = [AccessInterceptorInterface::class, ValueHolderInterface::class];
     if ($originalClass->isInterface()) {
         $interfaces[] = $originalClass->getName();
     } else {
         $classGenerator->setExtendedClass($originalClass->getName());
     }
     $classGenerator->setImplementedInterfaces($interfaces);
     $classGenerator->addPropertyFromGenerator($valueHolder = new ValueHolderProperty());
     $classGenerator->addPropertyFromGenerator($prefixInterceptors = new MethodPrefixInterceptors());
     $classGenerator->addPropertyFromGenerator($suffixInterceptors = new MethodSuffixInterceptors());
     $classGenerator->addPropertyFromGenerator($publicProperties);
     array_map(function (MethodGenerator $generatedMethod) use($originalClass, $classGenerator) {
         ClassGeneratorUtils::addMethodIfNotFinal($originalClass, $classGenerator, $generatedMethod);
     }, array_merge(array_map(function (ReflectionMethod $method) use($prefixInterceptors, $suffixInterceptors, $valueHolder) {
         return InterceptedMethod::generateMethod(new MethodReflection($method->getDeclaringClass()->getName(), $method->getName()), $valueHolder, $prefixInterceptors, $suffixInterceptors);
     }, ProxiedMethodsFilter::getProxiedMethods($originalClass)), [Constructor::generateMethod($originalClass, $valueHolder), new StaticProxyConstructor($originalClass, $valueHolder, $prefixInterceptors, $suffixInterceptors), new GetWrappedValueHolderValue($valueHolder), new SetMethodPrefixInterceptor($prefixInterceptors), new SetMethodSuffixInterceptor($suffixInterceptors), new MagicGet($originalClass, $valueHolder, $prefixInterceptors, $suffixInterceptors, $publicProperties), new MagicSet($originalClass, $valueHolder, $prefixInterceptors, $suffixInterceptors, $publicProperties), new MagicIsset($originalClass, $valueHolder, $prefixInterceptors, $suffixInterceptors, $publicProperties), new MagicUnset($originalClass, $valueHolder, $prefixInterceptors, $suffixInterceptors, $publicProperties), new MagicClone($originalClass, $valueHolder, $prefixInterceptors, $suffixInterceptors), new MagicSleep($originalClass, $valueHolder), new MagicWakeup($originalClass, $valueHolder)]));
 }
 /**
  * {@inheritDoc}
  * @throws InvalidProxiedClassException
  * @throws InvalidArgumentException
  */
 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($originalClass, $parameterValuesProperty);
     $wrapBeanAsLazyMethod = new WrapBeanAsLazy($originalClass, $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->getName()));
     }
     $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 = [];
     $aliases = [];
     $methods = $originalClass->getMethods(ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_PROTECTED);
     foreach ($methods as $method) {
         if (null !== $reader->getMethodAnnotation($method, BeanPostProcessor::class)) {
             $postProcessorMethods[] = $method->getName();
             continue;
         }
         /* @var \bitExpert\Disco\Annotations\Bean $beanAnnotation */
         $beanAnnotation = $reader->getMethodAnnotation($method, Bean::class);
         if (null === $beanAnnotation) {
             throw new InvalidProxiedClassException(sprintf('Method "%s" on "%s" is missing the @Bean annotation!', $method->getName(), $originalClass->getName()));
         }
         // if alias is defined append it to the aliases list
         if ($beanAnnotation->getAlias() !== '' && !isset($aliases[$beanAnnotation->getAlias()])) {
             $aliases[$beanAnnotation->getAlias()] = $method->getName();
         }
         /* @var \bitExpert\Disco\Annotations\Parameters $parametersAnnotation */
         $parametersAnnotation = $reader->getMethodAnnotation($method, Parameters::class);
         if (null === $parametersAnnotation) {
             $parametersAnnotation = new Parameters();
         }
         $beanType = $method->getReturnType();
         if (null === $beanType) {
             throw new InvalidProxiedClassException(sprintf('Method "%s" on "%s" is missing the return typehint!', $method->getName(), $originalClass->getName()));
         }
         $beanType = (string) $beanType;
         if (!in_array($beanType, ['array', 'callable', 'bool', 'float', 'int', 'string']) && !class_exists($beanType) && !interface_exists($beanType)) {
             throw new InvalidProxiedClassException(sprintf('Return type of method "%s" on "%s" cannot be found! Did you use the full qualified name?', $method->getName(), $originalClass->getName()));
         }
         $methodReflection = new MethodReflection($method->class, $method->getName());
         $proxyMethod = BeanMethod::generateMethod($methodReflection, $beanAnnotation, $parametersAnnotation, $beanType, $forceLazyInitProperty, $sessionBeansProperty, $postProcessorsProperty, $beanFactoryConfigurationProperty, $getParameterMethod, $wrapBeanAsLazyMethod);
         $classGenerator->addMethodFromGenerator($proxyMethod);
     }
     $aliasesProperty->setDefaultValue($aliases);
     $classGenerator->addMethodFromGenerator(new Constructor($originalClass, $parameterValuesProperty, $sessionBeansProperty, $beanFactoryConfigurationProperty, $postProcessorsProperty, $postProcessorMethods));
     $classGenerator->addMethodFromGenerator($wrapBeanAsLazyMethod);
     $classGenerator->addMethodFromGenerator($getParameterMethod);
     $classGenerator->addMethodFromGenerator(new MagicSleep($originalClass, $sessionBeansProperty));
     $classGenerator->addMethodFromGenerator(new GetAlias($originalClass, $aliasesProperty));
     $classGenerator->addMethodFromGenerator(new HasAlias($originalClass, $aliasesProperty));
 }
 /**
  * @param string $className
  *
  * @dataProvider validClasses
  */
 public function testAllowedClass($className)
 {
     CanProxyAssertion::assertClassCanBeProxied(new ReflectionClass($className));
     $this->assertTrue(true);
     // not nice, but assertions are just fail-checks, no real code executed
 }