Generate code

@param \ReflectionClass $class

@return MockedCode

@throws MockCodeGeneratorException
558366
public function generate(\ReflectionClass $class) : MockedCode
    {
        // checks class modifiers
        $mod = $class->getModifiers();
    
        if (Util::isAllBitSet($mod, \ReflectionClass::IS_FINAL)){
            throw new MockCodeGeneratorException('Final class can not be mocked!');
        }
    
        // generate mock class code
        list($code, $mocked_class, $namespace) = $this->generateClassCode($class);
        $filename = $this->generateMockClassFilename($class);
    
        $namespace_dir = str_replace('\\', '/', $namespace);
        
        $file_path = $namespace_dir . '/' . $filename;
    
        // save mock class code into cache directory
        $file = vfsStream::newFile($file_path);
        $this->vfsRoot->addChild($file);
        
        $code = implode(PHP_EOL, $code);
        $file->setContent($code);
        
        return new MockedCode($this->vfsRoot, $mocked_class, $namespace, $file);
    }
1044048
public function loadMetadataForClass(\ReflectionClass $class)
    {
        $classMetadata = new ClassMetadata($class->getName());

        // should class be exposed?
        $annotation = $this->reader->getClassAnnotation(
            $class,
            Entity\Expose::class
        );

        $classMetadata->setExposed($annotation !== null);

        // not exposed so just return here
        if (!$classMetadata->isExposed()) {
            return $classMetadata;
        }

        if ($annotation->name) {
            $classMetadata->setExposedName($annotation->name);
        }

        $this->parseProperties($class, $classMetadata);

        while ($class = $class->getParentClass()) {
            $this->parseProperties($class, $classMetadata);
        }

        return $classMetadata;
    }
414472
public function build ($class)
    {
        $reflection = new \ReflectionClass($class);
        $parameters = [];

        if (!is_null($reflection->getConstructor())) {
            $parameters = $this->getParameters($reflection->getConstructor());
        }

        return new $class(...$parameters);
    }
80880
private static function methodsOf(\ReflectionClass $class): \Iterator
    {
        return new \CallbackFilterIterator(
                new \ArrayIterator($class->getMethods()),
                function(\ReflectionMethod $method)
                {
                    return !$method->isPrivate()
                            && !$method->isFinal()
                            && !$method->isStatic()
                            && !$method->isConstructor()
                            && !$method->isDestructor();
                }
        );
    }
1118448
private function generateClass(): ServiceDTOGenerator
    {
        $this->DTOFile = (new PhpFile())
            ->addComment('This file is auto-generated.');

        $namespace = $this->inputData['namespace'] . '\\' . $this->inputData['module'] . 'Module\\' . $this->inputData['type'];

        $this->DTOClass = $this->DTOFile
            ->addNamespace($namespace)
            ->addClass($this->inputData['class'] . $this->inputData['type'])
            ->addComment($this->inputData['class'] . ' service ' . strtolower($this->inputData['type']) . PHP_EOL)
            ->addComment('@package ' . $namespace);

        return $this;
    }
105447
protected function generateClass()
    {
        if ($this->class != null) {
            throw new Exception("The class has already been generated");
        }

        $classBaseType = $this->getBaseTypeClass();

        $this->class = new PhpClass(
            $this->phpIdentifier,
            false,
            $classBaseType,
            null,
            false,
            $this->abstract
        );

        $constructorComment = new PhpDocComment();
        $constructorSource = '';
        $constructorParameters = array();
        $accessors = array();

        // Add base type members to constructor parameter list first and call base class constructor
        $parentMembers = $this->getBaseTypeMembers($this);
        if (!empty($parentMembers)) {
            foreach ($parentMembers as $member) {
                $type = Validator::validateType($member->getType());
                $name = Validator::validateAttribute($member->getName());

                if (!$member->getNullable()) {
                    $constructorComment->addParam(PhpDocElementFactory::getParam($type, $name, ''));
                    $constructorParameters[$name] = Validator::validateTypeHint($type);
                }
            }
            $constructorSource .= '  parent::__construct(' . $this->buildParametersString($constructorParameters, false) . ');' . PHP_EOL;
        }

        // Add member variables
        foreach ($this->members as $member) {
            $type = Validator::validateType($member->getType());
            $name = Validator::validateAttribute($member->getName());
            $typeHint = Validator::validateTypeHint($type);

            $comment = new PhpDocComment();
            $comment->setVar(PhpDocElementFactory::getVar($type, $name, ''));
            $var = new PhpVariable('protected', $name, 'null', $comment);
            $this->class->addVariable($var);

            if (!$member->getNullable()) {
                if ($type == '\DateTime') {
                    if ($this->config->get('constructorParamsDefaultToNull')) {
                        $constructorSource .= '  $this->' . $name . ' = $' . $name . ' ? $' . $name . '->format(\DateTime::ATOM) : null;' . PHP_EOL;
                    } else {
                        $constructorSource .= '  $this->' . $name . ' = $' . $name . '->format(\DateTime::ATOM);' . PHP_EOL;
                    }
                } else {
                    $constructorSource .= '  $this->' . $name . ' = $' . $name . ';' . PHP_EOL;
                }
                $constructorComment->addParam(PhpDocElementFactory::getParam($type, $name, ''));
                $constructorParameters[$name] = $typeHint;
            }

            $getterComment = new PhpDocComment();
            $getterComment->setReturn(PhpDocElementFactory::getReturn($type, ''));
            if ($type == '\DateTime') {
                $getterCode = '  if ($this->' . $name . ' == null) {' . PHP_EOL
                    . '    return null;' . PHP_EOL
                    . '  } else {' . PHP_EOL
                    . '    try {' . PHP_EOL
                    . '      return new \DateTime($this->' . $name . ');' . PHP_EOL
                    . '    } catch (\Exception $e) {' . PHP_EOL
                    . '      return false;' . PHP_EOL
                    . '    }' . PHP_EOL
                    . '  }' . PHP_EOL;
            } else {
                $getterCode = '  return $this->' . $name . ';' . PHP_EOL;
            }
            $getter = new PhpFunction('public', 'get' . ucfirst($name), '', $getterCode, $getterComment);
            $accessors[] = $getter;

            $setterComment = new PhpDocComment();
            $setterComment->addParam(PhpDocElementFactory::getParam($type, $name, ''));
            $setterComment->setReturn(PhpDocElementFactory::getReturn($this->phpNamespacedIdentifier, ''));
            if ($type == '\DateTime') {
                if ($member->getNullable()) {
                    $setterCode = '  if ($' . $name . ' == null) {' . PHP_EOL
                        . '   $this->' . $name . ' = null;' . PHP_EOL
                        . '  } else {' . PHP_EOL
                        . '    $this->' . $name . ' = $' . $name . '->format(\DateTime::ATOM);' . PHP_EOL
                        . '  }' . PHP_EOL;
                } else {
                    $setterCode = '  $this->' . $name . ' = $' . $name . '->format(\DateTime::ATOM);' . PHP_EOL;
                }
            } else {
                $setterCode = '  $this->' . $name . ' = $' . $name . ';' . PHP_EOL;
            }
            $setterCode .= '  return $this;' . PHP_EOL;
            $setter = new PhpFunction(
                'public',
                'set' . ucfirst($name),
                $this->buildParametersString(
                    array($name => $typeHint),
                    true,
                    // If the type of a member is nullable we should allow passing null to the setter. If the type
                    // of the member is a class and not a primitive this is only possible if setter parameter has
                    // a default null value. We can detect whether the type is a class by checking the type hint.
                    $member->getNullable() && !empty($typeHint)
                ),
                $setterCode,
                $setterComment
            );
            $accessors[] = $setter;
        }

        $constructor = new PhpFunction(
            'public',
            '__construct',
            $this->buildParametersString(
                $constructorParameters,
                true,
                $this->config->get('constructorParamsDefaultToNull')
            ),
            $constructorSource,
            $constructorComment
        );
        $this->class->addFunction($constructor);

        foreach ($accessors as $accessor) {
            $this->class->addFunction($accessor);
        }
    }
1252274
private static function createMethods(\ReflectionClass $class): string
    {
        $code    = '';
        $methods = [];
        $params  = [];
        $voidMethods = [];
        foreach (self::methodsOf($class) as $method) {
            $return = true;
            $returnType = determineReturnTypeOf($method);
            if ($returnType === ': void') {
                $voidMethods[$method->getName()] = $method->getName();
                $return = false;
            }

            $param = paramsOf($method);
            /* @var $method \ReflectionMethod */
            $code .= sprintf(
                    "    %s function %s(%s)%s {\n"
                  . "        %s\$this->handleMethodCall('%s', func_get_args(), %s);\n"
                  . "    }\n",
                    ($method->isPublic() ? 'public' : 'protected'),
                    $method->getName(),
                    $param['string'],
                    $returnType,
                    $return ? 'return ' : '',
                    $method->getName(),
                    self::shouldReturnSelf($class, $method) ? 'true' : 'false'
            );
            $methods[] = "'" . $method->getName() . "' => '" . $method->getName() . "'";
            $params[$method->getName()] = $param['names'];
        }

        return $code . sprintf(
                "\n    private \$_allowedMethods = [%s];\n",
                join(', ', $methods)
        ) . sprintf(
                "\n    private \$_methodParams = %s;\n",
                var_export($params, true)
        ) . sprintf(
                "\n    private \$_voidMethods = %s;\n",
                var_export($voidMethods, true)
        );
    }
224804
public function loadMetadataForClass(\ReflectionClass $class)
    {
        foreach ($this->drivers as $driver) {
            if (null !== $metadata = $driver->loadMetadataForClass($class)) {
                return $metadata;
            }
        }
    }
385236
private function generateMagicGet(ClassMetadata $class)
    {
        $lazyPublicProperties = array_keys($this->getLazyLoadedPublicProperties($class));
        $reflectionClass      = $class->getReflectionClass();
        $hasParentGet         = false;
        $returnReference      = '';
        $inheritDoc           = '';

        if ($reflectionClass->hasMethod('__get')) {
            $hasParentGet = true;
            $inheritDoc   = '{@inheritDoc}';

            if ($reflectionClass->getMethod('__get')->returnsReference()) {
                $returnReference = '& ';
            }
        }

        if (empty($lazyPublicProperties) && ! $hasParentGet) {
            return '';
        }

        $magicGet = <<<EOT
    /**
     * $inheritDoc
     * @param string \$name
     */
    public function {$returnReference}__get(\$name)
    {

EOT;

        if ( ! empty($lazyPublicProperties)) {
            $magicGet .= <<<'EOT'
        if (array_key_exists($name, $this->__getLazyProperties())) {
            $this->__initializer__ && $this->__initializer__->__invoke($this, '__get', [$name]);

            return $this->$name;
        }


EOT;
        }

        if ($hasParentGet) {
            $magicGet .= <<<'EOT'
        $this->__initializer__ && $this->__initializer__->__invoke($this, '__get', [$name]);

        return parent::__get($name);

EOT;
        } else {
            $magicGet .= <<<'EOT'
        trigger_error(sprintf('Undefined property: %s::$%s', __CLASS__, $name), E_USER_NOTICE);

EOT;
        }

        $magicGet .= "    }";

        return $magicGet;
    }
1141870
public static function get($class)
    {
        $key = strtolower($class);

        if (isset(static::$instances[$key])) {
            return static::$instances[$key];
        }

        static::override($class);

        if (!class_exists($class)) {
            throw new ReflectionException("Class $class does not exist");
        }

        $instance = static::getInstance($class);
        static::register($class, $instance);
        return $instance;
    }
600474
public function generateProxyCode(\ReflectionClass $ref)
	{
		$methods = $this->collectProxyMethods($ref);
		$implements = ['\KoolKode\Context\Scope\ScopedProxyInterface'];
				
		$code = 'namespace ' . $ref->getNamespaceName() . ' { ';
		$code .= 'if(!class_exists(' . var_export($ref->name . '__scoped', true) . ', false)) { ';
		$code .= 'final class ' . $ref->getShortName() . '__scoped';
		
		if($ref->isInterface())
		{
			$implements[] = '\\' . $ref->name;
		}
		else
		{
			$code .= ' extends \\' . $ref->name;
		}
		
		$code .= ' implements ' . implode(', ', $implements) . ' { ';
		$code .= 'use \KoolKode\Context\Scope\ScopedProxyTrait; ';
		
		$code .= 'private $__K2Binding, $__K2Scope, $__K2Target; ';
		
		$code .= 'public final function __construct(\KoolKode\Context\Bind\BindingInterface $binding, \KoolKode\Context\Scope\ScopeManagerInterface $scope, \SplObjectStorage & $target) { ';
		$code .= '$this->__K2Binding = $binding; $this->__K2Scope = $scope; $this->__K2Target = & $target; ';
		
		$fieldNames = array_unique($this->collectRemovedFieldNames($ref));
		
		if(!empty($fieldNames))
		{
			$code .= ' unset(';
			
			foreach($fieldNames as $i => $name)
			{
				if($i != 0)
				{
					$code .= ', ';
				}
				
				$code .= '$this->' . $name;
			}
			
			$code .= ');';
		}
		
		$code.= ' } ';
		
		foreach($methods as $method)
		{
			$code .= $this->buildMethodSignature($method, true);
			
			$code .= ' { ';
			$code .= 'if(!$this->__K2Target->offsetExists($this)) { $this->__K2Scope->activateInstance($this); } ';
			$code .= 'return call_user_func_array([$this->__K2Target[$this], __FUNCTION__], func_get_args()); ';
			$code .= '} ';
		}
		
		return $code . ' } } } ';
	}
928597
public static function getCodeGenerators($entityClass = null)
    {
        if ($entityClass) {
            if (!isset(self::$generators[$entityClass])) {
                throw new \Exception("There is no registered entity code generator for class $entityClass");
            }

            return self::$generators[$entityClass];
        } else {
            return self::$generators;
        }
    }
68821
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($originalClass));
        $classGenerator->addPropertyFromGenerator($initializer = new InitializerProperty());
        $classGenerator->addPropertyFromGenerator($publicProperties);

        array_map(
            static function (MethodGenerator $generatedMethod) use ($originalClass, $classGenerator) : void {
                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),
                ]
            )
        );
    }
614441
private function getCacheFile(\ReflectionClass $reflectionClass)
    {
        return sprintf('%s/%s/%s.php.cache', $this->kernel->getCacheDir(), Constants::CACHE_DIR, str_replace('\\', '_', $reflectionClass->getName()));
    }
806790
public function loadMetadataForClass(\ReflectionClass $class)
    {
        $classMetadata = new ClassMetadata($class->getName());

        foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC) as $reflectionMethod) {
            if (false === strpos($reflectionMethod->getName(), 'Action')) {
                continue;
            }

            if ($reflectionMethod->isAbstract()) {
                continue;
            }

            $methodMetadata = new ActionMetadata($class->getName(), $reflectionMethod->getName());

            $annotations = $this->reader->getMethodAnnotations($reflectionMethod);

            foreach ($annotations as $annotation) {
                if ($annotation instanceof \BackBee\Rest\Controller\Annotations\QueryParam) {
                    $data = array(
                        'name' => $annotation->name,
                        'key' => $annotation->key ? $annotation->key : $annotation->name,
                        'default' => $annotation->default,
                        'description' => $annotation->description,
                        'requirements' => $annotation->requirements,
                    );

                    $methodMetadata->queryParams[] = $data;
                } elseif ($annotation instanceof \BackBee\Rest\Controller\Annotations\RequestParam) {
                    $data = array(
                        'name' => $annotation->name,
                        'key' => $annotation->key ? $annotation->key : $annotation->name,
                        'default' => $annotation->default,
                        'description' => $annotation->description,
                        'requirements' => $annotation->requirements,
                    );

                    $methodMetadata->requestParams[] = $data;
                } elseif ($annotation instanceof \BackBee\Rest\Controller\Annotations\Pagination) {
                    $methodMetadata->default_start = $annotation->default_start;
                    $methodMetadata->default_count = $annotation->default_count;
                    $methodMetadata->max_count = $annotation->max_count;
                    $methodMetadata->min_count = $annotation->min_count;
                } elseif ($annotation instanceof \BackBee\Rest\Controller\Annotations\ParamConverter) {
                    $methodMetadata->param_converter_bag[] = $annotation;
                } elseif ($annotation instanceof \BackBee\Rest\Controller\Annotations\Security) {
                    $methodMetadata->security[] = $annotation;
                }
            }

            $classMetadata->addMethodMetadata($methodMetadata);
        }

        return $classMetadata;
    }
1180658
public function generate(ReflectionClass $originalClass, ClassGenerator $classGenerator)
    {
        CanProxyAssertion::assertClassCanBeProxied($originalClass);

        $publicProperties = new PublicPropertiesMap(Properties::fromReflectionClass($originalClass));
        $interfaces       = [AccessInterceptorValueHolderInterface::class];

        if ($originalClass->isInterface()) {
            $interfaces[] = $originalClass->getName();
        } else {
            $classGenerator->setExtendedClass($originalClass->getName());
        }

        $classGenerator->setImplementedInterfaces($interfaces);
        $classGenerator->addPropertyFromGenerator($valueHolder        = new ValueHolderProperty($originalClass));
        $classGenerator->addPropertyFromGenerator($prefixInterceptors = new MethodPrefixInterceptors());
        $classGenerator->addPropertyFromGenerator($suffixInterceptors = new MethodSuffixInterceptors());
        $classGenerator->addPropertyFromGenerator($publicProperties);

        array_map(
            static function (MethodGenerator $generatedMethod) use ($originalClass, $classGenerator) : void {
                ClassGeneratorUtils::addMethodIfNotFinal($originalClass, $classGenerator, $generatedMethod);
            },
            array_merge(
                array_map(
                    $this->buildMethodInterceptor($prefixInterceptors, $suffixInterceptors, $valueHolder),
                    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),
                ]
            )
        );
    }
413979
public static function createResourceForClass(\ReflectionClass $reflectionClass)
    {
        $metadata = array();

        if ($constructor = $reflectionClass->getConstructor()) {
            $metadata['__construct'] = self::getResourceMetadataForMethod($constructor);
        }

        foreach (self::getSetters($reflectionClass) as $reflectionMethod) {
            $metadata[$reflectionMethod->name] = self::getResourceMetadataForMethod($reflectionMethod);
        }

        return new AutowireServiceResource($reflectionClass->name, $reflectionClass->getFileName(), $metadata);
    }