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(); }
/** * @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(); }
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); } }
/** * {@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; }
/** * 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; }
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); }
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); }
/** * 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; }
/** * 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); } } }
/** * 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); }
/** * 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); }
/** * 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; }