diff --git a/src/NotFoundException.php b/src/NotFoundException.php new file mode 100644 index 000000000..35f9ec1fe --- /dev/null +++ b/src/NotFoundException.php @@ -0,0 +1,14 @@ +all(); } + /** + * Shortcut for {@see findAll()} method with throwing {@see NotFoundException} if no records found. + * + * ```php + * $customers = Customer::findAllOrFail(['is_active' => true]); + * ``` + * + * @param array|ExpressionInterface|string|null $condition The condition to be applied to the query where clause. + * Returns all records if `null` (by default). + * @param array $params The parameters to be bound to the SQL statement during execution. + * + * @throws NotFoundException + * + * @return ActiveRecordInterface[]|array[] An array of ActiveRecord instance, or throws {@see NotFoundException} + * if nothing matches. + */ + public static function findAllOrFail(array|string|ExpressionInterface|null $condition = null, array $params = []): array + { + return static::findAll($condition, $params) ?: throw new NotFoundException('No records found.'); + } + /** * Finds an ActiveRecord instance by the given primary key value. * In the examples below, the `id` column is the primary key of the table. @@ -123,6 +153,10 @@ public static function findAll(array|string|ExpressionInterface|null $condition * $customer = Customer::findByPk($id); * } * ``` + * + * @param array|float|int|string $values The primary key value(s) to find the record. + * + * @return ActiveRecordInterface|array|null Instance matching the primary key value(s), or `null` if nothing matches. */ public static function findByPk(array|float|int|string $values): array|ActiveRecordInterface|null { @@ -130,10 +164,29 @@ public static function findByPk(array|float|int|string $values): array|ActiveRec } /** - * Creates an {@see ActiveQuery} instance with a given SQL statement. + * Shortcut for {@see findByPk()} method with throwing {@see NotFoundException} if no records found. + * + * ```php + * $customer = Customer::findByPkOrFail(1); + * ``` + * + * @param array|float|int|string $values The primary key value(s) to find the record. + * + * @throws NotFoundException + * + * @return ActiveRecordInterface|array|null Instance matching the primary key value(s), + * or throws {@see NotFoundException} if nothing matches. + */ + public static function findByPkOrFail(array|float|int|string $values): array|ActiveRecordInterface|null + { + return static::findByPk($values) ?? throw new NotFoundException('No records found.'); + } + + /** + * Creates an {@see ActiveQueryInterface} instance with a given SQL statement. * * Note: That because the SQL statement is already specified, calling more query modification methods - * (such as {@see where()}, {@see order()) on the created {@see ActiveQuery} instance will have no effect. + * (such as {@see where()}, {@see order()) on the created {@see ActiveQueryInterface} instance will have no effect. * * However, calling {@see with()}, {@see asArray()}, {@see indexBy()} or {@see resultCallback()} is still fine. * @@ -145,6 +198,8 @@ public static function findByPk(array|float|int|string $values): array|ActiveRec * * @param string $sql The SQL statement to be executed. * @param array $params The parameters to be bound to the SQL statement during execution. + * + * @return ActiveQueryInterface The newly created {@see ActiveQueryInterface} instance. */ public static function findBySql(string $sql, array $params = []): ActiveQueryInterface { @@ -183,6 +238,10 @@ public static function findBySql(string $sql, array $params = []): ActiveQueryIn * $post = Post::findByPk($id); * ``` * + * @param array|ExpressionInterface|string|null $condition The condition to be applied to the query where clause. + * Returns the first record if `null` (by default). + * @param array $params The parameters to be bound to the SQL statement during execution. + * * @return ActiveRecordInterface|array|null Instance matching the condition, or `null` if nothing matches. */ public static function findOne( @@ -192,6 +251,29 @@ public static function findOne( return static::find($condition, $params)->one(); } + /** + * Shortcut for {@see findOne()} method with throwing {@see NotFoundException} if no records found. + * + * ```php + * $customer = Customer::findOneOrFail(['id' => 1]); + * ``` + * + * @param array|ExpressionInterface|string|null $condition The condition to be applied to the query where clause. + * Returns the first record if `null` (by default). + * @param array $params The parameters to be bound to the SQL statement during execution. + * + * @throws NotFoundException + * + * @return ActiveRecordInterface|array|null Instance matching the condition, or throws {@see NotFoundException} + * if nothing matches. + */ + public static function findOneOrFail( + array|string|ExpressionInterface|null $condition = null, + array $params = [], + ): ActiveRecordInterface|array|null { + return static::findOne($condition, $params) ?? throw new NotFoundException('No records found.'); + } + protected static function instantiate(): ActiveRecordInterface { return new static(); diff --git a/tests/RepositoryTraitTest.php b/tests/RepositoryTraitTest.php index 040baa9e6..cec6e6af9 100644 --- a/tests/RepositoryTraitTest.php +++ b/tests/RepositoryTraitTest.php @@ -5,6 +5,7 @@ namespace Yiisoft\ActiveRecord\Tests; use Yiisoft\ActiveRecord\ActiveQuery; +use Yiisoft\ActiveRecord\NotFoundException; use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\Customer; abstract class RepositoryTraitTest extends TestCase @@ -45,6 +46,21 @@ public function testFindOne(): void $this->assertNull($customer); } + public function testFindOneOrFail(): void + { + $customerQuery = new ActiveQuery(new Customer()); + + $this->assertEquals( + $customerQuery->where(['id' => 1])->one(), + Customer::findOneOrFail(['id' => 1]), + ); + + $this->expectException(NotFoundException::class); + $this->expectExceptionMessage('No records found.'); + + Customer::findOneOrFail(['name' => 'user5']); + } + public function testFindAll(): void { $customerQuery = new ActiveQuery(new Customer()); @@ -63,6 +79,21 @@ public function testFindAll(): void $this->assertCount(3, Customer::findAll(['id' => [1, 2, 3]])); } + public function testFindAllOrFail(): void + { + $customerQuery = new ActiveQuery(new Customer()); + + $this->assertEquals( + $customerQuery->where(['id' => [1, 2, 3]])->all(), + Customer::findAllOrFail(['id' => [1, 2, 3]]), + ); + + $this->expectException(NotFoundException::class); + $this->expectExceptionMessage('No records found.'); + + Customer::findAllOrFail(['id' => 5]); + } + public function testFindByPk(): void { $customerQuery = new ActiveQuery(new Customer()); @@ -76,6 +107,21 @@ public function testFindByPk(): void $this->assertNull($customer); } + public function testFindByPkOrFail(): void + { + $customerQuery = new ActiveQuery(new Customer()); + + $this->assertEquals( + $customerQuery->where(['id' => 1])->one(), + Customer::findByPkOrFail(1), + ); + + $this->expectException(NotFoundException::class); + $this->expectExceptionMessage('No records found.'); + + Customer::findByPkOrFail(5); + } + public function testFindBySql(): void { $customerQuery = new ActiveQuery(new Customer());