From 11c07404c51bed87cdc8e3fa89a873fba74ff4bd Mon Sep 17 00:00:00 2001 From: Philipp Reisigl Date: Thu, 7 Sep 2023 20:16:48 +0200 Subject: [PATCH] Proper Readme; Move to namespace PhilippR\Atk4\Cron --- README.md | 34 +++++++++++++------ docs/sample.php | 14 ++++++-- ...ntermediateModel.php => JunctionModel.php} | 8 ++--- src/MToMTait.php | 30 ++++++++-------- tests/IntermediateModelTest.php | 12 +++---- tests/Testmodels/Lesson.php | 15 ++++++++ tests/Testmodels/StudentToLesson.php | 4 +-- tests/Testmodels/TeacherToLesson.php | 4 +-- 8 files changed, 78 insertions(+), 43 deletions(-) rename src/{IntermediateModel.php => JunctionModel.php} (92%) diff --git a/README.md b/README.md index 14581e3..9678088 100644 --- a/README.md +++ b/README.md @@ -1,29 +1,29 @@ # mtomforatk [![codecov](https://codecov.io/gh/PhilippGrashoff/mtomforatk/branch/master/graph/badge.svg)](https://codecov.io/gh/PhilippGrashoff/mtomforatk) -An addition to atk4/data to easily manage Many To Many (MToM) Relations. The purpose -is to write as little code as possible for actual MToM operations. + +An addition to [atk4/data](https://github.com/atk4/data) to easily manage Many To Many (MToM) Relations. The purpose is to write as little code as possible for actual MToM operations. # Project Content The project consists of two files: -* MToMModel: A base model for the intermediate class (like StudentToLesson). Working descendants can be coded with a few lines of code. -* MToMRelationForModelTrait: A Trait which is added to the models to be linked, (like Student and Lesson). With this trait, only a few more lines need to be added to make operations like `$lesson->addStudent(5);` work. +* **JunctionModel**: A base model for the junction class (like StudentToLesson). Working descendants can be coded with a few lines of code. +* **MToMTrait**: A Trait which is added to the models to be linked, (like Student and Lesson). With this trait, only a few more lines need to be added to make operations like `$lesson->addStudent(5);` work. # How to use ## Installation -The easiest way to use this repository is to add it to your composer.json in the require section: +The easiest way to use this repository is to add it to your composer.json in the requirement section: ```json { "require": { - "philippgrashoff/cronforatk": "4.0.*" + "philippgrashoff/mtomforatk": "4.0.*" } } ``` ## Sample code As example, lets use Students and Lessons. A Student can have many Lessons, a Lesson can have many Students. To map this MToM relationship, 3 classes are created. Demo models for this example can be found in tests\Testmodels: -* Student: A normal model which additionally uses ModelWithMToMTrait. 3 little helpers methods are implemented to make MToM handling easier: addLesson(), removeLesson() and hasLesson(); -* Lesson: A normal model which additionally uses ModelWithMToMTrait. 3 little helpers methods are implemented to make MToM handling easier: addStudent(), removeStudent() and hasStudent(); -* StudentToLesson: The intermediate model carrying the student_id and lesson_id for each MToM relation between Students and Lessons. +* Student: A normal model which uses MToMTrait. 3 little helpers methods are implemented to make MToM handling easier: addLesson(), removeLesson() and hasLesson(); +* Lesson: A normal model which uses MToMTrait. 3 little helpers methods are implemented to make MToM handling easier: addStudent(), removeStudent() and hasStudent(); +* StudentToLesson: The junction model carrying the student_id and lesson_id for each MToM relation between Students and Lessons. After setting these classes up using this project, MToM operations can be done easily: ```php @@ -42,7 +42,7 @@ $studentHarry->addLesson($lessonGeography); $lessonBiology = (new Lesson($persistence))->createEntity(); $lessonBiology->set('name', 'Biology'); $lessonBiology->save(); -//adding/removing can either be done by passong the other model or only it's ID. In this case, we just pass the ID +//adding/removing can either be done by passing the other model or only it's ID. In this case, we just pass the ID - that's what you typically get from UI $studentHarry->addLesson($lessonBiology->getId()); //this created another StudentToLesson record with student_id = studentHarry's ID and lesson_id = lessonBiology's ID @@ -53,4 +53,16 @@ $studentHarry->hasLesson($lessonGeography); //true; $studentHarry->removeLesson($lessonGeography); //this removed the StudentToLesson Record linking Harry to Geography. $studentHarry->hasLesson($lessonGeography); //false -``` \ No newline at end of file + +//Linda attends both courses. Let's add Linda to both courses. But this time we do it the other way around: We use Lesson's helper functions: +$studentLinda = (new Student($persistence))->createEntity(); +$studentLinda->set('name', 'Linda'); +$studentLinda->save(); +$lessonGeography->addStudent($studentLinda); +$lessonBiology->addStudent($studentLinda); +``` + +The sample code from this readme can be found in the `docs` directory. + +# Versioning +The version numbers of this repository correspond with the atk4\data versions. So 4.0.x is compatible with atk4\data 4.0.x and so on. diff --git a/docs/sample.php b/docs/sample.php index f86529e..a73bf0e 100644 --- a/docs/sample.php +++ b/docs/sample.php @@ -1,9 +1,10 @@ createEntity(); $studentHarry->set('name', 'Harry'); @@ -20,7 +21,7 @@ $lessonBiology = (new Lesson($persistence))->createEntity(); $lessonBiology->set('name', 'Biology'); $lessonBiology->save(); -//adding/removing can either be done by passong the other model or only it's ID. In this case, we just pass the ID +//adding/removing can either be done by passing the other model or only it's ID. In this case, we just pass the ID - that's what you typically get from UI $studentHarry->addLesson($lessonBiology->getId()); //this created another StudentToLesson record with student_id = studentHarry's ID and lesson_id = lessonBiology's ID @@ -30,4 +31,11 @@ //harry is tired of Geography, lets remove him from this lesson: $studentHarry->removeLesson($lessonGeography); //this removed the StudentToLesson Record linking Harry to Geography. -$studentHarry->hasLesson($lessonGeography); //false \ No newline at end of file +$studentHarry->hasLesson($lessonGeography); //false + +//Linda attends both courses. Let's add Linda to both courses. But this time we do it the other way around: We use Lesson's helper functions: +$studentLinda = (new Student($persistence))->createEntity(); +$studentLinda->set('name', 'Linda'); +$studentLinda->save(); +$lessonGeography->addStudent($studentLinda); +$lessonBiology->addStudent($studentLinda); diff --git a/src/IntermediateModel.php b/src/JunctionModel.php similarity index 92% rename from src/IntermediateModel.php rename to src/JunctionModel.php index 40c3de9..7c9e572 100644 --- a/src/IntermediateModel.php +++ b/src/JunctionModel.php @@ -6,7 +6,7 @@ use Atk4\Data\Model; -abstract class IntermediateModel extends Model +abstract class JunctionModel extends Model { /** @@ -88,7 +88,7 @@ public function getReferencedEntity(string $className): Model /** - * used by ModelWithMToMTrait to make records available in getReferencedEntity() without extra DB request + * used by MToMTrait to make records available in getReferencedEntity() without extra DB request * * @param Model $entity * @return void @@ -108,7 +108,7 @@ public function addReferencedEntity(Model $entity): void /** - * used by ModelWithMToMTrait to get the correct field name that corresponds to one of the linked Models + * used by MToMTrait to get the correct field name that corresponds to one of the linked Models * * @param Model $model * @return string @@ -142,7 +142,7 @@ public function addConditionForModel(Model $entity): void /** - * We will have 2 Model classes defined which the MToMModel will connect. This function returns the class name of + * We have 2 Model classes defined which the JunctionModel will connect. This function returns the class name of * the other class if one is passed * * @param Model $model diff --git a/src/MToMTait.php b/src/MToMTait.php index d616077..1c27170 100644 --- a/src/MToMTait.php +++ b/src/MToMTait.php @@ -17,18 +17,18 @@ trait MToMTait * Create a new MToM relation, e.g. a new StudentToLesson record. Called from either Student or Lesson class. * First checks if record does exist already, and only then adds new relation. * - * @param IntermediateModel $mToMModel + * @param JunctionModel $mToMModel * @param int|Model $otherEntity //if int, then it's only an ID * @param array $additionalFields - * @return IntermediateModel + * @return JunctionModel * @throws Exception * @throws \Atk4\Core\Exception */ public function addMToMRelation( - IntermediateModel $mToMModel, + JunctionModel $mToMModel, int|Model $otherEntity, array $additionalFields = [] - ): IntermediateModel { + ): JunctionModel { //$this needs to be loaded to get ID $this->assertIsLoaded(); $otherEntity = $this->getOtherEntity($otherEntity, $mToMModel); @@ -60,12 +60,12 @@ public function addMToMRelation( * method used to remove a MToMModel record like StudentToLesson. Either used from Student or Lesson class. * GuestToGroup etc. * - * @param IntermediateModel $mToMModel + * @param JunctionModel $mToMModel * @param int|Model $otherEntity //if int, then it's only an ID - * @return IntermediateModel + * @return JunctionModel * @throws Exception */ - public function removeMToMRelation(IntermediateModel $mToMModel, int|Model $otherEntity): IntermediateModel + public function removeMToMRelation(JunctionModel $mToMModel, int|Model $otherEntity): JunctionModel { //$this needs to be loaded to get ID $this->assertIsLoaded(); @@ -85,12 +85,12 @@ public function removeMToMRelation(IntermediateModel $mToMModel, int|Model $othe * checks if a MtoM reference to the given entity exists or not, e.g. if a StudentToLesson record exists for a * specific student and lesson * - * @param IntermediateModel $mToMModel + * @param JunctionModel $mToMModel * @param int|Model $otherEntity //if int, then it's only an ID * @return bool * @throws Exception */ - public function hasMToMRelation(IntermediateModel $mToMModel, int|Model $otherEntity): bool + public function hasMToMRelation(JunctionModel $mToMModel, int|Model $otherEntity): bool { $this->assertIsLoaded(); $otherEntity = $this->getOtherEntity($otherEntity, $mToMModel); @@ -103,12 +103,12 @@ public function hasMToMRelation(IntermediateModel $mToMModel, int|Model $otherEn } /** - * 1) adds HasMany Reference to intermediate model. - * 2) adds after delete hook which deletes any intermediate model linked to the deleted "main" model. - * This way, no outdated intermediate models exist. + * 1) adds HasMany Reference linking the junction model. + * 2) adds after delete hook which deletes any junctions models linked to the deleted "main" model. + * This way, no outdated junction models exist. * Returns HasMany reference for further modifying reference if needed. * - * @param class-string $mtomClassName + * @param class-string $mtomClassName * @param string $referenceName * @param array $referenceDefaults * @param array $mtomClassDefaults @@ -157,11 +157,11 @@ function ($model) use ($referenceName): void { * Check other model is loaded so id can be gotten. * * @param int|Model $otherEntity //if int, then it's only an ID - * @param IntermediateModel $mToMModel + * @param JunctionModel $mToMModel * @return Model * @throws Exception */ - protected function getOtherEntity(int|Model $otherEntity, IntermediateModel $mToMModel): Model + protected function getOtherEntity(int|Model $otherEntity, JunctionModel $mToMModel): Model { $otherModelClass = $mToMModel->getOtherModelClass($this); if (is_object($otherEntity)) { diff --git a/tests/IntermediateModelTest.php b/tests/IntermediateModelTest.php index e091a83..6a71ae4 100644 --- a/tests/IntermediateModelTest.php +++ b/tests/IntermediateModelTest.php @@ -5,7 +5,7 @@ use Atk4\Data\Exception; use Atk4\Data\Model; use atkextendedtestcase\TestCase; -use PhilippR\Atk4\MToM\IntermediateModel; +use PhilippR\Atk4\MToM\JunctionModel; use PhilippR\Atk4\MToM\Tests\Testmodels\Lesson; use PhilippR\Atk4\MToM\Tests\Testmodels\Student; use PhilippR\Atk4\MToM\Tests\Testmodels\StudentToLesson; @@ -13,7 +13,7 @@ use ReflectionClass; -class MToMModelTest extends TestCase +class IntermediateModelTest extends TestCase { protected array $sqlitePersistenceModels = [ Student::class, @@ -34,7 +34,7 @@ public function testInit(): void public function testExceptionMoreThanTwoElementsInFieldNamesForReferencedClasses(): void { $persistence = $this->getSqliteTestPersistence(); - $someClassWith3Elements = new class() extends IntermediateModel { + $someClassWith3Elements = new class() extends JunctionModel { protected array $relationFieldNames = [ 'field1' => 'Blabla', 'field2' => 'DaDa', @@ -48,7 +48,7 @@ public function testExceptionMoreThanTwoElementsInFieldNamesForReferencedClasses public function testExceptionLessThanTwoElementsInFieldNamesForReferencedClasses(): void { $persistence = $this->getSqliteTestPersistence(); - $someClassWith1Element = new class() extends IntermediateModel { + $someClassWith1Element = new class() extends JunctionModel { protected array $relationFieldNames = [ 'field1' => 'Blabla' ]; @@ -60,7 +60,7 @@ public function testExceptionLessThanTwoElementsInFieldNamesForReferencedClasses public function testExceptionInvalidClassInFieldNamesForReferencedClasses(): void { $persistence = $this->getSqliteTestPersistence(); - $someClassWithInvalidClassDefinition = new class() extends IntermediateModel { + $someClassWithInvalidClassDefinition = new class() extends JunctionModel { protected array $relationFieldNames = [ 'field1' => Student::class, 'field2' => 'SomeNonExistantModel' @@ -203,7 +203,7 @@ public function testAddReferencedEntityExceptionInvalidModelClassGiven(): void $teacher = (new Teacher($persistence))->createEntity(); $teacher->save(); self::expectExceptionMessage( - 'This PhilippR\Atk4\MToM\MToMModel does not have a reference to mtomforatk\tests\Testmodels\Teacher' + 'This PhilippR\Atk4\MToM\JunctionModel does not have a reference to PhilippR\Atk4\MToM\Tests\Testmodels\Teacher' ); $studentToLesson->addReferencedEntity($teacher); } diff --git a/tests/Testmodels/Lesson.php b/tests/Testmodels/Lesson.php index d938e18..8a44ab9 100644 --- a/tests/Testmodels/Lesson.php +++ b/tests/Testmodels/Lesson.php @@ -22,4 +22,19 @@ protected function init(): void $this->addMToMReferenceAndDeleteHook(StudentToLesson::class); $this->addMToMReferenceAndDeleteHook(TeacherToLesson::class); } + + public function addStudent($student, array $additionalFields = []): StudentToLesson + { + return $this->addMToMRelation(new StudentToLesson($this->getPersistence()), $student, $additionalFields); + } + + public function removeStudent($student): StudentToLesson + { + return $this->removeMToMRelation(new StudentToLesson($this->getPersistence()), $student); + } + + public function hasStudent($student): bool + { + return $this->hasMToMRelation(new StudentToLesson($this->getPersistence()), $student); + } } diff --git a/tests/Testmodels/StudentToLesson.php b/tests/Testmodels/StudentToLesson.php index cfc3cf3..f327196 100644 --- a/tests/Testmodels/StudentToLesson.php +++ b/tests/Testmodels/StudentToLesson.php @@ -2,9 +2,9 @@ namespace PhilippR\Atk4\MToM\Tests\Testmodels; -use PhilippR\Atk4\MToM\IntermediateModel; +use PhilippR\Atk4\MToM\JunctionModel; -class StudentToLesson extends IntermediateModel +class StudentToLesson extends JunctionModel { public $table = 'student_to_lesson'; diff --git a/tests/Testmodels/TeacherToLesson.php b/tests/Testmodels/TeacherToLesson.php index 6cb6de0..614e39e 100644 --- a/tests/Testmodels/TeacherToLesson.php +++ b/tests/Testmodels/TeacherToLesson.php @@ -2,10 +2,10 @@ namespace PhilippR\Atk4\MToM\Tests\Testmodels; -use PhilippR\Atk4\MToM\IntermediateModel; +use PhilippR\Atk4\MToM\JunctionModel; -class TeacherToLesson extends IntermediateModel +class TeacherToLesson extends JunctionModel { public $table = 'teacher_to_lesson';