Skip to content

Commit

Permalink
#15 Create Validation Hashed Exist (#19)
Browse files Browse the repository at this point in the history
* Create Validation Hashed Exist

* Apply fixes from StyleCI (#18)

Co-authored-by: Emad Rashdan <[email protected]>

* Update readme.md

Co-authored-by: Emad Rashdan <[email protected]>
  • Loading branch information
erashdan and erashdan committed Jan 5, 2021
1 parent fac129a commit 975dfe4
Show file tree
Hide file tree
Showing 10 changed files with 145 additions and 17 deletions.
8 changes: 8 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 10 additions & 0 deletions src/Exceptions/UndefinedKey.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace Erashdan\Hashid\Exceptions;

use Exception;

class UndefinedKey extends Exception
{
protected $message = 'Unable to define hashing key';
}
10 changes: 10 additions & 0 deletions src/Exceptions/UndefinedLength.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace Erashdan\Hashid\Exceptions;

use Exception;

class UndefinedLength extends Exception
{
protected $message = 'Unable to define hashing length';
}
3 changes: 2 additions & 1 deletion src/HashData.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Erashdan\Hashid;

use Erashdan\Hashid\Exceptions\UndefinedLength;
use Hashids\Hashids;

class HashData
Expand Down Expand Up @@ -53,7 +54,7 @@ private static function getLength(): int
(config('hashid.hash_data.length') == '') ||
! is_int(config('hashid.hash_data.length'))
) {
throw new \Exception('Unable to define hashing length');
throw new UndefinedLength();
}

return config('hashid.hash_data.length');
Expand Down
15 changes: 15 additions & 0 deletions src/HashedIdValidator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace Erashdan\Hashid;

class HashedIdValidator
{
public function validate($attribute, $value, $parameters, $validator)
{
if (! isset($parameters[0])) {
return false;
}

return $parameters[0]::FindHashed($value) !== null;
}
}
20 changes: 17 additions & 3 deletions src/HashidServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Erashdan\Hashid;

use Illuminate\Support\Facades\Validator;
use Illuminate\Support\ServiceProvider;

class HashidServiceProvider extends ServiceProvider
Expand All @@ -13,9 +14,14 @@ class HashidServiceProvider extends ServiceProvider
*/
public function boot()
{
$this->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.')
);
}

/**
Expand All @@ -25,5 +31,13 @@ public function boot()
*/
public function register()
{
//
}

protected function bootForConsole()
{
$this->publishes([
__DIR__.'/../config/hashid.php' => config_path('hashid.php'),
], 'config');
}
}
38 changes: 33 additions & 5 deletions src/Traits/Hashid.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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))) {
Expand All @@ -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);
}
Expand All @@ -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;
Expand Down
18 changes: 11 additions & 7 deletions tests/HashingTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,34 @@

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');
$this->assertEquals(1, $element->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]);
Expand All @@ -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']);
Expand Down
2 changes: 1 addition & 1 deletion tests/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

abstract class TestCase extends Orchestra
{
/** @var \Erashdan\Hashid\Test\TestModel */
/** @var TestModel */
protected $testModel;

public function setUp(): void
Expand Down
38 changes: 38 additions & 0 deletions tests/ValidationTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

namespace Erashdan\Hashid\Test;

use Erashdan\Hashid\HashedIdValidator;
use Illuminate\Support\Facades\Validator;

class ValidationTest extends TestCase
{
/** @test * */
public function it_can_validate_if_hashed_id_exist_on_database_using_model_base()
{
$this->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.'));
}
}

0 comments on commit 975dfe4

Please sign in to comment.