From 594e7f1330627a3405113c278e67bd230b54aa3f Mon Sep 17 00:00:00 2001 From: zsilbi Date: Thu, 3 Oct 2019 14:06:54 +0200 Subject: [PATCH 1/9] Changed the unique key generation for reusable records to contain the retrieve method (find, findFirst, count.. etc.) --- phalcon/Mvc/Model/Manager.zep | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phalcon/Mvc/Model/Manager.zep b/phalcon/Mvc/Model/Manager.zep index cf40dbbbc4d..fbd881352ac 100644 --- a/phalcon/Mvc/Model/Manager.zep +++ b/phalcon/Mvc/Model/Manager.zep @@ -1412,7 +1412,7 @@ class Manager implements ManagerInterface, InjectionAwareInterface, EventsAwareI let reusable = (bool) relation->isReusable(); if reusable { - let uniqueKey = unique_key(referencedModel, arguments), + let uniqueKey = unique_key(referencedModel, [findParams, retrieveMethod]), records = this->getReusableRecords(referencedModel, uniqueKey); if typeof records == "array" || typeof records == "object" { From c705e8d9faedfa3876a9979bd8ba25d379658374 Mon Sep 17 00:00:00 2001 From: zsilbi Date: Thu, 3 Oct 2019 14:08:06 +0200 Subject: [PATCH 2/9] Moved "arguments" variable declaration --- phalcon/Mvc/Model/Manager.zep | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phalcon/Mvc/Model/Manager.zep b/phalcon/Mvc/Model/Manager.zep index fbd881352ac..403aded6271 100644 --- a/phalcon/Mvc/Model/Manager.zep +++ b/phalcon/Mvc/Model/Manager.zep @@ -1404,8 +1404,6 @@ class Manager implements ManagerInterface, InjectionAwareInterface, EventsAwareI let retrieveMethod = method; } - let arguments = [findParams]; - /** * Find first results could be reusable */ @@ -1420,6 +1418,8 @@ class Manager implements ManagerInterface, InjectionAwareInterface, EventsAwareI } } + let arguments = [findParams]; + /** * Load the referenced model * Call the function in the model From ec0fad2a183518c74ea59e74f29fcb2fae70dfbe Mon Sep 17 00:00:00 2001 From: zsilbi Date: Thu, 3 Oct 2019 14:18:30 +0200 Subject: [PATCH 3/9] Tests for Phalcon\Mvc\Model :: __call() --- .../Mvc/Model/UnderscoreCallCest.php | 86 ++++++++++++++++++- 1 file changed, 83 insertions(+), 3 deletions(-) diff --git a/tests/integration/Mvc/Model/UnderscoreCallCest.php b/tests/integration/Mvc/Model/UnderscoreCallCest.php index 6c2e9097106..4d78fb237d9 100644 --- a/tests/integration/Mvc/Model/UnderscoreCallCest.php +++ b/tests/integration/Mvc/Model/UnderscoreCallCest.php @@ -12,18 +12,98 @@ namespace Phalcon\Test\Integration\Mvc\Model; use IntegrationTester; +use Phalcon\Test\Fixtures\Traits\DiTrait; +use Phalcon\Test\Models; class UnderscoreCallCest { + use DiTrait; + + public function _before(IntegrationTester $I) + { + $this->setNewFactoryDefault(); + $this->setDiMysql(); + } + + public function _after(IntegrationTester $I) + { + $this->container['db']->close(); + } + /** * Tests Phalcon\Mvc\Model :: __call() * - * @author Phalcon Team - * @since 2018-11-13 + * @author Balázs Németh + * @since 2019-10-03 */ public function mvcModelCall(IntegrationTester $I) { $I->wantToTest("Mvc\Model - __call()"); - $I->skipTest('Need implementation'); + + /** + * Belongs-to relationship + */ + $robotPart = Models\RobotsParts::findFirst(); + + $part = $robotPart->getPart(); + + $I->assertInstanceOf( + Models\Parts::class, + $part + ); + + $nonExistentPart = $robotPart->getPart( + [ + 'id < 0', + 'order' => 'id DESC', + ] + ); + + $I->assertNull($nonExistentPart); + + /** + * Testing has-one relationship + */ + $customer = Models\Customers::findFirst(); + + $user = $customer->getUser(); + + $I->assertInstanceOf( + Models\Users::class, + $user + ); + + $nonExistentUser = $customer->getUser( + [ + 'id < 0', + 'order' => 'id DESC', + ] + ); + + $I->assertNull($nonExistentUser); + + /** + * Has-many relationship + */ + $robot = Models\Robots::findFirst(); + + $robotParts = $robot->getRobotsParts(); + + $I->assertInstanceOf( + \Phalcon\Mvc\Model\Resultset\Simple::class, + $robotParts + ); + + $nonExistentRobotParts = $robot->getRobotsParts( + [ + 'id < 0', + 'order' => 'id DESC', + ] + ); + + $I->assertEquals( + 0, + $nonExistentRobotParts->count() + ); } } From 18166ad1900509e7b891635b2934fa2444895c91 Mon Sep 17 00:00:00 2001 From: zsilbi Date: Thu, 3 Oct 2019 14:22:25 +0200 Subject: [PATCH 4/9] Reusable relation test --- tests/_data/fixtures/models/Robots.php | 11 ++++++ .../Mvc/Model/UnderscoreCallCest.php | 38 +++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/tests/_data/fixtures/models/Robots.php b/tests/_data/fixtures/models/Robots.php index 7d33e7d9448..31a0261eefb 100644 --- a/tests/_data/fixtures/models/Robots.php +++ b/tests/_data/fixtures/models/Robots.php @@ -26,5 +26,16 @@ public function initialize() 'foreignKey' => true, ] ); + + $this->hasMany( + 'id', + RobotsParts::class, + 'robots_id', + [ + 'alias' => 'reusableRobotsParts', + 'foreignKey' => true, + 'reusable' => true + ] + ); } } diff --git a/tests/integration/Mvc/Model/UnderscoreCallCest.php b/tests/integration/Mvc/Model/UnderscoreCallCest.php index 4d78fb237d9..3e1b8517b8a 100644 --- a/tests/integration/Mvc/Model/UnderscoreCallCest.php +++ b/tests/integration/Mvc/Model/UnderscoreCallCest.php @@ -94,6 +94,13 @@ public function mvcModelCall(IntegrationTester $I) $robotParts ); + $countRobotParts = $robot->countRobotsParts(); + + $I->assertEquals( + $robotParts->count(), + $countRobotParts + ); + $nonExistentRobotParts = $robot->getRobotsParts( [ 'id < 0', @@ -105,5 +112,36 @@ public function mvcModelCall(IntegrationTester $I) 0, $nonExistentRobotParts->count() ); + + /** + * Reusable has-many relationship + */ + $reusableRobot = Models\Robots::findFirst(); + + $reusableRobotParts = $reusableRobot->getReusableRobotsParts(); + + $I->assertInstanceOf( + \Phalcon\Mvc\Model\Resultset\Simple::class, + $reusableRobotParts + ); + + $countReusableRobotParts = $reusableRobot->countReusableRobotsParts(); + + $I->assertEquals( + $reusableRobotParts->count(), + $countReusableRobotParts + ); + + $nonExistentReusableRobotParts = $reusableRobot->getReusableRobotsParts( + [ + 'id < 0', + 'order' => 'id DESC', + ] + ); + + $I->assertEquals( + 0, + $nonExistentReusableRobotParts->count() + ); } } From c3a4b9c07f59afac1e47203efc3d4156b8ce9083 Mon Sep 17 00:00:00 2001 From: zsilbi Date: Thu, 3 Oct 2019 14:54:57 +0200 Subject: [PATCH 5/9] Modified relations New RobotsReusable model for testing reusable relation --- tests/_data/fixtures/models/Robots.php | 11 ------- .../_data/fixtures/models/RobotsReusable.php | 31 +++++++++++++++++++ .../Mvc/Model/UnderscoreCallCest.php | 8 ++--- 3 files changed, 35 insertions(+), 15 deletions(-) create mode 100644 tests/_data/fixtures/models/RobotsReusable.php diff --git a/tests/_data/fixtures/models/Robots.php b/tests/_data/fixtures/models/Robots.php index 31a0261eefb..7d33e7d9448 100644 --- a/tests/_data/fixtures/models/Robots.php +++ b/tests/_data/fixtures/models/Robots.php @@ -26,16 +26,5 @@ public function initialize() 'foreignKey' => true, ] ); - - $this->hasMany( - 'id', - RobotsParts::class, - 'robots_id', - [ - 'alias' => 'reusableRobotsParts', - 'foreignKey' => true, - 'reusable' => true - ] - ); } } diff --git a/tests/_data/fixtures/models/RobotsReusable.php b/tests/_data/fixtures/models/RobotsReusable.php new file mode 100644 index 00000000000..8ab299853ee --- /dev/null +++ b/tests/_data/fixtures/models/RobotsReusable.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE.txt + * file that was distributed with this source code. + */ + +namespace Phalcon\Test\Models; + +use Phalcon\Mvc\Model; + +class RobotsReusable extends Model +{ + public function initialize() + { + $this->hasMany( + 'id', + RobotsParts::class, + 'robots_id', + [ + 'alias' => 'robotsParts', + 'foreignKey' => true, + 'reusable' => true + ] + ); + } +} diff --git a/tests/integration/Mvc/Model/UnderscoreCallCest.php b/tests/integration/Mvc/Model/UnderscoreCallCest.php index 3e1b8517b8a..dc61c5173a7 100644 --- a/tests/integration/Mvc/Model/UnderscoreCallCest.php +++ b/tests/integration/Mvc/Model/UnderscoreCallCest.php @@ -116,23 +116,23 @@ public function mvcModelCall(IntegrationTester $I) /** * Reusable has-many relationship */ - $reusableRobot = Models\Robots::findFirst(); + $reusableRobot = Models\RobotsReusable::findFirst(); - $reusableRobotParts = $reusableRobot->getReusableRobotsParts(); + $reusableRobotParts = $reusableRobot->getRobotsParts(); $I->assertInstanceOf( \Phalcon\Mvc\Model\Resultset\Simple::class, $reusableRobotParts ); - $countReusableRobotParts = $reusableRobot->countReusableRobotsParts(); + $countReusableRobotParts = $reusableRobot->countRobotsParts(); $I->assertEquals( $reusableRobotParts->count(), $countReusableRobotParts ); - $nonExistentReusableRobotParts = $reusableRobot->getReusableRobotsParts( + $nonExistentReusableRobotParts = $reusableRobot->getRobotsParts( [ 'id < 0', 'order' => 'id DESC', From 051ae96fbfcb0d6b2a7ad1b33f4ad6c5120d8b3a Mon Sep 17 00:00:00 2001 From: zsilbi Date: Fri, 11 Oct 2019 18:50:25 +0200 Subject: [PATCH 6/9] If there are no single records for findFirstBy(), invokeFinder returns null. Therefore it should return false, instead of null when the requested method doesn't exist. --- phalcon/Mvc/Model.zep | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phalcon/Mvc/Model.zep b/phalcon/Mvc/Model.zep index 3fea4047fb9..15fc48ae952 100644 --- a/phalcon/Mvc/Model.zep +++ b/phalcon/Mvc/Model.zep @@ -188,7 +188,7 @@ abstract class Model extends AbstractInjectionAware implements EntityInterface, let records = self::_invokeFinder(method, arguments); - if records !== null { + if records !== false { return records; } @@ -4246,7 +4246,7 @@ abstract class Model extends AbstractInjectionAware implements EntityInterface, let modelName = get_called_class(); if !extraMethod { - return null; + return false; } if unlikely !fetch value, arguments[0] { From 0198f59c521264d29b9a2caa5b072304edca6161 Mon Sep 17 00:00:00 2001 From: zsilbi Date: Fri, 11 Oct 2019 18:51:47 +0200 Subject: [PATCH 7/9] If there are no single related records for belongsTo relations, _getRelatedRecords returns null. Therefore it should return false, instead of null when the requested relation doesn't exist. --- phalcon/Mvc/Model.zep | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/phalcon/Mvc/Model.zep b/phalcon/Mvc/Model.zep index 15fc48ae952..9957f6c01e4 100644 --- a/phalcon/Mvc/Model.zep +++ b/phalcon/Mvc/Model.zep @@ -199,7 +199,7 @@ abstract class Model extends AbstractInjectionAware implements EntityInterface, */ let records = this->_getRelatedRecords(modelName, method, arguments); - if records !== null { + if records !== false { return records; } @@ -4080,7 +4080,7 @@ abstract class Model extends AbstractInjectionAware implements EntityInterface, * Return if the relation was not found because getRelated() throws an exception if the relation is unknown */ if typeof relation != "object" { - return null; + return false; } return this->getRelated(alias, extraArgs); @@ -4101,7 +4101,7 @@ abstract class Model extends AbstractInjectionAware implements EntityInterface, * If the relation was found perform the query via the models manager */ if typeof relation != "object" { - return null; + return false; } return manager->getRelationRecords( @@ -4112,7 +4112,7 @@ abstract class Model extends AbstractInjectionAware implements EntityInterface, ); } - return null; + return false; } /** From 69a7d72538633da597f915535cfd9f37d81dd938 Mon Sep 17 00:00:00 2001 From: zsilbi Date: Fri, 11 Oct 2019 18:52:16 +0200 Subject: [PATCH 8/9] Updated comments and docblock for Model::_getRelatedRecords() --- phalcon/Mvc/Model.zep | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/phalcon/Mvc/Model.zep b/phalcon/Mvc/Model.zep index 9957f6c01e4..3cacc0fa703 100644 --- a/phalcon/Mvc/Model.zep +++ b/phalcon/Mvc/Model.zep @@ -4050,12 +4050,16 @@ abstract class Model extends AbstractInjectionAware implements EntityInterface, } /** - * Returns related records defined relations depending on the method name + * Returns related records defined relations depending on the method name. + * Returns false if the relation is non-existent. * - * @param array arguments - * @return mixed + * @param string modelName + * @param string method + * @param array arguments + * + * @return ResultsetInterface|ModelInterface|bool|null */ - protected function _getRelatedRecords(string! modelName, string! method, var arguments) + protected function _getRelatedRecords(string! modelName, string! method, array! arguments) { var manager, relation, queryMethod, extraArgs, alias; @@ -4077,7 +4081,8 @@ abstract class Model extends AbstractInjectionAware implements EntityInterface, ); /** - * Return if the relation was not found because getRelated() throws an exception if the relation is unknown + * Return if the relation was not found because getRelated() + * throws an exception if the relation is unknown */ if typeof relation != "object" { return false; From 261ae7f026b34fb1093d3946247d672cf507f941 Mon Sep 17 00:00:00 2001 From: zsilbi Date: Sat, 12 Oct 2019 13:40:33 +0200 Subject: [PATCH 9/9] Changed model source --- tests/_data/fixtures/models/RobotsReusable.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/_data/fixtures/models/RobotsReusable.php b/tests/_data/fixtures/models/RobotsReusable.php index 8ab299853ee..a0efca9592f 100644 --- a/tests/_data/fixtures/models/RobotsReusable.php +++ b/tests/_data/fixtures/models/RobotsReusable.php @@ -17,6 +17,8 @@ class RobotsReusable extends Model { public function initialize() { + $this->setSource('robots'); + $this->hasMany( 'id', RobotsParts::class,