/** * @param \PhpParser\Node\Stmt\Class_ $classNode * @return \EBT\ExtensionBuilder\Domain\Model\ClassObject\ClassObject */ public function buildClassObject(\PhpParser\Node\Stmt\Class_ $classNode) { $classObject = new Model\ClassObject\ClassObject($classNode->name); foreach ($classNode->implements as $interfaceNode) { $classObject->addInterfaceName($interfaceNode, false); } $classObject->setModifiers($classNode->type); if (!is_null($classNode->extends)) { $classObject->setParentClassName(NodeConverter::getValueFromNode($classNode->extends)); } $this->addCommentsFromAttributes($classObject, $classNode); return $classObject; }
/** * @param \PhpParser\Node $node */ public function leaveNode(\PhpParser\Node $node) { array_pop($this->contextStack); if ($this->isContainerNode(end($this->contextStack)) || count($this->contextStack) === 0) { // we are on the first level if ($node instanceof Node\Stmt\Class_) { if (count($this->contextStack) > 0) { if (end($this->contextStack)->getType() == 'Stmt_Namespace') { $currentNamespaceName = NodeConverter::getValueFromNode(end($this->contextStack)); $this->currentClassObject->setNamespaceName($currentNamespaceName); $this->currentNamespace->addClass($this->currentClassObject); } } else { $this->fileObject->addClass($this->currentClassObject); $this->currentClassObject = null; $this->currentContainer = $this->fileObject; } } elseif ($node instanceof Node\Stmt\Namespace_) { if (null !== $this->currentNamespace) { $this->fileObject->addNamespace($this->currentNamespace); $this->currentNamespace = null; $this->currentContainer = $this->fileObject; } else { //TODO: find how this could happen } } elseif ($node instanceof Node\Stmt\TraitUse) { if ($this->currentClassObject) { $this->currentClassObject->addUseTraitStatement($node); } } elseif ($node instanceof Node\Stmt\Use_) { $this->currentContainer->addAliasDeclaration(NodeConverter::convertUseAliasStatementNodeToArray($node)); } elseif ($node instanceof Node\Stmt\ClassConst) { $constants = NodeConverter::convertClassConstantNodeToArray($node); foreach ($constants as $constant) { $this->currentContainer->setConstant($constant['name'], $constant['value']); } } elseif ($node instanceof Node\Stmt\ClassMethod) { $this->onFirstLevel = true; $method = $this->classFactory->buildClassMethodObject($node); $this->currentClassObject->addMethod($method); } elseif ($node instanceof Node\Stmt\Property) { $property = $this->classFactory->buildPropertyObject($node); $this->currentClassObject->addProperty($property); } elseif ($node instanceof Node\Stmt\Function_) { $this->onFirstLevel = true; $function = $this->classFactory->buildFunctionObject($node); $this->currentContainer->addFunction($function); } elseif (!$node instanceof Node\Name) { // any other nodes (except the name node of the current container node) // go into statements container if ($this->currentContainer->getFirstClass() === false) { $this->currentContainer->addPreClassStatements($node); } else { $this->currentContainer->addPostClassStatements($node); } } } }
/** * @param \EBT\ExtensionBuilder\Domain\Model\ClassObject\ClassObject $classObject * @param bool $skipStatements * @return \PhpParser\Node\Stmt\Class_ */ public function buildClassNode($classObject, $skipStatements = FALSE) { $factory = new \PhpParser\BuilderFactory(); $classNodeBuilder = $factory->class($classObject->getName()); if ($classObject->getParentClassName()) { $classNodeBuilder->extend(self::buildNodeFromName($classObject->getParentClassName())); } $interfaceNames = $classObject->getInterfaceNames(); if (count($interfaceNames) > 0) { call_user_func_array(array($classNodeBuilder, 'implement'), $interfaceNames); } if (!$skipStatements) { $stmts = array(); $properties = array(); $methods = array(); foreach ($classObject->getMethods() as $method) { $methods[$method->getName()] = $this->buildMethodNode($method); } foreach ($classObject->getProperties() as $property) { $properties[$property->getName()] = $this->buildPropertyNode($property); } $constants = $classObject->getConstants(); if (is_array($constants)) { foreach ($constants as $name => $value) { $stmts[] = self::buildClassConstantNode($name, $value); } } foreach ($properties as $property) { $stmts[] = $property; } foreach ($methods as $method) { $stmts[] = $method; } $classNodeBuilder->addStmts($stmts); } $classNode = $classNodeBuilder->getNode(); $classNode->type = $classObject->getModifiers(); $this->addCommentAttributes($classObject, $classNode); return $classNode; }
/** * Not used right now * TODO: Needs better implementation * @param \EBT\ExtensionBuilder\Domain\Model\DomainObject $domainObject * @return void */ public function sortMethods($domainObject) { $objectProperties = $domainObject->getProperties(); $sortedProperties = array(); $propertyRelatedMethods = array(); $customMethods = array(); // sort all properties and methods according to domainObject sort order foreach ($objectProperties as $objectProperty) { if ($this->classObject->propertyExists($objectProperty->getName())) { $sortedProperties[$objectProperty->getName()] = $this->classObject->getProperty($objectProperty->getName()); $methodPrefixes = array('get', 'set', 'add', 'remove', 'is'); foreach ($methodPrefixes as $methodPrefix) { $methodName = self::getMethodName($objectProperty, $methodPrefix); if ($this->classObject->methodExists($methodName)) { $propertyRelatedMethods[$methodName] = $this->classObject->getMethod($methodName); } } } } // add the properties that were not in the domainObject $classProperties = $this->classObject->getProperties(); $sortedPropertyNames = array_keys($sortedProperties); foreach ($classProperties as $classProperty) { if (!in_array($classProperty->getName(), $sortedProperties)) { $sortedProperties[$classProperty->getName()] = $classProperty; } } // add custom methods that were manually added to the class $classMethods = $this->classObject->getMethods(); $propertyRelatedMethodNames = array_keys($propertyRelatedMethods); foreach ($classMethods as $classMethod) { if (!in_array($classMethod->getName(), $propertyRelatedMethodNames)) { $customMethods[$classMethod->getName()] = $classMethod; } } $sortedMethods = array_merge($customMethods, $propertyRelatedMethods); $this->classObject->setProperties($sortedProperties); $this->classObject->setMethods($sortedMethods); }
/** * compares the number of properties found by parsing * with those retrieved from the reflection class * * @param \EBT\ExtensionBuilder\Domain\Model\ClassObject\ClassObject $classObject * @param \TYPO3\CMS\Extbase\Reflection\ClassReflection $classReflection * @return void */ public function ParserFindsAllProperties($classObject, $classReflection) { $reflectionPropertyCount = count($classReflection->getProperties()); $classObjectPropertCount = count($classObject->getProperties()); $this->assertEquals($classObjectPropertCount, $reflectionPropertyCount, 'Not all Properties were found!'); }
/** * generate a docComment for class files. Add a license haeder if none found * @param \EBT\ExtensionBuilder\Domain\Model\ClassObject\ClassObject $classObject * * @return void; */ protected function addLicenseHeader($classObject) { $comments = $classObject->getComments(); $needsLicenseHeader = true; foreach ($comments as $comment) { if (strpos($comment, 'GNU General Public License') !== false) { $needsLicenseHeader = false; } } if ($needsLicenseHeader) { $licenseHeader = $this->renderTemplate('Partials/Classes/licenseHeader.phpt', array('persons' => $this->extension->getPersons())); $classObject->addComment($licenseHeader); } }
/** * update means renaming of method name, parameter and replacing * parameter names in method body * * @param \EBT\ExtensionBuilder\Domain\Model\DomainObject\AbstractProperty $oldProperty * @param \EBT\ExtensionBuilder\Domain\Model\DomainObject\AbstractProperty $newProperty * @param string $methodType get,set,add,remove,is * * @return void */ protected function updateMethod($oldProperty, $newProperty, $methodType) { $oldMethodName = ClassBuilder::getMethodName($oldProperty, $methodType); // the method to be merged $mergedMethod = $this->classObject->getMethod($oldMethodName); if (!$mergedMethod) { // no previous version of the method exists return; } $newMethodName = ClassBuilder::getMethodName($newProperty, $methodType); $this->log('updateMethod:' . $oldMethodName . '=>' . $newMethodName, 'extension_builder'); if ($oldProperty->getName() != $newProperty->getName()) { // rename the method $mergedMethod->setName($newMethodName); $oldMethodBody = $mergedMethod->getBodyStmts(); $oldComment = $mergedMethod->getDocComment(); $newMethodBody = $this->replacePropertyNameInMethodBody($oldProperty->getName(), $newProperty->getName(), $oldMethodBody); $mergedMethod->setBodyStmts($newMethodBody); } // update the method parameters $methodParameters = $mergedMethod->getParameters(); if (!empty($methodParameters)) { $parameterTags = $mergedMethod->getTagValues('param'); foreach ($methodParameters as $methodParameter) { $oldParameterName = $methodParameter->getName(); if ($oldParameterName == ClassBuilder::getParameterName($oldProperty, $methodType)) { $newParameterName = ClassBuilder::getParameterName($newProperty, $methodType); $methodParameter->setName($newParameterName); $newMethodBody = $this->replacePropertyNameInMethodBody($oldParameterName, $newParameterName, $mergedMethod->getBodyStmts()); $mergedMethod->setBodyStmts($newMethodBody); } $typeHint = $methodParameter->getTypeHint(); if ($typeHint) { if ($oldProperty->isRelation()) { /** @var $oldProperty \EBT\ExtensionBuilder\Domain\Model\DomainObject\Relation\AbstractRelation */ if ($typeHint == $oldProperty->getForeignClassName()) { $methodParameter->setTypeHint($this->updateExtensionKey($this->getForeignClassName($newProperty))); } } } $parameterTags[$methodParameter->getPosition()] = ClassBuilder::getParamTag($newProperty, $methodType); $mergedMethod->replaceParameter($methodParameter); } $mergedMethod->setTag('param', $parameterTags); } $returnTagValue = $mergedMethod->getTagValue('return'); if ($returnTagValue != 'void') { $mergedMethod->setTag('return', $newProperty->getTypeForComment() . ' ' . $newProperty->getName()); } // replace property names in description $mergedMethod->setDescription(str_replace($oldProperty->getName(), $newProperty->getName(), $mergedMethod->getDescription())); if ($oldProperty instanceof AbstractRelation && $newProperty instanceof AbstractRelation) { $mergedMethod->setDescription(str_replace($oldProperty->getForeignClassName(), $newProperty->getForeignClassName(), $mergedMethod->getDescription())); } $this->classObject->removeMethod($oldMethodName); $this->classObject->addMethod($mergedMethod); }
/** * generate a docComment for class files. Add a license header if none found * @param \EBT\ExtensionBuilder\Domain\Model\ClassObject\ClassObject $classObject * * @return void; */ protected function addLicenseHeader($classObject) { $comments = $classObject->getComments(); $needsLicenseHeader = true; foreach ($comments as $comment) { if (strpos($comment, 'license information') !== false) { $needsLicenseHeader = false; } } $extensionSettings = $this->extension->getSettings(); if ($needsLicenseHeader && empty($extensionSettings['skipDocComment'])) { $licenseHeader = $this->renderTemplate('Partials/Classes/licenseHeader.phpt', array('extension' => $this->extension)); $classObject->addComment($licenseHeader); } }