Kohana_Jam_Behavior_Sluggable   A
last analyzed

Complexity

Total Complexity 36

Size/Duplication

Total Lines 225
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 11

Test Coverage

Coverage 67.16%

Importance

Changes 0
Metric Value
wmc 36
lcom 1
cbo 11
dl 0
loc 225
ccs 45
cts 67
cp 0.6716
rs 9.52
c 0
b 0
f 0

16 Methods

Rating   Name   Duplication   Size   Complexity  
B initialize() 0 21 6
A auto_save() 0 4 1
A unique() 0 4 1
A uses_primary_key() 0 4 1
A pattern() 0 4 1
A slug() 0 4 1
A model_before_check() 0 8 4
A model_after_save() 0 16 5
A _uses_primary_key_pattern() 0 4 1
A _no_primary_key_pattern() 0 4 1
A model_call_build_slug() 0 9 2
A builder_call_where_slug() 0 11 4
A builder_call_find_by_slug() 0 7 2
A builder_call_find_by_slug_insist() 0 10 1
A model_call_matches_slug() 0 4 3
A model_call_matches_slug_insist() 0 7 2
1
<?php defined('SYSPATH') OR die('No direct access allowed.');
2
3
/**
4
 * Resource_Jam_Behavior_Sluggable class
5
 *
6
 *  Sluggable behavior for Jam ORM library
7
 *  Provides functionality to generate a slug based on a combination of the model primary value, model singular name and the id
8
 *  e.g news: some-news-title-23
9
 *  Slugs are automatically updated upon save
10
 *
11
 * @package    Jam
12
 * @author     Yasen Yanev
13
 * @author     Ivan Kerin
14
 * @author     Haralan Dobrev
15
 * @copyright  (c) 2012 Despark Ltd.
16
 * @license    http://creativecommons.org/licenses/by-sa/3.0/legalcode
17
 * @version 1.0
18
 */
19
class Kohana_Jam_Behavior_Sluggable extends Jam_Behavior {
20
21
	const SLUG = "/^[a-z0-9-]+$/";
22
	const ID_SLUG = "/^([a-z0-9-]+?-)?([1-9][0-9]*)$/";
23
24
	protected $_slug = NULL;
25
26
	protected $_pattern = NULL;
27
28
	protected $_uses_primary_key = TRUE;
29
30
	protected $_auto_save = TRUE;
31
32
	protected $_unique = TRUE;
33
34
	/**
35
	 * Initializes the behavior
36
	 *
37
	 * It sets the fields used in generating the slug
38
	 *
39
	 * @param  Jam_Event $event the jam event for the behavior
0 ignored issues
show
Bug introduced by
There is no parameter named $event. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
40
	 * @param  Jam_Model      $model The Jam_Model object on which the behavior is applies
0 ignored issues
show
Bug introduced by
There is no parameter named $model. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
41
	 * @param  string      $name
42
	 * @return void
43
	 */
44
	public function initialize(Jam_Meta $meta, $name)
45
	{
46
		parent::initialize($meta, $name);
47
48
		$meta->field('slug', Jam::field('slug'));
49
50
		if ($this->_unique)
51
		{
52
			$meta->validator('slug', array('unique' => $this->_unique));
53
		}
54
55
		if ( ! $this->_slug)
56
		{
57
			$this->_slug = $this->_uses_primary_key ? 'Jam_Behavior_Sluggable::_uses_primary_key_pattern' : 'Jam_Behavior_Sluggable::_no_primary_key_pattern';
58
		}
59
60
		if (empty($this->_pattern))
61
		{
62
			$this->_pattern = $this->_uses_primary_key ? Jam_Behavior_Sluggable::ID_SLUG : Jam_Behavior_Sluggable::SLUG;
63
		}
64
	}
65
66
	/**
67
	 * Getter for parameter
68
	 * @return bool
69
	 */
70 11
	public function auto_save()
71
	{
72 11
		return $this->_auto_save;
73
	}
74
75
	/**
76
	 * Getter for parameter
77
	 * @return bool
78
	 */
79
	public function unique()
80
	{
81
		return $this->_unique;
82
	}
83
84
	/**
85
	 * Getter for parameter
86
	 * @return bool
87
	 */
88 11
	public function uses_primary_key()
89
	{
90 11
		return $this->_uses_primary_key;
91
	}
92
93
	/**
94
	 * Getter for parameter
95
	 * @return bool
96
	 */
97
	public function pattern()
98
	{
99
		return $this->_pattern;
100
	}
101
102
	/**
103
	 * Getter for parameter
104
	 * @return bool
105
	 */
106
	public function slug()
107
	{
108
		return $this->_slug;
109
	}
110
111
	/**
112
	 * Called before validation.
113
	 * If the slug does not use the primary key the slug is built event before
114
	 * the validation. This way it could be validated and there are no
115
	 * additional database queries to update it.
116
	 *
117
	 * @param  Jam_Model $model
118
	 */
119 12
	public function model_before_check(Jam_Model $model)
120
	{
121 12
		if ($this->auto_save() AND ! $this->uses_primary_key() AND ! $model->changed('slug'))
122
		{
123
			// Use the built in slug transformation
124 1
			$model->slug = $model->build_slug();
0 ignored issues
show
Documentation introduced by
The property slug does not exist on object<Jam_Model>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
Documentation Bug introduced by
The method build_slug does not exist on object<Jam_Model>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
125
		}
126 12
	}
127
128
	/**
129
	 * Called after save.
130
	 * If the slug uses the primary key it is built after save and it is updated
131
	 * with an additional database query.
132
	 *
133
	 * @param  Jam_Model $model
134
	 */
135 13
	public function model_after_save(Jam_Model $model)
136
	{
137 13
		if ($this->auto_save() AND $this->uses_primary_key() AND ! $model->changed('slug'))
138
		{
139
			// Use the built in slug transformation
140 12
			$model->slug = $model->build_slug();
0 ignored issues
show
Documentation introduced by
The property slug does not exist on object<Jam_Model>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
Documentation Bug introduced by
The method build_slug does not exist on object<Jam_Model>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
141
142 12
			if ($model->slug != $model->original('slug'))
0 ignored issues
show
Documentation introduced by
The property slug does not exist on object<Jam_Model>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
143
			{
144 12
				Jam::update($this->_model)
145 12
					->where_key($model->id())
146 12
					->value('slug', $model->slug)
0 ignored issues
show
Documentation introduced by
The property slug does not exist on object<Jam_Model>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
147 12
					->execute();
148
			}
149
		}
150 13
	}
151
152 10
	static public function _uses_primary_key_pattern(Jam_Model $model)
153
	{
154 10
		return $model->name().'-'.$model->id();
155
	}
156
157
	static public function _no_primary_key_pattern(Jam_Model $model)
158
	{
159
		return $model->name();
160
	}
161
162
	/**
163
	 * Generates the slug for a model object
164
	 * @param  Jam_Model $model the Jam_Model object
165
	 * @return string the generated slug
166
	 * @uses URL::title to strip obsolete characters and build the slug
167
	 */
168 13
	public function model_call_build_slug(Jam_Model $model, Jam_Event_Data $data)
169
	{
170 13
		$source_string = trim(strtolower(URL::title(call_user_func($this->_slug, $model), '-', TRUE)), '-');
171
172 13
		if (empty($source_string))
173
			throw new Jam_Exception_Sluggable('The slug source is empty!', $model);
174
175 13
		return $data->return = $source_string;
176
	}
177
178
179
	/**
180
	 * Generated a find_by_slug method for Jam_Builder
181
	 * @param  Jam_Builder    $builder the builder object
182
	 * @param  string           $slug    the slug to search for
183
	 * @param  Jam_Event_Data $data
184
	 * @return void
185
	 */
186 16
	public function builder_call_where_slug(Jam_Query_Builder_Select $builder, Jam_Event_Data $data, $slug)
0 ignored issues
show
Unused Code introduced by
The parameter $data is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
187
	{
188 16
		if (preg_match($this->_pattern, $slug, $matches))
189
		{
190 8
			$builder->where($this->_uses_primary_key ? ':primary_key' : 'slug', '=', $matches[$this->_uses_primary_key ? 2 : 0]);
191
		}
192
		else
193
		{
194 8
			throw new Kohana_Exception("Invalid Slug :slug for :model", array(':slug' => $slug, ':model' => $builder->meta()->model()));
195
		}
196 8
	}
197
198
	/**
199
	 * Generated a find_by_slug method for Jam_Builder
200
	 * @param  Jam_Builder    $builder the builder object
201
	 * @param  string           $slug    the slug to search for
202
	 * @param  Jam_Event_Data $data
203
	 * @return void
204
	 */
205 5
	public function builder_call_find_by_slug(Jam_Query_Builder_Select $builder, Jam_Event_Data $data, $slug)
206
	{
207 5
		$this->builder_call_where_slug($builder, $data, $slug);
208 1
		$result = $builder->first();
0 ignored issues
show
Documentation Bug introduced by
The method first does not exist on object<Jam_Query_Builder_Select>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
209 1
		$data->stop = TRUE;
210 1
		return $data->return = ($result !== NULL) ? $result : FALSE;
211
	}
212
213
	/**
214
	 * Generates a find_by_slug_insist method for Jam_Builder
215
	 * @param  Jam_Builder    $builder the builder object
216
	 * @param  string           $slug    the slug to search for
217
	 * @param  Jam_Event_Data $data
218
	 * @return void
219
	 */
220 2
	public function builder_call_find_by_slug_insist(Jam_Query_Builder_Select $builder, Jam_Event_Data $data, $slug)
221
	{
222 2
		$this->builder_call_where_slug($builder, $data, $slug);
223 2
		$model = $builder->first_insist();
0 ignored issues
show
Documentation Bug introduced by
The method first_insist does not exist on object<Jam_Query_Builder_Select>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
224
225 1
		$model->matches_slug_insist($slug);
226
227
		$data->return = $model;
228
		$data->stop = TRUE;
229
	}
230
231 8
	public function model_call_matches_slug(Jam_Model $model, Jam_Event_Data $data, $slug)
232
	{
233 8
		$data->return = ! ($this->_uses_primary_key AND $model->slug AND $model->slug != $slug);
0 ignored issues
show
Documentation introduced by
The property slug does not exist on object<Jam_Model>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
234 8
	}
235
236 3
	public function model_call_matches_slug_insist(Jam_Model $model, Jam_Event_Data $data, $slug)
237
	{
238 3
		if ( ! $model->matches_slug($slug))
0 ignored issues
show
Documentation Bug introduced by
The method matches_slug does not exist on object<Jam_Model>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
239 2
			throw new Jam_Exception_Slugmismatch("Stale slug :slug for model :model ", $model, $slug);
240
241 1
		$data->return = TRUE;
242 1
	}
243
} // End Jam_Behavior_Sluggable
244