Exemple #1
0
 public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias)
 {
     $account = $this->getParameter('account');
     $properties = $targetEntity->getReflectionProperties();
     $dql = '';
     if (isset($properties['account'])) {
         $dql = $targetTableAlias . '.account = ' . $account;
     }
     return $dql;
 }
 /**
  * @depends testGeneratedEntityClass
  * @param ClassMetadata $metadata
  */
 public function testEntityUpdatingWorks($metadata)
 {
     $metadata->mapField(array('fieldName' => 'test', 'type' => 'string'));
     $this->_generator->writeEntityClass($metadata, __DIR__);
     $code = file_get_contents(__DIR__ . '/EntityGeneratorBook.php');
     $this->assertTrue(strstr($code, 'private $test;') !== false);
     $this->assertTrue(strstr($code, 'private $test;') !== false);
     $this->assertTrue(strstr($code, 'public function getTest(') !== false);
     $this->assertTrue(strstr($code, 'public function setTest(') !== false);
     unlink(__DIR__ . '/EntityGeneratorBook.php');
 }
 public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias)
 {
     if (array_key_exists($targetEntity->getName(), $this->disabled)) {
         return '';
     }
     $config = $this->getListener()->getConfiguration($this->getEntityManager(), $targetEntity->name);
     if (!isset($config['softDeleteable']) || !$config['softDeleteable']) {
         return '';
     }
     $column = $targetEntity->columnNames[$config['fieldName']];
     return $targetTableAlias . '.' . $column . ' IS NULL';
 }
 public function testStringModel()
 {
     $this->markTestskipped();
     $builder = new FormBuilder();
     $model = new TestModel();
     $form = $builder->createFormBuilder($model)->add('string', 'text')->getForm();
     $form->handle(['string' => 'test']);
     $classMetadata = new ClassMetadata(TestModel::class);
     $classMetadata->mapField(array('name' => 'string', 'type' => 'string'));
     $validatorMetadata = new ClassMetadata(TestModel::class);
     $validatorMetadata->addConstraint();
 }
Exemple #5
0
 /**
  * @param ClassMetaData $targetEntity
  * @param string        $targetTableAlias
  *
  * @return string
  */
 public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias)
 {
     $annotationReader = $this->getListener()->getAnnotationReader();
     if (!$annotationReader->isDraft($targetEntity->getName())) {
         return "";
     }
     // Check if the entity implements the DraftInterface interface
     if (!$targetEntity->reflClass->implementsInterface('Opifer\\Revisions\\DraftInterface')) {
         return "";
     }
     return "{$targetTableAlias}.created_at IS NOT NULL";
 }
 public function load()
 {
     $this->evalClass($this->classmetadata);
     $builder = new ProxyBuilder();
     $builder->setNamespace($this->classmetadata->getNamespace());
     $builder->setClassName($this->originalClassName);
     $builder->setParentClass("\\" . $this->classmetadata->getNamespace() . "\\" . $this->classmetadata->getName());
     foreach ($this->classmetadata->getMethods() as $method) {
         $builder->addMethod($method);
     }
     $builder->loadProxy();
 }
Exemple #7
0
 public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias)
 {
     $mappings = $targetEntity->getAssociationMappings();
     if (!array_key_exists('journal', $mappings) || $mappings['journal']['targetEntity'] !== 'Ojs\\JournalBundle\\Entity\\Journal') {
         return '';
     }
     $selectedJournal = $this->journalService->getSelectedJournal();
     if (!$selectedJournal) {
         return '';
     }
     $journalJoinColumn = $mappings['journal']['joinColumns'][0]['name'];
     $addCondSql = $targetTableAlias . '.' . $journalJoinColumn . ' = ' . $selectedJournal->getId();
     return $addCondSql;
 }
 /**
  * Gets the SQL query part to add to a query.
  *
  * @param ClassMetaData $targetEntity Metadata object for the target entity to be filtered
  * @param string $targetTableAlias The target table alias used in the current query
  * @return string The constraint SQL if there is available, empty string otherwise
  */
 public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias)
 {
     $this->initializeDependencies();
     /*
      * TODO: Instead of checking for class account we could introduce some interface for white listing entities from entity security checks
      * Problem with checking the Account is, that this filter calls getRoles() on the security context while accounts are not
      * yet fully initialized. By this we get a half built account object that will end up in access denied exception,
      * as it has no roles (and other properties) set
      */
     if ($this->securityContext->areAuthorizationChecksDisabled() || $targetEntity->getName() === \TYPO3\Flow\Security\Account::class) {
         return '';
     }
     if (!$this->securityContext->isInitialized()) {
         if (!$this->securityContext->canBeInitialized()) {
             return '';
         }
         $this->securityContext->initialize();
     }
     // This is needed to include the current context of roles into query cache identifier
     $this->setParameter('__contextHash', $this->securityContext->getContextHash(), 'string');
     $sqlConstraints = array();
     $grantedConstraints = array();
     $deniedConstraints = array();
     foreach ($this->securityContext->getRoles() as $role) {
         $entityPrivileges = $role->getPrivilegesByType(\TYPO3\Flow\Security\Authorization\Privilege\Entity\EntityPrivilegeInterface::class);
         /** @var EntityPrivilegeInterface $privilege */
         foreach ($entityPrivileges as $privilege) {
             if (!$privilege->matchesEntityType($targetEntity->getName())) {
                 continue;
             }
             $sqlConstraint = $privilege->getSqlConstraint($targetEntity, $targetTableAlias);
             if ($sqlConstraint === null) {
                 continue;
             }
             $sqlConstraints[] = ' NOT (' . $sqlConstraint . ')';
             if ($privilege->isGranted()) {
                 $grantedConstraints[] = ' NOT (' . $sqlConstraint . ')';
             } elseif ($privilege->isDenied()) {
                 $deniedConstraints[] = ' NOT (' . $sqlConstraint . ')';
             }
         }
     }
     $grantedConstraints = array_diff($grantedConstraints, $deniedConstraints);
     $effectiveConstraints = array_diff($sqlConstraints, $grantedConstraints);
     if (count($effectiveConstraints) > 0) {
         return ' (' . implode(') AND (', $effectiveConstraints) . ') ';
     }
     return '';
 }
 /**
  * @return array
  */
 private function getData()
 {
     $columns = $this->prefixColumnsForFetch(array_keys($this->classMetadata->getProperties()));
     switch ($this->joinParameters['relation']) {
         case ClassMetadata::JOIN_ONE_TO_MANY:
             $where = sprintf("a.%s = %%s", $this->joinParameters['join']['referenceColumn']);
             return $this->manager->getDibiConnection()->select($columns)->from($this->classMetadata->getTable())->as('a')->where($where, DataHelperLoader::getPropertyValue($this->parent, $this->joinParameters['join']['column']))->fetchAll();
             break;
         case ClassMetadata::JOIN_MANY_TO_MANY:
             $targetClassMetadata = $this->manager->createClassMetadata($this->joinParameters['entity']);
             return $this->manager->getDibiConnection()->select($columns)->from($targetClassMetadata->getTable())->as('a')->innerJoin($this->joinParameters['joiningTable'])->as('b')->on(sprintf('a.%s = b.%s', $this->joinParameters['joinSecondary']['referenceColumn'], $this->joinParameters['joinSecondary']['column']))->and('b.' . $this->joinParameters['joinPrimary']['referenceColumn'] . ' = %s', DataHelperLoader::getPropertyValue($this->parent, $this->joinParameters['joinPrimary']['column']))->fetchAll();
             break;
         default:
             throw new \InvalidArgumentException(sprintf('Invalid join specified %s', $this->joinParameters['relation']));
     }
 }
 public function merge(ClassMetadata $metadata)
 {
     $reflection = $metadata->getReflection();
     if (false === $reflection->isInterface()) {
         throw new \InvalidArgumentException('You can only merge metadata from interfaces.');
     }
     if (false === $this->reflection->implementsInterface($reflection->getName())) {
         throw new \InvalidArgumentException(sprintf('"%s" does not implement "%s".', $this->reflection->getName(), $reflection->getName()));
     }
     foreach ($metadata->getMethods() as $name => $method) {
         if (!isset($this->methods[$name])) {
             $this->methods[$name] = new MethodMetadata($this->reflection->getMethod($name));
         }
         $this->methods[$name]->merge($method);
     }
 }
Exemple #11
0
 /**
  * {@inheritdoc}
  */
 public function isCollectionValuedAssociation($fieldName)
 {
     if (!isset($this->associationMappings[$fieldName])) {
         throw new \InvalidArgumentException(sprintf('Association name expected, "%s" is not an association.', $fieldName));
     }
     return parent::isCollectionValuedAssociation($fieldName);
 }
 public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias)
 {
     if (!in_array(SoftDeletable::class, $targetEntity->reflClass->getInterfaceNames())) {
         return '';
     }
     $class = $targetEntity->getReflectionClass();
     $reader = new AnnotationReader();
     $constraint = '';
     $isFirst = true;
     foreach ($class->getProperties() as $property) {
         if ($reader->getPropertyAnnotation($property, SoftDeletableMapping::class) !== null) {
             $constraint .= ($isFirst ? '' : ' AND ') . $targetTableAlias . '.' . $targetEntity->getColumnName($property->getName()) . ' IS NULL';
             $isFirst = false;
         }
     }
     return $constraint;
 }
Exemple #13
0
 /**
  * Reads annotations for a selected property in the class
  * 
  * @param ReflectionProperty $property
  * @param ClassMetadata $metadata
  */
 private function readProperty($property, $metadata)
 {
     $reflClass = $metadata->getReflectionClass();
     // Skip if this property is not from this class
     if ($property->getDeclaringClass()->getName() != $metadata->getClassName()) {
         return;
     }
     //Iterate over all annotations
     foreach ($this->reader->getPropertyAnnotations($property) as $rule) {
         //Skip is its not a rule
         if (!$rule instanceof Rules\Rule) {
             continue;
         }
         //Add Rule
         $metadata->addPropertyRule($property->getName(), $rule);
     }
 }
 /**
  * Gets the criteria part to add to a query.
  *
  * @return array The criteria array, if there is available, empty array otherwise
  */
 public function addFilterCriteria(ClassMetadata $targetEntity)
 {
     $class = $targetEntity->getName();
     if (array_key_exists($class, $this->disabled) && $this->disabled[$class] === true) {
         return array();
     } elseif (array_key_exists($targetEntity->rootDocumentName, $this->disabled) && $this->disabled[$targetEntity->rootDocumentName] === true) {
         return array();
     }
     $config = $this->getListener()->getConfiguration($this->getDocumentManager(), $targetEntity->name);
     if (!isset($config['softDeleteable']) || !$config['softDeleteable']) {
         return array();
     }
     $column = $targetEntity->fieldMappings[$config['fieldName']];
     if (isset($config['timeAware']) && $config['timeAware']) {
         return array('$or' => array(array($column['fieldName'] => NULL), array($column['fieldName'] => array('$gt' => new \DateTime('now')))));
     }
     return array($column['fieldName'] => NULL);
 }
 public function addFilterCriteria(ClassMetadata $targetDocument)
 {
     if (empty($this->reader)) {
         return '';
     }
     // The Doctrine filter is called for any query on any entity
     // Check if the current entity is "user aware" (marked with an annotation)
     $recordState = $this->reader->getClassAnnotation($targetDocument->getReflectionClass(), 'GreGosPhaTos\\DoctrineFiltersBundle\\Doctrine\\Annotation\\RecordState');
     if (!$recordState) {
         return '';
     }
     $stateFieldName = $recordState->stateFieldName;
     $activeValue = $recordState->activeValue;
     if (empty($stateFieldName) || empty($activeValue)) {
         return '';
     }
     return array($stateFieldName => $activeValue);
 }
 public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias)
 {
     $class = $targetEntity->getName();
     if (array_key_exists($class, $this->disabled) && $this->disabled[$class] === true) {
         return '';
     } elseif (array_key_exists($targetEntity->rootEntityName, $this->disabled) && $this->disabled[$targetEntity->rootEntityName] === true) {
         return '';
     }
     $config = $this->getListener()->getConfiguration($this->getEntityManager(), $targetEntity->name);
     if (!isset($config['clientAware']) || !$config['clientAware']) {
         return '';
     }
     /**
      * TODO: This is a hard dependency on client_id and should be done a little cleaner
      */
     $this->populateClientId();
     $addCondSql = $targetTableAlias . '.client_id = ' . $this->getParameter('client_id');
     return $addCondSql;
 }
 public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias)
 {
     if (empty($this->reader)) {
         return '';
     }
     // The Doctrine filter is called for any query on any entity
     // Check if the current entity is "active" (marked with an annotation)
     $recordState = $this->reader->getClassAnnotation($targetEntity->getReflectionClass(), 'GreGosPhaTos\\DoctrineFiltersBundle\\Doctrine\\Annotation\\RecordState');
     if (!$recordState) {
         return '';
     }
     $stateFieldName = $recordState->stateFieldName;
     $activeValue = $recordState->activeValue;
     if (empty($stateFieldName) || empty($activeValue)) {
         return '';
     }
     $query = sprintf('%s.%s = "%s"', $targetTableAlias, $stateFieldName, $activeValue);
     return $query;
 }
Exemple #18
0
 public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias)
 {
     if ('Omeka\\Entity\\Resource' !== $targetEntity->getName()) {
         return '';
     }
     $acl = $this->getServiceLocator()->get('Omeka\\Acl');
     if ($acl->userIsAllowed('Omeka\\Entity\\Resource', 'view-all')) {
         return '';
     }
     // Users can view public resources they do not own.
     $constraints = ["{$targetTableAlias}.is_public = 1"];
     $identity = $this->getServiceLocator()->get('Omeka\\AuthenticationService')->getIdentity();
     if ($identity) {
         // Users can view all resources they own.
         $connection = $this->getServiceLocator()->get('Omeka\\Connection');
         $constraints[] = 'OR';
         $constraints[] = sprintf("{$targetTableAlias}.owner_id = %s", $connection->quote($identity->getId(), Type::INTEGER));
     }
     return implode(' ', $constraints);
 }
Exemple #19
0
 public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias)
 {
     $mappings = $targetEntity->getAssociationMappings();
     if (!array_key_exists('journal', $mappings) || $mappings['journal']['targetEntity'] !== 'Ojs\\JournalBundle\\Entity\\Journal') {
         return '';
     }
     //return if journal filter disabled globally for current entity
     if (isset($GLOBALS[$targetEntity->getName() . '#journalFilter']) && $GLOBALS[$targetEntity->getName() . '#journalFilter'] == false) {
         return '';
     }
     try {
         $selectedJournal = $this->journalService->getSelectedJournal();
     } catch (\Exception $e) {
         return '';
     }
     if (!$selectedJournal) {
         return '';
     }
     $journalJoinColumn = $mappings['journal']['joinColumns'][0]['name'];
     $addCondSql = $targetTableAlias . '.' . $journalJoinColumn . ' = ' . $selectedJournal->getId();
     return $addCondSql;
 }
 public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias)
 {
     $class = $targetEntity->getName();
     if (array_key_exists($class, $this->disabled) && $this->disabled[$class] === true) {
         return '';
     } elseif (array_key_exists($targetEntity->rootEntityName, $this->disabled) && $this->disabled[$targetEntity->rootEntityName] === true) {
         return '';
     }
     $config = $this->getListener()->getConfiguration($this->getEntityManager(), $targetEntity->name);
     if (!isset($config['softDeleteable']) || !$config['softDeleteable']) {
         return '';
     }
     $conn = $this->getEntityManager()->getConnection();
     $platform = $conn->getDatabasePlatform();
     $column = $targetEntity->getQuotedColumnName($config['fieldName'], $platform);
     $addCondSql = $platform->getIsNullExpression($targetTableAlias . '.' . $column);
     if (isset($config['timeAware']) && $config['timeAware']) {
         $now = $conn->quote(date($platform->getDateTimeFormatString()));
         // should use UTC in database and PHP
         $addCondSql = "({$addCondSql} OR {$targetTableAlias}.{$column} > {$now})";
     }
     return $addCondSql;
 }
 /**
  * @param ClassMetadata $metadata
  */
 public function addClassMetadata(ClassMetadata $metadata)
 {
     $this->name = $metadata->getName();
     $this->properties = array_merge($this->properties, $metadata->getProperties());
     $this->fileResources = array_merge($this->fileResources, $metadata->getFileResources());
     if ($metadata->getCreatedAt() < $this->createdAt) {
         $this->createdAt = $metadata->getCreatedAt();
     }
 }
 /**
  * This function tries, given an array of data, to convert it to an object if the given array contains
  * an identifier for the object. This is useful in a context of updating existing entities, without ugly
  * tricks like setting manually the existing id directly into the entity
  *
  * @param  array  $data
  * @param  object $object
  * @return object
  */
 protected function tryConvertArrayToObject($data, $object)
 {
     $identifierNames = $this->metadata->getIdentifierFieldNames($object);
     $identifierValues = array();
     if (empty($identifierNames)) {
         return $object;
     }
     foreach ($identifierNames as $identifierName) {
         if (!isset($data[$identifierName]) || empty($data[$identifierName])) {
             return $object;
         }
         $identifierValues[$identifierName] = $data[$identifierName];
     }
     return $this->find(get_class($object), $identifierValues);
 }
Exemple #23
0
 /**
  * Generates the SQL JOINs that are necessary for Class Table Inheritance
  * for the given class.
  *
  * @param ClassMetadata $class The class for which to generate the joins.
  * @param string $dqlAlias The DQL alias of the class.
  * @return string The SQL.
  */
 private function _generateClassTableInheritanceJoins($class, $dqlAlias)
 {
     $sql = '';
     $baseTableAlias = $this->getSqlTableAlias($class->primaryTable['name'], $dqlAlias);
     // INNER JOIN parent class tables
     foreach ($class->parentClasses as $parentClassName) {
         $parentClass = $this->_em->getClassMetadata($parentClassName);
         $tableAlias = $this->getSqlTableAlias($parentClass->primaryTable['name'], $dqlAlias);
         $sql .= ' INNER JOIN ' . $parentClass->getQuotedTableName($this->_platform) . ' ' . $tableAlias . ' ON ';
         $first = true;
         foreach ($class->identifier as $idField) {
             if ($first) {
                 $first = false;
             } else {
                 $sql .= ' AND ';
             }
             $columnName = $class->getQuotedColumnName($idField, $this->_platform);
             $sql .= $baseTableAlias . '.' . $columnName . ' = ' . $tableAlias . '.' . $columnName;
         }
     }
     // LEFT JOIN subclass tables, if partial objects disallowed
     if (!$this->_query->getHint(Query::HINT_FORCE_PARTIAL_LOAD)) {
         foreach ($class->subClasses as $subClassName) {
             $subClass = $this->_em->getClassMetadata($subClassName);
             $tableAlias = $this->getSqlTableAlias($subClass->primaryTable['name'], $dqlAlias);
             $sql .= ' LEFT JOIN ' . $subClass->getQuotedTableName($this->_platform) . ' ' . $tableAlias . ' ON ';
             $first = true;
             foreach ($class->identifier as $idField) {
                 if ($first) {
                     $first = false;
                 } else {
                     $sql .= ' AND ';
                 }
                 $columnName = $class->getQuotedColumnName($idField, $this->_platform);
                 $sql .= $baseTableAlias . '.' . $columnName . ' = ' . $tableAlias . '.' . $columnName;
             }
         }
     }
     return $sql;
 }
Exemple #24
0
 /**
  * Merges attributes' groups.
  *
  * @param ClassMetadata $classMetadata
  */
 public function mergeAttributesGroups(ClassMetadata $classMetadata)
 {
     foreach ($classMetadata->getAttributesGroups() as $group => $attributes) {
         foreach ($attributes as $attribute) {
             $this->addAttributeGroup($attribute, $group);
         }
     }
 }
Exemple #25
0
 /**
  * Gather columns and fk constraints that are required for one part of relationship.
  * 
  * @param array $joinColumns
  * @param \Doctrine\DBAL\Schema\Table $theJoinTable
  * @param ClassMetadata $class
  * @param \Doctrine\ORM\Mapping\AssociationMapping $mapping
  * @param array $primaryKeyColumns
  * @param array $uniqueConstraints
  */
 private function _gatherRelationJoinColumns($joinColumns, $theJoinTable, $class, $mapping, &$primaryKeyColumns, &$uniqueConstraints)
 {
     $localColumns = array();
     $foreignColumns = array();
     $fkOptions = array();
     foreach ($joinColumns as $joinColumn) {
         // Note that this thing might be quoted, i.e. `foo`, [foo], ...
         $columnName = $mapping->getQuotedJoinColumnName($joinColumn['name'], $this->_platform);
         $referencedFieldName = $class->getFieldName($joinColumn['referencedColumnName']);
         if (!$class->hasField($referencedFieldName)) {
             throw new \Doctrine\Common\DoctrineException("Column name `" . $joinColumn['referencedColumnName'] . "` referenced for relation from " . "{$mapping->sourceEntityName} towards {$mapping->targetEntityName} does not exist.");
         }
         $primaryKeyColumns[] = $columnName;
         $localColumns[] = $columnName;
         $foreignColumns[] = $joinColumn['referencedColumnName'];
         if (!$theJoinTable->hasColumn($joinColumn['name'])) {
             // Only add the column to the table if it does not exist already.
             // It might exist already if the foreign key is mapped into a regular
             // property as well.
             $fieldMapping = $class->getFieldMapping($referencedFieldName);
             $columnDef = null;
             if (isset($joinColumn['columnDefinition'])) {
                 $columnDef = $joinColumn['columnDefinition'];
             } else {
                 if (isset($fieldMapping['columnDefinition'])) {
                     $columnDef = $fieldMapping['columnDefinition'];
                 }
             }
             $columnOptions = array('notnull' => false, 'columnDefinition' => $columnDef);
             if (isset($joinColumn['nullable'])) {
                 $columnOptions['notnull'] = !$joinColumn['nullable'];
             }
             $theJoinTable->createColumn($columnName, $class->getTypeOfColumn($joinColumn['referencedColumnName']), $columnOptions);
         }
         if (isset($joinColumn['unique']) && $joinColumn['unique'] == true) {
             $uniqueConstraints[] = array('columns' => array($columnName));
         }
         if (isset($joinColumn['onUpdate'])) {
             $fkOptions['onUpdate'] = $joinColumn['onUpdate'];
         }
         if (isset($joinColumn['onDelete'])) {
             $fkOptions['onDelete'] = $joinColumn['onDelete'];
         }
     }
     $theJoinTable->addUnnamedForeignKeyConstraint($class->getQuotedTableName($this->_platform), $localColumns, $foreignColumns, $fkOptions);
 }
Exemple #26
0
 /**
  * Checks if $field type is valid as Sluggable field
  *
  * @param ClassMetadata $meta
  * @param string $field
  * @return boolean
  */
 protected function isValidField($meta, $field)
 {
     $mapping = $meta->getFieldMapping($field);
     return $mapping && in_array($mapping['type'], $this->validTypes);
 }
 /**
  * @param mixed $id
  * @return object|NULL
  */
 public function find($id)
 {
     // TODO solve possibility to call with more column in primary key
     return $this->manager->find($this->classMetadata->getEntityName(), $id);
 }
Exemple #28
0
 /**
  * Computes the changes done to a single entity.
  *
  * Modifies/populates the following properties:
  *
  * {@link _originalEntityData}
  * If the entity is NEW or MANAGED but not yet fully persisted (only has an id)
  * then it was not fetched from the database and therefore we have no original
  * entity data yet. All of the current entity data is stored as the original entity data.
  *
  * {@link _entityChangeSets}
  * The changes detected on all properties of the entity are stored there.
  * A change is a tuple array where the first entry is the old value and the second
  * entry is the new value of the property. Changesets are used by persisters
  * to INSERT/UPDATE the persistent entity state.
  *
  * {@link _entityUpdates}
  * If the entity is already fully MANAGED (has been fetched from the database before)
  * and any changes to its properties are detected, then a reference to the entity is stored
  * there to mark it for an update.
  *
  * {@link _collectionDeletions}
  * If a PersistentCollection has been de-referenced in a fully MANAGED entity,
  * then this collection is marked for deletion.
  *
  * @param ClassMetadata $class The class descriptor of the entity.
  * @param object $entity The entity for which to compute the changes.
  */
 private function _computeEntityChanges($class, $entity)
 {
     $oid = spl_object_hash($entity);
     if (!$class->isInheritanceTypeNone()) {
         $class = $this->_em->getClassMetadata(get_class($entity));
     }
     $actualData = array();
     foreach ($class->reflFields as $name => $refProp) {
         if (!$class->isIdentifier($name) || !$class->isIdGeneratorIdentity()) {
             $actualData[$name] = $refProp->getValue($entity);
         }
         if ($class->isCollectionValuedAssociation($name) && $actualData[$name] !== null && !$actualData[$name] instanceof PersistentCollection) {
             //TODO: If $actualData[$name] is Collection then unwrap the array
             $assoc = $class->associationMappings[$name];
             //echo PHP_EOL . "INJECTING PCOLL into $name" . PHP_EOL;
             // Inject PersistentCollection
             $coll = new PersistentCollection($this->_em, $this->_em->getClassMetadata($assoc->targetEntityName), $actualData[$name] ? $actualData[$name] : array());
             $coll->setOwner($entity, $assoc);
             if (!$coll->isEmpty()) {
                 $coll->setDirty(true);
             }
             $class->reflFields[$name]->setValue($entity, $coll);
             $actualData[$name] = $coll;
         }
     }
     if (!isset($this->_originalEntityData[$oid])) {
         // Entity is either NEW or MANAGED but not yet fully persisted
         // (only has an id). These result in an INSERT.
         $this->_originalEntityData[$oid] = $actualData;
         $this->_entityChangeSets[$oid] = array_map(function ($e) {
             return array(null, $e);
         }, $actualData);
     } else {
         // Entity is "fully" MANAGED: it was already fully persisted before
         // and we have a copy of the original data
         $originalData = $this->_originalEntityData[$oid];
         $changeSet = array();
         $entityIsDirty = false;
         foreach ($actualData as $propName => $actualValue) {
             $orgValue = isset($originalData[$propName]) ? $originalData[$propName] : null;
             if (is_object($orgValue) && $orgValue !== $actualValue) {
                 $changeSet[$propName] = array($orgValue, $actualValue);
             } else {
                 if ($orgValue != $actualValue || $orgValue === null ^ $actualValue === null) {
                     $changeSet[$propName] = array($orgValue, $actualValue);
                 }
             }
             if (isset($changeSet[$propName])) {
                 if (isset($class->associationMappings[$propName])) {
                     $assoc = $class->associationMappings[$propName];
                     if ($assoc->isOneToOne() && $assoc->isOwningSide) {
                         $entityIsDirty = true;
                     } else {
                         if ($orgValue instanceof PersistentCollection) {
                             // A PersistentCollection was de-referenced, so delete it.
                             if (!in_array($orgValue, $this->_collectionDeletions, true)) {
                                 $this->_collectionDeletions[] = $orgValue;
                             }
                         }
                     }
                 } else {
                     $entityIsDirty = true;
                 }
             }
         }
         if ($changeSet) {
             if ($entityIsDirty) {
                 $this->_entityUpdates[$oid] = $entity;
             }
             $this->_entityChangeSets[$oid] = $changeSet;
             $this->_originalEntityData[$oid] = $actualData;
         }
     }
 }
 /**
  * INTERNAL:
  * Computes the changeset of an individual entity, independently of the
  * computeChangeSets() routine that is used at the beginning of a UnitOfWork#commit().
  * 
  * The passed entity must be a managed entity. If the entity already has a change set
  * because this method is invoked during a commit cycle then the change sets are added.
  * whereby changes detected in this method prevail.
  * 
  * @ignore
  * @param ClassMetadata $class The class descriptor of the entity.
  * @param object $entity The entity for which to (re)calculate the change set.
  * @throws InvalidArgumentException If the passed entity is not MANAGED.
  */
 public function recomputeSingleEntityChangeSet($class, $entity)
 {
     $oid = spl_object_hash($entity);
     if (!isset($this->_entityStates[$oid]) || $this->_entityStates[$oid] != self::STATE_MANAGED) {
         throw new \InvalidArgumentException('Entity must be managed.');
     }
     /* TODO: Just return if changetracking policy is NOTIFY?
        if ($class->isChangeTrackingNotify()) {
            return;
        }*/
     if (!$class->isInheritanceTypeNone()) {
         $class = $this->_em->getClassMetadata(get_class($entity));
     }
     $actualData = array();
     foreach ($class->reflFields as $name => $refProp) {
         if (!$class->isIdentifier($name) || !$class->isIdGeneratorIdentity()) {
             $actualData[$name] = $refProp->getValue($entity);
         }
     }
     $originalData = $this->_originalEntityData[$oid];
     $changeSet = array();
     foreach ($actualData as $propName => $actualValue) {
         $orgValue = isset($originalData[$propName]) ? $originalData[$propName] : null;
         if (is_object($orgValue) && $orgValue !== $actualValue) {
             $changeSet[$propName] = array($orgValue, $actualValue);
         } else {
             if ($orgValue != $actualValue || $orgValue === null ^ $actualValue === null) {
                 $changeSet[$propName] = array($orgValue, $actualValue);
             }
         }
     }
     if ($changeSet) {
         if (isset($this->_entityChangeSets[$oid])) {
             $this->_entityChangeSets[$oid] = $changeSet + $this->_entityChangeSets[$oid];
         }
         $this->_originalEntityData[$oid] = $actualData;
     }
 }
 /**
  * Generates the SQL JOINs that are necessary for Class Table Inheritance
  * for the given class.
  *
  * @param ClassMetadata $class The class for which to generate the joins.
  * @param string $dqlAlias The DQL alias of the class.
  * @return string The SQL.
  */
 private function _generateClassTableInheritanceJoins($class, $dqlAlias)
 {
     $sql = '';
     $baseTableAlias = $this->getSQLTableAlias($class->table['name'], $dqlAlias);
     // INNER JOIN parent class tables
     foreach ($class->parentClasses as $parentClassName) {
         $parentClass = $this->_em->getClassMetadata($parentClassName);
         $tableAlias = $this->getSQLTableAlias($parentClass->table['name'], $dqlAlias);
         // If this is a joined association we must use left joins to preserve the correct result.
         $sql .= isset($this->_queryComponents[$dqlAlias]['relation']) ? ' LEFT ' : ' INNER ';
         $sql .= 'JOIN ' . $parentClass->getQuotedTableName($this->_platform) . ' ' . $tableAlias . ' ON ';
         $first = true;
         foreach ($class->identifier as $idField) {
             if ($first) {
                 $first = false;
             } else {
                 $sql .= ' AND ';
             }
             $columnName = $class->getQuotedColumnName($idField, $this->_platform);
             $sql .= $baseTableAlias . '.' . $columnName . ' = ' . $tableAlias . '.' . $columnName;
         }
     }
     // LEFT JOIN subclass tables, if partial objects disallowed.
     if (!$this->_query->getHint(Query::HINT_FORCE_PARTIAL_LOAD)) {
         foreach ($class->subClasses as $subClassName) {
             $subClass = $this->_em->getClassMetadata($subClassName);
             $tableAlias = $this->getSQLTableAlias($subClass->table['name'], $dqlAlias);
             $sql .= ' LEFT JOIN ' . $subClass->getQuotedTableName($this->_platform) . ' ' . $tableAlias . ' ON ';
             $first = true;
             foreach ($class->identifier as $idField) {
                 if ($first) {
                     $first = false;
                 } else {
                     $sql .= ' AND ';
                 }
                 $columnName = $class->getQuotedColumnName($idField, $this->_platform);
                 $sql .= $baseTableAlias . '.' . $columnName . ' = ' . $tableAlias . '.' . $columnName;
             }
         }
     }
     return $sql;
 }