Skip to content

Commit 69306d1

Browse files
authored
Merge pull request #38 from burzum/callbacks
#36 Allow scope option to be a callable
2 parents 301ec72 + 8816624 commit 69306d1

File tree

2 files changed

+83
-21
lines changed

2 files changed

+83
-21
lines changed

src/Model/Behavior/SlugBehavior.php

Lines changed: 72 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ class SlugBehavior extends Behavior
3434
* to `Muffin\Slug\Slugger\CakeSlugger`.
3535
* - unique: Tells if slugs should be unique. Set this to a callable if you
3636
* want to customize how unique slugs are generated. Defaults to `true`.
37-
* - scope: Extra conditions used when checking a slug for uniqueness.
37+
* - scope: Extra conditions or a callable `$callable($entity)` used when
38+
* checking a slug for uniqueness.
3839
* - implementedEvents: Events this behavior listens to. Defaults to
3940
* `['Model.buildValidator' => 'buildValidator', 'Model.beforeSave' => 'beforeSave']`.
4041
* By default the behavior adds validation for the `displayField` fields
@@ -218,25 +219,37 @@ public function beforeSave(Event $event, Entity $entity, ArrayObject $options)
218219
return;
219220
}
220221

222+
$parts = $this->_getPartsFromEntity($entity);
223+
if (empty($parts)) {
224+
return;
225+
}
226+
227+
$slug = $this->slug($entity, implode($separator, $parts), $separator);
228+
$entity->set($field, $slug);
229+
}
230+
231+
/**
232+
* Gets the parts from an entity
233+
*
234+
* @param \Cake\Datasource\EntityInterface $entity Entity
235+
* @return array
236+
*/
237+
protected function _getPartsFromEntity($entity)
238+
{
221239
$parts = [];
222240
foreach ((array)$this->getConfig('displayField') as $displayField) {
223241
$value = Hash::get($entity, $displayField);
224242

225243
if ($value === null && !$entity->isNew()) {
226-
return;
244+
return [];
227245
}
228246

229247
if (!empty($value) || is_numeric($value)) {
230248
$parts[] = $value;
231249
}
232250
}
233251

234-
if (!count($parts)) {
235-
return;
236-
}
237-
238-
$slug = $this->slug($entity, implode($separator, $parts), $separator);
239-
$entity->set($field, $slug);
252+
return $parts;
240253
}
241254

242255
/**
@@ -278,14 +291,7 @@ public function slug($entity, $string = null, $separator = null)
278291
$string = $entity;
279292
unset($entity);
280293
} elseif (($entity instanceof Entity) && $string === null) {
281-
$string = [];
282-
foreach ((array)$this->getConfig('displayField') as $field) {
283-
if ($entity->getError($field)) {
284-
throw new InvalidArgumentException();
285-
}
286-
$string[] = $value = Hash::get($entity, $field);
287-
}
288-
$string = implode($separator, $string);
294+
$string = $this->_getSlugStringFromEntity($entity, $separator);
289295
}
290296

291297
$slug = $this->_slug($string, $separator);
@@ -298,6 +304,55 @@ public function slug($entity, $string = null, $separator = null)
298304
return $slug;
299305
}
300306

307+
/**
308+
* Gets the slug string based on an entity
309+
*
310+
* @param \Cake\Datasource\EntityInterface $entity Entity
311+
* @param string $separator Separator
312+
* @return string
313+
*/
314+
protected function _getSlugStringFromEntity($entity, $separator)
315+
{
316+
$string = [];
317+
foreach ((array)$this->getConfig('displayField') as $field) {
318+
if ($entity->getError($field)) {
319+
throw new InvalidArgumentException(sprintf('Error while generating the slug, the field `%s` contains an invalid value.', $field));
320+
}
321+
$string[] = $value = Hash::get($entity, $field);
322+
}
323+
324+
return implode($separator, $string);
325+
}
326+
327+
/**
328+
* Builds the conditions
329+
*
330+
* @param \Cake\ORM\Entity $entity Entity.
331+
* @param string $slug Slug
332+
* @return array
333+
*/
334+
protected function _conditions($entity, $slug)
335+
{
336+
/** @var string $primaryKey */
337+
$primaryKey = $this->_table->getPrimaryKey();
338+
$field = $this->_table->aliasField($this->getConfig('field'));
339+
340+
$conditions = [$field => $slug];
341+
342+
if (is_callable($this->getConfig('scope'))) {
343+
$scope = $this->getConfig('scope');
344+
$conditions += $scope($entity);
345+
} else {
346+
$conditions += $this->getConfig('scope');
347+
}
348+
349+
if ($id = $entity->{$primaryKey}) {
350+
$conditions['NOT'][$this->_table->aliasField($primaryKey)] = $id;
351+
}
352+
353+
return $conditions;
354+
}
355+
301356
/**
302357
* Returns a unique slug.
303358
*
@@ -312,11 +367,7 @@ protected function _uniqueSlug(Entity $entity, $slug, $separator)
312367
$primaryKey = $this->_table->getPrimaryKey();
313368
$field = $this->_table->aliasField($this->getConfig('field'));
314369

315-
$conditions = [$field => $slug];
316-
$conditions += $this->getConfig('scope');
317-
if ($id = $entity->{$primaryKey}) {
318-
$conditions['NOT'][$this->_table->aliasField($primaryKey)] = $id;
319-
}
370+
$conditions = $this->_conditions($entity, $slug);
320371

321372
$i = 0;
322373
$suffix = '';

tests/TestCase/Model/Behavior/SlugBehaviorTest.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,4 +429,15 @@ public function testCallableForSlugger()
429429
$result = $this->Behavior->slug('FOO');
430430
$this->assertEquals('foo', $result);
431431
}
432+
433+
public function testCallableForUnique()
434+
{
435+
$this->Behavior->setConfig('scope', function ($entity) {
436+
return ['namespace' => $entity->namespace];
437+
});
438+
439+
$newEntity = $this->Tags->newEntity(['namespace' => 'foo', 'name' => 'Color']);
440+
441+
$this->assertEquals('color', $this->Tags->slug($newEntity));
442+
}
432443
}

0 commit comments

Comments
 (0)