1
0
mirror of synced 2024-12-14 23:26:04 +03:00
doctrine2/lib/Doctrine/ORM/Tools/EntityGenerator.php

1146 lines
39 KiB
PHP
Raw Normal View History

<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Tools;
use Doctrine\ORM\Mapping\ClassMetadataInfo,
Doctrine\ORM\Mapping\AssociationMapping,
Doctrine\Common\Util\Inflector;
/**
* Generic class used to generate PHP5 entity classes from ClassMetadataInfo instances
*
* [php]
* $classes = $em->getClassMetadataFactory()->getAllMetadata();
*
* $generator = new \Doctrine\ORM\Tools\EntityGenerator();
* $generator->setGenerateAnnotations(true);
* $generator->setGenerateStubMethods(true);
* $generator->setRegenerateEntityIfExists(false);
* $generator->setUpdateEntityIfExists(true);
* $generator->generate($classes, '/path/to/generate/entities');
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
* @since 2.0
* @version $Revision$
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Jonathan Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
*/
class EntityGenerator
{
/**
* Specifies class fields should be protected
*/
const FIELD_VISIBLE_PROTECTED = 'protected';
/**
* Specifies class fields should be private
*/
const FIELD_VISIBLE_PRIVATE = 'private';
/**
* @var bool
*/
private $_backupExisting = true;
/** The extension to use for written php files */
private $_extension = '.php';
/** Whether or not the current ClassMetadataInfo instance is new or old */
private $_isNew = true;
private $_staticReflection = array();
/** Number of spaces to use for indention in generated code */
private $_numSpaces = 4;
/** The actual spaces to use for indention */
private $_spaces = ' ';
/** The class all generated entities should extend */
private $_classToExtend;
/** Whether or not to generation annotations */
private $_generateAnnotations = false;
/**
* @var string
*/
private $_annotationsPrefix = '';
/** Whether or not to generated sub methods */
private $_generateEntityStubMethods = false;
/** Whether or not to update the entity class if it exists already */
private $_updateEntityIfExists = false;
/** Whether or not to re-generate entity class if it exists already */
private $_regenerateEntityIfExists = false;
private $_fieldVisibility = 'private';
private static $_classTemplate =
'<?php
<namespace>
use Doctrine\ORM\Mapping as ORM;
<entityAnnotation>
<entityClassName>
{
<entityBody>
}';
private static $_getMethodTemplate =
'/**
* <description>
*
* @return <variableType>
*/
public function <methodName>()
{
<spaces>return $this-><fieldName>;
}';
private static $_setMethodTemplate =
'/**
* <description>
*
* @param <variableType>$<variableName>
* @return <entity>
*/
public function <methodName>(<methodTypeHint>$<variableName><variableDefault>)
{
<spaces>$this-><fieldName> = $<variableName>;
<spaces>return $this;
}';
private static $_addMethodTemplate =
'/**
* <description>
*
* @param <variableType>$<variableName>
*/
public function <methodName>(<methodTypeHint>$<variableName>)
{
<spaces>$this-><fieldName>[] = $<variableName>;
}';
private static $_lifecycleCallbackMethodTemplate =
'/**
* @<name>
*/
public function <methodName>()
{
<spaces>// Add your code here
}';
private static $_constructorMethodTemplate =
'public function __construct()
{
<spaces><collections>
}
';
public function __construct()
{
if (version_compare(\Doctrine\Common\Version::VERSION, '2.2.0-DEV', '>=')) {
$this->_annotationsPrefix = 'ORM\\';
}
}
/**
* Generate and write entity classes for the given array of ClassMetadataInfo instances
*
* @param array $metadatas
* @param string $outputDirectory
* @return void
*/
public function generate(array $metadatas, $outputDirectory)
{
foreach ($metadatas as $metadata) {
$this->writeEntityClass($metadata, $outputDirectory);
}
}
/**
* Generated and write entity class to disk for the given ClassMetadataInfo instance
*
* @param ClassMetadataInfo $metadata
* @param string $outputDirectory
* @return void
*/
public function writeEntityClass(ClassMetadataInfo $metadata, $outputDirectory)
{
$path = $outputDirectory . '/' . str_replace('\\', DIRECTORY_SEPARATOR, $metadata->name) . $this->_extension;
$dir = dirname($path);
if ( ! is_dir($dir)) {
mkdir($dir, 0777, true);
}
$this->_isNew = !file_exists($path) || (file_exists($path) && $this->_regenerateEntityIfExists);
if ( ! $this->_isNew) {
$this->_parseTokensInEntityFile(file_get_contents($path));
} else {
$this->_staticReflection[$metadata->name] = array('properties' => array(), 'methods' => array());
}
if ($this->_backupExisting && file_exists($path)) {
$backupPath = dirname($path) . DIRECTORY_SEPARATOR . basename($path) . "~";
if (!copy($path, $backupPath)) {
throw new \RuntimeException("Attempt to backup overwritten entity file but copy operation failed.");
}
}
// If entity doesn't exist or we're re-generating the entities entirely
if ($this->_isNew) {
file_put_contents($path, $this->generateEntityClass($metadata));
// If entity exists and we're allowed to update the entity class
} else if ( ! $this->_isNew && $this->_updateEntityIfExists) {
file_put_contents($path, $this->generateUpdatedEntityClass($metadata, $path));
}
}
/**
* Generate a PHP5 Doctrine 2 entity class from the given ClassMetadataInfo instance
*
* @param ClassMetadataInfo $metadata
* @return string $code
*/
public function generateEntityClass(ClassMetadataInfo $metadata)
{
$placeHolders = array(
'<namespace>',
'<entityAnnotation>',
'<entityClassName>',
'<entityBody>'
);
$replacements = array(
$this->_generateEntityNamespace($metadata),
$this->_generateEntityDocBlock($metadata),
$this->_generateEntityClassName($metadata),
$this->_generateEntityBody($metadata)
);
$code = str_replace($placeHolders, $replacements, self::$_classTemplate);
return str_replace('<spaces>', $this->_spaces, $code);
}
/**
* Generate the updated code for the given ClassMetadataInfo and entity at path
*
* @param ClassMetadataInfo $metadata
* @param string $path
* @return string $code;
*/
public function generateUpdatedEntityClass(ClassMetadataInfo $metadata, $path)
{
$currentCode = file_get_contents($path);
$body = $this->_generateEntityBody($metadata);
$body = str_replace('<spaces>', $this->_spaces, $body);
$last = strrpos($currentCode, '}');
return substr($currentCode, 0, $last) . $body . (strlen($body) > 0 ? "\n" : ''). "}";
}
/**
* Set the number of spaces the exported class should have
*
* @param integer $numSpaces
* @return void
*/
public function setNumSpaces($numSpaces)
{
$this->_spaces = str_repeat(' ', $numSpaces);
$this->_numSpaces = $numSpaces;
}
/**
* Set the extension to use when writing php files to disk
*
* @param string $extension
* @return void
*/
public function setExtension($extension)
{
$this->_extension = $extension;
}
/**
* Set the name of the class the generated classes should extend from
*
* @return void
*/
public function setClassToExtend($classToExtend)
{
$this->_classToExtend = $classToExtend;
}
/**
* Set whether or not to generate annotations for the entity
*
* @param bool $bool
* @return void
*/
public function setGenerateAnnotations($bool)
{
$this->_generateAnnotations = $bool;
}
/**
* Set the class fields visibility for the entity (can either be private or protected)
*
* @param bool $bool
* @return void
*/
public function setFieldVisibility($visibility)
{
if ($visibility !== self::FIELD_VISIBLE_PRIVATE && $visibility !== self::FIELD_VISIBLE_PROTECTED) {
throw new \InvalidArgumentException('Invalid provided visibilty (only private and protected are allowed): ' . $visibility);
}
$this->_fieldVisibility = $visibility;
}
/**
* Set an annotation prefix.
*
* @param string $prefix
*/
public function setAnnotationPrefix($prefix)
{
$this->_annotationsPrefix = $prefix;
}
/**
* Set whether or not to try and update the entity if it already exists
*
* @param bool $bool
* @return void
*/
public function setUpdateEntityIfExists($bool)
{
$this->_updateEntityIfExists = $bool;
}
/**
* Set whether or not to regenerate the entity if it exists
*
* @param bool $bool
* @return void
*/
public function setRegenerateEntityIfExists($bool)
{
$this->_regenerateEntityIfExists = $bool;
}
/**
* Set whether or not to generate stub methods for the entity
*
* @param bool $bool
* @return void
*/
public function setGenerateStubMethods($bool)
{
$this->_generateEntityStubMethods = $bool;
}
/**
* Should an existing entity be backed up if it already exists?
*/
public function setBackupExisting($bool)
{
$this->_backupExisting = $bool;
}
private function _generateEntityNamespace(ClassMetadataInfo $metadata)
{
if ($this->_hasNamespace($metadata)) {
return 'namespace ' . $this->_getNamespace($metadata) .';';
}
}
private function _generateEntityClassName(ClassMetadataInfo $metadata)
{
return 'class ' . $this->_getClassName($metadata) .
($this->_extendsClass() ? ' extends ' . $this->_getClassToExtendName() : null);
}
private function _generateEntityBody(ClassMetadataInfo $metadata)
{
$fieldMappingProperties = $this->_generateEntityFieldMappingProperties($metadata);
$associationMappingProperties = $this->_generateEntityAssociationMappingProperties($metadata);
$stubMethods = $this->_generateEntityStubMethods ? $this->_generateEntityStubMethods($metadata) : null;
$lifecycleCallbackMethods = $this->_generateEntityLifecycleCallbackMethods($metadata);
$code = array();
if ($fieldMappingProperties) {
$code[] = $fieldMappingProperties;
}
if ($associationMappingProperties) {
$code[] = $associationMappingProperties;
}
$code[] = $this->_generateEntityConstructor($metadata);
if ($stubMethods) {
$code[] = $stubMethods;
}
if ($lifecycleCallbackMethods) {
$code[] = $lifecycleCallbackMethods;
}
return implode("\n", $code);
}
private function _generateEntityConstructor(ClassMetadataInfo $metadata)
{
if ($this->_hasMethod('__construct', $metadata)) {
return '';
}
$collections = array();
foreach ($metadata->associationMappings AS $mapping) {
if ($mapping['type'] & ClassMetadataInfo::TO_MANY) {
$collections[] = '$this->'.$mapping['fieldName'].' = new \Doctrine\Common\Collections\ArrayCollection();';
}
}
if ($collections) {
2011-10-19 11:07:18 +04:00
return $this->_prefixCodeWithSpaces(str_replace("<collections>", implode("\n".$this->_spaces, $collections), self::$_constructorMethodTemplate));
}
return '';
}
/**
* @todo this won't work if there is a namespace in brackets and a class outside of it.
* @param string $src
*/
private function _parseTokensInEntityFile($src)
{
$tokens = token_get_all($src);
$lastSeenNamespace = "";
$lastSeenClass = false;
$inNamespace = false;
$inClass = false;
for ($i = 0; $i < count($tokens); $i++) {
$token = $tokens[$i];
if (in_array($token[0], array(T_WHITESPACE, T_COMMENT, T_DOC_COMMENT))) {
continue;
}
if ($inNamespace) {
if ($token[0] == T_NS_SEPARATOR || $token[0] == T_STRING) {
$lastSeenNamespace .= $token[1];
} else if (is_string($token) && in_array($token, array(';', '{'))) {
$inNamespace = false;
}
}
if ($inClass) {
$inClass = false;
$lastSeenClass = $lastSeenNamespace . ($lastSeenNamespace ? '\\' : '') . $token[1];
$this->_staticReflection[$lastSeenClass]['properties'] = array();
$this->_staticReflection[$lastSeenClass]['methods'] = array();
}
if ($token[0] == T_NAMESPACE) {
$lastSeenNamespace = "";
$inNamespace = true;
} else if ($token[0] == T_CLASS) {
$inClass = true;
} else if ($token[0] == T_FUNCTION) {
if ($tokens[$i+2][0] == T_STRING) {
$this->_staticReflection[$lastSeenClass]['methods'][] = $tokens[$i+2][1];
} else if ($tokens[$i+2] == "&" && $tokens[$i+3][0] == T_STRING) {
$this->_staticReflection[$lastSeenClass]['methods'][] = $tokens[$i+3][1];
}
} else if (in_array($token[0], array(T_VAR, T_PUBLIC, T_PRIVATE, T_PROTECTED)) && $tokens[$i+2][0] != T_FUNCTION) {
$this->_staticReflection[$lastSeenClass]['properties'][] = substr($tokens[$i+2][1], 1);
}
}
}
private function _hasProperty($property, ClassMetadataInfo $metadata)
{
if ($this->_extendsClass()) {
// don't generate property if its already on the base class.
$reflClass = new \ReflectionClass($this->_getClassToExtend());
if ($reflClass->hasProperty($property)) {
return true;
}
}
return (
isset($this->_staticReflection[$metadata->name]) &&
in_array($property, $this->_staticReflection[$metadata->name]['properties'])
);
}
private function _hasMethod($method, ClassMetadataInfo $metadata)
{
if ($this->_extendsClass()) {
// don't generate method if its already on the base class.
$reflClass = new \ReflectionClass($this->_getClassToExtend());
if ($reflClass->hasMethod($method)) {
return true;
}
}
return (
isset($this->_staticReflection[$metadata->name]) &&
in_array($method, $this->_staticReflection[$metadata->name]['methods'])
);
}
private function _hasNamespace(ClassMetadataInfo $metadata)
{
return strpos($metadata->name, '\\') ? true : false;
}
private function _extendsClass()
{
return $this->_classToExtend ? true : false;
}
private function _getClassToExtend()
{
return $this->_classToExtend;
}
private function _getClassToExtendName()
{
$refl = new \ReflectionClass($this->_getClassToExtend());
return '\\' . $refl->getName();
}
private function _getClassName(ClassMetadataInfo $metadata)
{
return ($pos = strrpos($metadata->name, '\\'))
? substr($metadata->name, $pos + 1, strlen($metadata->name)) : $metadata->name;
}
private function _getNamespace(ClassMetadataInfo $metadata)
{
return substr($metadata->name, 0, strrpos($metadata->name, '\\'));
}
private function _generateEntityDocBlock(ClassMetadataInfo $metadata)
{
$lines = array();
$lines[] = '/**';
$lines[] = ' * '.$metadata->name;
if ($this->_generateAnnotations) {
$lines[] = ' *';
$methods = array(
'_generateTableAnnotation',
'_generateInheritanceAnnotation',
'_generateDiscriminatorColumnAnnotation',
'_generateDiscriminatorMapAnnotation'
);
foreach ($methods as $method) {
if ($code = $this->$method($metadata)) {
$lines[] = ' * ' . $code;
}
}
if ($metadata->isMappedSuperclass) {
2011-05-01 12:01:38 +04:00
$lines[] = ' * @' . $this->_annotationsPrefix . 'MappedSuperClass';
} else {
$lines[] = ' * @' . $this->_annotationsPrefix . 'Entity';
}
if ($metadata->customRepositoryClassName) {
$lines[count($lines) - 1] .= '(repositoryClass="' . $metadata->customRepositoryClassName . '")';
}
if (isset($metadata->lifecycleCallbacks) && $metadata->lifecycleCallbacks) {
$lines[] = ' * @' . $this->_annotationsPrefix . 'HasLifecycleCallbacks';
}
}
$lines[] = ' */';
return implode("\n", $lines);
}
private function _generateTableAnnotation($metadata)
{
$table = array();
if (isset($metadata->table['schema'])) {
$table[] = 'schema="' . $metadata->table['schema'] . '"';
}
if (isset($metadata->table['name'])) {
$table[] = 'name="' . $metadata->table['name'] . '"';
}
if (isset($metadata->table['uniqueConstraints']) && $metadata->table['uniqueConstraints']) {
$constraints = $this->_generateTableConstraints('UniqueConstraint', $metadata->table['uniqueConstraints']);
$table[] = 'uniqueConstraints={' . $constraints . '}';
}
if (isset($metadata->table['indexes']) && $metadata->table['indexes']) {
$constraints = $this->_generateTableConstraints('Index', $metadata->table['indexes']);
$table[] = 'indexes={' . $constraints . '}';
}
return '@' . $this->_annotationsPrefix . 'Table(' . implode(', ', $table) . ')';
}
private function _generateTableConstraints($constraintName, $constraints)
{
$annotations = array();
foreach ($constraints as $name => $constraint) {
$columns = array();
foreach ($constraint['columns'] as $column) {
$columns[] = '"' . $column . '"';
}
$annotations[] = '@' . $this->_annotationsPrefix . $constraintName . '(name="' . $name . '", columns={' . implode(', ', $columns) . '})';
}
return implode(', ', $annotations);
}
private function _generateInheritanceAnnotation($metadata)
{
if ($metadata->inheritanceType != ClassMetadataInfo::INHERITANCE_TYPE_NONE) {
return '@' . $this->_annotationsPrefix . 'InheritanceType("'.$this->_getInheritanceTypeString($metadata->inheritanceType).'")';
}
}
private function _generateDiscriminatorColumnAnnotation($metadata)
{
if ($metadata->inheritanceType != ClassMetadataInfo::INHERITANCE_TYPE_NONE) {
$discrColumn = $metadata->discriminatorValue;
$columnDefinition = 'name="' . $discrColumn['name']
. '", type="' . $discrColumn['type']
. '", length=' . $discrColumn['length'];
return '@' . $this->_annotationsPrefix . 'DiscriminatorColumn(' . $columnDefinition . ')';
}
}
private function _generateDiscriminatorMapAnnotation($metadata)
{
if ($metadata->inheritanceType != ClassMetadataInfo::INHERITANCE_TYPE_NONE) {
$inheritanceClassMap = array();
foreach ($metadata->discriminatorMap as $type => $class) {
$inheritanceClassMap[] .= '"' . $type . '" = "' . $class . '"';
}
return '@' . $this->_annotationsPrefix . 'DiscriminatorMap({' . implode(', ', $inheritanceClassMap) . '})';
}
}
private function _generateEntityStubMethods(ClassMetadataInfo $metadata)
{
$methods = array();
foreach ($metadata->fieldMappings as $fieldMapping) {
if ( ! isset($fieldMapping['id']) || ! $fieldMapping['id'] || $metadata->generatorType == ClassMetadataInfo::GENERATOR_TYPE_NONE) {
if ($code = $this->_generateEntityStubMethod($metadata, 'set', $fieldMapping['fieldName'], $fieldMapping['type'])) {
$methods[] = $code;
}
}
if ($code = $this->_generateEntityStubMethod($metadata, 'get', $fieldMapping['fieldName'], $fieldMapping['type'])) {
$methods[] = $code;
}
}
foreach ($metadata->associationMappings as $associationMapping) {
if ($associationMapping['type'] & ClassMetadataInfo::TO_ONE) {
2011-10-24 14:00:11 +04:00
$nullable = $this->_isAssociationIsNullable($associationMapping) ? 'null' : null;
if ($code = $this->_generateEntityStubMethod($metadata, 'set', $associationMapping['fieldName'], $associationMapping['targetEntity'], $nullable)) {
$methods[] = $code;
}
if ($code = $this->_generateEntityStubMethod($metadata, 'get', $associationMapping['fieldName'], $associationMapping['targetEntity'])) {
$methods[] = $code;
}
} else if ($associationMapping['type'] & ClassMetadataInfo::TO_MANY) {
if ($code = $this->_generateEntityStubMethod($metadata, 'add', $associationMapping['fieldName'], $associationMapping['targetEntity'])) {
$methods[] = $code;
}
if ($code = $this->_generateEntityStubMethod($metadata, 'get', $associationMapping['fieldName'], 'Doctrine\Common\Collections\Collection')) {
$methods[] = $code;
}
}
}
return implode("\n\n", $methods);
}
private function _isAssociationIsNullable($associationMapping)
{
2012-02-15 15:43:55 +04:00
if (isset($associationMapping['id']) && $associationMapping['id']) {
return false;
}
2011-10-24 12:19:01 +04:00
if (isset($associationMapping['joinColumns'])) {
$joinColumns = $associationMapping['joinColumns'];
2011-10-24 12:19:01 +04:00
} else {
//@todo thereis no way to retreive targetEntity metadata
$joinColumns = array();
}
foreach ($joinColumns as $joinColumn) {
2011-10-24 12:19:01 +04:00
if(isset($joinColumn['nullable']) && !$joinColumn['nullable']) {
return false;
}
}
return true;
}
private function _generateEntityLifecycleCallbackMethods(ClassMetadataInfo $metadata)
{
if (isset($metadata->lifecycleCallbacks) && $metadata->lifecycleCallbacks) {
$methods = array();
foreach ($metadata->lifecycleCallbacks as $name => $callbacks) {
foreach ($callbacks as $callback) {
if ($code = $this->_generateLifecycleCallbackMethod($name, $callback, $metadata)) {
$methods[] = $code;
}
}
}
return implode("\n\n", $methods);
}
return "";
}
private function _generateEntityAssociationMappingProperties(ClassMetadataInfo $metadata)
{
$lines = array();
foreach ($metadata->associationMappings as $associationMapping) {
if ($this->_hasProperty($associationMapping['fieldName'], $metadata)) {
continue;
}
$lines[] = $this->_generateAssociationMappingPropertyDocBlock($associationMapping, $metadata);
$lines[] = $this->_spaces . $this->_fieldVisibility . ' $' . $associationMapping['fieldName']
. ($associationMapping['type'] == 'manyToMany' ? ' = array()' : null) . ";\n";
}
return implode("\n", $lines);
}
private function _generateEntityFieldMappingProperties(ClassMetadataInfo $metadata)
{
$lines = array();
foreach ($metadata->fieldMappings as $fieldMapping) {
if ($this->_hasProperty($fieldMapping['fieldName'], $metadata) ||
$metadata->isInheritedField($fieldMapping['fieldName'])) {
continue;
}
$lines[] = $this->_generateFieldMappingPropertyDocBlock($fieldMapping, $metadata);
$lines[] = $this->_spaces . $this->_fieldVisibility . ' $' . $fieldMapping['fieldName']
. (isset($fieldMapping['default']) ? ' = ' . var_export($fieldMapping['default'], true) : null) . ";\n";
}
return implode("\n", $lines);
}
private function _generateEntityStubMethod(ClassMetadataInfo $metadata, $type, $fieldName, $typeHint = null, $defaultValue = null)
{
if ($type == "add") {
$addMethod = explode("\\", $typeHint);
$addMethod = end($addMethod);
$methodName = $type . $addMethod;
} else {
$methodName = $type . Inflector::classify($fieldName);
}
if ($this->_hasMethod($methodName, $metadata)) {
return;
}
$this->_staticReflection[$metadata->name]['methods'][] = $methodName;
$var = sprintf('_%sMethodTemplate', $type);
$template = self::$$var;
$variableType = $typeHint ? $typeHint . ' ' : null;
$types = \Doctrine\DBAL\Types\Type::getTypesMap();
$methodTypeHint = $typeHint && ! isset($types[$typeHint]) ? '\\' . $typeHint . ' ' : null;
$replacements = array(
'<description>' => ucfirst($type) . ' ' . $fieldName,
'<methodTypeHint>' => $methodTypeHint,
'<variableType>' => $variableType,
'<variableName>' => Inflector::camelize($fieldName),
'<methodName>' => $methodName,
'<fieldName>' => $fieldName,
'<variableDefault>' => ($defaultValue !== null ) ? (' = '.$defaultValue) : '',
2011-09-20 17:50:32 +04:00
'<entity>' => $this->_getClassName($metadata)
);
$method = str_replace(
array_keys($replacements),
array_values($replacements),
$template
);
return $this->_prefixCodeWithSpaces($method);
}
private function _generateLifecycleCallbackMethod($name, $methodName, $metadata)
{
if ($this->_hasMethod($methodName, $metadata)) {
return;
}
$this->_staticReflection[$metadata->name]['methods'][] = $methodName;
$replacements = array(
'<name>' => $this->_annotationsPrefix . $name,
'<methodName>' => $methodName,
);
$method = str_replace(
array_keys($replacements),
array_values($replacements),
self::$_lifecycleCallbackMethodTemplate
);
return $this->_prefixCodeWithSpaces($method);
}
private function _generateJoinColumnAnnotation(array $joinColumn)
{
$joinColumnAnnot = array();
if (isset($joinColumn['name'])) {
$joinColumnAnnot[] = 'name="' . $joinColumn['name'] . '"';
}
if (isset($joinColumn['referencedColumnName'])) {
$joinColumnAnnot[] = 'referencedColumnName="' . $joinColumn['referencedColumnName'] . '"';
}
if (isset($joinColumn['unique']) && $joinColumn['unique']) {
$joinColumnAnnot[] = 'unique=' . ($joinColumn['unique'] ? 'true' : 'false');
}
if (isset($joinColumn['nullable'])) {
$joinColumnAnnot[] = 'nullable=' . ($joinColumn['nullable'] ? 'true' : 'false');
}
if (isset($joinColumn['onDelete'])) {
$joinColumnAnnot[] = 'onDelete="' . ($joinColumn['onDelete'] . '"');
}
if (isset($joinColumn['columnDefinition'])) {
$joinColumnAnnot[] = 'columnDefinition="' . $joinColumn['columnDefinition'] . '"';
}
return '@' . $this->_annotationsPrefix . 'JoinColumn(' . implode(', ', $joinColumnAnnot) . ')';
}
private function _generateAssociationMappingPropertyDocBlock(array $associationMapping, ClassMetadataInfo $metadata)
{
$lines = array();
$lines[] = $this->_spaces . '/**';
2011-10-24 12:19:01 +04:00
if ($associationMapping['type'] & ClassMetadataInfo::TO_MANY) {
$lines[] = $this->_spaces . ' * @var \Doctrine\Common\Collections\ArrayCollection';
2011-10-24 12:19:01 +04:00
} else {
$lines[] = $this->_spaces . ' * @var ' . $associationMapping['targetEntity'];
}
if ($this->_generateAnnotations) {
$lines[] = $this->_spaces . ' *';
$type = null;
switch ($associationMapping['type']) {
case ClassMetadataInfo::ONE_TO_ONE:
$type = 'OneToOne';
break;
case ClassMetadataInfo::MANY_TO_ONE:
$type = 'ManyToOne';
break;
case ClassMetadataInfo::ONE_TO_MANY:
$type = 'OneToMany';
break;
case ClassMetadataInfo::MANY_TO_MANY:
$type = 'ManyToMany';
break;
}
$typeOptions = array();
if (isset($associationMapping['targetEntity'])) {
$typeOptions[] = 'targetEntity="' . $associationMapping['targetEntity'] . '"';
}
if (isset($associationMapping['inversedBy'])) {
$typeOptions[] = 'inversedBy="' . $associationMapping['inversedBy'] . '"';
}
if (isset($associationMapping['mappedBy'])) {
$typeOptions[] = 'mappedBy="' . $associationMapping['mappedBy'] . '"';
}
if ($associationMapping['cascade']) {
$cascades = array();
if ($associationMapping['isCascadePersist']) $cascades[] = '"persist"';
if ($associationMapping['isCascadeRemove']) $cascades[] = '"remove"';
if ($associationMapping['isCascadeDetach']) $cascades[] = '"detach"';
if ($associationMapping['isCascadeMerge']) $cascades[] = '"merge"';
if ($associationMapping['isCascadeRefresh']) $cascades[] = '"refresh"';
$typeOptions[] = 'cascade={' . implode(',', $cascades) . '}';
}
if (isset($associationMapping['orphanRemoval']) && $associationMapping['orphanRemoval']) {
$typeOptions[] = 'orphanRemoval=' . ($associationMapping['orphanRemoval'] ? 'true' : 'false');
}
$lines[] = $this->_spaces . ' * @' . $this->_annotationsPrefix . '' . $type . '(' . implode(', ', $typeOptions) . ')';
if (isset($associationMapping['joinColumns']) && $associationMapping['joinColumns']) {
$lines[] = $this->_spaces . ' * @' . $this->_annotationsPrefix . 'JoinColumns({';
$joinColumnsLines = array();
foreach ($associationMapping['joinColumns'] as $joinColumn) {
if ($joinColumnAnnot = $this->_generateJoinColumnAnnotation($joinColumn)) {
$joinColumnsLines[] = $this->_spaces . ' * ' . $joinColumnAnnot;
}
}
$lines[] = implode(",\n", $joinColumnsLines);
$lines[] = $this->_spaces . ' * })';
}
if (isset($associationMapping['joinTable']) && $associationMapping['joinTable']) {
$joinTable = array();
$joinTable[] = 'name="' . $associationMapping['joinTable']['name'] . '"';
if (isset($associationMapping['joinTable']['schema'])) {
$joinTable[] = 'schema="' . $associationMapping['joinTable']['schema'] . '"';
}
$lines[] = $this->_spaces . ' * @' . $this->_annotationsPrefix . 'JoinTable(' . implode(', ', $joinTable) . ',';
$lines[] = $this->_spaces . ' * joinColumns={';
foreach ($associationMapping['joinTable']['joinColumns'] as $joinColumn) {
$lines[] = $this->_spaces . ' * ' . $this->_generateJoinColumnAnnotation($joinColumn);
}
$lines[] = $this->_spaces . ' * },';
$lines[] = $this->_spaces . ' * inverseJoinColumns={';
foreach ($associationMapping['joinTable']['inverseJoinColumns'] as $joinColumn) {
$lines[] = $this->_spaces . ' * ' . $this->_generateJoinColumnAnnotation($joinColumn);
}
$lines[] = $this->_spaces . ' * }';
$lines[] = $this->_spaces . ' * )';
}
if (isset($associationMapping['orderBy'])) {
$lines[] = $this->_spaces . ' * @' . $this->_annotationsPrefix . 'OrderBy({';
foreach ($associationMapping['orderBy'] as $name => $direction) {
$lines[] = $this->_spaces . ' * "' . $name . '"="' . $direction . '",';
}
$lines[count($lines) - 1] = substr($lines[count($lines) - 1], 0, strlen($lines[count($lines) - 1]) - 1);
$lines[] = $this->_spaces . ' * })';
}
}
$lines[] = $this->_spaces . ' */';
return implode("\n", $lines);
}
private function _generateFieldMappingPropertyDocBlock(array $fieldMapping, ClassMetadataInfo $metadata)
{
$lines = array();
$lines[] = $this->_spaces . '/**';
$lines[] = $this->_spaces . ' * @var ' . $fieldMapping['type'] . ' $' . $fieldMapping['fieldName'];
if ($this->_generateAnnotations) {
$lines[] = $this->_spaces . ' *';
$column = array();
if (isset($fieldMapping['columnName'])) {
$column[] = 'name="' . $fieldMapping['columnName'] . '"';
}
if (isset($fieldMapping['type'])) {
$column[] = 'type="' . $fieldMapping['type'] . '"';
}
if (isset($fieldMapping['length'])) {
$column[] = 'length=' . $fieldMapping['length'];
}
if (isset($fieldMapping['precision'])) {
$column[] = 'precision=' . $fieldMapping['precision'];
}
if (isset($fieldMapping['scale'])) {
$column[] = 'scale=' . $fieldMapping['scale'];
}
if (isset($fieldMapping['nullable'])) {
$column[] = 'nullable=' . var_export($fieldMapping['nullable'], true);
}
if (isset($fieldMapping['columnDefinition'])) {
$column[] = 'columnDefinition="' . $fieldMapping['columnDefinition'] . '"';
}
if (isset($fieldMapping['unique'])) {
$column[] = 'unique=' . var_export($fieldMapping['unique'], true);
}
$lines[] = $this->_spaces . ' * @' . $this->_annotationsPrefix . 'Column(' . implode(', ', $column) . ')';
if (isset($fieldMapping['id']) && $fieldMapping['id']) {
$lines[] = $this->_spaces . ' * @' . $this->_annotationsPrefix . 'Id';
if ($generatorType = $this->_getIdGeneratorTypeString($metadata->generatorType)) {
$lines[] = $this->_spaces.' * @' . $this->_annotationsPrefix . 'GeneratedValue(strategy="' . $generatorType . '")';
}
if ($metadata->sequenceGeneratorDefinition) {
$sequenceGenerator = array();
if (isset($metadata->sequenceGeneratorDefinition['sequenceName'])) {
$sequenceGenerator[] = 'sequenceName="' . $metadata->sequenceGeneratorDefinition['sequenceName'] . '"';
}
if (isset($metadata->sequenceGeneratorDefinition['allocationSize'])) {
$sequenceGenerator[] = 'allocationSize="' . $metadata->sequenceGeneratorDefinition['allocationSize'] . '"';
}
if (isset($metadata->sequenceGeneratorDefinition['initialValue'])) {
$sequenceGenerator[] = 'initialValue="' . $metadata->sequenceGeneratorDefinition['initialValue'] . '"';
}
$lines[] = $this->_spaces . ' * @' . $this->_annotationsPrefix . 'SequenceGenerator(' . implode(', ', $sequenceGenerator) . ')';
}
}
if (isset($fieldMapping['version']) && $fieldMapping['version']) {
$lines[] = $this->_spaces . ' * @' . $this->_annotationsPrefix . 'Version';
}
}
$lines[] = $this->_spaces . ' */';
return implode("\n", $lines);
}
private function _prefixCodeWithSpaces($code, $num = 1)
{
$lines = explode("\n", $code);
foreach ($lines as $key => $value) {
$lines[$key] = str_repeat($this->_spaces, $num) . $lines[$key];
}
return implode("\n", $lines);
}
private function _getInheritanceTypeString($type)
{
switch ($type) {
case ClassMetadataInfo::INHERITANCE_TYPE_NONE:
return 'NONE';
case ClassMetadataInfo::INHERITANCE_TYPE_JOINED:
return 'JOINED';
case ClassMetadataInfo::INHERITANCE_TYPE_SINGLE_TABLE:
return 'SINGLE_TABLE';
case ClassMetadataInfo::INHERITANCE_TYPE_TABLE_PER_CLASS:
return 'PER_CLASS';
default:
throw new \InvalidArgumentException('Invalid provided InheritanceType: ' . $type);
}
}
private function _getChangeTrackingPolicyString($policy)
{
switch ($policy) {
case ClassMetadataInfo::CHANGETRACKING_DEFERRED_IMPLICIT:
return 'DEFERRED_IMPLICIT';
case ClassMetadataInfo::CHANGETRACKING_DEFERRED_EXPLICIT:
return 'DEFERRED_EXPLICIT';
case ClassMetadataInfo::CHANGETRACKING_NOTIFY:
return 'NOTIFY';
default:
throw new \InvalidArgumentException('Invalid provided ChangeTrackingPolicy: ' . $policy);
}
}
private function _getIdGeneratorTypeString($type)
{
switch ($type) {
case ClassMetadataInfo::GENERATOR_TYPE_AUTO:
return 'AUTO';
case ClassMetadataInfo::GENERATOR_TYPE_SEQUENCE:
return 'SEQUENCE';
case ClassMetadataInfo::GENERATOR_TYPE_TABLE:
return 'TABLE';
case ClassMetadataInfo::GENERATOR_TYPE_IDENTITY:
return 'IDENTITY';
case ClassMetadataInfo::GENERATOR_TYPE_NONE:
return 'NONE';
default:
throw new \InvalidArgumentException('Invalid provided IdGeneratorType: ' . $type);
}
}
}