From 975dfe424d884c23129a098f72190b4ee5da967a Mon Sep 17 00:00:00 2001 From: Emad Rashdan Date: Tue, 5 Jan 2021 15:37:48 +0200 Subject: [PATCH] #15 Create Validation Hashed Exist (#19) * Create Validation Hashed Exist * Apply fixes from StyleCI (#18) Co-authored-by: Emad Rashdan * Update readme.md Co-authored-by: Emad Rashdan --- readme.md | 8 +++++++ src/Exceptions/UndefinedKey.php | 10 ++++++++ src/Exceptions/UndefinedLength.php | 10 ++++++++ src/HashData.php | 3 ++- src/HashedIdValidator.php | 15 ++++++++++++ src/HashidServiceProvider.php | 20 +++++++++++++--- src/Traits/Hashid.php | 38 ++++++++++++++++++++++++++---- tests/HashingTest.php | 18 ++++++++------ tests/TestCase.php | 2 +- tests/ValidationTest.php | 38 ++++++++++++++++++++++++++++++ 10 files changed, 145 insertions(+), 17 deletions(-) create mode 100644 src/Exceptions/UndefinedKey.php create mode 100644 src/Exceptions/UndefinedLength.php create mode 100644 src/HashedIdValidator.php create mode 100644 tests/ValidationTest.php diff --git a/readme.md b/readme.md index 9ce6cdb..831b104 100644 --- a/readme.md +++ b/readme.md @@ -75,6 +75,14 @@ $post = \App\Post::FindOrFailHashed('x7LR5oQJleJX60yPpNWV'); $post->id; //1 ``` +## Validation +You can validate if hashed id is existed in model or not +```php + request()->validate([ + 'post_id' => 'hashed_exists:' . \App\Post::class + ]); +``` + ### Testing ``` bash diff --git a/src/Exceptions/UndefinedKey.php b/src/Exceptions/UndefinedKey.php new file mode 100644 index 0000000..ed901a2 --- /dev/null +++ b/src/Exceptions/UndefinedKey.php @@ -0,0 +1,10 @@ +publishes([ - __DIR__.'/../config/hashid.php' => config_path('hashid.php'), - ], 'config'); + if ($this->app->runningInConsole()) { + $this->bootForConsole(); + } + + Validator::extend('hashed_exists', + HashedIdValidator::class.'@validate', + trans('The selected :attribute is invalid.') + ); } /** @@ -25,5 +31,13 @@ public function boot() */ public function register() { + // + } + + protected function bootForConsole() + { + $this->publishes([ + __DIR__.'/../config/hashid.php' => config_path('hashid.php'), + ], 'config'); } } diff --git a/src/Traits/Hashid.php b/src/Traits/Hashid.php index 222ac55..618bb20 100644 --- a/src/Traits/Hashid.php +++ b/src/Traits/Hashid.php @@ -2,7 +2,9 @@ namespace Erashdan\Hashid\Traits; +use Erashdan\Hashid\Exceptions\UndefinedKey; use Erashdan\Hashid\HashData; +use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\ModelNotFoundException; trait Hashid @@ -36,6 +38,16 @@ public static function DecodeId($id) } } + // ---------- Scope ---------- + + /** + * Find or fail by hash ID. + * + * @param $query + * @param $id + * @return mixed + * @throws \Exception + */ public function scopeFindOrFailHashed($query, $id) { if (empty($decoded = self::DecodeId($id))) { @@ -45,18 +57,34 @@ public function scopeFindOrFailHashed($query, $id) return $query->findOrFail(self::DecodeId($id)); } - public function scopeFindHashed($query, $id) + /** + * Find resource by hashed id. + * + * @param $id + * @return null|Model + * @throws \Exception + */ + public static function FindHashed($id) { if (empty($decoded = self::DecodeId($id))) { - return; + return null; } - return $query->find(self::DecodeId($id)); + return self::find(self::DecodeId($id)); } - public function scopeWhereInHashed($query, $values) + /** + * Find multiple resources by hash ids. + * + * @param $query + * @param array $values + * @return mixed + * @throws \Exception + */ + public function scopeWhereInHashed($query, array $values) { $hash = []; + foreach ($values as $value) { $hash[] = self::DecodeId($value); } @@ -70,7 +98,7 @@ private static function setHashKey($class) (config('hashid.hash_data.key') == null) || (config('hashid.hash_data.key') == '') ) { - throw new \Exception('Unable to define hashing key'); + throw new UndefinedKey(); } return config('hashid.hash_data.key').$class; diff --git a/tests/HashingTest.php b/tests/HashingTest.php index 1186e8f..aeae526 100644 --- a/tests/HashingTest.php +++ b/tests/HashingTest.php @@ -2,17 +2,19 @@ namespace Erashdan\Hashid\Test; +use Erashdan\Hashid\Exceptions\UndefinedKey; +use Erashdan\Hashid\Exceptions\UndefinedLength; use Illuminate\Database\Eloquent\ModelNotFoundException; class HashingTest extends TestCase { - /** @test * */ + /** @test **/ public function hashid_can_hash_primary_key() { $this->assertEquals('N5zQE4', $this->testModel->hashed_id); } - /** @test * */ + /** @test **/ public function get_correct_element_by_hashed_id() { $element = TestModel::FindOrFailHashed('N5zQE4'); @@ -20,14 +22,14 @@ public function get_correct_element_by_hashed_id() $this->assertEquals(2, $element->another_key); } - /** @test * */ + /** @test **/ public function throw_exception_if_element_not_exist() { $this->expectException(ModelNotFoundException::class); TestModel::FindOrFailHashed('FAKE_HASH'); } - /** @test * */ + /** @test **/ public function hashing_id_length_is_changeable() { config(['hashid.hash_data.length' => 10]); @@ -37,23 +39,25 @@ public function hashing_id_length_is_changeable() ); } - /** @test * */ + /** @test **/ public function throw_exception_if_hash_key_not_exist() { config(['hashid.hash_data.key' => null]); + $this->expectException(UndefinedKey::class); $this->expectExceptionMessage('Unable to define hashing key'); $this->assertNotNull($this->testModel->hashed_id); } - /** @test * */ + /** @test **/ public function throw_exception_if_hash_length_not_exist() { config(['hashid.hash_data.length' => null]); + $this->expectException(UndefinedLength::class); $this->expectExceptionMessage('Unable to define hashing length'); $this->assertNotNull($this->testModel->hashed_id); } - /** @test * */ + /** @test **/ public function throw_exception_if_hash_length_not_integer() { config(['hashid.hash_data.length' => 'STRING']); diff --git a/tests/TestCase.php b/tests/TestCase.php index ab224db..83832d2 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -7,7 +7,7 @@ abstract class TestCase extends Orchestra { - /** @var \Erashdan\Hashid\Test\TestModel */ + /** @var TestModel */ protected $testModel; public function setUp(): void diff --git a/tests/ValidationTest.php b/tests/ValidationTest.php new file mode 100644 index 0000000..0ec52b4 --- /dev/null +++ b/tests/ValidationTest.php @@ -0,0 +1,38 @@ +registerValidator(); + + $rules = [ + 'key' => 'hashed_exists:'.TestModel::class, + ]; + + $invalid_data = [ + 'key' => 'ANY KEY', + ]; + + $valid_data = [ + 'key' => 'N5zQE4', + ]; + + $failed_validation = $this->app['validator']->make($invalid_data, $rules); + $this->assertFalse($failed_validation->passes()); + + $success_validation = $this->app['validator']->make($valid_data, $rules); + $this->assertTrue($success_validation->passes()); + } + + protected function registerValidator() + { + Validator::extend('hashed_exists', HashedIdValidator::class.'@validate', trans('The selected :attribute is invalid.')); + } +}