-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add entity compatible SluggableBehavior with tests
- Loading branch information
1 parent
1e77fc7
commit 6b743d3
Showing
7 changed files
with
261 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
<?php | ||
|
||
namespace albertborsos\ddd\behaviors; | ||
|
||
use albertborsos\ddd\base\EntityEvent; | ||
use albertborsos\ddd\interfaces\ActiveRepositoryInterface; | ||
use albertborsos\ddd\interfaces\EntityInterface; | ||
use albertborsos\ddd\interfaces\RepositoryInterface; | ||
use albertborsos\ddd\traits\EvaluateAttributesTrait; | ||
use Yii; | ||
use yii\base\InvalidConfigException; | ||
use yii\db\BaseActiveRecord; | ||
use yii\helpers\ArrayHelper; | ||
use yii\validators\UniqueValidator; | ||
|
||
class SluggableBehavior extends \yii\behaviors\SluggableBehavior | ||
{ | ||
use EvaluateAttributesTrait; | ||
|
||
/** @var ActiveRepositoryInterface */ | ||
public $repository; | ||
|
||
public function init() | ||
{ | ||
if (empty($this->attributes)) { | ||
$this->attributes = [ | ||
EntityInterface::EVENT_BEFORE_INSERT => $this->slugAttribute, | ||
EntityInterface::EVENT_BEFORE_UPDATE => $this->slugAttribute, | ||
]; | ||
} | ||
|
||
if ($this->attribute === null && $this->value === null) { | ||
throw new InvalidConfigException('Either "attribute" or "value" property must be specified.'); | ||
} | ||
|
||
if ($this->ensureUnique && empty($this->repository)) { | ||
throw new InvalidConfigException(get_called_class() . '::$repository must be set!'); | ||
} | ||
|
||
if ($this->repository) { | ||
/** @var ActiveRepositoryInterface $repository */ | ||
$repository = \Yii::createObject($this->repository); | ||
$this->setRepository($repository); | ||
} | ||
} | ||
|
||
/** | ||
* @return ActiveRepositoryInterface | ||
*/ | ||
protected function getRepository() | ||
{ | ||
return $this->repository; | ||
} | ||
|
||
/** | ||
* @param ActiveRepositoryInterface $repository | ||
*/ | ||
protected function setRepository(ActiveRepositoryInterface $repository): void | ||
{ | ||
$this->repository = $repository; | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
protected function getValue($event) | ||
{ | ||
if (!$this->isNewSlugNeededByEvent($event)) { | ||
return $this->owner->{$this->slugAttribute}; | ||
} | ||
|
||
if ($this->attribute !== null) { | ||
$slugParts = []; | ||
foreach ((array)$this->attribute as $attribute) { | ||
$part = ArrayHelper::getValue($this->owner, $attribute); | ||
if ($this->skipOnEmpty && $this->isEmpty($part)) { | ||
return $this->owner->{$this->slugAttribute}; | ||
} | ||
$slugParts[] = $part; | ||
} | ||
$slug = $this->generateSlug($slugParts); | ||
} else { | ||
$slug = parent::getValue($event); | ||
} | ||
|
||
return $this->ensureUnique ? $this->makeUnique($slug) : $slug; | ||
} | ||
|
||
protected function isNewSlugNeededByEvent(EntityEvent $event) | ||
{ | ||
if (empty($this->owner->{$this->slugAttribute})) { | ||
return true; | ||
} | ||
|
||
if ($this->immutable) { | ||
return false; | ||
} | ||
|
||
if ($this->attribute === null) { | ||
return true; | ||
} | ||
|
||
foreach ((array)$this->attribute as $attribute) { | ||
if (in_array($attribute, array_keys($event->dirtyAttributes))) { | ||
return true; | ||
} | ||
} | ||
|
||
return false; | ||
} | ||
|
||
/** | ||
* Checks if given slug value is unique. | ||
* @param string $slug slug value | ||
* @return bool whether slug is unique. | ||
*/ | ||
protected function validateSlug($slug) | ||
{ | ||
/* @var $validator UniqueValidator */ | ||
/* @var $model BaseActiveRecord */ | ||
$validator = Yii::createObject(array_merge( | ||
[ | ||
'class' => UniqueValidator::className(), | ||
], | ||
$this->uniqueValidator | ||
)); | ||
|
||
$model = Yii::createObject($this->repository->getDataModelClass()); | ||
$model->clearErrors(); | ||
$model->{$this->slugAttribute} = $slug; | ||
|
||
$validator->validateAttribute($model, $this->slugAttribute); | ||
return !$model->hasErrors(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,6 +14,7 @@ public function attributeLabels() | |
return [ | ||
'id' => 'ID', | ||
'name' => 'Name', | ||
'slug' => 'Slug', | ||
]; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
<?php | ||
|
||
namespace albertborsos\ddd\tests\behaviors; | ||
|
||
use albertborsos\ddd\repositories\AbstractActiveRepository; | ||
use albertborsos\ddd\tests\fixtures\CustomerWithBehaviorsFixtures; | ||
use albertborsos\ddd\tests\support\base\domains\customer\entities\CustomerWithBehaviors; | ||
use albertborsos\ddd\tests\support\base\domains\customer\mysql\CustomerWithBehaviorsActiveRepository; | ||
use albertborsos\ddd\tests\support\base\domains\customer\mysql\CustomerWithModifiedBehaviorsActiveRepository; | ||
use Codeception\PHPUnit\TestCase; | ||
use yii\test\FixtureTrait; | ||
|
||
class SluggableBehaviorTest extends TestCase | ||
{ | ||
use FixtureTrait; | ||
|
||
public function fixtures() | ||
{ | ||
return [ | ||
'customers' => CustomerWithBehaviorsFixtures::class, | ||
]; | ||
} | ||
|
||
protected function setUp(): void | ||
{ | ||
parent::setUp(); | ||
$this->initFixtures(); | ||
} | ||
|
||
public function testInsert() | ||
{ | ||
$data = [ | ||
'id' => 3, | ||
'name' => 'Test slug attribute is filled on insert', | ||
]; | ||
|
||
/** @var AbstractActiveRepository $repository */ | ||
$repository = \Yii::createObject(CustomerWithBehaviorsActiveRepository::class); | ||
|
||
$entity = $repository->hydrate($data); | ||
$this->assertTrue($repository->insert($entity)); | ||
|
||
/** @var CustomerWithBehaviors $entity */ | ||
$entity = $repository->findOne($data['id']); | ||
|
||
$this->assertNotEmpty($entity->slug); | ||
} | ||
|
||
public function testUpdate() | ||
{ | ||
$data = [ | ||
'id' => 1, | ||
'name' => 'Test slug attribute is modified on update', | ||
]; | ||
|
||
/** @var AbstractActiveRepository $repository */ | ||
$repository = \Yii::createObject(CustomerWithBehaviorsActiveRepository::class); | ||
/** @var CustomerWithBehaviors $entity */ | ||
$entity = $repository->findOne($data['id']); | ||
|
||
$oldSlug = $entity->slug; | ||
|
||
$entity->setAttributes($data, false); | ||
$this->assertTrue($repository->update($entity)); | ||
|
||
$entity = $repository->findOne($data['id']); | ||
|
||
$this->assertNotEquals($oldSlug, $entity->slug); | ||
} | ||
|
||
public function testUpdateWithoutModification() | ||
{ | ||
$data = [ | ||
'id' => 1, | ||
'name' => 'Albert', | ||
]; | ||
|
||
/** @var AbstractActiveRepository $repository */ | ||
$repository = \Yii::createObject(CustomerWithBehaviorsActiveRepository::class); | ||
/** @var CustomerWithBehaviors $entity */ | ||
$entity = $repository->findOne($data['id']); | ||
|
||
$oldSlug = $entity->slug; | ||
|
||
$entity->setAttributes($data, false); | ||
$this->assertTrue($repository->update($entity)); | ||
|
||
$entity = $repository->findOne($data['id']); | ||
|
||
$this->assertEquals($oldSlug, $entity->slug); | ||
} | ||
|
||
public function testUniqueSlug() | ||
{ | ||
$data = [ | ||
'id' => 3, | ||
'name' => 'Albert', | ||
]; | ||
|
||
/** @var AbstractActiveRepository $repository */ | ||
$repository = \Yii::createObject(CustomerWithBehaviorsActiveRepository::class); | ||
/** @var CustomerWithBehaviors $entity */ | ||
$entity = $repository->hydrate($data); | ||
$this->assertTrue($repository->insert($entity)); | ||
|
||
$entity = $repository->findOne($data['id']); | ||
|
||
$this->assertNotEquals('albert', $entity->slug); | ||
} | ||
} |