/** * @param Record $other * * @return string */ protected function failureDescription($other) { $otherOid = $other && $other instanceof Record ? $other->getOid() : 'NULL'; $relation = $this->record->getTableRelation($this->relationName); $otherTableName = $relation->isOwningSide($this->relationName) ? $relation->getOwningTable() : $relation->getReferencedTable(); $msg = $this->toString() . " to {$otherTableName}[{$otherOid}]"; if ($otherOid === $this->record->getOid()) { $msg .= ", both have the same oid"; } return $msg; }
/** * @param Record $record * @return bool */ public function validate($record) { if (!$record instanceof Record) { throw new \InvalidArgumentException("Argument #1 should be an instance of \\Dive\\Record!"); } $record->getErrorStack()->clear(); $disabledChecks = $this->getDisabledChecks(); foreach ($this->validators as $validator) { $validator->setDisabledChecks($disabledChecks); if (!$validator->validate($record)) { return false; } } return true; }
/** * @param array $recordData */ private function thenItShouldHaveCreatedARecordWithData(array $recordData) { $this->assertNotNull($this->resultRecord); $this->assertFalse($this->resultRecord->exists()); foreach ($recordData as $fieldName => $fieldValue) { $this->assertEquals($fieldValue, $this->resultRecord->get($fieldName)); } }
/** * @param array $errorFields */ private function thenItShouldHaveMarkedUniqueErrorForFields(array $errorFields) { $expectedErrors = array(); foreach ($errorFields as $errorField) { $expectedErrors[$errorField] = array('unique'); } $this->assertEquals($expectedErrors, $this->record->getErrorStack()->toArray()); }
/** * @param Record $record * @return RecordInvalidException */ public static function createByRecord(Record $record) { $errorStack = $record->getErrorStack(); $message = "Record {$record} is invalid!\n"; foreach ($errorStack as $fieldName => $errorCodes) { $value = $record->get($fieldName); $type = gettype($value); $valueAsString = "({$type})"; if (is_string($value) || is_numeric($value)) { $valueAsString .= $value; } else { if (is_bool($value)) { $valueAsString .= $value ? 'TRUE' : 'FALSE'; } } $message .= " {$fieldName}: {$valueAsString} [codes: " . implode(', ', $errorCodes) . "]\n"; } return new self($message); }
/** * Sets owning record reference to the referenced record given by it's id * * @param Record $record * @param string $newId */ public function setOwningReferenceByForeignKey(Record $record, $newId) { if (!$newId) { return; } $id = $record->getInternalId(); $this->assignReference($newId, $id); }
/** * @param string $fieldName * @param string $value */ private function whenISetRecordField_to($fieldName, $value) { $this->record->set($fieldName, $value); }
/** * @return mixed */ private function isRecordValid() { return $this->record->getRecordManager()->getRecordValidationContainer()->validate($this->record); }
/** * @param Record $owningRecord * @param Relation $relation * @param string $refObjectId */ private function assertReferencedRelatedReferences(Record $owningRecord, Relation $relation, $refObjectId) { $oldIdentifier = Record::NEW_RECORD_ID_MARK . $owningRecord->getOid(); $newIdentifier = $owningRecord->getInternalId(); $rm = $owningRecord->getRecordManager(); /** @var ReferenceMap $referenceMap */ $referenceMap = self::readAttribute($relation, 'map'); $referenceMapping = $referenceMap->getMapping(); $refTable = $relation->getJoinTable($rm, $relation->getReferencedAlias()); $refTableRepository = $refTable->getRepository(); $referencedRecord = $refTableRepository->getByOid($refObjectId); $refId = $referencedRecord->getInternalId(); // assert that owning record id is mapped for referenced record $this->assertArrayHasKey($refId, $referenceMapping); if ($relation->isOneToMany()) { $this->assertNotContains($oldIdentifier, $referenceMapping[$refId]); $this->assertContains($newIdentifier, $referenceMapping[$refId]); } else { $this->assertEquals($newIdentifier, $referenceMapping[$refId]); } // assert record collection if ($relation->isOneToMany()) { $recordCollection = $referenceMap->getRelatedCollection($referencedRecord->getOid()); $this->assertNotNull($recordCollection); $this->assertTrue($recordCollection->has($owningRecord), "Expected '{$owningRecord}' is referenced in relation '" . $relation->getReferencedAlias() . "'"); } }
/** * @param Record $record * @param array $visited * @return array */ private function getLoadedReferences(Record $record, array $visited = array()) { $oid = $record->getOid(); if (in_array($oid, $visited)) { return false; } $visited[] = $oid; $actualReferences = array(); $table = $record->getTable(); $relations = $table->getRelations(); foreach ($relations as $relationName => $relation) { if ($relation->hasReferenceLoadedFor($record, $relationName)) { $related = $relation->getReferenceFor($record, $relationName); if ($related instanceof RecordCollection) { foreach ($related as $relatedRecord) { $loadedReferences = $this->getLoadedReferences($relatedRecord, $visited); if ($loadedReferences !== false) { $actualReferences[$relationName] = $loadedReferences; } } } else { if ($related instanceof Record) { $loadedReferences = $this->getLoadedReferences($related, $visited); if ($loadedReferences !== false) { $actualReferences[$relationName] = $loadedReferences; } } } } } return $actualReferences; }
/** * @param Record $other * * @return string */ protected function failureDescription($other) { $otherId = $other->getInternalId(); $relation = $this->record->getTableRelation($this->relationName); $otherTableName = $relation->isOwningSide($this->relationName) ? $relation->getOwningTable() : $relation->getReferencedTable(); return $this->toString() . " to {$otherTableName}[{$otherId}]"; }
/** * @return Relation */ private function getRelation() { $relationName = CamelCase::toCamelCase($this->relatedRecord->getTable()->getTableName()); return $this->storedRecord->getTableRelation($relationName); }
/** * @param Record $record */ private function markRecordForRestrictOnCommitWhenNotDeleted(Record $record) { $oid = $record->getOid(); // record will have to be deleted before record with restricted relation $this->recordIdentityMap[$oid] = $record; $this->restrictNotDeletedOnCommit[$oid] = $record; }
/** * @param Record $record */ protected function unsetReferenceForOwningRecordOnUnloadedReference(Record $record) { $owningId = $record->getInternalId(); foreach ($this->references as $refId => $owningIds) { if ($this->removeOwningReference($refId, $owningId)) { break; } } $this->unsetFieldMapping($record->getOid()); }
/** * @param string $relationName * @param Record|null $reference * @throws RelationException */ private function throwReferenceMustBeRecordCollectionException($relationName, $reference) { if (!$reference instanceof RecordCollection) { throw new RelationException("Reference for relation '{$relationName}' must be an instance of \\Dive\\Collection\\RecordCollection!"); } $joinTableName = $this->getJoinTableName($relationName); if ($reference->getTable()->getTableName() !== $joinTableName) { throw new RelationException("RecordCollection for relation '{$relationName}' must be a collection for table '{$joinTableName}'!"); } }
/** * @param Record $record * @param string $relationName * @param string $message */ private function assertRecordIsNotReferencedByRelation(Record $record, $relationName, $message = '') { $internalId = $record->getInternalId(); $relation = $record->getTableRelation($relationName); $isReferencedSide = $relation->isReferencedSide($relationName); /** @var ReferenceMap $referenceMap */ $referenceMap = self::readAttribute($relation, 'map'); $isOneToMany = $relation->isOneToMany(); /** @var RecordCollection[] $relatedCollections */ $relatedCollections = $isOneToMany ? self::readAttribute($referenceMap, 'relatedCollections') : null; $references = $referenceMap->getMapping(); $referencedMessage = $message . " expected not be referenced (relation '{$relationName}')"; $relatedCollectionMessage = $message . " expected not to be in a related collection (relation '{$relationName}')"; $oid = $record->getOid(); if ($isReferencedSide) { foreach ($references as $owningIds) { if ($isOneToMany) { $this->assertNotContains($internalId, $owningIds, $referencedMessage); } else { $this->assertNotEquals($internalId, $owningIds, $referencedMessage); } } if ($isOneToMany) { foreach ($relatedCollections as $relatedCollection) { $this->assertFalse($relatedCollection->has($record), $relatedCollectionMessage); } } $this->assertFalse($referenceMap->hasFieldMapping($oid)); } else { $this->assertArrayNotHasKey($internalId, $references, $referencedMessage); if ($isOneToMany) { $this->assertArrayNotHasKey($oid, $relatedCollections, $relatedCollectionMessage); } } }
/** * @depends testHasMappedValue * @param \Dive\Record $record */ public function testGetMappedValue(Record $record) { $this->assertEquals('bar', $record->getMappedValue('id')); }
/** * @param Record $record * @param array $uniqueIndexesToCheck * @return \Dive\Query\Query * @throws \Dive\Exception */ private function getUniqueIndexesQuery(Record $record, array $uniqueIndexesToCheck) { $table = $record->getTable(); $conn = $table->getConnection(); $conditions = array(); $queryParams = array(); $recordExists = $record->exists(); $identifier = array(); if ($recordExists) { $condition = ''; foreach ($record->getIdentifierFieldIndexed() as $idField => $idValue) { $condition .= $conn->quoteIdentifier($idField) . ' != ? AND '; $identifier[] = $idValue; } // strip last AND from string $condition = substr($condition, 0, -4); $conditions['primary'] = $condition; } foreach ($uniqueIndexesToCheck as $uniqueName => $uniqueIndexToCheck) { $isNullConstrained = $table->isUniqueIndexNullConstrained($uniqueName); $conditionParams = array(); $condition = ''; $fieldNames = $uniqueIndexToCheck['fields']; foreach ($fieldNames as $fieldName) { $fieldNameQuoted = $conn->quoteIdentifier($fieldName); $fieldValue = $record->get($fieldName); if ($fieldValue !== null) { $condition .= $fieldNameQuoted . ' = ? AND '; $conditionParams[] = $fieldValue; } else { if ($isNullConstrained) { $condition .= $fieldNameQuoted . ' IS NULL AND '; } else { throw new Exception("Cannot process unique index for creating query to check whether the record is unique, or not!"); } } } // strip last AND from string $condition = substr($condition, 0, -4); $conditions[$uniqueName] = $condition; $queryParams = array_merge($queryParams, $conditionParams); } $whereCondition = ($recordExists ? array_shift($conditions) . ' AND (' : '') . implode(' OR ', $conditions) . ($recordExists ? ')' : ''); $query = $table->createQuery(); $query->where($whereCondition); foreach ($conditions as $uniqueName => $condition) { $query->addSelect("({$condition}) AS " . $conn->quoteIdentifier($uniqueName)); } $whereParams = $recordExists ? array_merge($identifier, $queryParams) : $queryParams; $query->setParams(Query::PART_SELECT, $queryParams); $query->setParams(Query::PART_WHERE, $whereParams); $query->limit(1); return $query; }
/** * Updates identity map on record insert/update or removes identity map entry on record delete * Refreshes record identity in repository * * @param Record $record * @param string $oldInternalIdentifier */ public function refreshIdentity(Record $record, $oldInternalIdentifier = null) { $oid = $record->getOid(); if (!$this->has($oid)) { return; } $id = $record->getIdentifierAsString(); if ($record->exists()) { if ($oldInternalIdentifier) { unset($this->identityMap[$oldInternalIdentifier]); } $this->identityMap[$id] = $record->getOid(); } else { unset($this->identityMap[$id]); } }
/** * @param Record $record * @param string $fieldName * @param string $errorCode */ private function addErrorToStack(Record $record, $fieldName, $errorCode) { $record->getErrorStack()->add($fieldName, $errorCode); }
/** * Sets owning record reference to the referenced record given by it's id * * @param Record $record * @param string $newId */ public function setOwningReferenceByForeignKey(Record $record, $newId) { if (!$newId) { return; } $id = $record->getInternalId(); if ($this->relation->isOneToMany()) { $refRepository = $this->getRefRepository($record, $this->relation->getOwningAlias()); $newRefRecord = $refRepository->getByInternalId($newId); if ($newRefRecord) { $relatedCollection = $this->getRelatedCollection($newRefRecord->getOid()); // TODO exception, or if not set create one?? if ($relatedCollection) { $relatedCollection->add($record); } } } $this->assignReference($newId, $id); }
/** * @param Record $other * @return string */ protected function failureDescription($other) { $tableName = $other->getTable()->getTableName(); return 'Record ' . $tableName . ' ' . $this->toString(); }
/** * @param Record $record * @param array $fields */ private function setFieldTimestamps(Record $record, array $fields) { $timestamp = $this->getTimestamp(); foreach ($fields as $field) { $record->set($field, $timestamp); } }