From 8a2c97c3ba1e405ad9b7cd7a980b5013e996ab11 Mon Sep 17 00:00:00 2001 From: Austin Collier Date: Tue, 12 Mar 2024 09:55:48 -0600 Subject: [PATCH 1/2] Fixed relation protected keyword issue and setDatabaseConnection --- src/ActiveRecord.php | 47 +++++++++++++++++++++++- tests/ActiveRecordPdoIntegrationTest.php | 40 ++++++++++++++++++++ tests/ActiveRecordTest.php | 23 ++++++++++++ 3 files changed, 108 insertions(+), 2 deletions(-) diff --git a/src/ActiveRecord.php b/src/ActiveRecord.php index bf33edf..ee3e4cf 100644 --- a/src/ActiveRecord.php +++ b/src/ActiveRecord.php @@ -78,6 +78,18 @@ abstract class ActiveRecord extends Base implements JsonSerializable */ protected array $sqlExpressions = []; + /** + * @var string SQL that is built to be used by execute() + */ + protected string $built_sql = ''; + + /** + * Captures all the joins that are made + * + * @var Expressions|null + */ + protected ?Expressions $join = null; + /** * Database connection * @@ -361,6 +373,20 @@ public function getDatabaseConnection() return $this->databaseConnection; } + /** + * set the database connection. + * @param DatabaseInterface|mysqli|PDO $databaseConnection + * @return void + */ + public function setDatabaseConnection($databaseConnection): void + { + if (($databaseConnection instanceof DatabaseInterface) === true) { + $this->databaseConnection = $databaseConnection; + } else { + $this->transformAndPersistConnection($databaseConnection); + } + } + /** * function to find one record and assign in to current object. * @param int|string $id If call this function using this param, will find record by using this id. If not set, just find the first record in database. @@ -535,6 +561,12 @@ public function query(string $sql, array $param = [], ActiveRecord $obj = null, */ protected function &getRelation(string $name) { + + // can't set the name of a relation to a protected keyword + if(in_array($name, ['select', 'from', 'join', 'where', 'group', 'having', 'order', 'limit', 'offset'], true) === true) { + throw new Exception($name. ' is a protected keyword and cannot be used as a relation name'); + } + $relation = $this->relations[$name]; if (is_array($relation) === true) { // ActiveRecordData::BELONGS_TO etc @@ -604,8 +636,19 @@ protected function buildSql(array $sql_statements = []): string } //this code to debug info. //echo 'SQL: ', implode(' ', $sql_statements), "\n", "PARAMS: ", implode(', ', $this->params), "\n"; - return implode(' ', $sql_statements); - } + $this->built_sql = implode(' ', $sql_statements); + return $this->built_sql; + } + + /** + * Gets the built SQL after buildSql has been called + * + * @return string + */ + public function getBuiltSql(): string + { + return $this->built_sql; + } /** * make wrap when build the SQL expressions of WHERE. * @param string $op If give this param will build one WrapExpressions include the stored expressions add into WHERE. Otherwise will stored the expressions into array. diff --git a/tests/ActiveRecordPdoIntegrationTest.php b/tests/ActiveRecordPdoIntegrationTest.php index 17b7285..643400c 100644 --- a/tests/ActiveRecordPdoIntegrationTest.php +++ b/tests/ActiveRecordPdoIntegrationTest.php @@ -3,6 +3,7 @@ namespace flight\tests; use flight\ActiveRecord; +use flight\database\pdo\PdoAdapter; use flight\tests\classes\Contact; use flight\tests\classes\User; use PDO; @@ -509,4 +510,43 @@ public function testRelationsCascadingSave() $this->assertGreaterThan(0, $user->contact->id); $this->assertFalse($user->isDirty()); } + + public function testSetDatabaseConnection() + { + $user = new User(); + $user->setDatabaseConnection(new PDO('sqlite:test.db')); + $user->name = 'bob'; + $user->password = 'pass'; + $user->save(); + + $this->assertGreaterThan(0, $user->id); + } + + public function testSetDatabaseConnectionWithAdapter() + { + $user = new User(); + $user->setDatabaseConnection(new PdoAdapter(new PDO('sqlite:test.db'))); + $user->name = 'bob'; + $user->password = 'pass'; + $user->save(); + + $this->assertGreaterThan(0, $user->id); + } + + public function testRelationWithProtectedKeyword() { + $user = new User(new PDO('sqlite:test.db')); + $user->name = 'demo'; + $user->password = md5('demo'); + $user->insert(); + + $contact = new class(new PDO('sqlite:test.db')) extends ActiveRecord { + protected array $relations = [ + 'group' => [self::HAS_ONE, User::class, 'user_id'] + ]; + }; + + $this->expectException(\Exception::class); + $this->expectExceptionMessage('group is a protected keyword and cannot be used as a relation name'); + $contact->group->id; + } } diff --git a/tests/ActiveRecordTest.php b/tests/ActiveRecordTest.php index 5d12204..ee99878 100644 --- a/tests/ActiveRecordTest.php +++ b/tests/ActiveRecordTest.php @@ -117,4 +117,27 @@ public function testCopyFrom() $this->assertEquals('John', $record->name); $this->assertEquals(['name' => 'John'], $record->getData()); } + + public function testIsset() + { + $record = new class (null, 'test_table') extends ActiveRecord { + }; + $record->name = 'John'; + $this->assertTrue(isset($record->name)); + $this->assertFalse(isset($record->email)); + } + + public function testMultipleJoins() + { + $record = new class (null, 'test_table') extends ActiveRecord { + public function query(string $sql, array $param = [], ?ActiveRecord $obj = null, bool $single = false) + { + return $this; + } + }; + $record->join('table1', 'table1.some_id = test_table.id'); + $record->join('table2', 'table2.some_id = table1.id'); + $result = $record->find()->getBuiltSql(); + $this->assertEquals('SELECT test_table.* FROM test_table LEFT JOIN table1 ON table1.some_id = test_table.id LEFT JOIN table2 ON table2.some_id = table1.id LIMIT 1 ', $result); + } } From ea0d8d4c276833835527a4c1d0ffedd3baaaf87b Mon Sep 17 00:00:00 2001 From: Austin Collier Date: Tue, 12 Mar 2024 09:59:25 -0600 Subject: [PATCH 2/2] phpcs fixes --- src/ActiveRecord.php | 72 ++++++++-------- tests/ActiveRecordPdoIntegrationTest.php | 103 ++++++++++++----------- tests/ActiveRecordTest.php | 30 +++---- 3 files changed, 103 insertions(+), 102 deletions(-) diff --git a/src/ActiveRecord.php b/src/ActiveRecord.php index ee3e4cf..3b2a06f 100644 --- a/src/ActiveRecord.php +++ b/src/ActiveRecord.php @@ -78,17 +78,17 @@ abstract class ActiveRecord extends Base implements JsonSerializable */ protected array $sqlExpressions = []; - /** - * @var string SQL that is built to be used by execute() - */ - protected string $built_sql = ''; + /** + * @var string SQL that is built to be used by execute() + */ + protected string $built_sql = ''; - /** - * Captures all the joins that are made - * - * @var Expressions|null - */ - protected ?Expressions $join = null; + /** + * Captures all the joins that are made + * + * @var Expressions|null + */ + protected ?Expressions $join = null; /** * Database connection @@ -373,19 +373,19 @@ public function getDatabaseConnection() return $this->databaseConnection; } - /** - * set the database connection. - * @param DatabaseInterface|mysqli|PDO $databaseConnection - * @return void - */ - public function setDatabaseConnection($databaseConnection): void - { - if (($databaseConnection instanceof DatabaseInterface) === true) { + /** + * set the database connection. + * @param DatabaseInterface|mysqli|PDO $databaseConnection + * @return void + */ + public function setDatabaseConnection($databaseConnection): void + { + if (($databaseConnection instanceof DatabaseInterface) === true) { $this->databaseConnection = $databaseConnection; } else { - $this->transformAndPersistConnection($databaseConnection); - } - } + $this->transformAndPersistConnection($databaseConnection); + } + } /** * function to find one record and assign in to current object. @@ -500,7 +500,7 @@ public function save(): ActiveRecord } } - return $record; + return $record; } /** @@ -562,10 +562,10 @@ public function query(string $sql, array $param = [], ActiveRecord $obj = null, protected function &getRelation(string $name) { - // can't set the name of a relation to a protected keyword - if(in_array($name, ['select', 'from', 'join', 'where', 'group', 'having', 'order', 'limit', 'offset'], true) === true) { - throw new Exception($name. ' is a protected keyword and cannot be used as a relation name'); - } + // can't set the name of a relation to a protected keyword + if (in_array($name, ['select', 'from', 'join', 'where', 'group', 'having', 'order', 'limit', 'offset'], true) === true) { + throw new Exception($name . ' is a protected keyword and cannot be used as a relation name'); + } $relation = $this->relations[$name]; if (is_array($relation) === true) { @@ -636,19 +636,19 @@ protected function buildSql(array $sql_statements = []): string } //this code to debug info. //echo 'SQL: ', implode(' ', $sql_statements), "\n", "PARAMS: ", implode(', ', $this->params), "\n"; - $this->built_sql = implode(' ', $sql_statements); + $this->built_sql = implode(' ', $sql_statements); return $this->built_sql; } - /** - * Gets the built SQL after buildSql has been called - * - * @return string - */ - public function getBuiltSql(): string - { - return $this->built_sql; - } + /** + * Gets the built SQL after buildSql has been called + * + * @return string + */ + public function getBuiltSql(): string + { + return $this->built_sql; + } /** * make wrap when build the SQL expressions of WHERE. * @param string $op If give this param will build one WrapExpressions include the stored expressions add into WHERE. Otherwise will stored the expressions into array. diff --git a/tests/ActiveRecordPdoIntegrationTest.php b/tests/ActiveRecordPdoIntegrationTest.php index 643400c..a124ce1 100644 --- a/tests/ActiveRecordPdoIntegrationTest.php +++ b/tests/ActiveRecordPdoIntegrationTest.php @@ -492,61 +492,62 @@ public function testIsHydratedGoodFindAll() $this->assertTrue($users[0]->isHydrated()); } - public function testRelationsCascadingSave() + public function testRelationsCascadingSave() { $user = new User(new PDO('sqlite:test.db')); $user->name = 'demo'; $user->password = md5('demo'); $user->insert(); - $user->name = 'bobby'; - $user->contact->user_id = $user->id; - $user->contact->email = 'test@amail.com'; - $user->contact->address = 'test address'; - $user->save(); - - $this->assertEquals($user->id, $user->contact->user_id); - $this->assertFalse($user->contact->isDirty()); - $this->assertGreaterThan(0, $user->contact->id); - $this->assertFalse($user->isDirty()); - } - - public function testSetDatabaseConnection() - { - $user = new User(); - $user->setDatabaseConnection(new PDO('sqlite:test.db')); - $user->name = 'bob'; - $user->password = 'pass'; - $user->save(); - - $this->assertGreaterThan(0, $user->id); - } - - public function testSetDatabaseConnectionWithAdapter() - { - $user = new User(); - $user->setDatabaseConnection(new PdoAdapter(new PDO('sqlite:test.db'))); - $user->name = 'bob'; - $user->password = 'pass'; - $user->save(); - - $this->assertGreaterThan(0, $user->id); - } - - public function testRelationWithProtectedKeyword() { - $user = new User(new PDO('sqlite:test.db')); - $user->name = 'demo'; - $user->password = md5('demo'); - $user->insert(); - - $contact = new class(new PDO('sqlite:test.db')) extends ActiveRecord { - protected array $relations = [ - 'group' => [self::HAS_ONE, User::class, 'user_id'] - ]; - }; - - $this->expectException(\Exception::class); - $this->expectExceptionMessage('group is a protected keyword and cannot be used as a relation name'); - $contact->group->id; - } + $user->name = 'bobby'; + $user->contact->user_id = $user->id; + $user->contact->email = 'test@amail.com'; + $user->contact->address = 'test address'; + $user->save(); + + $this->assertEquals($user->id, $user->contact->user_id); + $this->assertFalse($user->contact->isDirty()); + $this->assertGreaterThan(0, $user->contact->id); + $this->assertFalse($user->isDirty()); + } + + public function testSetDatabaseConnection() + { + $user = new User(); + $user->setDatabaseConnection(new PDO('sqlite:test.db')); + $user->name = 'bob'; + $user->password = 'pass'; + $user->save(); + + $this->assertGreaterThan(0, $user->id); + } + + public function testSetDatabaseConnectionWithAdapter() + { + $user = new User(); + $user->setDatabaseConnection(new PdoAdapter(new PDO('sqlite:test.db'))); + $user->name = 'bob'; + $user->password = 'pass'; + $user->save(); + + $this->assertGreaterThan(0, $user->id); + } + + public function testRelationWithProtectedKeyword() + { + $user = new User(new PDO('sqlite:test.db')); + $user->name = 'demo'; + $user->password = md5('demo'); + $user->insert(); + + $contact = new class (new PDO('sqlite:test.db')) extends ActiveRecord { + protected array $relations = [ + 'group' => [self::HAS_ONE, User::class, 'user_id'] + ]; + }; + + $this->expectException(\Exception::class); + $this->expectExceptionMessage('group is a protected keyword and cannot be used as a relation name'); + $contact->group->id; + } } diff --git a/tests/ActiveRecordTest.php b/tests/ActiveRecordTest.php index ee99878..9a92e46 100644 --- a/tests/ActiveRecordTest.php +++ b/tests/ActiveRecordTest.php @@ -118,26 +118,26 @@ public function testCopyFrom() $this->assertEquals(['name' => 'John'], $record->getData()); } - public function testIsset() - { - $record = new class (null, 'test_table') extends ActiveRecord { - }; - $record->name = 'John'; - $this->assertTrue(isset($record->name)); - $this->assertFalse(isset($record->email)); - } + public function testIsset() + { + $record = new class (null, 'test_table') extends ActiveRecord { + }; + $record->name = 'John'; + $this->assertTrue(isset($record->name)); + $this->assertFalse(isset($record->email)); + } - public function testMultipleJoins() + public function testMultipleJoins() { $record = new class (null, 'test_table') extends ActiveRecord { - public function query(string $sql, array $param = [], ?ActiveRecord $obj = null, bool $single = false) - { - return $this; - } + public function query(string $sql, array $param = [], ?ActiveRecord $obj = null, bool $single = false) + { + return $this; + } }; $record->join('table1', 'table1.some_id = test_table.id'); - $record->join('table2', 'table2.some_id = table1.id'); + $record->join('table2', 'table2.some_id = table1.id'); $result = $record->find()->getBuiltSql(); - $this->assertEquals('SELECT test_table.* FROM test_table LEFT JOIN table1 ON table1.some_id = test_table.id LEFT JOIN table2 ON table2.some_id = table1.id LIMIT 1 ', $result); + $this->assertEquals('SELECT test_table.* FROM test_table LEFT JOIN table1 ON table1.some_id = test_table.id LEFT JOIN table2 ON table2.some_id = table1.id LIMIT 1 ', $result); } }