From a8a8eca7097063b63fc6be74ddb11b0a17855c1b Mon Sep 17 00:00:00 2001 From: haogatyp Date: Thu, 24 Feb 2022 15:26:21 +0100 Subject: [PATCH 1/5] #156 Basic ORM mapping for the Person model. --- library/Opus/Db2/PersonRepository.php | 43 +++ library/Opus/Model2/Person.php | 410 ++++++++++++++++++++++++++ tests/Opus/PersonTest.php | 214 +++++++------- 3 files changed, 560 insertions(+), 107 deletions(-) create mode 100644 library/Opus/Db2/PersonRepository.php create mode 100644 library/Opus/Model2/Person.php diff --git a/library/Opus/Db2/PersonRepository.php b/library/Opus/Db2/PersonRepository.php new file mode 100644 index 00000000..d1f20aeb --- /dev/null +++ b/library/Opus/Db2/PersonRepository.php @@ -0,0 +1,43 @@ +id; + } + + /** + * @param int $id + */ + public function setId($id) + { + $this->id = $id; + } + + /** + * @return string + */ + public function getTitle() + { + return $this->title; + } + + /** + * @param string $title + */ + public function setTitle($title) + { + $this->title = $title; + } + + /** + * @return string + */ + public function getFirstName() + { + return $this->firstName; + } + + /** + * @param string $firstName + */ + public function setFirstName($firstName) + { + $this->firstName = $firstName; + } + + /** + * @return string + */ + public function getLastName() + { + return $this->lastName; + } + + /** + * @param string $lastName + */ + public function setLastName($lastName) + { + $this->lastName = $lastName; + } + + /** + * @return Date + */ + public function getDateOfBirth() + { + return $this->dateOfBirth; + } + + /** + * @param Date $dateOfBirth + */ + public function setDateOfBirth($dateOfBirth) + { + $this->dateOfBirth = $dateOfBirth; + } + + /** + * @return string + */ + public function getPlaceOfBirth() + { + return $this->placeOfBirth; + } + + /** + * @param string $placeOfBirth + */ + public function setPlaceOfBirth($placeOfBirth) + { + $this->placeOfBirth = $placeOfBirth; + } + + /** + * @return string + */ + public function getIdentifierOrcid() + { + return $this->identifierOrcid; + } + + /** + * @param string $identifierOrcid + */ + public function setIdentifierOrcid($identifierOrcid) + { + $this->identifierOrcid = $identifierOrcid; + } + + /** + * @return string + */ + public function getIdentifierGnd() + { + return $this->identifierGnd; + } + + /** + * @param string $identifierGnd + */ + public function setIdentifierGnd($identifierGnd) + { + $this->identifierGnd = $identifierGnd; + } + + /** + * @return string + */ + public function getIdentifierMisc() + { + return $this->identifierMisc; + } + + /** + * @param string $identifierMisc + */ + public function setIdentifierMisc($identifierMisc) + { + $this->identifierMisc = $identifierMisc; + } + + /** + * @return string + */ + public function getEmail() + { + return $this->email; + } + + /** + * @param string $email + */ + public function setEmail($email) + { + $this->email = $email; + } + + /** + * @return string + */ + public function getOpusId() + { + return $this->opusId; + } + + /** + * @param string $opusId + */ + public function setOpusId($opusId) + { + $this->opusId = $opusId; + } + + /** + * Returns the relevant properties of the class + * + * @return array + */ + protected static function describe() + { + return [ + 'Title', + 'FirstName', + 'LastName', + 'DateOfBirth', + 'PlaceOfBirth', + 'IdentifierOrcid', + 'IdentifierGnd', + 'IdentifierMisc', + 'Email', + 'OpusId' + ]; + } + + /** + * Plugins to load + * + * @var array + */ + public function getDefaultPlugins() + { + return [ + Model\Plugin\InvalidateDocumentCache::class, + ]; + } + + /** + * Get uniform representation of names. + * + * @return string + */ + public function getName() + { + $firstName = $this->getFirstName(); + + if ($firstName !== null) { + return $this->getLastName() . ', ' . $firstName; + } else { + return $this->getLastName(); + } + } + + /** + * Returns name. + */ + public function getDisplayName() + { + return $this->getName(); + } +} diff --git a/tests/Opus/PersonTest.php b/tests/Opus/PersonTest.php index 87a0f43a..3a68bb3c 100644 --- a/tests/Opus/PersonTest.php +++ b/tests/Opus/PersonTest.php @@ -44,7 +44,7 @@ use Opus\Document; use Opus\Model\ModelException; use Opus\Model\Xml\Cache; -use Opus\Person; +use Opus\Model2\Person; use Opus\Title; use OpusTest\TestAsset\TestCase; @@ -91,13 +91,13 @@ public function setUp() // create documents for ($i = 0; $i < 10; $i++) { - $doc = new Document(); + $doc = Document::new(); $doc->store(); $this->documents[] = $doc; } for ($i = 0; $i < 10; $i++) { - $p = new Person(); + $p = Person::new(); $p->setFirstName("Dummy-$i") ->setLastName("Empty-$i") ->store(); @@ -106,7 +106,7 @@ public function setUp() // add a person as author to every document // and add the person to the list of authors foreach ($this->documents as $document) { - $p = new Person(); + $p = Person::new(); $p->setFirstName('Rainer') ->setLastName('Zufall') ->setAcademicTitle('Prof. Dr.') @@ -161,7 +161,7 @@ public function testGetAllPersonIdsByRole() public function testDeletePerson() { $docId = $this->documents[0]->getId(); - $d = new Document($docId); + $d = Document::get($docId); $persons = $d->getPerson(); $this->assertTrue(1 === count($persons)); @@ -172,13 +172,13 @@ public function testDeletePerson() $d->setPerson([]); $d->store(); - $d = new Document($docId); + $d = Document::get($docId); $this->assertTrue(0 === count($d->getPerson())); } public function testOnlyLastNameMandatory() { - $person = new Person(); + $person = Person::new(); $fields = $person->describe(); @@ -195,7 +195,7 @@ public function testOnlyLastNameMandatory() public function testGetNameForLastAndFirstName() { - $person = new Person(); + $person = Person::new(); $person->setFirstName('Jane'); $person->setLastName('Doe'); @@ -205,7 +205,7 @@ public function testGetNameForLastAndFirstName() public function testGetNameForLastNameOnly() { - $person = new Person(); + $person = Person::new(); $person->setLastName('Doe'); @@ -214,7 +214,7 @@ public function testGetNameForLastNameOnly() public function testSetGetIdentifiers() { - $person = new Person(); + $person = Person::new(); $person->setLastName('Tester'); $person->setIdentifierOrcid('http://orcid.org/0000-0002-1694-233X'); $person->setIdentifierGnd('test_gnd_identifier'); @@ -222,7 +222,7 @@ public function testSetGetIdentifiers() $personId = $person->store(); - $person = new Person($personId); + $person = Person::get($personId); $this->assertEquals('http://orcid.org/0000-0002-1694-233X', $person->getIdentifierOrcid()); $this->assertEquals('test_gnd_identifier', $person->getIdentifierGnd()); @@ -234,11 +234,11 @@ public function testSetGetIdentifiers() */ public function testInvalidateDocumentCache() { - $person = new Person(); + $person = Person::new(); $person->setFirstName('Jane'); $person->setLastName('Doe'); $person->store(); - $doc = new Document(); + $doc = Document::new(); $doc->setType("article") ->setServerState('published') ->setPersonAuthor($person); @@ -318,8 +318,8 @@ public function testGetAllPersonsInRole() $docId = $this->documents[0]->getId(); - $doc = new Document($docId); - $other = new Person(); + $doc = Document::get($docId); + $other = Person::new(); $other->setLastName('Musterfrau'); $other->setFirstName('Erika'); $doc->addPersonOther($other); @@ -353,17 +353,17 @@ public function testGetAllPersonsInUnknownRole() public function testGetAllPersonsSorting() { - $doc = new Document($this->documents[0]->getId()); + $doc = Document::get($this->documents[0]->getId()); - $person = new Person(); + $person = Person::new(); $person->setLastName('Blau'); $doc->addPersonReferee($person); - $person = new Person(); + $person = Person::new(); $person->setLastName('Rot'); $doc->addPersonReferee($person); - $person = new Person(); + $person = Person::new(); $person->setLastName('Grün'); $doc->addPersonReferee($person); @@ -384,17 +384,17 @@ public function testGetAllPersonsSorting() */ public function testGetAllPersonsSortingWithLeadingSpaces() { - $doc = new Document($this->documents[0]->getId()); + $doc = Document::get($this->documents[0]->getId()); - $person = new Person(); + $person = Person::new(); $person->setLastName('A'); $doc->addPersonReferee($person); - $person = new Person(); + $person = Person::new(); $person->setLastName('B'); $doc->addPersonReferee($person); - $person = new Person(); + $person = Person::new(); $person->setLastName('C'); $doc->addPersonReferee($person); @@ -420,17 +420,17 @@ public function testGetAllPersonsSortingWithLeadingSpaces() */ public function testGetAllPersonsHandlingOfIdentifier() { - $doc = new Document($this->documents[0]->getId()); + $doc = Document::get($this->documents[0]->getId()); - $person1 = new Person(); + $person1 = Person::new(); $person1->setLastName('Person'); $doc->addPersonReferee($person1); - $person2 = new Person(); + $person2 = Person::new(); $person2->setLastName('Person'); $doc->addPersonReferee($person2); - $person3 = new Person(); + $person3 = Person::new(); $person3->setLastName('Person'); $doc->addPersonReferee($person3); @@ -492,8 +492,8 @@ public function testGetPersonRoles() $this->assertArrayHasKey('documents', $role); $this->assertEquals(10, $role['documents']); - $doc = new Document($this->documents[0]->getId()); - $person = new Person(); + $doc = Document::get($this->documents[0]->getId()); + $person = Person::new(); $person->setLastName('Zufall'); $person->setFirstName('Rainer'); $doc->addPersonOther($person); @@ -512,8 +512,8 @@ public function testGetPersonDocuments() $this->assertInternalType('array', $documents); $this->assertCount(10, $documents); - $doc = new Document($this->documents[0]->getId()); - $person = new Person(); + $doc = Document::get($this->documents[0]->getId()); + $person = Person::new(); $person->setLastName('Zufall'); $doc->addPersonOther($person); $doc->store(); @@ -560,7 +560,7 @@ public function testGetPersonDocumentsDistinct() $this->assertCount(10, $documents); - $person2 = new Person(); + $person2 = Person::new(); $person2->setLastName('Zufall'); $this->documents[0]->addPersonAuthor($person2); $this->documents[0]->store(); @@ -573,14 +573,14 @@ public function testGetPersonDocumentsDistinct() public function testGetPersonDocumentsSortedById() { - $doc1 = new Document(); - $person = new Person(); + $doc1 = Document::new(); + $person = Person::new(); $person->setLastName('Testy'); $doc1->addPersonAuthor($person); $docId1 = $doc1->store(); - $doc2 = new Document(); - $person = new Person(); + $doc2 = Document::new(); + $person = Person::new(); $person->setLastName('Testy'); $doc2->addPersonAuthor($person); $docId2 = $doc2->store(); @@ -608,16 +608,16 @@ public function testGetPersonDocumentsSortedById() public function testGetPersonDocumentsSortedByType() { - $doc1 = new Document(); + $doc1 = Document::new(); $doc1->setType('article'); - $person = new Person(); + $person = Person::new(); $person->setLastName('Testy'); $doc1->addPersonAuthor($person); $docId1 = $doc1->store(); - $doc2 = new Document(); + $doc2 = Document::new(); $doc2->setType('dissertation'); - $person = new Person(); + $person = Person::new(); $person->setLastName('Testy'); $doc2->addPersonAuthor($person); $docId2 = $doc2->store(); @@ -645,20 +645,20 @@ public function testGetPersonDocumentsSortedByType() public function testGetPersonDocumentsSortedByPublicationDate() { - $doc1 = new Document(); + $doc1 = Document::new(); $date = new Date(new DateTime()); $doc1->setServerDatePublished($date); - $person = new Person(); + $person = Person::new(); $person->setLastName('Testy'); $doc1->addPersonAuthor($person); $docId1 = $doc1->store(); sleep(2); - $doc2 = new Document(); + $doc2 = Document::new(); $date = new Date(new DateTime()); $doc2->setServerDatePublished($date); - $person = new Person(); + $person = Person::new(); $person->setLastName('Testy'); $doc2->addPersonAuthor($person); $docId2 = $doc2->store(); @@ -686,20 +686,20 @@ public function testGetPersonDocumentsSortedByPublicationDate() public function testGetPersonDocumentsSortedByTitle() { - $doc1 = new Document(); + $doc1 = Document::new(); $title = $doc1->addTitleMain(); $title->setValue('A Title'); $title->setLanguage('eng'); - $person = new Person(); + $person = Person::new(); $person->setLastName('Testy'); $doc1->addPersonAuthor($person); $docId1 = $doc1->store(); - $doc2 = new Document(); + $doc2 = Document::new(); $title = $doc2->addTitleMain(); $title->setValue('B Title'); $title->setLanguage('eng'); - $person = new Person(); + $person = Person::new(); $person->setLastName('Testy'); $doc2->addPersonAuthor($person); $docId2 = $doc2->store(); @@ -728,19 +728,19 @@ public function testGetPersonDocumentsSortedByTitle() public function testGetPersonDocumentsSortedByAuthor() { $this->markTestSkipped('TODO - sorting by author not properly working yet OPUSVIER-3810'); - $doc1 = new Document(); - $person = new Person(); + $doc1 = Document::new(); + $person = Person::new(); $person->setLastName('A Person'); $personLink = $doc1->addPersonAuthor($person); $personLink->setSortOrder(0); - $person = new Person(); + $person = Person::new(); $person->setLastName('Testy'); $personLink = $doc1->addPersonAuthor($person); $personLink->setSortOrder(1); $docId1 = $doc1->store(); - $doc2 = new Document(); - $person = new Person(); + $doc2 = Document::new(); + $person = Person::new(); $person->setLastName('Testy'); $doc2->addPersonAuthor($person); $docId2 = $doc2->store(); @@ -768,20 +768,20 @@ public function testGetPersonDocumentsSortedByAuthor() public function testGetPersonDocumentsByStateSorted() { - $doc1 = new Document(); + $doc1 = Document::new(); $title = $doc1->addTitleMain(); $title->setValue('A Title'); $title->setLanguage('eng'); - $person = new Person(); + $person = Person::new(); $person->setLastName('Testy'); $doc1->addPersonAuthor($person); $docId1 = $doc1->store(); - $doc2 = new Document(); + $doc2 = Document::new(); $title = $doc2->addTitleMain(); $title->setValue('B Title'); $title->setLanguage('eng'); - $person = new Person(); + $person = Person::new(); $person->setLastName('Testy'); $doc2->addPersonAuthor($person); $docId2 = $doc2->store(); @@ -821,7 +821,7 @@ public function testGetPersonDocumentsByRole() $doc = $this->documents[0]; - $editor = new Person(); + $editor = Person::new(); $editor->setLastName('Zufall'); $editor->setFirstName('Rainer'); $doc->addPersonEditor($editor); @@ -848,7 +848,7 @@ public function testGetPersonDocumentsByStateAndRole() $doc = $this->documents[0]; $doc->setServerState('published'); - $editor = new Person(); + $editor = Person::new(); $editor->setLastName('Zufall'); $editor->setFirstName('Rainer'); $doc->addPersonEditor($editor); @@ -876,8 +876,8 @@ public function testGetAllPersonsWithFilter() public function testGetAllPersonsWithFilterFirstName() { - $doc = new Document($this->documents[0]->getId()); - $person = new Person(); + $doc = Document::get($this->documents[0]->getId()); + $person = Person::new(); $person->setLastName('Mustermann'); $person->setFirstName('Bafala'); $doc->addPersonOther($person); @@ -928,12 +928,12 @@ public function testGetAllPersonsCount() public function testOpusId() { - $person = new Person(); + $person = Person::new(); $person->setLastName('Testy'); $person->setOpusId('12345'); $personId = $person->store(); - $person = new Person($personId); + $person = Person::get($personId); $this->assertEquals('12345', $person->getOpusId()); $this->assertEquals('Testy', $person->getLastName()); @@ -964,7 +964,7 @@ public function testGetPersonValues() } } - $person = new Person($personIds[0]); + $person = Person::get($personIds[0]); $person->setPlaceOfBirth('Hamburg'); $person->store(); @@ -1051,7 +1051,7 @@ public function testCreatePersonTestFunction() $this->assertInternalType('array', $personIds); $this->assertCount(1, $personIds); - $person = new Person($personIds[0]); + $person = Person::get($personIds[0]); $this->assertEquals(' Spacey ', $person->getLastName()); } @@ -1067,7 +1067,7 @@ public function testUpdateAll() Person::updateAll($personCrit, $changes); foreach ($this->authors as $author) { - $person = new Person($author->getId()); + $person = Person::get($author->getId()); $this->assertEquals('bulktest@example.org', $person->getEmail()); } @@ -1086,7 +1086,7 @@ public function testUpdateAllForSpecifiedDocuments() Person::updateAll($personCrit, $changes, $documents); foreach ($this->authors as $author) { - $person = new Person($author->getId()); + $person = Person::get($author->getId()); $personDocs = $person->getDocumentsByRole('author'); @@ -1110,14 +1110,14 @@ public function testUpdateAllForDocumentWithoutMatchingPerson() 'Email' => 'bulktest@example.org', ]; - $doc = new Document(); + $doc = Document::new(); $title = new Title(); $title->setLanguage('deu'); $title->setValue('Document with no author'); $doc->addTitleMain($title); $docId = $doc->store(); - $doc = new Document($docId); + $doc = Document::get($docId); $documents = [3, 5, $docId]; @@ -1138,7 +1138,7 @@ public function testUpdateAllForDocumentWithoutMatchingPerson() //filtered documents were not modified foreach ($this->documents as $doc) { - $document = new Document($doc->getId()); // don't use old objects - they are not updated + $document = Document::get($doc->getId()); // don't use old objects - they are not updated $dateModified = $document->getServerDateModified(); @@ -1211,11 +1211,11 @@ public function testUpdateAllWithSpaces() Person::updateAll($personCrit, $changes); for ($index = 0; $index < 4; $index++) { - $person = new Person($personIds[$index]); + $person = Person::get($personIds[$index]); $this->assertEquals('bulktest@example.org', $person->getEmail()); } - $person = new Person($personIds[4]); + $person = Person::get($personIds[4]); $this->assertNull($person->getEmail()); } @@ -1233,7 +1233,7 @@ public function testUpdateAllValuesAreTrimmed() Person::updateAll($personCrit, $changes); - $person = new Person($personIds[0]); + $person = Person::get($personIds[0]); $this->assertEquals('John', $person->getFirstName()); } @@ -1251,7 +1251,7 @@ public function testUpdateAllWithoutDocuments() Person::updateAll($personCrit, $changes, $documents); foreach ($this->authors as $author) { - $person = new Person($author->getId()); + $person = Person::get($author->getId()); $personDocs = $person->getDocumentsByRole('author'); @@ -1273,7 +1273,7 @@ public function testUpdateAllWithoutDocumentsInArray() Person::updateAll($personCrit, $changes, $documents); foreach ($this->authors as $author) { - $person = new Person($author->getId()); + $person = Person::get($author->getId()); $personDocs = $person->getDocumentsByRole('author'); @@ -1313,7 +1313,7 @@ public function testGetPersons() { $personCrit = ['last_name' => 'Zufall', 'first_name' => 'Rainer']; - $person = new Person(); + $person = Person::new(); $person->setLastName('Zufall'); $person->store(); // not Rainer @@ -1337,7 +1337,7 @@ public function testGetPersonsForDocuments() $this->assertCount(4, $personIds); foreach ($personIds as $personId) { - $person = new Person($personId); + $person = Person::get($personId); $documents = $person->getDocumentsByRole('author'); @@ -1367,7 +1367,7 @@ public function testGetPersonsForDocumentsCaseInsensitive() $this->assertCount(3, $personIds); foreach ($personIds as $personId) { - $person = new Person($personId); + $person = Person::get($personId); $this->assertEquals('Zufall', $person->getLastName()); } @@ -1382,7 +1382,7 @@ public function testUpdateAllChangeLastName() Person::updateAll($personCrit, $changes); foreach ($this->authors as $author) { - $person = new Person($author->getId()); + $person = Person::get($author->getId()); $this->assertEquals('Plannt', $person->getLastName()); $this->assertEquals('Volge', $person->getFirstName()); @@ -1449,7 +1449,7 @@ protected function createPersons($persons) $database = $table->getAdapter(); foreach ($persons as $name => $values) { - $person = new Person(); + $person = Person::new(); $person->setLastName($name); foreach ($values as $fieldName => $value) { @@ -1489,7 +1489,7 @@ public function testGetPersonsAndDocuments() $this->assertArrayHasKey('document_id', $match); $personId = $match['person_id']; $docId = $match['document_id']; - $person = new Person($personId); + $person = Person::get($personId); $assocDocs = $person->getDocumentIds(); $this->assertContains($docId, $assocDocs); } @@ -1520,7 +1520,7 @@ public function testGetPersonsAndDocumentsForSubset() $this->assertContains(6, $documentIds); $this->assertContains(10, $documentIds); - $doc = new Document($this->documents[1]->getId()); + $doc = Document::get($this->documents[1]->getId()); $this->assertEquals(2, $doc->getId()); @@ -1540,9 +1540,9 @@ public function testGetPersonsAndDocumentsMultiplePersonsOnDocument() { $personCrit = ['last_name' => 'Zufall', 'first_name' => 'Rainer']; - $doc = new Document($this->documents[0]->getId()); + $doc = Document::get($this->documents[0]->getId()); - $person = new Person(); + $person = Person::new(); $person->setLastName('Zufall'); $person->setFirstName('Rainer'); @@ -1566,7 +1566,7 @@ public function testGetPersonsAndDocumentsMultipleDocumentsOnPerson() { $personCrit = ['last_name' => 'Zufall', 'first_name' => 'Rainer']; - $doc = new Document(); + $doc = Document::new(); $doc->setType('article'); $title = new Title(); $title->setLanguage('eng'); @@ -1590,7 +1590,7 @@ public function testGetPersonsAndDocumentsMultipleDocumentsOnPerson() public function testGetDocumentIds() { - $person = new Person($this->authors[0]->getId()); + $person = Person::get($this->authors[0]->getId()); $docIds = $person->getDocumentIds(); @@ -1602,8 +1602,8 @@ public function testGetDocumentIds() public function testGetDocumentIdsUniqueValues() { - $person = new Person($this->authors[0]->getId()); - $doc = new Document($this->documents[0]->getId()); + $person = Person::get($this->authors[0]->getId()); + $doc = Document::get($this->documents[0]->getId()); $doc->addPersonAdvisor($person); $doc->store(); @@ -1618,7 +1618,7 @@ public function testGetDocumentIdsUniqueValues() public function testGetDocumentIdsForRole() { - $person = new Person($this->authors[0]->getId()); + $person = Person::get($this->authors[0]->getId()); $docIds = $person->getDocumentIds('author'); @@ -1680,7 +1680,7 @@ public function testGetDocumentsBadArgument() public function testGetDocumentsOnePersonTwoDocuments() { - $doc = new Document($this->documents[1]->getId()); + $doc = Document::get($this->documents[1]->getId()); $doc->addPersonSubmitter($this->authors[0]); $docId = $doc->store(); @@ -1701,8 +1701,8 @@ public function testGetDocumentsOnePersonTwoDocuments() public function testGetDocumentsTwoPersonsOneDocument() { - $doc = new Document($this->documents[0]->getId()); - $person = new Person(); + $doc = Document::get($this->documents[0]->getId()); + $person = Person::new(); $person->setLastName('Tester'); $plink = $doc->addPersonSubmitter($person); $doc->store(); @@ -1776,12 +1776,12 @@ public function testPersonRolesWithSpacesAroundParameterValues() public function testStoreValuesAreTrimmed() { - $person = new Person(); + $person = Person::new(); $person->setLastName(' Zufall '); $person->setFirstName(' Rainer '); $personId = $person->store(); - $person = new Person($personId); + $person = Person::get($personId); $this->assertEquals('Zufall', $person->getLastName()); $this->assertEquals('Rainer', $person->getFirstName()); @@ -1794,11 +1794,11 @@ public function testDeleteAssignedPerson() { $this->markTestIncomplete('TODO not sure what/how to test'); - $doc = new Document(); + $doc = Document::new(); $doc->setServerState('published'); $doc->setType('article'); - $person = new Person(); + $person = Person::new(); $person->setLastName('Tester'); $doc->addPersonAuthor($person); @@ -1807,29 +1807,29 @@ public function testDeleteAssignedPerson() $person->delete(); - // $doc = new Document($docId); + // $doc = Document::get($docId); $doc->delete(); $this->setExpectedException(ModelException::class, 'No Opus\Db\Documents with id'); - new Document($docId); + Document::get($docId); } public function testSortOrderDefault() { - $doc = new Document(); + $doc = Document::new(); - $person = new Person(); + $person = Person::new(); $person->setLastName('Person1'); $doc->addPersonAuthor($person); - $person = new Person(); + $person = Person::new(); $person->setLastName('Person2'); $doc->addPersonAuthor($person); $docId = $doc->store(); - $doc = new Document($docId); + $doc = Document::get($docId); $authors = $doc->getPersonAuthor(); @@ -1844,8 +1844,8 @@ public function testSortOrderDefault() public function testMatchesPersonObjects() { - $person1 = new Person(); - $person2 = new Person(); + $person1 = Person::new(); + $person2 = Person::new(); // Test LastName matching @@ -1922,7 +1922,7 @@ public function testMatchesPersonObjects() public function testToArray() { - $person = new Person(); + $person = Person::new(); $person->setAcademicTitle('Prof.'); $person->setFirstName('Thomas'); $person->setLastName('Mueller'); @@ -1986,7 +1986,7 @@ public function testFromArray() public function testUpdateFromArray() { - $person = new Person(); + $person = Person::new(); $person->updateFromArray([ 'AcademicTitle' => 'Prof.', @@ -2015,7 +2015,7 @@ public function testUpdateFromArray() public function testGetModelType() { - $person = new Person(); + $person = Person::new(); $this->assertEquals('person', $person->getModelType()); } } From 9746e011d2c608f0f743d033a7d651b385d88199 Mon Sep 17 00:00:00 2001 From: haogatyp Date: Thu, 10 Mar 2022 15:14:30 +0100 Subject: [PATCH 2/5] #155 Move administrative functions from Opus\Person to a Doctrine Person Repository --- library/Opus/Db2/PersonRepository.php | 550 ++++++++++++++++++++++++++ library/Opus/Model2/AbstractModel.php | 36 ++ library/Opus/Model2/Person.php | 323 +++++++++++++-- tests/Opus/PersonTest.php | 7 +- 4 files changed, 886 insertions(+), 30 deletions(-) diff --git a/library/Opus/Db2/PersonRepository.php b/library/Opus/Db2/PersonRepository.php index d1f20aeb..66695e6d 100644 --- a/library/Opus/Db2/PersonRepository.php +++ b/library/Opus/Db2/PersonRepository.php @@ -31,7 +31,29 @@ namespace Opus\Db2; +use Doctrine\DBAL\Connection; +use Doctrine\DBAL\Query\QueryBuilder; use Doctrine\ORM\EntityRepository; +use Opus\Date; +use Opus\Document; +use Opus\Model\ModelException; +use Opus\Model2\Person; + +use function array_fill_keys; +use function array_key_exists; +use function array_map; +use function array_merge; +use function array_push; +use function array_search; +use function array_unique; +use function count; +use function implode; +use function in_array; +use function is_array; +use function lcfirst; +use function property_exists; +use function strlen; +use function trim; /** * Database specific class for Person functions. @@ -40,4 +62,532 @@ */ class PersonRepository extends EntityRepository { + /** + * Constructs select statement for getting all persons matching criteria. + * + * @param string|null $role + * @param string|null $filter + * @return QueryBuilder + */ + public function getAllPersonsSelect($role = null, $filter = null) + { + $conn = $this->getEntityManager()->getConnection(); + + $columns = ['last_name', 'first_name', 'identifier_orcid', 'identifier_gnd', 'identifier_misc']; + + $trimmedColumns = implode( + ',', + array_map(function ($value) { + return "trim($value) as $value"; + }, $columns) + ); + + $groupColumns = implode( + ',', + array_map(function ($value) { + return "trim($value)"; + }, $columns) + ); + + $identityColumns = implode(',', $columns); + + $subSelect = $conn->createQueryBuilder() + ->select($trimmedColumns) + ->from('persons', 'pe'); + + if ($role !== null) { + $subSelect->join('pe', 'link_persons_documents', 'link', 'pe.id = link.person_id') + ->where('link.role = :role') + ->setParameter('role', $role); + } + + if ($filter !== null) { + $subSelect->andWhere('last_name LIKE :lastName OR first_name LIKE :firstName') + ->setParameter('lastName', '%' . $filter . '%') + ->setParameter('firstName', '%' . $filter . '%'); + } + + // result still contains name duplicates because of leading spaces -> group trimmed result + $select = $conn->createQueryBuilder() + ->select($identityColumns) + ->from('(' . $subSelect->getSQL() . ') as p') + ->groupBy($groupColumns); + + if ($subSelect->getParameters()) { + $select->setParameters($subSelect->getParameters()); + } + + return $select; + } + + /** + * Returns all persons in the database without duplicates. + * + * Every real person might be represented by several objects, one for each document. + * + * @param string|null $role + * @param int $start + * @param int $limit + * @param string|null $filter + * @return array + */ + public function getAllPersons($role = null, $start = 0, $limit = 0, $filter = null) + { + $select = $this->getAllPersonsSelect($role, $filter); + + if ($start !== 0 || $limit !== 0) { + $select->setFirstResult($start) + ->setMaxResults($limit); + } + + $select->orderBy('trim(last_name)') + ->addOrderBy('trim(first_name)'); + + return $select->execute()->fetchAllAssociative(); + } + + /** + * Returns total count of persons for role and filter string. + * + * @param string|null $role + * @param string|null $filter + * @return mixed + */ + public function getAllPersonsCount($role = null, $filter = null) + { + $subSelect = $this->getAllPersonsSelect($role, $filter); + + $conn = $this->getEntityManager()->getConnection(); + $select = $conn->createQueryBuilder() + ->select('count(*) as num') + ->from('(' . $subSelect->getSQL() . ') as pc'); + + if ($subSelect->getParameters()) { + $select->setParameters($subSelect->getParameters()); + } + + return $select->execute()->fetchOne(); + } + + /** + * Fetches all documents associated to the person by a certain role. + * + * @param Person $person The ID of the desired person. + * @param string $role The role that the person has for the documents. + * @return array An array of Opus\Document + */ + public function getDocumentsByRole($person, $role) + { + if ($person->getId() === 0) { + return []; + } + + $conn = $this->getEntityManager()->getConnection(); + $queryBuilder = $conn->createQueryBuilder(); + + $select = $queryBuilder->select('d.id') + ->from('documents', 'd') + ->join('d', 'link_persons_documents', 'link', 'd.id = link.document_id') + ->where('link.role = :role') + ->andWhere('link.person_id = :personId') + ->distinct() + ->setParameter('role', $role) + ->setParameter('personId', $person->getId()); + + $documents = []; + + $result = $select->execute()->fetchFirstColumn(); + + foreach ($result as $id) { + $documents[] = Document::get($id); + } + + return $documents; + } + + /** + * Returns the ids for all linked documents. + * + * @param Person $person + * @param string|null $role + * @return array + */ + public function getDocumentIds($person, $role = null) + { + if ($person->getId() === 0) { + // TODO do more? + return []; + } + + $conn = $this->getEntityManager()->getConnection(); + $queryBuilder = $conn->createQueryBuilder(); + + $select = $queryBuilder->select('distinct(document_id)') + ->from('link_persons_documents') + ->where('person_id = :personId') + ->setParameter('personId', $person->getId()); + + if ($role !== null) { + $select->andWhere('role = :role') + ->setParameter('role', $role); + } + + return $select->execute()->fetchFirstColumn(); + } + + /** + * Get a list of IDs for Persons that have the specified role for + * certain documents. + * + * @param string $role Role name. + * @return array List of Opus\Person Ids for Person models assigned to the specified Role. + */ + public function getAllIdsByRole($role) + { + $conn = $this->getEntityManager()->getConnection(); + + $select = $conn->createQueryBuilder() + ->select('person_id') + ->from('link_persons_documents') + ->where('role = :role') + ->setParameter('role', $role); + + return $select->execute()->fetchFirstColumn(); + } + + /** + * Returns roles for a person. + * + * TODO verify columns + * TODO use object for person + * + * @param array $person + * @return mixed + */ + public function getPersonRoles($person) + { + $conn = $this->getEntityManager()->getConnection(); + + $select = $conn->createQueryBuilder() + ->select('link.role, count(link.document_id) as documents') + ->from('link_persons_documents', 'link') + ->join('link', 'persons', 'p', 'link.person_id = p.id') + ->groupBy('link.role'); + + self::addWherePerson($select, $person); + + return $select->execute()->fetchAllAssociative(); + } + + /** + * Returns document for person. + * + * The $person parameter is an array of columns and values that determine which person is meant. + * + * - first name + * - last name + * - identifier_orcid + * - identifier_gnd + * - identifier_misc + * + * @param array $person + * @param string|null $state + * @param string|null $role + * @param string|null $sort + * @param bool $order + * @return array + */ + public function getPersonDocuments($person, $state = null, $role = null, $sort = null, $order = true) + { + $conn = $this->getEntityManager()->getConnection(); + + $select = $conn->createQueryBuilder() + ->select('distinct(d.id)') + ->from('documents', 'd') + ->join('d', 'link_persons_documents', 'link', 'link.document_id = d.id') + ->join('link', 'persons', 'p', 'link.person_id = p.id'); + + self::addWherePerson($select, $person); + + if ( + $state !== null && in_array( + $state, + ['published', 'unpublished', 'inprogress', 'audited', 'restricted', 'deleted'] + ) + ) { + $select->andWhere('d.server_state = :state')->setParameter('state', $state); + } + + if ( + $role !== null && in_array( + $role, + ['author', 'editor', 'contributor', 'referee', 'advisor', 'other', 'translator', 'submitter'] + ) + ) { + $select->andWhere('link.role = :role')->setParameter('role', $role); + } + + if ($sort !== null && in_array($sort, ['id', 'title', 'publicationDate', 'docType', 'author'])) { + switch ($sort) { + case 'id': + $select->orderBy('d.id' . ($order ? ' ASC' : ' DESC')); + break; + case 'title': + $select->select('d.id, t.value'); + $select->join( + 'd', + 'document_title_abstracts', + 't', + 't.document_id = d.id' + ); + $select->orderBy('t.value' . ($order ? ' ASC' : ' DESC')); + break; + case 'publicationDate': + $select->select('d.id, d.server_date_published'); + $select->orderBy('d.server_date_published' . ($order ? ' ASC' : ' DESC')); + break; + case 'docType': + $select->select('d.id, d.type'); + $select->orderBy('d.type' . ($order ? ' ASC' : ' DESC')); + break; + case 'author': + $select->select('d.id, p.last_name'); + $select->orderBy('p.last_name' . ($order ? ' ASC' : ' DESC')); + break; + } + } + + $documents = $select->execute()->fetchFirstColumn(); + + $documents = array_unique($documents); // just in case (TODO sorting by title creates duplicates) + + return $documents; + } + + /** + * Returns the value of matching person objects. + * + * @param array $person + * @return array|null + */ + public function getPersonValues($person) + { + $conn = $this->getEntityManager()->getConnection(); + + $result = null; + + $select = $conn->createQueryBuilder() + ->select('*') + ->from('persons', 'p'); + + self::addWherePerson($select, $person); + + $result = $select->execute(); + + if ($result->rowCount() === 0) { + return null; + } + + $data = $result->fetchAllAssociative(); + + $merged = []; + + foreach ($data as $personId => $values) { + foreach ($values as $key => $value) { + if (array_key_exists($key, $merged)) { + $allValues = $merged[$key]; + + if (is_array($allValues)) { + if (array_search($value, $allValues) === false) { + array_push($merged[$key], $value); + } + } else { + if ($value !== $allValues) { + $merged[$key] = []; + array_push($merged[$key], $allValues, $value); + } + } + } else { + $merged[$key] = $value; + } + } + } + + return $merged; + } + + /** + * Returns ids of person objects matching criteria and documents. + * + * TODO filter by role? + * + * @param array $person Criteria for matching persons + * @param array|null $documents Array with ids of documents + * @return array Array with IDs of persons + */ + public function getPersons($person, $documents = null) + { + $conn = $this->getEntityManager()->getConnection(); + + $select = $conn->createQueryBuilder() + ->select('distinct(p.id)') + ->from('persons', 'p'); + + // TODO handle single document id value + if ($documents !== null && is_array($documents) && count($documents) > 0) { + $select->join('p', 'link_persons_documents', 'link', 'link.person_id = p.id'); + $select->where('link.document_id IN (:documents)') + ->setParameter('documents', $documents, Connection::PARAM_INT_ARRAY); + } + + self::addWherePerson($select, $person); + + return $select->execute()->fetchFirstColumn(); + } + + /** + * @param array $person + * @param array|null $documents + * @return array + */ + public function getPersonsAndDocuments($person, $documents = null) + { + $conn = $this->getEntityManager()->getConnection(); + + $select = $conn->createQueryBuilder() + ->select('link.person_id', 'link.document_id') + ->from('persons', 'p') + ->join('p', 'link_persons_documents', 'link', 'link.person_id = p.id'); + + if ($documents !== null) { + $select->where('link.document_id IN (:documents)') + ->setParameter('documents', $documents, Connection::PARAM_INT_ARRAY); + } + + self::addWherePerson($select, $person); + + return $select->execute()->fetchAllAssociative(); + } + + /** + * @param array $personIds + * @param array|null $documents + * @return array + */ + public function getDocuments($personIds, $documents = null) + { + $conn = $this->getEntityManager()->getConnection(); + + $select = $conn->createQueryBuilder() + ->select('distinct(link.document_id)') + ->from('persons', 'p') + ->join('p', 'link_persons_documents', 'link', 'link.person_id = p.id') + ->where('link.person_id IN (:personIds)') + ->setParameter('personIds', $personIds, Connection::PARAM_INT_ARRAY); + + if ($documents !== null && count($documents) > 0) { + $select->andWhere('link.document_id IN (:documents)') + ->setParameter('documents', $documents, Connection::PARAM_INT_ARRAY); + } + + return $select->execute()->fetchFirstColumn(); + } + + /** + * @param QueryBuilder $select + * @param array $person + * + * TODO review + * + * This currently adds criteria to match any person with matching values for the specified columns. + * + * TODO shoudln't it be an exact match for columns that are empty (only null/empty matches)? + * + * NOTE: Function updateAll does not use this, because there does not seem to be a way to hand over + * an update object like for the select. + */ + protected static function addWherePerson($select, $person) + { + $defaults = array_fill_keys([ + 'last_name', + 'first_name', + 'identifier_orcid', + 'identifier_gnd', + 'identifier_misc', + ], null); + $person = array_merge($defaults, $person); + + foreach ($person as $column => $value) { + if (strlen(trim($value)) > 0) { + $select->andWhere("trim(p.$column) = :$column") + ->setParameter($column, trim($value)); + } else { + $select->andWhere("p.$column IS NULL"); + } + } + } + + /** + * Updates select columns of matching persons. + * + * Optionally the scope can be limited to specified set of documents. + * + * @param array $person Criteria for matching persons + * @param array $changes Map of column names and new values + * @param array|null $documents Array with document Ids + * + * TODO update ServerDateModified for modified documents (How?) + */ + public function updateAll($person, $changes, $documents = null) + { + if (empty($person)) { + // TODO do logging? + return; + } + + if (empty($changes)) { + // TODO do logging? + return; + } + + foreach ($changes as $name => $value) { + if (! property_exists(Person::class, lcfirst($name))) { + // TODO use + throw new ModelException("unknown field '$name' for update"); + } else { + if ($value !== null) { + $changes[$name] = trim($value); + } else { + $changes[$name] = null; + } + } + } + + $personIds = self::getPersons($person, $documents); + $documentIds = self::getDocuments($personIds, $documents); + + if (! empty($personIds)) { + $queryBuilder = $this->getEntityManager()->createQueryBuilder(); + $update = $queryBuilder->update(Person::class, 'p'); + + foreach ($changes as $key => $value) { + $update->set('p.' . lcfirst($key), ':' . $key) + ->setParameter($key, $value); + } + + $update->where('p.id IN (:personIds)') + ->setParameter('personIds', $personIds, Connection::PARAM_INT_ARRAY); + + $update->getQuery()->execute(); + + $this->getEntityManager()->clear(Person::class); + + if (! empty($documentIds)) { + $date = new Date(); + $date->setNow(); + + Document::setServerDateModifiedByIds($date, $documentIds); + } + } + } } diff --git a/library/Opus/Model2/AbstractModel.php b/library/Opus/Model2/AbstractModel.php index 2184fed1..111dbd36 100644 --- a/library/Opus/Model2/AbstractModel.php +++ b/library/Opus/Model2/AbstractModel.php @@ -41,6 +41,10 @@ use Opus\Model\NotFoundException; use function in_array; +use function preg_replace; +use function preg_replace_callback; +use function strtolower; +use function strtoupper; /** * Base class for OPUS 4 model classes. @@ -61,6 +65,14 @@ abstract class AbstractModel // TODO The use of String as the type of $modelId become necessary due to the existence of models // which do not use "id" as the primary key + /** + * @return static + */ + public static function new() + { + return new static(); + } + /** * @param int|string $modelId * @return self|null @@ -222,4 +234,28 @@ public static function fromArray($data) $model->updateFromArray($data); return $model; } + + /** + * @param string $fieldname Field name in camel case + * @return string Column name with case-change replaced by underscores "_" + */ + public static function convertFieldnameToColumn($fieldname) + { + return strtolower(preg_replace('/(?!^)[[:upper:]]/', '_\0', $fieldname)); + } + + /** + * @param string $column Column name as string + * @return string Field name in camel case + */ + public static function convertColumnToFieldname($column) + { + return preg_replace_callback( + '/(?:^|_)([a-z])([a-z]+)/', + function ($matches) { + return strtoupper($matches[1]) . $matches[2]; + }, + $column + ); + } } diff --git a/library/Opus/Model2/Person.php b/library/Opus/Model2/Person.php index 641a259f..8e0a4a9b 100644 --- a/library/Opus/Model2/Person.php +++ b/library/Opus/Model2/Person.php @@ -35,30 +35,13 @@ namespace Opus\Model2; use Doctrine\ORM\Mapping as ORM; - use Opus\Date; -use Opus\Db\LinkPersonsDocuments; -use Opus\Db\TableGateway; -use Opus\Model\AbstractDb; -use Opus\Model\Field; -use Opus\Model\ModelException; -use Zend_Validate_EmailAddress; -use Zend_Validate_NotEmpty; use function array_fill_keys; -use function array_key_exists; -use function array_map; use function array_merge; -use function array_push; -use function array_search; -use function array_unique; -use function count; -use function in_array; use function is_array; use function is_string; use function stristr; -use function strlen; -use function trim; /** * Domain model for persons in the Opus framework @@ -93,9 +76,6 @@ * * TODO use OPUS-ID for people without external identifier * - * @category Framework - * @package Opus - * * phpcs:disable * * @ORM\Entity(repositoryClass="Opus\Db2\PersonRepository") @@ -103,6 +83,9 @@ * indexes={ * @ORM\Index(name="last_name", columns={"last_name"}) * }) + * + * @category Framework + * @package Opus */ class Person extends AbstractModel { @@ -119,7 +102,7 @@ class Person extends AbstractModel * @ORM\Column(name="academic_title", type="string", length=255, nullable="true") * @var string */ - private $title; + private $academicTitle; /** * @ORM\Column(name="first_name", type="string", length=255, nullable="true") @@ -173,7 +156,7 @@ class Person extends AbstractModel * @ORM\Column(name="opus_id", type="integer") * @var string */ - private $opusId; + private $opusId = 0; /** * @return int @@ -194,17 +177,18 @@ public function setId($id) /** * @return string */ - public function getTitle() + public function getAcademicTitle() { - return $this->title; + return $this->academicTitle; } /** * @param string $title + * @return $this */ - public function setTitle($title) + public function setAcademicTitle($title) { - $this->title = $title; + return $this->academicTitle = $title; } /** @@ -217,10 +201,12 @@ public function getFirstName() /** * @param string $firstName + * @return $this */ public function setFirstName($firstName) { $this->firstName = $firstName; + return $this; } /** @@ -233,10 +219,12 @@ public function getLastName() /** * @param string $lastName + * @return $this */ public function setLastName($lastName) { $this->lastName = $lastName; + return $this; } /** @@ -249,10 +237,12 @@ public function getDateOfBirth() /** * @param Date $dateOfBirth + * @return $this */ public function setDateOfBirth($dateOfBirth) { $this->dateOfBirth = $dateOfBirth; + return $this; } /** @@ -265,10 +255,12 @@ public function getPlaceOfBirth() /** * @param string $placeOfBirth + * @return $this */ public function setPlaceOfBirth($placeOfBirth) { $this->placeOfBirth = $placeOfBirth; + return $this; } /** @@ -281,10 +273,12 @@ public function getIdentifierOrcid() /** * @param string $identifierOrcid + * @return $this */ public function setIdentifierOrcid($identifierOrcid) { $this->identifierOrcid = $identifierOrcid; + return $this; } /** @@ -297,10 +291,12 @@ public function getIdentifierGnd() /** * @param string $identifierGnd + * @return $this */ public function setIdentifierGnd($identifierGnd) { $this->identifierGnd = $identifierGnd; + return $this; } /** @@ -313,10 +309,12 @@ public function getIdentifierMisc() /** * @param string $identifierMisc + * @return $this */ public function setIdentifierMisc($identifierMisc) { $this->identifierMisc = $identifierMisc; + return $this; } /** @@ -329,10 +327,12 @@ public function getEmail() /** * @param string $email + * @return $this */ public function setEmail($email) { $this->email = $email; + return $this; } /** @@ -345,10 +345,12 @@ public function getOpusId() /** * @param string $opusId + * @return $this */ public function setOpusId($opusId) { $this->opusId = $opusId; + return $this; } /** @@ -359,7 +361,7 @@ public function setOpusId($opusId) protected static function describe() { return [ - 'Title', + 'AcademicTitle', 'FirstName', 'LastName', 'DateOfBirth', @@ -407,4 +409,271 @@ public function getDisplayName() { return $this->getName(); } + + /** + * Checks if person matches criteria. + * + * @param $criteria + * @return bool + * + * TODO refactor + */ + public function matches($criteria) + { + if ($criteria instanceof Person) { + $person = $criteria; + + $criteria = []; + $criteria['LastName'] = $person->getLastName(); + $criteria['FirstName'] = $person->getFirstName(); + $criteria['IdentifierOrcid'] = $person->getIdentifierOrcid(); + $criteria['IdentifierGnd'] = $person->getIdentifierGnd(); + $criteria['IdentifierMisc'] = $person->getIdentifierMisc(); + } + + if (!is_array($criteria)) { + // TODO do some logging + return false; + } + + $defaults = array_fill_keys([ + 'LastName', + 'FirstName', + 'IdentifierOrcid', + 'IdentifierGnd', + 'IdentifierMisc', + ], null); + $criteria = array_merge($defaults, $criteria); + + foreach ($criteria as $fieldName => $criteriaValue) { + $getField = 'get' . $fieldName; + $value = $this->$getField(); + + if (is_string($value)) { + if (stristr($value, $criteriaValue) === false) { + return false; + } + } else { + if ($value !== $criteriaValue) { + return false; + } + } + } + + return true; + } + + /** + * @return string + */ + public function getModelType() + { + return 'person'; + } + + /** + * Retrieve all persons from the database. + * + * @return array|object[] Array of Person objects. + */ + public static function getAll() + { + return self::getRepository()->findAll(); + } + + /** + * Returns all persons in the database without duplicates. + * + * Every real person might be represented by several objects, one for each document. + * + * @param string|null $role + * @param int $start + * @param int $limit + * @param string|null $filter + * @return array + */ + public static function getAllPersons($role = null, $start = 0, $limit = 0, $filter = null) + { + return self::getRepository()->getAllPersons($role, $start, $limit, $filter); + } + + /** + * Returns total count of persons for role and filter string. + * + * @param string|null $role + * @param string|null $filter + * @return mixed + */ + public static function getAllPersonsCount($role = null, $filter = null) + { + return self::getRepository()->getAllPersonsCount($role, $filter); + } + + /** + * Fetches all documents associated to the person by a certain role. + * + * @param string $role The role that the person has for the documents. + * @return array An array of Opus\Document + */ + public function getDocumentsByRole($role) + { + return self::getRepository()->getDocumentsByRole($this, $role); + } + + /** + * Returns the ids for all linked documents. + * + * @param string|null $role + * @return array|void + */ + public function getDocumentIds($role = null) + { + return self::getRepository()->getDocumentIds($this, $role); + } + + + /** + * Get a list of IDs for Persons that have the specified role for + * certain documents. + * + * @param string $role Role name. + * @return array List of Opus\Person Ids for Person models assigned to the specified Role. + */ + public static function getAllIdsByRole($role) + { + return self::getRepository()->getAllIdsByRole($role); + } + + /** + * Returns roles for a person. + * + * TODO verify columns + * TODO use object for person + */ + public static function getPersonRoles($person) + { + return self::getRepository()->getPersonRoles($person); + } + + /** + * Returns document for person. + * + * The $person parameter is an array of columns and values that determine which person is meant. + * + * - first name + * - last name + * - identifier_orcid + * - identifier_gnd + * - identifier_misc + * + * @param array $person + * @param string|null $state + * @param string|null $role + * @param string|null $sort + * @param bool $order + * @return array + */ + public static function getPersonDocuments($person, $state = null, $role = null, $sort = null, $order = true) + { + return self::getRepository()->getPersonDocuments($person, $state, $role, $sort, $order); + } + + /** + * Returns the value of matching person objects. + * + * @param array $person + * @return array + */ + public static function getPersonValues($person) + { + return self::getRepository()->getPersonValues($person); + } + + /** + * Returns ids of person objects matching criteria and documents. + * + * TODO filter by role? + * + * @param array $person Criteria for matching persons + * @param array|null $documents Array with ids of documents + * @return array Array with IDs of persons + */ + public static function getPersons($person, $documents = null) + { + return self::getRepository()->getPersons($person, $documents); + } + + /** + * @param array $person + * @param array|null $documents + * @return array + */ + public static function getPersonsAndDocuments($person, $documents = null) + { + return self::getRepository()->getPersonsAndDocuments($person, $documents); + } + + /** + * @param array $personIds + * @param array|null $documents + * @return array + */ + public static function getDocuments($personIds, $documents = null) + { + return self::getRepository()->getDocuments($personIds, $documents); + } + + /** + * Updates select columns of matching persons. + * + * Optionally the scope can be limited to specified set of documents. + * + * @param array $person Criteria for matching persons + * @param array $changes Map of column names and new values + * @param array|null $documents Array with document Ids + * + * TODO update ServerDateModified for modified documents (How?) + */ + public static function updateAll($person, $changes, $documents = null) + { + return self::getRepository()->updateAll($person, $changes, $documents); + } + + /** + * Converts map with field names into array with column names. + * + * @param array $changes Map of field names and values + * @return array Map of column names and values + */ + public static function convertChanges($changes) + { + $columnChanges = []; + + foreach ($changes as $fieldName => $value) { + $column = self::convertFieldnameToColumn($fieldName); + + $columnChanges[$column] = $value; + } + + return $columnChanges; + } + + /** + * Convert array with column names into array with field names. + * + * @param array $person + * @return array + */ + public static function convertToFieldNames($person) + { + $values = []; + + foreach ($person as $column => $value) { + $fieldName = self::convertColumnToFieldname($column); + + $values[$fieldName] = $value; + } + + return $values; + } } diff --git a/tests/Opus/PersonTest.php b/tests/Opus/PersonTest.php index 3a68bb3c..81a3dade 100644 --- a/tests/Opus/PersonTest.php +++ b/tests/Opus/PersonTest.php @@ -44,7 +44,7 @@ use Opus\Document; use Opus\Model\ModelException; use Opus\Model\Xml\Cache; -use Opus\Model2\Person; +use Opus\Person; use Opus\Title; use OpusTest\TestAsset\TestCase; @@ -97,7 +97,7 @@ public function setUp() } for ($i = 0; $i < 10; $i++) { - $p = Person::new(); + $p = new Person(); $p->setFirstName("Dummy-$i") ->setLastName("Empty-$i") ->store(); @@ -106,7 +106,7 @@ public function setUp() // add a person as author to every document // and add the person to the list of authors foreach ($this->documents as $document) { - $p = Person::new(); + $p = new Person(); $p->setFirstName('Rainer') ->setLastName('Zufall') ->setAcademicTitle('Prof. Dr.') @@ -127,6 +127,7 @@ public function testGetDocumentsByRole() // TODO: der Tabelle link_persons_documents. // // TODO: Die ID der Person erhält man mit getLinkedModelId() + // TODO: Die ID der Person foreach ($this->authors as $author) { $docs = $author->getDocumentsByRole('author'); From 1da135aa64146531e80fb8244b0ceb38fb4943c3 Mon Sep 17 00:00:00 2001 From: haogatyp Date: Thu, 17 Mar 2022 18:16:14 +0100 Subject: [PATCH 3/5] #204 Linking documents and persons using ORM mapped DocumentPerson model. --- library/Opus/Model2/Document.php | 377 +++++++++++++++++++++++++ library/Opus/Model2/DocumentPerson.php | 229 +++++++++++++++ library/Opus/Model2/Person.php | 8 + tests/Opus/DocumentTest.php | 2 +- 4 files changed, 615 insertions(+), 1 deletion(-) create mode 100644 library/Opus/Model2/DocumentPerson.php diff --git a/library/Opus/Model2/Document.php b/library/Opus/Model2/Document.php index 4e7dc04c..e2d0d3b2 100644 --- a/library/Opus/Model2/Document.php +++ b/library/Opus/Model2/Document.php @@ -236,6 +236,12 @@ class Document extends AbstractModel */ private $titles; + /** + * @ORM\OneToMany(targetEntity="DocumentPerson", mappedBy="document", cascade={"persist"}) + * @var Collection|DocumentPerson[] + */ + private $documentPersons; + // FIXME: Taken from the original document class due to a dependency on DocumentTest private static $defaultPlugins; @@ -244,6 +250,7 @@ class Document extends AbstractModel */ public function __construct() { $this->titles = new ArrayCollection(); + $this->documentPersons = new ArrayCollection(); } /** @@ -581,4 +588,374 @@ public function setTitleAdditional($title) { $this->setTitle(Title::TYPE_MAIN, $title); } + + /** + * Generic method for setting persons used by the role specific person methods, e.g. setPersonAuthor() + * + * @param ArrayCollection|Collection|DocumentPerson[] $persons + * @param string|null $role + */ + protected function setDocumentPerson($persons, $role = null) + { + $documentPersons = $this->getPerson($role); + + foreach ($documentPersons as $element) { + $this->documentPersons->removeElement($element); + $element->setDocument(null); + } + + foreach ($persons as $newPerson) { + $this->addTitle($newPerson, $role); + } + } + + /** + * Generic method for getting persons|document-persons used by role specific person methods, e.g. getPersonAuthor() + * Returns the collection of DocumentPersons related to this document, or just the DocumentPerson of the + * specified index. + * + * @param string|null $role + * @param int|null $index + * @return ArrayCollection|Collection|DocumentPerson[]|DocumentPerson + */ + protected function getDocumentPerson($role = null, $index = null) + { + $criteria = Criteria::create() + ->orderBy(["sortOrder" => Criteria::ASC]) + ->setFirstResult(0); + + if ($role !== null) { + // We want only persons of the given role + $criteria->where(Criteria::expr()->eq("role", $role)); + } + + $documentPersons = $this->titles->matching($criteria); + + if ($index !== null) { + if (! isset($documentPersons[$index])) { + throw new InvalidArgumentException('Invalid index: ' . $index); + } + return $documentPersons[$index]; + } + + return $documentPersons->toArray(); + } + + /** + * Generic method for adding persons used by role specific person methods, e.g. addPersonAuthor() + * + * @param Person $person + * @param string|null $role + * @return DocumentPerson + */ + protected function addDocumentPerson($person, $role = null) + { + $documentPerson = DocumentPerson::new(); + $documentPerson->setDocument($this); + $documentPerson->setPerson($person); + if (isset($role)) { + $documentPerson->setRole($role); + } + $this->documentPersons->add($documentPerson); + + return $documentPerson; + } + + /** + * Sets the persons of the document + * + * @param ArrayCollection|Collection|DocumentPerson[] $persons + */ + public function setPerson($persons) + { + $this->setDocumentPerson($persons); + } + + /** + * Gets all persons related to this document, + * or just the person of the specified index. + * + * @param int|null $index + * @return ArrayCollection|Collection|DocumentPerson[]|DocumentPerson + */ + public function getPerson($index = null) + { + return $this->getDocumentPerson(null, $index); + } + + /** + * Adds a person to the document + * + * @param Person $person + * @return DocumentPerson + */ + public function addPerson($person) + { + return $this->addDocumentPerson($person); + } + + /** + * Sets all persons of the role 'author' + * + * @param ArrayCollection|Collection|DocumentPerson[] $persons + */ + public function setPersonAuthor($persons) + { + $this->setDocumentPerson($persons, DocumentPerson::ROLE_AUTHOR); + } + + /** + * Gets all persons of the role 'author' + * or just the person of the specified index. + * + * @param int|null $index + * @return ArrayCollection|Collection|DocumentPerson[]|DocumentPerson + */ + public function getPersonAuthor($index = null) + { + return $this->getDocumentPerson(DocumentPerson::ROLE_AUTHOR, $index); + } + + /** + * Adds a person of the role 'author' + * + * @param Person $person + * @return DocumentPerson + */ + public function addPersonAuthor($person) + { + return $this->addDocumentPerson($person, DocumentPerson::ROLE_AUTHOR); + } + + /** + * Sets all persons of the role 'advisor' + * + * @param ArrayCollection|Collection|DocumentPerson[] $persons + */ + public function setPersonAdvisor($persons) + { + $this->setDocumentPerson($persons, DocumentPerson::ROLE_ADVISOR); + } + + /** + * Gets all persons of the role 'advisor' + * or just the person of the specified index. + * + * @param int|null $index + * @return ArrayCollection|Collection|DocumentPerson[]|DocumentPerson + */ + public function getPersonAdvisor($index = null) + { + return $this->getDocumentPerson(DocumentPerson::ROLE_ADVISOR, $index); + } + + /** + * Adds a person of the role 'advisor' + * + * @param Person $person + * @return DocumentPerson + */ + public function addPersonAdvisor($person) + { + return $this->addDocumentPerson($person, DocumentPerson::ROLE_ADVISOR); + } + + /** + * Sets all persons of the role 'contributor' + * + * @param ArrayCollection|Collection|DocumentPerson[] $persons + */ + public function setPersonContributor($persons) + { + $this->setDocumentPerson($persons, DocumentPerson::ROLE_CONTRIBUTOR); + } + + /** + * Gets all persons of the role 'contributor' + * or just the person of the specified index. + * + * @param int|null $index + * @return ArrayCollection|Collection|DocumentPerson[]|DocumentPerson + */ + public function getPersonContributor($index = null) + { + return $this->getDocumentPerson(DocumentPerson::ROLE_CONTRIBUTOR, $index); + } + + /** + * Adds a person of the role 'contributor' + * + * @param Person $person + * @return DocumentPerson + */ + public function addPersonContributor($person) + { + return $this->addDocumentPerson($person, DocumentPerson::ROLE_CONTRIBUTOR); + } + + /** + * Sets all persons of the role 'editor' + * + * @param ArrayCollection|Collection|DocumentPerson[] $persons + */ + public function setPersonEditor($persons) + { + $this->setDocumentPerson($persons, DocumentPerson::ROLE_EDITOR); + } + + /** + * Gets all persons of the role 'editor' + * or just the person of the specified index. + * + * @param int|null $index + * @return ArrayCollection|Collection|DocumentPerson[]|DocumentPerson + */ + public function getPersonEditor($index = null) + { + return $this->getDocumentPerson(DocumentPerson::ROLE_EDITOR, $index); + } + + /** + * Adds a person of the role 'editor' + * + * @param Person $person + * @return DocumentPerson + */ + public function addPersonEditor($person) + { + return $this->addDocumentPerson($person, DocumentPerson::ROLE_EDITOR); + } + + /** + * Sets all persons of the role 'referee' + * + * @param ArrayCollection|Collection|DocumentPerson[] $persons + */ + public function setPersonReferee($persons) + { + $this->setDocumentPerson($persons, DocumentPerson::ROLE_REFEREE); + } + + /** + * Gets all persons of the role 'referee' + * or just the person of the specified index. + * + * @param int|null $index + * @return ArrayCollection|Collection|DocumentPerson[]|DocumentPerson + */ + public function getPersonReferee($index = null) + { + return $this->getDocumentPerson(DocumentPerson::ROLE_REFEREE, $index); + } + + /** + * Adds a person of the role 'referee' + * + * @param Person $person + * @return DocumentPerson + */ + public function addPersonReferee($person) + { + return $this->addDocumentPerson($person, DocumentPerson::ROLE_REFEREE); + } + + /** + * Sets all persons of the role 'other' + * + * @param ArrayCollection|Collection|DocumentPerson[] $persons + */ + public function setPersonOther($persons) + { + $this->setDocumentPerson($persons, DocumentPerson::ROLE_OTHER); + } + + /** + * Gets all persons of the role 'other' + * or just the person of the specified index. + * + * @param int|null $index + * @return ArrayCollection|Collection|DocumentPerson[]|DocumentPerson + */ + public function getPersonOther($index = null) + { + return $this->getDocumentPerson(DocumentPerson::ROLE_OTHER, $index); + } + + /** + * Adds a person of the role 'other' + * + * @param Person $person + * @return DocumentPerson + */ + public function addPersonOther($person) + { + return $this->addDocumentPerson($person, DocumentPerson::ROLE_OTHER); + } + + + /** + * Sets all persons of the role 'translator' + * + * @param ArrayCollection|Collection|DocumentPerson[] $persons + */ + public function setPersonTranslator($persons) + { + $this->setDocumentPerson($persons, DocumentPerson::ROLE_TRANSLATOR); + } + + /** + * Gets all persons of the role 'translator' + * or just the person of the specified index. + * + * @param int|null $index + * @return ArrayCollection|Collection|DocumentPerson[]|DocumentPerson + */ + public function getPersonTranslator($index = null) + { + return $this->getDocumentPerson(DocumentPerson::ROLE_TRANSLATOR, $index); + } + + /** + * Adds a person of the role 'translator' + * + * @param Person $person + * @return DocumentPerson + */ + public function addPersonTranslator($person) + { + return $this->addDocumentPerson($person, DocumentPerson::ROLE_TRANSLATOR); + } + + /** + * Sets all persons of the role 'submitter' + * + * @param ArrayCollection|Collection|DocumentPerson[] $persons + */ + public function setPersonSubmitter($persons) + { + $this->setDocumentPerson($persons, DocumentPerson::ROLE_SUBMITTER); + } + + /** + * Gets all persons of the role 'submitter' + * or just the person of the specified index. + * + * @param int|null $index + * @return ArrayCollection|Collection|DocumentPerson[]|DocumentPerson + */ + public function getPersonSubmitter($index = null) + { + return $this->getDocumentPerson(DocumentPerson::ROLE_SUBMITTER, $index); + } + + /** + * Adds a person of the role 'submitter' + * + * @param Person $person + * @return DocumentPerson + */ + public function addPersonSubmitter($person) + { + return $this->addDocumentPerson($person, DocumentPerson::ROLE_SUBMITTER); + } } diff --git a/library/Opus/Model2/DocumentPerson.php b/library/Opus/Model2/DocumentPerson.php new file mode 100644 index 00000000..8a3d1bd4 --- /dev/null +++ b/library/Opus/Model2/DocumentPerson.php @@ -0,0 +1,229 @@ +modelClass; + } + + public function setModelClass(string $modelClass) + { + $this->modelClass = $modelClass; + } + + /** + * @return string + */ + public function getRole() + { + return $this->role; + } + + /** + * @param string $role + */ + public function setRole($role) + { + $this->role = $role; + } + + /** + * @return int + */ + public function getSortOrder() + { + return $this->sortOrder; + } + + /** + * @param int $sortOrder + */ + public function setSortOrder($sortOrder) + { + $this->sortOrder = $sortOrder; + } + + /** + * @return bool + */ + public function isAllowEmailContact() + { + return $this->allowEmailContact; + } + + /** + * @param bool $allowEmailContact + */ + public function setAllowEmailContact($allowEmailContact) + { + $this->allowEmailContact = $allowEmailContact; + } + + /** + * @return Person + */ + public function getPerson() + { + return $this->person; + } + + /** + * @param Person $person + */ + public function setPerson($person) + { + $this->person = $person; + } + + /** + * @return Document + */ + public function getDocument() + { + return $this->document; + } + + /** + * @param Document $document + */ + public function setDocument($document) + { + $this->document = $document; + } + + /** + * @return array + */ + protected static function describe() + { + // TODO: Implement describe() method. + return []; + } + + /** + * Return the primary key of the Link Model if it has been persisted. + * + * @return int|null + * + * TODO: To be clarified + */ + public function getId() + { + if ($this->person === null && $this->document === null) { + // its a new record, so return null + return null; + } + + return $this->person->getId(); + } +} diff --git a/library/Opus/Model2/Person.php b/library/Opus/Model2/Person.php index 8e0a4a9b..305db4b6 100644 --- a/library/Opus/Model2/Person.php +++ b/library/Opus/Model2/Person.php @@ -34,6 +34,7 @@ namespace Opus\Model2; +use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; use Opus\Date; @@ -158,6 +159,13 @@ class Person extends AbstractModel */ private $opusId = 0; + /** + * @ORM\OneToMany(targetEntity="DocumentPerson", mappedBy="person", fetch="EXTRA_LAZY") + * + * @var Collection|DocumentPerson[] + */ + private $documentPerson; + /** * @return int */ diff --git a/tests/Opus/DocumentTest.php b/tests/Opus/DocumentTest.php index 5babf542..fa2e956d 100644 --- a/tests/Opus/DocumentTest.php +++ b/tests/Opus/DocumentTest.php @@ -69,7 +69,7 @@ use Opus\Model\Xml\Version1; use Opus\Note; use Opus\Patent; -use Opus\Person; +use Opus\Model2\Person; use Opus\Series; use Opus\Subject; use Opus\SubjectSwd; From 68f0d918922db2f811d0a0972bbcfd88ad282e03 Mon Sep 17 00:00:00 2001 From: haogatyp Date: Wed, 23 Mar 2022 15:28:00 +0100 Subject: [PATCH 4/5] #204 Fix problems with some person related tests due to not nullable Document fields. --- library/Opus/Db2/PersonRepository.php | 4 +-- library/Opus/Model2/AbstractModel.php | 10 ++++++ library/Opus/Model2/Document.php | 44 +++++++++++++++++++++++++-- 3 files changed, 53 insertions(+), 5 deletions(-) diff --git a/library/Opus/Db2/PersonRepository.php b/library/Opus/Db2/PersonRepository.php index 66695e6d..69db4034 100644 --- a/library/Opus/Db2/PersonRepository.php +++ b/library/Opus/Db2/PersonRepository.php @@ -178,7 +178,7 @@ public function getAllPersonsCount($role = null, $filter = null) */ public function getDocumentsByRole($person, $role) { - if ($person->getId() === 0) { + if ($person->isNewRecord()) { return []; } @@ -214,7 +214,7 @@ public function getDocumentsByRole($person, $role) */ public function getDocumentIds($person, $role = null) { - if ($person->getId() === 0) { + if ($person->isNewRecord()) { // TODO do more? return []; } diff --git a/library/Opus/Model2/AbstractModel.php b/library/Opus/Model2/AbstractModel.php index 111dbd36..370463bc 100644 --- a/library/Opus/Model2/AbstractModel.php +++ b/library/Opus/Model2/AbstractModel.php @@ -164,6 +164,16 @@ public function store() return $modelId; } + /** + * Returns whether model is a new record. + * + * @return bool + */ + public function isNewRecord() + { + return $this->getId() === 0 || $this->getId() === null; + } + /** * Remove the model instance from the database. * diff --git a/library/Opus/Model2/Document.php b/library/Opus/Model2/Document.php index e2d0d3b2..19875c67 100644 --- a/library/Opus/Model2/Document.php +++ b/library/Opus/Model2/Document.php @@ -48,8 +48,9 @@ use Doctrine\Common\Collections\Criteria; use Doctrine\ORM\Mapping as ORM; -use http\Exception\InvalidArgumentException; +use InvalidArgumentException; use Opus\Date; +use Opus\Model\DbException; use Opus\Model\ModelException; /** @@ -58,6 +59,20 @@ */ class Document extends AbstractModel { + const STATE_DELETED = 'deleted'; + + const STATE_INPROGRESS = 'inprogress'; + + const STATE_RESTRICTED = 'restricted'; + + const STATE_UNPUBLISHED = 'unpublished'; + + const STATE_PUBLISHED = 'published'; + + const STATE_TEMPORARY = 'temporary'; + + const STATE_AUDITED = 'audited'; + /** * @ORM\Id * @ORM\Column(type="integer") @@ -186,7 +201,7 @@ class Document extends AbstractModel * @ORM\Column(type="string", name="publication_state", columnDefinition="ENUM('draft','accepted','submitted','published','updated')") * @var string */ - protected $publicationState; + protected $publicationState = 'draft'; /** * @ORM\Column(type="opusDate", name="server_date_created") @@ -216,7 +231,7 @@ class Document extends AbstractModel * @ORM\Column(type="string", name="server_state", columnDefinition="ENUM('audited','published','restricted','inprogress','unpublished','deleted','temporary')") * @var string */ - private $serverState; + private $serverState = self::STATE_TEMPORARY; /** * @ORM\Column(type="string") @@ -253,6 +268,29 @@ public function __construct() { $this->documentPersons = new ArrayCollection(); } + /** + * Perform any actions needed to provide storing. + * + * @return mixed|null Anything else than null will cancel the storage process. + */ + protected function preStore() + { + $result = parent::preStore(); + + $date = new Date(); + $date->setNow(); + + if ($this->isNewRecord()) { + if ($this->getServerDateCreated() === null) { + $this->setServerDateCreated($date); + } + } + $this->setServerDateModified($date); + + return $result; + } + + /** * @return int */ From 2a2eb22347aba71c5d47cb6ee1edcbaf909b9149 Mon Sep 17 00:00:00 2001 From: haogatyp Date: Thu, 24 Mar 2022 10:14:33 +0100 Subject: [PATCH 5/5] #204 Fix, using wrong property --- library/Opus/Model2/Document.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/Opus/Model2/Document.php b/library/Opus/Model2/Document.php index 19875c67..8da3fc67 100644 --- a/library/Opus/Model2/Document.php +++ b/library/Opus/Model2/Document.php @@ -667,7 +667,7 @@ protected function getDocumentPerson($role = null, $index = null) $criteria->where(Criteria::expr()->eq("role", $role)); } - $documentPersons = $this->titles->matching($criteria); + $documentPersons = $this->documentPersons->matching($criteria); if ($index !== null) { if (! isset($documentPersons[$index])) {