diff --git a/composer.json b/composer.json index afb9af6e0..d78757da5 100644 --- a/composer.json +++ b/composer.json @@ -37,20 +37,20 @@ "php": ">=7.4 <8.2", "atk4/core": "dev-develop", "doctrine/dbal": "^3.3", - "mvorisek/atk4-hintable": "~1.7.1" + "mvorisek/atk4-hintable": "~1.8.0" }, "require-release": { "php": ">=7.4 <8.2", "atk4/core": "~3.2.0", "doctrine/dbal": "^3.3", - "mvorisek/atk4-hintable": "~1.7.1" + "mvorisek/atk4-hintable": "~1.8.0" }, "require-dev": { "ergebnis/composer-normalize": "^2.13", "friendsofphp/php-cs-fixer": "^3.0", "johnkary/phpunit-speedtrap": "^3.3", "phpstan/extension-installer": "^1.1", - "phpstan/phpstan": "^1.0", + "phpstan/phpstan": "^1.6", "phpstan/phpstan-deprecation-rules": "^1.0", "phpunit/phpunit": "^9.5.5" }, diff --git a/docs/advanced.rst b/docs/advanced.rst index 839d13dbc..7ae72f7ff 100644 --- a/docs/advanced.rst +++ b/docs/advanced.rst @@ -166,7 +166,7 @@ which I want to define like this:: $this->getOwner()->addField('updated_dts', ['type' => 'datetime']); - $this->getOwner()->onHook(Model::HOOK_BEFORE_UPDATE, function($m, $data) { + $this->getOwner()->onHook(Model::HOOK_BEFORE_UPDATE, function ($m, $data) { if(isset($this->getApp()->user) && $this->getApp()->user->isLoaded()) { $data['updated_by'] = $this->getApp()->user->getId(); } @@ -440,7 +440,7 @@ inside your model are unique:: $mm->addCondition($mm->id_field != $this->id); $mm = $mm->tryLoadBy($field, $m->get($field)); - if ($mm->isLoaded()) { + if ($mm !== null) { throw (new \Atk4\Core\Exception('Duplicate record exists')) ->addMoreInfo('field', $field) ->addMoreInfo('value', $m->get($field)); @@ -514,7 +514,7 @@ Next we need to define reference. Inside Model_Invoice add:: $this->hasMany('InvoicePayment'); - $this->hasMany('Payment', ['model' => function($m) { + $this->hasMany('Payment', ['model' => function ($m) { $p = new Model_Payment($m->persistence); $j = $p->join('invoice_payment.payment_id'); $j->addField('amount_closed'); @@ -570,24 +570,23 @@ payment towards a most suitable invoice:: while($this->get('amount_due') > 0) { - // See if any invoices match by 'reference'; - $invoices = $invoices->tryLoadBy('reference', $this->get('reference')); + // see if any invoices match by 'reference' + $invoice = $invoices->tryLoadBy('reference', $this->get('reference')); - if (!$invoices->isLoaded()) { + if ($invoice === null) { // otherwise load any unpaid invoice - $invoices = $invoices->tryLoadAny(); + $invoice = $invoices->tryLoadAny(); - if(!$invoices->isLoaded()) { - - // couldn't load any invoice. + if ($invoice === null) { + // couldn't load any invoice return; } } // How much we can allocate to this invoice - $alloc = min($this->get('amount_due'), $invoices->get('amount_due')) - $this->ref('InvoicePayment')->insert(['amount_closed' => $alloc, 'invoice_id' => $invoices->getId()]); + $alloc = min($this->get('amount_due'), $invoice->get('amount_due')) + $this->ref('InvoicePayment')->insert(['amount_closed' => $alloc, 'invoice_id' => $invoice->getId()]); // Reload ourselves to refresh amount_due $this->reload(); @@ -744,7 +743,7 @@ section. Add this into your Invoice Model:: Next both payment and lines need to be added after invoice is actually created, so:: - $this->onHookShort(Model::HOOK_AFTER_SAVE, function($is_update) { + $this->onHookShort(Model::HOOK_AFTER_SAVE, function ($is_update) { if($this->_isset('payment')) { $this->ref('Payment')->insert($this->get('payment')); } @@ -800,7 +799,7 @@ field only to offer payments made by the same client. Inside Model_Invoice add:: $this->hasOne('client_id', 'Client'); - $this->hasOne('payment_invoice_id', ['model' => function($m) { + $this->hasOne('payment_invoice_id', ['model' => function ($m) { return $m->ref('client_id')->ref('Payment'); }]); @@ -809,13 +808,13 @@ field only to offer payments made by the same client. Inside Model_Invoice add:: $m = new Model_Invoice($db); $m->set('client_id', 123); - $m->set('payment_invoice_id', $m->ref('payment_invoice_id')->tryLoadOne()->getId()); + $m->set('payment_invoice_id', $m->ref('payment_invoice_id')->loadOne()->getId()); In this case the payment_invoice_id will be set to ID of any payment by client 123. There also may be some better uses:: foreach ($cl->ref('Invoice') as $m) { - $m->set('payment_invoice_id', $m->ref('payment_invoice_id')->tryLoadOne()->getId()); + $m->set('payment_invoice_id', $m->ref('payment_invoice_id')->loadOne()->getId()); $m->save(); } @@ -826,7 +825,7 @@ Agile Data allow you to define multiple references between same entities, but sometimes that can be quite useful. Consider adding this inside your Model_Contact:: $this->hasMany('Invoice', 'Model_Invoice'); - $this->hasMany('OverdueInvoice', ['model' => function($m) { + $this->hasMany('OverdueInvoice', ['model' => function ($m) { return $m->ref('Invoice')->addCondition('due', '<', date('Y-m-d')) }]); diff --git a/docs/hooks.rst b/docs/hooks.rst index 6f5e5f7de..973dedefa 100644 --- a/docs/hooks.rst +++ b/docs/hooks.rst @@ -52,7 +52,7 @@ Example with beforeSave The next code snippet demonstrates a basic usage of a `beforeSave` hook. This one will update field values just before record is saved:: - $m->onHook(Model::HOOK_BEFORE_SAVE, function($m) { + $m->onHook(Model::HOOK_BEFORE_SAVE, function ($m) { $m->set('name', strtoupper($m->get('name'))); $m->set('surname', strtoupper($m->get('surname'))); }); @@ -136,7 +136,7 @@ of save. You may actually drop validation exception inside save, insert or update hooks:: - $m->onHook(Model::HOOK_BEFORE_SAVE, function($m) { + $m->onHook(Model::HOOK_BEFORE_SAVE, function ($m) { if ($m->get('name') === 'Yagi') { throw new \Atk4\Data\ValidationException(['name' => "We don't serve like you"]); } @@ -193,7 +193,7 @@ and your update() may not actually update anything. This does not normally generate an error, however if you want to actually make sure that update() was effective, you can implement this through a hook:: - $m->onHook(Persistence\Sql::HOOK_AFTER_UPDATE_QUERY, function($m, $update, $c) { + $m->onHook(Persistence\Sql::HOOK_AFTER_UPDATE_QUERY, function ($m, $update, $c) { if ($c === 0) { throw (new \Atk4\Core\Exception('Update didn\'t affect any records')) ->addMoreInfo('query', $update->getDebugQuery()) @@ -210,7 +210,7 @@ In some cases you want to prevent default actions from executing. Suppose you want to check 'memcache' before actually loading the record from the database. Here is how you can implement this functionality:: - $m->onHook(Model::HOOK_BEFORE_LOAD, function($m, $id) { + $m->onHook(Model::HOOK_BEFORE_LOAD, function ($m, $id) { $data = $m->getApp()->cacheFetch($m->table, $id); if ($data) { $dataRef = &$m->getDataRef(); @@ -237,7 +237,7 @@ This can be used in various situations. Save information into auditLog about failure: - $m->onHook(Model::HOOK_ROLLBACK, function($m) { + $m->onHook(Model::HOOK_ROLLBACK, function ($m) { $m->auditLog->registerFailure(); }); @@ -245,7 +245,7 @@ Upgrade schema: use Atk4\Data\Persistence\Sql\Exception as SqlException; - $m->onHook(Model::HOOK_ROLLBACK, function($m, $exception) { + $m->onHook(Model::HOOK_ROLLBACK, function ($m, $exception) { if ($exception instanceof SqlException) { $m->schema->upgrade(); $m->breakHook(false); // exception will not be thrown diff --git a/docs/model.rst b/docs/model.rst index cba1aed7e..3852d11ee 100644 --- a/docs/model.rst +++ b/docs/model.rst @@ -180,7 +180,7 @@ To invoke code from `init()` methods of ALL models (for example soft-delete logi you use Persistence's "afterAdd" hook. This will not affect ALL models but just models which are associated with said persistence:: - $db->onHook(Persistence::HOOK_AFTER_ADD, function($p, $m) use($acl) { + $db->onHook(Persistence::HOOK_AFTER_ADD, function ($p, $m) use ($acl) { $fields = $m->getFields(); diff --git a/docs/overview.rst b/docs/overview.rst index 06586d2a8..9a5a44e37 100644 --- a/docs/overview.rst +++ b/docs/overview.rst @@ -166,7 +166,7 @@ If your persistence does not support expressions (e.g. you are using Redis or MongoDB), you would need to define the field differently:: $model->addField('gross'); - $model->onHook(Model::HOOK_BEFORE_SAVE, function($m) { + $model->onHook(Model::HOOK_BEFORE_SAVE, function ($m) { $m->set('gross', $m->get('net') + $m->get('vat')); }); @@ -186,7 +186,7 @@ you want it to work with NoSQL, then your solution might be:: // persistence does not support expressions $model->addField('gross'); - $model->onHook(Model::HOOK_BEFORE_SAVE, function($m) { + $model->onHook(Model::HOOK_BEFORE_SAVE, function ($m) { $m->set('gross', $m->get('net') + $m->get('vat')); }); diff --git a/docs/persistence.rst b/docs/persistence.rst index 708925a3b..fb6f75aee 100644 --- a/docs/persistence.rst +++ b/docs/persistence.rst @@ -66,7 +66,7 @@ There are several ways to link your model up with the persistence:: .. php:method:: tryLoad - Same as load() but will silently fail if record is not found:: + Same as load() but will return null if record is not found:: $m = $m->tryLoad(10); $m->setMulti($data); @@ -482,7 +482,7 @@ Start by creating a beforeSave handler for Order:: ->addCondition('client_id', $this->get('client_id')) // same client ->addCondition($this->id_field, '!=', $this->getId()) // has another order ->tryLoadBy('ref', $this->get('ref')) // with same ref - ->isLoaded() + !== null ) { throw (new Exception('Order with ref already exists for this client')) ->addMoreInfo('client', $this->get('client_id')) @@ -580,8 +580,7 @@ application:: // first, try to load it from MemCache $m = $this->mdb->add(clone $class)->tryLoad($id); - if (!$m->isLoaded()) { - + if ($m === null) { // fall-back to load from SQL $m = $this->sql->add(clone $class)->load($id); @@ -589,11 +588,11 @@ application:: $m = $m->withPersistence($this->mdb)->save(); } - $m->onHook(Model::HOOK_BEFORE_SAVE, function($m) { + $m->onHook(Model::HOOK_BEFORE_SAVE, function ($m) { $m->withPersistence($this->sql)->save(); }); - $m->onHook(Model::HOOK_BEFORE_DELETE, function($m) { + $m->onHook(Model::HOOK_BEFORE_DELETE, function ($m) { $m->withPersistence($this->sql)->delete(); }); @@ -618,8 +617,7 @@ use a string). It will first be associated with the MemCache DB persistence and we will attempt to load a corresponding ID. Next, if no record is found in the cache:: - if (!$m->isLoaded()) { - + if ($m === null) { // fall-back to load from SQL $m = $this->sql->add(clone $class)->load($id); @@ -634,11 +632,11 @@ records. The last two hooks are in order to replicate any changes into the SQL database also:: - $m->onHook(Model::HOOK_BEFORE_SAVE, function($m) { + $m->onHook(Model::HOOK_BEFORE_SAVE, function ($m) { $m->withPersistence($this->sql)->save(); }); - $m->onHook(Model::HOOK_BEFORE_DELETE, function($m) { + $m->onHook(Model::HOOK_BEFORE_DELETE, function ($m) { $m->withPersistence($this->sql)->delete(); }); @@ -690,7 +688,7 @@ Archive Copies into different persistence If you wish that every time you save your model the copy is also stored inside some other database (for archive purposes) you can implement it like this:: - $m->onHook(Model::HOOK_BEFORE_SAVE, function($m) { + $m->onHook(Model::HOOK_BEFORE_SAVE, function ($m) { $arc = $this->withPersistence($m->getApp()->archive_db, false); // add some audit fields diff --git a/docs/references.rst b/docs/references.rst index 5ab1c43e3..a38fd5e80 100644 --- a/docs/references.rst +++ b/docs/references.rst @@ -106,7 +106,7 @@ There are several ways how to link models with hasMany:: $m->hasMany('Orders', ['model' => [Model_Order::class]]); // using seed - $m->hasMany('Order', ['model' => function($m, $r) { // using callback + $m->hasMany('Order', ['model' => function ($m, $r) { // using callback return new Model_Order(); }]); @@ -433,7 +433,7 @@ User-defined Reference Sometimes you would want to have a different type of relation between models, so with `addRef` you can define whatever reference you want:: - $m->addRef('Archive', ['model' => function($m) { + $m->addRef('Archive', ['model' => function ($m) { return $m->newInstance(null, ['table' => $m->table . '_archive']); }]); @@ -447,7 +447,7 @@ Note that you can create one-to-many or many-to-one relations, by using your custom logic. No condition will be applied by default so it's all up to you:: - $m->addRef('Archive', ['model' => function($m) { + $m->addRef('Archive', ['model' => function ($m) { $archive = $m->newInstance(null, ['table' => $m->table . '_archive']); $m->addField('original_id', ['type' => 'integer']); diff --git a/docs/types.rst b/docs/types.rst index 12f4c1af8..11d17609e 100644 --- a/docs/types.rst +++ b/docs/types.rst @@ -92,7 +92,7 @@ ATK Data prior to 1.5 supports the following types: In ATK Data the number of supported types has been extended with: - - percent (34.2%) ([':php:class:`Number`', 'format' => function($v) { return $v * 100; }, 'postfix' => '%']) + - percent (34.2%) ([':php:class:`Number`', 'format' => function ($v) { return $v * 100; }, 'postfix' => '%']) - rating (3 out of 5) ([':php:class:`Number`', 'max' => 5, 'precision' => 0]) - uuid (xxxxxxxx-xxxx-...) ([':php:class:`Number`', 'base' => 16, 'mask' => '########-##..']) - hex (number with base 16) ([':php:class:`Number`', 'base' => 16]) diff --git a/src/Model.php b/src/Model.php index e9d6e1a0a..39af6a94e 100644 --- a/src/Model.php +++ b/src/Model.php @@ -91,9 +91,9 @@ class Model implements \IteratorAggregate public const HOOK_ONLY_FIELDS = self::class . '@onlyFields'; /** @const string */ - protected const ID_LOAD_ONE = self::class . '@idLoadOne'; + protected const ID_LOAD_ONE = self::class . '@idLoadOne-h7axmDNBB3qVXjVv'; /** @const string */ - protected const ID_LOAD_ANY = self::class . '@idLoadAny'; + protected const ID_LOAD_ANY = self::class . '@idLoadAny-h7axmDNBB3qVXjVv'; // {{{ Properties of the class @@ -1234,9 +1234,9 @@ private function remapIdLoadToPersistence($id) /** * @param mixed $id * - * @return $this + * @return ($fromTryLoad is true ? $this|null : $this) */ - private function _loadThis(bool $isTryLoad, $id) + private function _loadThis(bool $fromTryLoad, $id) { $this->assertIsEntity(); if ($this->isLoaded()) { @@ -1250,21 +1250,27 @@ private function _loadThis(bool $isTryLoad, $id) return $this; } $dataRef = &$this->getDataRef(); - $dataRef = $this->persistence->{$isTryLoad ? 'tryLoad' : 'load'}($this->getModel(), $this->remapIdLoadToPersistence($id)); - if ($isTryLoad && $dataRef === null) { - $dataRef = []; - $this->unload(); - } else { - if ($this->id_field) { - $this->setId($this->getId()); - } + $dataRef = $this->persistence->{$fromTryLoad ? 'tryLoad' : 'load'}($this->getModel(), $this->remapIdLoadToPersistence($id)); - $ret = $this->hook(self::HOOK_AFTER_LOAD); - if ($ret === false) { - $this->unload(); - } elseif (is_object($ret)) { - return $ret; // @phpstan-ignore-line + if ($dataRef === null) { + // $fromTryLoad is always true here + + return null; + } + + if ($this->id_field) { + $this->setId($this->getId()); + } + + $ret = $this->hook(self::HOOK_AFTER_LOAD); + if ($ret === false) { + if ($fromTryLoad) { + return null; } + + $this->unload(); + } elseif (is_object($ret)) { + return $ret; // @phpstan-ignore-line } return $this; diff --git a/src/Reference/ContainsOne.php b/src/Reference/ContainsOne.php index 2ec837cb9..5987ed002 100644 --- a/src/Reference/ContainsOne.php +++ b/src/Reference/ContainsOne.php @@ -94,7 +94,14 @@ public function ref(Model $ourModel, array $defaults = []): Model }); } - $theirModel = $theirModel->tryLoadOne(); + if ($ourModel->isEntity()) { + $theirModelOrig = $theirModel; + $theirModel = $theirModel->tryLoadOne(); + + if ($theirModel === null) { // TODO or implement tryRef? + $theirModel = $theirModelOrig->createEntity(); + } + } return $theirModel; } diff --git a/src/Reference/HasOne.php b/src/Reference/HasOne.php index 9e6d83101..a5787acd3 100644 --- a/src/Reference/HasOne.php +++ b/src/Reference/HasOne.php @@ -91,11 +91,16 @@ public function ref(Model $ourModel, array $defaults = []): Model $ourValue = $this->getOurFieldValue($ourModel); $this->assertReferenceValueNotNull($ourValue); + $theirModelOrig = $theirModel; if ($this->their_field) { $theirModel = $theirModel->tryLoadBy($this->their_field, $ourValue); } else { $theirModel = $theirModel->tryLoad($ourValue); } + + if ($theirModel === null) { // TODO or implement tryRef? + $theirModel = $theirModelOrig->createEntity(); + } } // their model will be reloaded after saving our model to reflect changes in referenced fields diff --git a/src/Util/DeepCopy.php b/src/Util/DeepCopy.php index 056bae74a..e08d01d91 100644 --- a/src/Util/DeepCopy.php +++ b/src/Util/DeepCopy.php @@ -43,7 +43,7 @@ class DeepCopy /** * @var array contains array similar to references but containing list of callback methods to transform fields/values: - * e.g. ['Invoices' => ['Lines' => function($data) { + * e.g. ['Invoices' => ['Lines' => function ($data) { * $data['exchanged_amount'] = $data['amount'] * getExRate($data['date'], $data['currency']); * return $data; * }]] @@ -112,12 +112,12 @@ public function excluding(array $exclusions) * May also contain arrays for related entries. * * ->transformData( - * [function($data) { // for Client entity + * [function ($data) { // for Client entity * $data['name'] => $data['last_name'] . ' ' . $data['first_name']; * unset($data['first_name'], $data['last_name']); * return $data; * }], - * 'Invoices' => ['Lines' => function($data) { // for nested Client->Invoices->Lines hasMany entity + * 'Invoices' => ['Lines' => function ($data) { // for nested Client->Invoices->Lines hasMany entity * $data['exchanged_amount'] = $data['amount'] * getExRate($data['date'], $data['currency']); * return $data; * }] diff --git a/tests/ConditionSqlTest.php b/tests/ConditionSqlTest.php index e6a4c1938..ecac3bb7a 100644 --- a/tests/ConditionSqlTest.php +++ b/tests/ConditionSqlTest.php @@ -33,7 +33,7 @@ public function testBasic(): void $mm2 = $mm->tryLoad(1); $this->assertSame('John', $mm2->get('name')); $mm2 = $mm->tryLoad(2); - $this->assertNull($mm2->get('name')); + $this->assertNull($mm2); if ($this->getDatabasePlatform() instanceof SqlitePlatform) { $this->assertSame( @@ -43,9 +43,9 @@ public function testBasic(): void } $mm = clone $m; - $mm->withId(2); // = addCondition(id, 2) + $mm->withId(2); // = addCondition('id', 2) $mm2 = $mm->tryLoad(1); - $this->assertNull($mm2->get('name')); + $this->assertNull($mm2); $mm2 = $mm->tryLoad(2); $this->assertSame('Sue', $mm2->get('name')); } @@ -130,19 +130,19 @@ public function testOperations(): void $mm2 = $mm->tryLoad(1); $this->assertSame('John', $mm2->get('name')); $mm2 = $mm->tryLoad(2); - $this->assertNull($mm2->get('name')); + $this->assertNull($mm2); $mm = clone $m; $mm->addCondition('gender', '!=', 'M'); $mm2 = $mm->tryLoad(1); - $this->assertNull($mm2->get('name')); + $this->assertNull($mm2); $mm2 = $mm->tryLoad(2); $this->assertSame('Sue', $mm2->get('name')); $mm = clone $m; $mm->addCondition('id', '>', 1); $mm2 = $mm->tryLoad(1); - $this->assertNull($mm2->get('name')); + $this->assertNull($mm2); $mm2 = $mm->tryLoad(2); $this->assertSame('Sue', $mm2->get('name')); @@ -151,7 +151,7 @@ public function testOperations(): void $mm2 = $mm->tryLoad(1); $this->assertSame('John', $mm2->get('name')); $mm2 = $mm->tryLoad(2); - $this->assertNull($mm2->get('name')); + $this->assertNull($mm2); } public function testExpressions1(): void @@ -174,14 +174,14 @@ public function testExpressions1(): void $mm = clone $m; $mm->addCondition($mm->expr('[] > 1', [$mm->getField('id')])); $mm2 = $mm->tryLoad(1); - $this->assertNull($mm2->get('name')); + $this->assertNull($mm2); $mm2 = $mm->tryLoad(2); $this->assertSame('Sue', $mm2->get('name')); $mm = clone $m; $mm->addCondition($mm->expr('[id] > 1')); $mm2 = $mm->tryLoad(1); - $this->assertNull($mm2->get('name')); + $this->assertNull($mm2); $mm2 = $mm->tryLoad(2); $this->assertSame('Sue', $mm2->get('name')); } @@ -206,14 +206,14 @@ public function testExpressions2(): void $mm = clone $m; $mm->addCondition($mm->expr('[name] = [surname]')); $mm2 = $mm->tryLoad(1); - $this->assertNull($mm2->get('name')); + $this->assertNull($mm2); $mm2 = $mm->tryLoad(2); $this->assertSame('Sue', $mm2->get('name')); $mm = clone $m; $mm->addCondition($m->getField('name'), $m->getField('surname')); $mm2 = $mm->tryLoad(1); - $this->assertNull($mm2->get('name')); + $this->assertNull($mm2); $mm2 = $mm->tryLoad(2); $this->assertSame('Sue', $mm2->get('name')); @@ -222,14 +222,14 @@ public function testExpressions2(): void $mm2 = $mm->tryLoad(1); $this->assertSame('John', $mm2->get('name')); $mm2 = $mm->tryLoad(2); - $this->assertNull($mm2->get('name')); + $this->assertNull($mm2); $mm = clone $m; $mm->addCondition($m->getField('name'), '!=', $m->getField('surname')); $mm2 = $mm->tryLoad(1); $this->assertSame('John', $mm2->get('name')); $mm2 = $mm->tryLoad(2); - $this->assertNull($mm2->get('name')); + $this->assertNull($mm2); } public function testExpressionJoin(): void @@ -264,12 +264,12 @@ public function testExpressionJoin(): void $mm = clone $m; $mm->addCondition($mm->expr('[name] = [surname]')); $mm2 = $mm->tryLoad(1); - $this->assertFalse($mm2->isLoaded()); + $this->assertNull($mm2); $mm2 = $mm->tryLoad(2); $this->assertSame('Sue', $mm2->get('name')); $this->assertSame('+321 sues', $mm2->get('contact_phone')); $mm2 = $mm->tryLoad(3); - $this->assertFalse($mm2->isLoaded()); + $this->assertNull($mm2); $mm = clone $m; $mm->addCondition($mm->expr('\'+123 smiths\' = [contact_phone]')); @@ -277,8 +277,7 @@ public function testExpressionJoin(): void $this->assertSame('John', $mm2->get('name')); $this->assertSame('+123 smiths', $mm2->get('contact_phone')); $mm2 = $mm->tryLoad(2); - $this->assertNull($mm2->get('name')); - $this->assertNull($mm2->get('contact_phone')); + $this->assertNull($mm2); $mm2 = $mm->tryLoad(3); $this->assertSame('Peter', $mm2->get('name')); $this->assertSame('+123 smiths', $mm2->get('contact_phone')); diff --git a/tests/ContainsManyTest.php b/tests/ContainsManyTest.php index e17e1de12..2948681ae 100644 --- a/tests/ContainsManyTest.php +++ b/tests/ContainsManyTest.php @@ -4,9 +4,9 @@ namespace Atk4\Data\Tests; -use Atk4\Data\Exception; use Atk4\Data\Schema\TestCase; use Atk4\Data\Tests\ContainsMany\Invoice; +use Atk4\Data\Tests\ContainsMany\Line; use Atk4\Data\Tests\ContainsMany\VatRate; /** @@ -75,16 +75,16 @@ public function testModelCaption(): void $this->assertSame('My Invoice Lines', $i->lines->getModelCaption()); } - /** - * Test containsMany. - */ public function testContainsMany(): void { $i = new Invoice($this->db); $i = $i->loadBy($i->fieldName()->ref_no, 'A1'); + $this->assertSame(Line::class, get_class($i->getModel()->lines)); + // now let's add some lines $l = $i->lines; + $this->assertNotNull($l); $rows = [ 1 => [ $l->fieldName()->id => 1, @@ -172,18 +172,6 @@ public function testContainsMany(): void $this->assertSame(10 * 2 * (1 + 21 / 100) + 40 * 1 * (1 + 21 / 100) + 50 * 3 * (1 + 15 / 100), $i->total_gross); // = 245.1 } - /** - * Model should be loaded before traversing to containsMany relation. - */ - /* Imants: it looks that this is not actually required - disabling - public function testEx1(): void - { - $i = new Invoice($this->db); - $this->expectException(Exception::class); - $i->lines; - } - */ - /** * Nested containsMany tests. */ diff --git a/tests/ContainsOneTest.php b/tests/ContainsOneTest.php index 3508e0ee7..35fed6dc9 100644 --- a/tests/ContainsOneTest.php +++ b/tests/ContainsOneTest.php @@ -4,9 +4,10 @@ namespace Atk4\Data\Tests; -use Atk4\Data\Exception; use Atk4\Data\Schema\TestCase; +use Atk4\Data\Tests\ContainsOne\Address; use Atk4\Data\Tests\ContainsOne\Country; +use Atk4\Data\Tests\ContainsOne\DoorCode; use Atk4\Data\Tests\ContainsOne\Invoice; /** @@ -65,7 +66,9 @@ protected function setUp(): void */ public function testModelCaption(): void { - $a = (new Invoice($this->db))->addr; + $i = new Invoice($this->db); + /** @var Address */ + $a = $i->ref($i->fieldName()->addr); // test caption of containsOne reference $this->assertSame('Secret Code', $a->getField($a->fieldName()->door_code)->getCaption()); @@ -73,17 +76,17 @@ public function testModelCaption(): void $this->assertSame('Secret Code', $a->door_code->getModelCaption()); } - /** - * Test containsOne. - */ public function testContainsOne(): void { $i = new Invoice($this->db); $i = $i->loadBy($i->fieldName()->ref_no, 'A1'); + $this->assertSame(Address::class, get_class($i->getModel()->addr)); + // check do we have address set - $a = $i->addr; - $this->assertFalse($a->isLoaded()); + $this->assertNull($i->addr); + /** @var Address */ + $a = $i->ref($i->fieldName()->addr); // now store some address $a->setMulti($row = [ @@ -106,7 +109,8 @@ public function testContainsOne(): void $this->assertSame('bar', $i->addr->address); // now add nested containsOne - DoorCode - $c = $i->addr->door_code; + /** @var DoorCode */ + $c = $i->addr->ref($i->addr->fieldName()->door_code); $c->setMulti($row = [ $c->fieldName()->id => 1, $c->fieldName()->code => 'ABC', @@ -153,12 +157,12 @@ public function testContainsOne(): void // so far so good. now let's try to delete door_code $i->addr->door_code->delete(); $this->assertNull($i->addr->get($i->addr->fieldName()->door_code)); - $this->assertFalse($i->addr->door_code->isLoaded()); + $this->assertNull($i->addr->door_code); // and now delete address $i->addr->delete(); $this->assertNull($i->get($i->fieldName()->addr)); - $this->assertFalse($i->addr->isLoaded()); + $this->assertNull($i->addr); } /** @@ -170,7 +174,9 @@ public function testContainsOneWhenChangeModelFields(): void $i = $i->loadBy($i->fieldName()->ref_no, 'A1'); // with address - $a = $i->addr; + $this->assertNull($i->addr); + /** @var Address */ + $a = $i->ref($i->fieldName()->addr); $a->setMulti($row = [ $a->fieldName()->id => 1, $a->fieldName()->country_id => 1, @@ -199,17 +205,4 @@ public function testContainsOneWhenChangeModelFields(): void $a = $i->addr; $this->assertEquals($row, $a->get()); } - - /* - * Model should be loaded before traversing to containsOne relation. - * Imants: it looks that this is not actually required - disabling. - */ - /* - public function testEx1(): void - { - $i = new Invoice($this->db); - $this->expectException(Exception::class); - $i->addr; - } - */ } diff --git a/tests/ExpressionSqlTest.php b/tests/ExpressionSqlTest.php index 95d9a8912..fc12eebab 100644 --- a/tests/ExpressionSqlTest.php +++ b/tests/ExpressionSqlTest.php @@ -151,7 +151,7 @@ public function testExpressions(): void ); $mm = $m->tryLoad(1); - $this->assertNull($mm->get('name')); + $this->assertNull($mm); $mm = $m->tryLoad(2); $this->assertSame('Sue', $mm->get('name')); } diff --git a/tests/IteratorTest.php b/tests/IteratorTest.php index 1cc5e2118..b8bda49a3 100644 --- a/tests/IteratorTest.php +++ b/tests/IteratorTest.php @@ -156,14 +156,14 @@ public function testRawIterator(): void $data[] = $row; } - $this->assertEquals([ - ['total_net' => 10, 'id' => 1], + $this->assertSame([ + ['total_net' => '10', 'id' => '1'], - ['total_net' => 10, 'id' => 1], - ['total_net' => 15, 'id' => 3], - ['total_net' => 20, 'id' => 2], + ['total_net' => '10', 'id' => '1'], + ['total_net' => '15', 'id' => '3'], + ['total_net' => '20', 'id' => '2'], - ['total_net' => 10, 'id' => 1], // affected by limit now + ['total_net' => '10', 'id' => '1'], // affected by limit now ], $data); } diff --git a/tests/JoinArrayTest.php b/tests/JoinArrayTest.php index 51cfc5c1d..b39951a6d 100644 --- a/tests/JoinArrayTest.php +++ b/tests/JoinArrayTest.php @@ -236,19 +236,21 @@ public function testJoinLoading(): void $j->addField('contact_phone'); $m_u2 = $m_u->load(1); - $this->assertEquals([ - 'name' => 'John', 'contact_id' => 1, 'contact_phone' => '+123', 'id' => 1, + $this->assertSame([ + 'id' => 1, 'contact_id' => 1, 'name' => 'John', 'contact_phone' => '+123', ], $m_u2->get()); $m_u2 = $m_u->load(3); - $this->assertEquals([ - 'name' => 'Joe', 'contact_id' => 2, 'contact_phone' => '+321', 'id' => 3, + $this->assertSame([ + 'id' => 3, 'contact_id' => 2, 'name' => 'Joe', 'contact_phone' => '+321', ], $m_u2->get()); - $m_u2 = $m_u->tryLoad(4); - $this->assertEquals([ - 'name' => null, 'contact_id' => null, 'contact_phone' => null, 'id' => null, + $m_u2 = $m_u2->unload(); + $this->assertSame([ + 'id' => null, 'contact_id' => null, 'name' => null, 'contact_phone' => null, ], $m_u2->get()); + + $this->assertNull($m_u->tryLoad(4)); } public function testJoinUpdate(): void @@ -304,7 +306,7 @@ public function testJoinUpdate(): void ], ], $this->getInternalPersistenceData($db)); - $m_u2 = $m_u->tryLoad(4); + $m_u2 = $m_u->createEntity(); $m_u2->set('name', 'YYY'); $m_u2->set('contact_phone', '+777'); $m_u2->save(); diff --git a/tests/JoinSqlTest.php b/tests/JoinSqlTest.php index 496c4e5b0..9e6302cdb 100644 --- a/tests/JoinSqlTest.php +++ b/tests/JoinSqlTest.php @@ -197,19 +197,21 @@ public function testJoinLoading(): void $j->addField('contact_phone'); $m_u2 = $m_u->load(1); - $this->assertEquals([ - 'name' => 'John', 'contact_id' => 1, 'contact_phone' => '+123', 'id' => 1, + $this->assertSame([ + 'id' => 1, 'name' => 'John', 'contact_id' => '1', 'contact_phone' => '+123', ], $m_u2->get()); $m_u2 = $m_u->load(3); - $this->assertEquals([ - 'name' => 'Joe', 'contact_id' => 2, 'contact_phone' => '+321', 'id' => 3, + $this->assertSame([ + 'id' => 3, 'name' => 'Joe', 'contact_id' => '2', 'contact_phone' => '+321', ], $m_u2->get()); - $m_u2 = $m_u->tryLoad(4); - $this->assertEquals([ - 'name' => null, 'contact_id' => null, 'contact_phone' => null, 'id' => null, + $m_u2 = $m_u2->unload(); + $this->assertSame([ + 'id' => null, 'name' => null, 'contact_id' => null, 'contact_phone' => null, ], $m_u2->get()); + + $this->assertNull($m_u->tryLoad(4)); } public function testJoinUpdate(): void @@ -283,7 +285,7 @@ public function testJoinUpdate(): void ], ], $this->getDb()); - $m_u2 = $m_u->tryLoad(4); + $m_u2 = $m_u->createEntity(); $m_u2->set('name', 'YYY'); $m_u2->set('contact_phone', '+777'); $m_u2->save(); @@ -409,7 +411,7 @@ public function testDoubleJoin(): void $m_u2->set('country_name', 'USA'); $m_u2->save(); - $m_u2 = $m_u->tryLoad(40); + $m_u2 = $m_u2->unload(); $this->assertFalse($m_u2->isLoaded()); $this->assertSame($m_u2->getModel()->getField('country_id')->getJoin(), $m_u2->getModel()->getField('contact_phone')->getJoin()); diff --git a/tests/Persistence/ArrayTest.php b/tests/Persistence/ArrayTest.php index 37ec80f6a..2994e7458 100644 --- a/tests/Persistence/ArrayTest.php +++ b/tests/Persistence/ArrayTest.php @@ -885,7 +885,7 @@ public function testTryLoadAnyNotThrowsExceptionOnRecordNotFound(): void $m->addField('name'); $m->addField('surname'); $m = $m->tryLoadAny(); - $this->assertFalse($m->isLoaded()); + $this->assertNull($m); } public function testTryLoadAnyReturnsFirstRecord(): void diff --git a/tests/Persistence/CsvTest.php b/tests/Persistence/CsvTest.php index 6fc46975c..5c0aefd46 100644 --- a/tests/Persistence/CsvTest.php +++ b/tests/Persistence/CsvTest.php @@ -144,7 +144,7 @@ public function testLoadAnyException(): void $this->assertSame('Jones', $mm->get('surname')); $mm = $m->tryLoadAny(); - $this->assertFalse($mm->isLoaded()); + $this->assertNull($mm); } public function testLoadByIdNotSupportedException(): void diff --git a/tests/Persistence/SqlTest.php b/tests/Persistence/SqlTest.php index 6593508b5..c6b2c3c42 100644 --- a/tests/Persistence/SqlTest.php +++ b/tests/Persistence/SqlTest.php @@ -53,7 +53,7 @@ public function testModelLoadOneAndAny(): void $mm = (clone $m)->addCondition($m->id_field, 1); $this->assertSame('John', $mm->load(1)->get('name')); - $this->assertNull($mm->tryLoad(2)->get('name')); + $this->assertNull($mm->tryLoad(2)); $this->assertSame('John', $mm->tryLoadOne()->get('name')); $this->assertSame('John', $mm->loadOne()->get('name')); $this->assertSame('John', $mm->tryLoadAny()->get('name')); @@ -61,7 +61,7 @@ public function testModelLoadOneAndAny(): void $mm = (clone $m)->addCondition('surname', 'Jones'); $this->assertSame('Sarah', $mm->load(2)->get('name')); - $this->assertNull($mm->tryLoad(1)->get('name')); + $this->assertNull($mm->tryLoad(1)); $this->assertSame('Sarah', $mm->tryLoadOne()->get('name')); $this->assertSame('Sarah', $mm->loadOne()->get('name')); $this->assertSame('Sarah', $mm->tryLoadAny()->get('name')); @@ -207,7 +207,7 @@ public function testPersistenceDelete(): void $m2->save(); $m2 = $m->tryLoad($ids[0]); - $this->assertFalse($m2->isLoaded()); + $this->assertNull($m2); $m2 = $m->load($ids[1]); $this->assertSame('Smith', $m2->get('surname')); diff --git a/tests/Persistence/StaticTest.php b/tests/Persistence/StaticTest.php index ae6a3180c..31315c13c 100644 --- a/tests/Persistence/StaticTest.php +++ b/tests/Persistence/StaticTest.php @@ -99,8 +99,7 @@ public function testEmpty(): void $m = new Model($p); $m = $m->tryLoadAny(); - - $this->assertFalse($m->isLoaded()); + $this->assertNull($m); } public function testCustomField(): void diff --git a/tests/ReferenceSqlTest.php b/tests/ReferenceSqlTest.php index 313b7ab4d..cb95553e4 100644 --- a/tests/ReferenceSqlTest.php +++ b/tests/ReferenceSqlTest.php @@ -43,17 +43,17 @@ public function testBasic(): void $ooo = $oo->tryLoad(1); $this->assertEquals(20, $ooo->get('amount')); $ooo = $oo->tryLoad(2); - $this->assertNull($ooo->get('amount')); + $this->assertNull($ooo); $ooo = $oo->tryLoad(3); $this->assertEquals(5, $ooo->get('amount')); $oo = $u->load(2)->ref('Orders'); $ooo = $oo->tryLoad(1); - $this->assertNull($ooo->get('amount')); + $this->assertNull($ooo); $ooo = $oo->tryLoad(2); $this->assertEquals(15, $ooo->get('amount')); $ooo = $oo->tryLoad(3); - $this->assertNull($ooo->get('amount')); + $this->assertNull($ooo); $oo = $u->addCondition('id', '>', '1')->ref('Orders');