diff --git a/.travis.yml b/.travis.yml
index bc06b36..9a9fdd8 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -12,22 +12,31 @@ env:
- REQUIRE="phpunit/phpunit:3.7.31"
matrix:
- - DB=mysql CAKE_VERSION=master
+ - DB=mysql CAKE_VERSION=2.7
matrix:
include:
- php: 5.3
env:
- - CAKE_VERSION=master
+ - CAKE_VERSION=2.7
- php: 5.4
env:
- - CAKE_VERSION=master
+ - CAKE_VERSION=2.7
- php: 5.5
env:
- - CAKE_VERSION=master
+ - CAKE_VERSION=2.7
+ - php: 5.3
+ env:
+ - CAKE_VERSION=2.6
+ - php: 5.4
+ env:
+ - CAKE_VERSION=2.6
+ - php: 5.5
+ env:
+ - CAKE_VERSION=2.6
before_script:
- - git clone https://github.com/burzum/travis.git --depth 1 ../travis
+ - git clone https://github.com/steinkel/travis.git --depth 1 ../travis
- ../travis/before_script.sh
- if [ "$PHPCS" != 1 ]; then
echo "
diff --git a/Config/Migration/001_initialize_tags_schema.php b/Config/Migration/001_initialize_tags_schema.php
index f1f0d8b..5ca746a 100644
--- a/Config/Migration/001_initialize_tags_schema.php
+++ b/Config/Migration/001_initialize_tags_schema.php
@@ -42,13 +42,13 @@ class M49ac311a54844a9d87o822502jedc423 extends CakeMigration {
'up' => array(
'create_table' => array(
'tagged' => array(
- 'id' => array('type' => 'string', 'null' => false, 'default' => NULL, 'length' => 36, 'key' => 'primary'),
- 'foreign_key' => array('type' => 'string', 'null' => false, 'default' => NULL, 'length' => 36),
- 'tag_id' => array('type' => 'string', 'null' => false, 'default' => NULL, 'length' => 36),
- 'model' => array('type' => 'string', 'null' => false, 'default' => NULL, 'key' => 'index'),
- 'language' => array('type' => 'string', 'null' => true, 'default' => NULL, 'length' => 6),
- 'created' => array('type' => 'datetime', 'null' => true, 'default' => NULL),
- 'modified' => array('type' => 'datetime', 'null' => true, 'default' => NULL),
+ 'id' => array('type' => 'string', 'null' => false, 'default' => null, 'length' => 36, 'key' => 'primary'),
+ 'foreign_key' => array('type' => 'string', 'null' => false, 'default' => null, 'length' => 36),
+ 'tag_id' => array('type' => 'string', 'null' => false, 'default' => null, 'length' => 36),
+ 'model' => array('type' => 'string', 'null' => false, 'default' => null, 'key' => 'index'),
+ 'language' => array('type' => 'string', 'null' => true, 'default' => null, 'length' => 6),
+ 'created' => array('type' => 'datetime', 'null' => true, 'default' => null),
+ 'modified' => array('type' => 'datetime', 'null' => true, 'default' => null),
'indexes' => array(
'PRIMARY' => array('column' => 'id', 'unique' => 1),
'UNIQUE_TAGGING' => array('column' => array('model', 'foreign_key', 'tag_id', 'language'), 'unique' => 1),
@@ -57,13 +57,13 @@ class M49ac311a54844a9d87o822502jedc423 extends CakeMigration {
)
),
'tags' => array(
- 'id' => array('type' => 'string', 'null' => false, 'default' => NULL, 'length' => 36, 'key' => 'primary'),
- 'identifier' => array('type' => 'string', 'null' => true, 'default' => NULL, 'length' => 30, 'key' => 'index'),
- 'name' => array('type' => 'string', 'null' => false, 'default' => NULL, 'length' => 30),
- 'keyname' => array('type' => 'string', 'null' => false, 'default' => NULL, 'length' => 30),
+ 'id' => array('type' => 'string', 'null' => false, 'default' => null, 'length' => 36, 'key' => 'primary'),
+ 'identifier' => array('type' => 'string', 'null' => true, 'default' => null, 'length' => 30, 'key' => 'index'),
+ 'name' => array('type' => 'string', 'null' => false, 'default' => null, 'length' => 30),
+ 'keyname' => array('type' => 'string', 'null' => false, 'default' => null, 'length' => 30),
'weight' => array('type' => 'integer', 'null' => false, 'default' => 0, 'length' => 2),
- 'created' => array('type' => 'datetime', 'null' => true, 'default' => NULL),
- 'modified' => array('type' => 'datetime', 'null' => true, 'default' => NULL),
+ 'created' => array('type' => 'datetime', 'null' => true, 'default' => null),
+ 'modified' => array('type' => 'datetime', 'null' => true, 'default' => null),
'indexes' => array(
'PRIMARY' => array('column' => 'id', 'unique' => 1),
'UNIQUE_TAG' => array('column' => array('identifier', 'keyname'), 'unique' => 1)
@@ -76,27 +76,4 @@ class M49ac311a54844a9d87o822502jedc423 extends CakeMigration {
)
);
-/**
- * Before migration callback
- *
- * @param string $direction, up or down direction of migration process
- * @return boolean Should process continue
- * @access public
- */
- public function before($direction) {
- return true;
- }
-
-/**
- * After migration callback
- *
- * @param string $direction, up or down direction of migration process
- * @return boolean Should process continue
- * @access public
- */
- public function after($direction) {
- return true;
- }
-
}
-?>
\ No newline at end of file
diff --git a/Config/Migration/002_create_times_tagged_field.php b/Config/Migration/002_create_times_tagged_field.php
index bf1914f..1bcf9c6 100644
--- a/Config/Migration/002_create_times_tagged_field.php
+++ b/Config/Migration/002_create_times_tagged_field.php
@@ -42,8 +42,8 @@ class M4c0d42bcd12c4db099c105f40e8f3d6d extends CakeMigration {
'create_field' => array(
'tagged' => array(
'times_tagged' => array('type' => 'integer', 'null' => false, 'default' => 1),
- )
),
+ ),
),
'down' => array(
'drop_field' => array(
@@ -52,26 +52,4 @@ class M4c0d42bcd12c4db099c105f40e8f3d6d extends CakeMigration {
),
);
-/**
- * Before migration callback
- *
- * @param string $direction, up or down direction of migration process
- * @return boolean Should process continue
- * @access public
- */
- public function before($direction) {
- return true;
- }
-
-/**
- * After migration callback
- *
- * @param string $direction, up or down direction of migration process
- * @return boolean Should process continue
- * @access public
- */
- public function after($direction) {
- return true;
- }
}
-?>
\ No newline at end of file
diff --git a/Config/Migration/003_occurrence_fields_for_tags.php b/Config/Migration/003_occurrence_fields_for_tags.php
index 1b46878..a1e9a6e 100644
--- a/Config/Migration/003_occurrence_fields_for_tags.php
+++ b/Config/Migration/003_occurrence_fields_for_tags.php
@@ -42,8 +42,8 @@ class M8d01880f01c11e0be500800200c9a66 extends CakeMigration {
'create_field' => array(
'tags' => array(
'occurrence' => array('type' => 'integer', 'null' => false, 'default' => 0, 'length' => 8),
- )
),
+ ),
'drop_field' => array(
'tags' => array('weight')
),
@@ -60,26 +60,4 @@ class M8d01880f01c11e0be500800200c9a66 extends CakeMigration {
),
);
-/**
- * Before migration callback
- *
- * @param string $direction, up or down direction of migration process
- * @return boolean Should process continue
- * @access public
- */
- public function before($direction) {
- return true;
- }
-
-/**
- * After migration callback
- *
- * @param string $direction, up or down direction of migration process
- * @return boolean Should process continue
- * @access public
- */
- public function after($direction) {
- return true;
- }
}
-?>
\ No newline at end of file
diff --git a/Config/Migration/map.php b/Config/Migration/map.php
index 1439cc8..f279118 100644
--- a/Config/Migration/map.php
+++ b/Config/Migration/map.php
@@ -17,10 +17,12 @@
$map = array(
1 => array(
- '001_initialize_tags_schema' => 'M49ac311a54844a9d87o822502jedc423'),
+ '001_initialize_tags_schema' => 'M49ac311a54844a9d87o822502jedc423',
+ ),
2 => array(
- '002_create_times_tagged_field' => 'M4c0d42bcd12c4db099c105f40e8f3d6d'),
+ '002_create_times_tagged_field' => 'M4c0d42bcd12c4db099c105f40e8f3d6d',
+ ),
3 => array(
- '003_occurrence_fields_for_tags' => 'M8d01880f01c11e0be500800200c9a66'),
+ '003_occurrence_fields_for_tags' => 'M8d01880f01c11e0be500800200c9a66',
+ ),
);
-?>
\ No newline at end of file
diff --git a/Config/Schema/schema.php b/Config/Schema/schema.php
index 2d04602..88388ee 100644
--- a/Config/Schema/schema.php
+++ b/Config/Schema/schema.php
@@ -11,26 +11,6 @@
class TagSchema extends CakeSchema {
-/**
- * Before callback
- *
- * @param array Event
- * @return boolean
- */
- public function before($event = array()) {
- return true;
- }
-
-/**
- * After callback
- *
- * @param array Event
- * @return boolean
- */
- public function after($event = array()) {
- return true;
- }
-
/**
* Schema for taggeds table
*
diff --git a/Controller/TagsController.php b/Controller/TagsController.php
index 4414043..2fafa1c 100644
--- a/Controller/TagsController.php
+++ b/Controller/TagsController.php
@@ -59,7 +59,7 @@ public function index() {
/**
* View
*
- * @param string
+ * @param string $keyName Tag key name
* @return void
*/
public function view($keyName = null) {
@@ -77,14 +77,14 @@ public function view($keyName = null) {
* @return void
*/
public function admin_index() {
- $this->{$this->modelClass}->recursive = 0;
+ $this->{$this->modelClass}->recursive = 0;
$this->set('tags', $this->Paginator->paginate());
}
/**
* Views a single tag
*
- * @param string tag UUID
+ * @param string $keyName Tag key name
* @return void
*/
public function admin_view($keyName) {
@@ -113,7 +113,7 @@ public function admin_add() {
/**
* Edits a tag
*
- * @param string tag UUID
+ * @param string $tagId Tag UUID
* @return void
*/
public function admin_edit($tagId = null) {
@@ -138,11 +138,11 @@ public function admin_edit($tagId = null) {
/**
* Deletes a tag
*
- * @param string tag UUID
+ * @param string $tagId Tag UUID
* @return void
*/
- public function admin_delete($id = null) {
- if ($this->{$this->modelClass}->delete($id)) {
+ public function admin_delete($tagId = null) {
+ if ($this->{$this->modelClass}->delete($tagId)) {
$this->Session->setFlash(__d('tags', 'Tag deleted.'));
} else {
$this->Session->setFlash(__d('tags', 'Invalid Tag.'));
diff --git a/Docs/Documentation/Configuration.md b/Docs/Documentation/Configuration.md
index 496f7c3..3868309 100644
--- a/Docs/Documentation/Configuration.md
+++ b/Docs/Documentation/Configuration.md
@@ -25,16 +25,20 @@ After adding the TaggableBehavior to your model, you will need to update your vi
```php
public $actsAs = array(
'Tags.Taggable' => array(
- 'separator' => '',
- 'field' => 'tags',
+ 'separator' => ',',
'tagAlias' => 'Tag',
'tagClass' => 'Tags.Tag',
+ 'taggedAlias' => 'Tagged',
'taggedClass' => 'Tags.Tagged',
+ 'field' => 'tags',
'foreignKey' => 'foreign_key',
'associationForeignKey' => 'tag_id',
+ 'cacheOccurrence' => true,
'automaticTagging' => true,
+ 'taggedCounter' => false,
'unsetInAfterFind' => false,
'resetBinding' => false,
+ 'deleteTagsOnEmptyField' => false,
)
);
```
@@ -42,14 +46,18 @@ public $actsAs = array(
The configuration above contains the default values for each setting. Here are some explanations:
* **separator:** String used to separate tags in the Model.tags value. (Default: ```,```)
-* **field:** Name of the Model field containing the tag list. (Default: ```tags```)
* **tagAlias:** Alias for the HABTM relationship between your Model and Tag. (Default: ```Tag```)
* **tagClass**: Name of the model representing Tags. (Default: ```Tags.Tag```)
+* **taggedAlias:** Alias for the HABTM join model. (Default: ```Tagged```)
* **taggedClass:** Name of the HABTM join model. (Default: ```Tags.Tagged```)
+* **field:** Name of the Model field containing the tag list. (Default: ```tags```)
* **foreignKey:** Name of the HABTM join model field containing the foreign key to the Tagable model. (Default: ```foreign_key```)
* **associationForeignKey:** Name of the HABTM join model field containing the foreign key to the Tag model. (Default: ```tag_id```)
+* **cacheOccurrence:** Name of the HABTM join model field containing the foreign key to the Tag model. (Default: ```true```)
* **automaticTagging:** Whether or not the behavior will automatically call saveTags() after each save. (Default: ```true```)
+* **taggedCounter:** True to update the number of times a particular tag was used for a specific record.
* **unsetInAfterFind:** Whether or not the related Tag entries have to be unset after a find. If this value is true, the ```$data['Tag']``` array will be unset and tags will only be available using the ```$data['Model']['tags']``` value. (Default: false)
* **resetBinding:** Value passed as the second param of to the ```bindModel()``` call when creating the HABTM association. If set to true, the binding will last only one query. (Default: false)
+* **deleteTagsOnEmptyField:** Delete associated Tags if field is empty or empty string.
Note that the ```tagClass```, ```taggedClass```, ```foreignKey``` and ```associationForeignKey``` values must not be changed if you use the plugin as it is shipped. Use these settings when you want to use your own models / tables structure.
diff --git a/Docs/Documentation/Installation.md b/Docs/Documentation/Installation.md
index b4b0017..345450a 100644
--- a/Docs/Documentation/Installation.md
+++ b/Docs/Documentation/Installation.md
@@ -3,6 +3,12 @@ Installation
To install the plugin, place the files in a directory labelled "Tags/" in your "app/Plugin/" directory.
+Then, include the following line in your `app/Config/bootstrap.php` to load the plugin in your application.
+
+```
+CakePlugin::load('Tags');
+```
+
Git Submodule
-------------
diff --git a/Docs/Documentation/The-Tag-Cloud-Helper.md b/Docs/Documentation/The-Tag-Cloud-Helper.md
index eb5d668..38ca055 100644
--- a/Docs/Documentation/The-Tag-Cloud-Helper.md
+++ b/Docs/Documentation/The-Tag-Cloud-Helper.md
@@ -44,5 +44,6 @@ The second param for the ```display()``` method is an array of options. The avai
* **after:** string to be displayed after each generated link. %size% will be replaced with tag size calculated from the weight. (Default: ```empty```)
* **maxSize:** size of the heaviest tag. (Default: ```160```)
* **minSize:** size of the lightest tag. (Default: ```80```)
-* **url:** an array containing the default url. (Default: ```array('controller' => 'search'```))
-* **named**: the named parameter used to send the tag keyname. (Default: ```by```)
\ No newline at end of file
+* **url:** an array containing the default URL. (Default: ```array('controller' => 'search'```))
+* **named**: the named parameter used to send the tag keyname. (Default: ```by```)
+* **paramType**: the type of URL parameters used (```named``` or ```querystring```). (Default: ```named```)
diff --git a/Model/Behavior/TaggableBehavior.php b/Model/Behavior/TaggableBehavior.php
index 23f39dd..c2fa759 100644
--- a/Model/Behavior/TaggableBehavior.php
+++ b/Model/Behavior/TaggableBehavior.php
@@ -28,18 +28,20 @@ class TaggableBehavior extends ModelBehavior {
/**
* Default settings
*
- * separator - separator used to enter a lot of tags, comma by default
- * tagAlias - model alias for Tag model
- * tagClass - class name of the table storing the tags
- * taggedClass - class name of the HABTM association table between tags and models
- * field - the fieldname that contains the raw tags as string
- * foreignKey - foreignKey used in the HABTM association
- * associationForeignKey - associationForeignKey used in the HABTM association
- * automaticTagging - if set to true you don't need to use saveTags() manually
- * language - only tags in a certain language, string or array
- * taggedCounter - true to update the number of times a particular tag was used for a specific record
- * unsetInAfterFind - unset 'Tag' results in afterFind
- * deleteTagsOnEmptyField - delete associated Tags if field is empty.
+ * separator - separator used to enter a lot of tags, comma by default
+ * field - the fieldname that contains the raw tags as string
+ * tagAlias - model alias for Tag model
+ * tagClass - class name of the table storing the tags
+ * taggedAlias - model alias for the HABTM join model
+ * taggedClass - class name of the HABTM association table between tags and models
+ * foreignKey - foreignKey used in the HABTM association
+ * associationForeignKey - associationForeignKey used in the HABTM association
+ * cacheOccurrence - cache the weight or occurence of a tag in the tags table
+ * automaticTagging - if set to true you don't need to use saveTags() manually
+ * taggedCounter - true to update the number of times a particular tag was used for a specific record
+ * unsetInAfterFind - unset 'Tag' results in afterFind
+ * resetBinding - reset the bindModel() calls, default is false
+ * deleteTagsOnEmptyField - delete associated Tags if field is empty
*
* @var array
*/
@@ -54,19 +56,17 @@ class TaggableBehavior extends ModelBehavior {
'associationForeignKey' => 'tag_id',
'cacheOccurrence' => true,
'automaticTagging' => true,
+ 'taggedCounter' => false,
'unsetInAfterFind' => false,
'resetBinding' => false,
- 'taggedCounter' => false,
- 'deleteTagsOnEmptyField' => false
+ 'deleteTagsOnEmptyField' => false,
);
/**
* Setup
*
- * @param Model $model
- * @param array $config
- *
- * @internal param array $settings
+ * @param Model $model Model instance that behavior is attached to
+ * @param array $config Configuration settings from model
* @return void
*/
public function setup(Model $model, $config = array()) {
@@ -80,14 +80,15 @@ public function setup(Model $model, $config = array()) {
}
/**
- * bindTagAssociations
+ * Bind tag assocations
*
- * @param Model $model
+ * @param Model $model Model instance that behavior is attached to
* @return void
*/
public function bindTagAssociations(Model $model) {
extract($this->settings[$model->alias]);
+ list($plugin, $withClass) = pluginSplit($withModel, true);
$model->bindModel(array(
'hasAndBelongsToMany' => array(
$tagAlias => array(
@@ -96,7 +97,8 @@ public function bindTagAssociations(Model $model) {
'associationForeignKey' => $associationForeignKey,
'unique' => true,
'conditions' => array(
- 'Tagged.model' => $model->name),
+ $withClass . '.model' => $model->name
+ ),
'fields' => '',
'dependent' => true,
'with' => $withModel
@@ -148,14 +150,14 @@ public function disassembleTags(Model $model, $string = '', $separator = ',') {
/**
* Saves a string of tags
*
- * @param Model $model
+ * @param Model $model Model instance that behavior is attached to
* @param string $string comma separeted list of tags to be saved
- * Tags can contain special tokens called `identifiers´ to namespace tags or classify them into catageories.
- * A valid string is "foo, bar, cakephp:special". The token `cakephp´ will end up as the identifier or category for the tag `special´
+ * Tags can contain special tokens called `identifiers´ to namespace tags or classify them into catageories.
+ * A valid string is "foo, bar, cakephp:special". The token `cakephp´ will end up as the identifier or category for the tag `special´
* @param mixed $foreignKey the identifier for the record to associate the tags with
- * @param boolean $update true will remove tags that are not in the $string, false wont
- * do this and just add new tags without removing existing tags associated to
- * the current set foreign key
+ * @param bool $update True will remove tags that are not in the $string, false won't
+ * do this and just add new tags without removing existing tags associated to
+ * the current set foreign key
* @return array
*/
public function saveTags(Model $model, $string = null, $foreignKey = null, $update = true) {
@@ -210,8 +212,9 @@ public function saveTags(Model $model, $string = null, $foreignKey = null, $upda
}
foreach ($newTags as $key => $newTag) {
$tagModel->create();
- $tagModel->save($newTag);
- $newTagIds[] = $tagModel->getLastInsertId();
+ if ($tagModel->save($newTag)) {
+ $newTagIds[] = $tagModel->getLastInsertId();
+ }
}
if ($foreignKey !== false) {
@@ -225,7 +228,7 @@ public function saveTags(Model $model, $string = null, $foreignKey = null, $upda
$taggedAlias . '.foreign_key' => $foreignKey,
$taggedAlias . '.language' => Configure::read('Config.language'),
$taggedAlias . '.tag_id' => $existingTagIds),
- 'fields' => 'Tagged.tag_id'
+ 'fields' => $taggedAlias . '.tag_id'
));
$deleteAll = array(
@@ -247,13 +250,16 @@ public function saveTags(Model $model, $string = null, $foreignKey = null, $upda
$taggedAlias . '.model' => $model->name,
$taggedAlias . '.foreign_key' => $foreignKey,
$taggedAlias . '.language' => Configure::read('Config.language')),
- 'fields' => 'Tagged.tag_id'
+ 'fields' => $taggedAlias . '.tag_id'
));
- $oldTagIds = Set::extract($oldTagIds, '/Tagged/tag_id');
+ $oldTagIds = Set::extract($oldTagIds, '/' . $taggedAlias . '/tag_id');
$tagModel->{$taggedAlias}->deleteAll($deleteAll, false);
} elseif ($this->settings[$model->alias]['taggedCounter'] && !empty($alreadyTagged)) {
- $tagModel->{$taggedAlias}->updateAll(array('times_tagged' => 'times_tagged + 1'), array('Tagged.tag_id' => $alreadyTagged));
+ $tagModel->{$taggedAlias}->updateAll(
+ array('times_tagged' => 'times_tagged + 1'),
+ array($taggedAlias . '.tag_id' => $alreadyTagged)
+ );
}
foreach ($existingTagIds as $tagId) {
@@ -273,11 +279,11 @@ public function saveTags(Model $model, $string = null, $foreignKey = null, $upda
$taggedAlias . '.model' => $model->name,
$taggedAlias . '.foreign_key' => $foreignKey,
$taggedAlias . '.language' => Configure::read('Config.language')),
- 'fields' => 'Tagged.tag_id'
+ 'fields' => $taggedAlias . '.tag_id'
));
if (!empty($newTagIds)) {
- $newTagIds = Set::extract($newTagIds, '{n}.Tagged.tag_id');
+ $newTagIds = Set::extract($newTagIds, '{n}.' . $taggedAlias . '.tag_id');
}
$this->cacheOccurrence($model, array_merge($oldTagIds, $newTagIds));
@@ -292,8 +298,8 @@ public function saveTags(Model $model, $string = null, $foreignKey = null, $upda
/**
* Cache the weight or occurence of a tag in the tags table
*
- * @param Model $model instance of a model
- * @param int|string|array $tagIds
+ * @param Model $model Model instance that behavior is attached to
+ * @param int|string|array $tagIds Tag ID or list of tag IDs
* @return void
*/
public function cacheOccurrence(Model $model, $tagIds) {
@@ -301,45 +307,49 @@ public function cacheOccurrence(Model $model, $tagIds) {
$tagIds = array($tagIds);
}
+ $tagAlias = $this->settings[$model->alias]['tagAlias'];
+ $taggedAlias = $this->settings[$model->alias]['taggedAlias'];
+
+ $tagModel = $model->{$tagAlias};
+ $taggedModel = $tagModel->{$taggedAlias};
+
+ $fieldName = Inflector::underscore($model->name) . '_occurrence';
foreach ($tagIds as $tagId) {
- $fieldName = Inflector::underscore($model->name) . '_occurrence';
- $tagModel = $model->{$this->settings[$model->alias]['tagAlias']};
- $taggedModel = $tagModel->{$this->settings[$model->alias]['taggedAlias']};
$data = array($tagModel->primaryKey => $tagId);
if ($tagModel->hasField($fieldName)) {
$data[$fieldName] = $taggedModel->find('count', array(
'conditions' => array(
- 'Tagged.tag_id' => $tagId,
- 'Tagged.model' => $model->name
+ $taggedAlias . '.tag_id' => $tagId,
+ $taggedAlias . '.model' => $model->name
)
));
}
$data['occurrence'] = $taggedModel->find('count', array(
'conditions' => array(
- 'Tagged.tag_id' => $tagId
+ $taggedAlias . '.tag_id' => $tagId
)
));
$tagModel->save($data, array(
'validate' => false,
- 'callbacks' => false)
- );
+ 'callbacks' => false,
+ ));
}
}
/**
* Creates a multibyte safe unique key
*
- * @param Model $model
- * @param string Tag name string
- * @returns string Multibyte safe key string
+ * @param Model $model Model instance that behavior is attached to
+ * @param string $string Tag name string
+ * @return string Multibyte safe key string
*/
public function multibyteKey(Model $model, $string = null) {
$str = mb_strtolower($string);
$str = preg_replace('/\xE3\x80\x80/', ' ', $str);
$str = str_replace(array('_', '-'), '', $str);
- $str = preg_replace( '#[:\#\*"()~$^{}`@+=;,<>!&%\.\]\/\'\\\\|\[]#', "\x20", $str );
+ $str = preg_replace('#[:\#\*"()~$^{}`@+=;,<>!&%\.\]\/\'\\\\|\[]#', "\x20", $str);
$str = str_replace('?', '', $str);
$str = trim($str);
$str = preg_replace('#\x20+#', '', $str);
@@ -351,14 +361,15 @@ public function multibyteKey(Model $model, $string = null) {
* initialization of data for text input
*
* Example usage (only 'Tag.name' field is needed inside of method):
+ *
*
* $this->Blog->hasAndBelongsToMany['Tag']['fields'] = array('name', 'keyname');
* $blog = $this->Blog->read(null, 123);
* $blog['Blog']['tags'] = $this->Blog->Tag->tagArrayToString($blog['Tag']);
*
*
- * @param Model $model
- * @param array $data
+ * @param Model $model Model instance that behavior is attached to
+ * @param array $data Tag data array
* @return string
*/
public function tagArrayToString(Model $model, $data = null) {
@@ -368,7 +379,7 @@ public function tagArrayToString(Model $model, $data = null) {
if (!empty($tag['identifier'])) {
$tags[] = $tag['identifier'] . ':' . $tag['name'];
} else {
- $tags[] = $tag['name'];
+ $tags[] = $tag['name'];
}
}
return join($this->settings[$model->alias]['separator'] . ' ', $tags);
@@ -379,16 +390,20 @@ public function tagArrayToString(Model $model, $data = null) {
/**
* afterSave callback
*
- * @param Model $model
- * @param array $created
- * @param array $options
+ * @param Model $model Model instance that behavior is attached to
+ * @param bool $created True if this save created a new record
+ * @param array $options Options passed from Model::save()
* @return void
*/
public function afterSave(Model $model, $created, $options = array()) {
- $hasTags = !empty($model->data[$model->alias][$this->settings[$model->alias]['field']]);
- if ($this->settings[$model->alias]['automaticTagging'] == true && $hasTags) {
- $this->saveTags($model, $model->data[$model->alias][$this->settings[$model->alias]['field']], $model->id);
- } else if (!$hasTags && $this->settings[$model->alias]['deleteTagsOnEmptyField']) {
+ if (!isset($model->data[$model->alias][$this->settings[$model->alias]['field']])) {
+ return;
+ }
+ $field = $model->data[$model->alias][$this->settings[$model->alias]['field']];
+ $hasTags = !empty($field);
+ if ($this->settings[$model->alias]['automaticTagging'] === true && $hasTags) {
+ $this->saveTags($model, $field, $model->id);
+ } elseif (!$hasTags && $this->settings[$model->alias]['deleteTagsOnEmptyField']) {
$this->deleteTagged($model);
}
}
@@ -396,16 +411,20 @@ public function afterSave(Model $model, $created, $options = array()) {
/**
* Delete associated Tags if record has no tags and deleteTagsOnEmptyField is true
*
- * @param Model $model Model instance
+ * @param Model $model Model instance that behavior is attached to
+ * @param mixed $id Foreign key of the model, string for UUID or integer
* @return void
*/
- public function deleteTagged(Model $model) {
+ public function deleteTagged(Model $model, $id = null) {
extract($this->settings[$model->alias]);
$tagModel = $model->{$tagAlias};
+ if (is_null($id)) {
+ $id = $model->id;
+ }
$tagModel->{$taggedAlias}->deleteAll(
array(
$taggedAlias . '.model' => $model->name,
- $taggedAlias . '.foreign_key' => $model->id,
+ $taggedAlias . '.foreign_key' => $id,
)
);
}
@@ -413,9 +432,9 @@ public function deleteTagged(Model $model) {
/**
* afterFind Callback
*
- * @param Model $model
- * @param array $results
- * @param boolean $primary
+ * @param Model $model Model instance that behavior is attached to
+ * @param mixed $results The results of the find operation
+ * @param bool $primary Whether this model is being queried directly (vs. being queried as an association)
* @return array
*/
public function afterFind(Model $model, $results, $primary = false) {
diff --git a/Model/Tag.php b/Model/Tag.php
index 80d9921..38baf5e 100644
--- a/Model/Tag.php
+++ b/Model/Tag.php
@@ -43,21 +43,40 @@ class Tag extends TagsAppModel {
* @var array
*/
public $validate = array(
- 'name' => array('rule' => 'notEmpty'),
- 'keyname' => array('rule' => 'notEmpty')
+ 'name' => array('rule' => 'notBlank'),
+ 'keyname' => array('rule' => 'notBlank')
);
+/**
+ * Custom validation for keeping BC to CakePHP version below 2.7
+ *
+ * @param array $check
+ * @return bool
+ */
+ public function notBlank($check) {
+ $value = array_values($check);
+ $value = $value[0];
+ if (method_exists('Validation', 'notBlank')) {
+ return Validation::notBlank($value);
+ } else {
+ // below 2.7
+ return Validation::notEmpty($value);
+ }
+ }
+
/**
* Returns the data for a single tag
*
+ * @param string $keyName Tag key name
* @throws CakeException
- * @param string keyname
* @return array
*/
public function view($keyName = null) {
$result = $this->find('first', array(
'conditions' => array(
- $this->alias . '.keyname' => $keyName)));
+ $this->alias . '.keyname' => $keyName
+ )
+ ));
if (empty($result)) {
throw new CakeException(__d('tags', 'Invalid Tag.'));
@@ -68,8 +87,8 @@ public function view($keyName = null) {
/**
* Pre-populates the tag table with entered tags
*
- * @param array post data, should be Contoller->data
- * @return boolean
+ * @param array $postData Post data, should be Contoller->data
+ * @return bool
*/
public function add($postData = null) {
if (isset($postData[$this->alias]['tags'])) {
@@ -88,16 +107,17 @@ public function add($postData = null) {
/**
* Edits an existing tag, allows only to modify upper/lowercased characters
*
+ * @param string $tagId Tag UUID
+ * @param array $postData Controller post data usually $this->request->data
* @throws CakeException
- * @param string tag uuid
- * @param array controller post data usually $this->request->data
* @return mixed True on successfully save else post data as array
*/
public function edit($tagId = null, $postData = null) {
$tag = $this->find('first', array(
'contain' => array(),
'conditions' => array(
- $this->alias . '.' . $this->primaryKey => $tagId)
+ $this->alias . '.' . $this->primaryKey => $tagId
+ )
));
$this->set($tag);
diff --git a/Model/Tagged.php b/Model/Tagged.php
index 50f2b2d..4f0ae38 100644
--- a/Model/Tagged.php
+++ b/Model/Tagged.php
@@ -50,14 +50,14 @@ class Tagged extends TagsAppModel {
* Returns a tag cloud
*
* The result contains a "weight" field which has a normalized size of the tag
- * occurrence set. The min and max size can be set by passing 'minSize" and
- * 'maxSize' to the query. This value can be used in the view to controll the
+ * occurrence set. The min and max size can be set by passing 'minSize' and
+ * 'maxSize' to the query. This value can be used in the view to control the
* size of the tag font.
*
+ * @param string $state State string ('before' or 'after')
+ * @param array $query Query array
+ * @param array $results Result set for 'after' state
* @todo Ideas to improve this are welcome
- * @param string $state
- * @param array $query
- * @param array $results
* @return array
* @link https://github.com/CakeDC/tags/issues/10
*/
@@ -135,16 +135,18 @@ public function _findCloud($state, $query, $results = array()) {
* Find all the Model entries tagged with a given tag
*
* The query must contain a Model name, and can contain a 'by' key with the Tag keyname to filter the results
+ *
*
* $this->Article->Tagged->find('tagged', array(
* 'by' => 'cakephp',
* 'model' => 'Article'));
- *
*
- * @TODO Find a way to populate the "magic" field Article.tags
- * @param string $state
- * @param array $query
- * @param array $results
+ * @param string $state State string ('before' or 'after')
+ * @param array $query Query array
+ * @param array $results Result set for 'after' state
+ * @todo Find a way to populate the "magic" field Article.tags
+ * @throws InvalidArgumentException if recursive setting is -1
* @return mixed Query array if state is before, array of results or integer (count) if state is after
*/
public function _findTagged($state, $query, $results = array()) {
@@ -157,7 +159,11 @@ public function _findTagged($state, $query, $results = array()) {
'foreignKey' => 'foreign_key',
'type' => 'INNER',
'conditions' => array(
- $this->alias . '.model' => $Model->alias)))), false);
+ $this->alias . '.model' => $Model->alias
+ )
+ )
+ )
+ ), false);
if (!isset($query['recursive'])) {
$query['recursive'] = 0;
diff --git a/Model/TagsAppModel.php b/Model/TagsAppModel.php
index 2c1a738..783b6e6 100644
--- a/Model/TagsAppModel.php
+++ b/Model/TagsAppModel.php
@@ -23,14 +23,15 @@ class TagsAppModel extends AppModel {
* @var array
*/
public $actsAs = array(
- 'Containable');
+ 'Containable'
+ );
/**
* Customized paginateCount method
*
- * @param array
- * @param integer
- * @param array
+ * @param array $conditions Query conditions
+ * @param int $recursive Recursive setting
+ * @param array $extra Extra settings
* @return array
*/
public function paginateCount($conditions = array(), $recursive = 0, $extra = array()) {
diff --git a/README.md b/README.md
index dd6b8e1..c3ba3c5 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,14 @@
Tags Plugin for CakePHP
=======================
-The **Tags** plugin includes the TaggableBehavior that allows you to simply tag everything.
-
-It saves all tags in a single tags table and connects any kind of records to them through the tagged table.
-
[![Bake Status](https://secure.travis-ci.org/CakeDC/tags.png?branch=master)](http://travis-ci.org/CakeDC/tags)
[![Downloads](https://poser.pugx.org/CakeDC/tags/d/total.png)](https://packagist.org/packages/CakeDC/tags)
[![Latest Version](https://poser.pugx.org/CakeDC/tags/v/stable.png)](https://packagist.org/packages/CakeDC/tags)
+The **Tags** plugin includes the TaggableBehavior that allows you to simply tag everything.
+
+It saves all tags in a single tags table and connects any kind of records to them through the tagged table.
+
Requirements
------------
diff --git a/Test/Case/Controller/TagsControllerTest.php b/Test/Case/Controller/TagsControllerTest.php
index 117bb55..d3ab2d2 100644
--- a/Test/Case/Controller/TagsControllerTest.php
+++ b/Test/Case/Controller/TagsControllerTest.php
@@ -23,7 +23,7 @@ class TestTagsController extends TagsController {
/**
* Auto render
*
- * @var boolean
+ * @var bool
*/
public $autoRender = false;
@@ -37,6 +37,9 @@ class TestTagsController extends TagsController {
/**
* Override controller method for testing
*
+ * @param string|array $url URL to redirect to (copied to `$this->redirectUrl`)
+ * @param int $status Optional HTTP status code (eg: 404)
+ * @param bool $exit If true, exit() will be called after the redirect
* @return void
*/
public function redirect($url, $status = null, $exit = true) {
@@ -46,11 +49,14 @@ public function redirect($url, $status = null, $exit = true) {
/**
* Override controller method for testing
*
+ * @param string $view View to use for rendering
+ * @param string $layout Layout to use
* @return void
*/
- public function render($action = null, $layout = null, $file = null) {
- $this->renderedView = $action;
+ public function render($view = null, $layout = null) {
+ $this->renderedView = $view;
}
+
}
/**
@@ -68,7 +74,8 @@ class TagsControllerTest extends CakeTestCase {
*/
public $fixtures = array(
'plugin.tags.tagged',
- 'plugin.tags.tag');
+ 'plugin.tags.tag'
+ );
/**
* Tags Controller Instance
@@ -87,7 +94,8 @@ public function setUp() {
$this->Tags = new TestTagsController(new CakeRequest(null, false));
$this->Tags->params = array(
'named' => array(),
- 'url' => array());
+ 'url' => array()
+ );
$this->Tags->constructClasses();
$this->Tags->Session = $this->getMock('SessionComponent', array(), array(), '', false);
}
@@ -175,7 +183,6 @@ public function testAdminDelete() {
->with($this->equalTo(__d('tags', 'Tag deleted.')))
->will($this->returnValue(true));
-
$this->Tags->admin_delete('WRONG-ID!!!');
$this->assertEquals($this->Tags->redirectUrl, array('action' => 'index'));
@@ -191,14 +198,18 @@ public function testAdminDelete() {
public function testAdminAdd() {
$this->Tags->data = array(
'Tag' => array(
- 'tags' => 'tag1, tag2, tag3'));
+ 'tags' => 'tag1, tag2, tag3'
+ )
+ );
$this->Tags->admin_add();
$this->assertEquals($this->Tags->redirectUrl, array('action' => 'index'));
// adding same tags again.
$this->Tags->data = array(
'Tag' => array(
- 'tags' => 'tag1, tag2, tag3'));
+ 'tags' => 'tag1, tag2, tag3'
+ )
+ );
$this->Tags->admin_add();
$this->assertEquals($this->Tags->redirectUrl, array('action' => 'index'));
}
@@ -219,14 +230,18 @@ public function testAdminEdit() {
'occurrence' => 1,
'article_occurrence' => 1,
'created' => '2008-06-02 18:18:11',
- 'modified' => '2008-06-02 18:18:37'));
+ 'modified' => '2008-06-02 18:18:37'
+ )
+ );
$this->assertEquals($this->Tags->data, $tag);
$this->Tags->data = array(
'Tag' => array(
'id' => 'tag-1',
- 'name' => 'CAKEPHP'));
+ 'name' => 'CAKEPHP'
+ )
+ );
$this->Tags->admin_edit('tag-1');
$this->assertEquals($this->Tags->redirectUrl, array('action' => 'index'));
diff --git a/Test/Case/Model/Behavior/TaggableBehaviorTest.php b/Test/Case/Model/Behavior/TaggableBehaviorTest.php
index a3bdf07..1cf72df 100644
--- a/Test/Case/Model/Behavior/TaggableBehaviorTest.php
+++ b/Test/Case/Model/Behavior/TaggableBehaviorTest.php
@@ -60,6 +60,40 @@ class Article extends CakeTestModel {
public $actsAs = array('Tags.Taggable');
}
+/**
+ * Custom tag model
+ *
+ * @package tags
+ * @subpackage tags.tests.cases.behaviors
+ */
+class CustomTag extends CakeTestModel {
+
+/**
+ * Use table
+ *
+ * @var string
+ */
+ public $useTable = 'tags';
+
+}
+
+/**
+ * Custom tagged model
+ *
+ * @package tags
+ * @subpackage tags.tests.cases.behaviors
+ */
+class CustomTagged extends CakeTestModel {
+
+/**
+ * Use table
+ *
+ * @var string
+ */
+ public $useTable = 'tagged';
+
+}
+
/**
* TaggableTest
*
@@ -91,7 +125,42 @@ class TaggableBehaviorTest extends CakeTestCase {
public $fixtures = array(
'plugin.tags.tagged',
'plugin.tags.tag',
- 'plugin.tags.article');
+ 'plugin.tags.article'
+ );
+
+/**
+ * Behavior settings.
+ *
+ * @var array
+ */
+ public $behaviorSettings = array(
+ 'default' => array(),
+ 'noPluginPrefix' => array(
+ 'tagClass' => 'Tag',
+ 'taggedClass' => 'Tagged',
+ ),
+ 'customAliasAndClass' => array(
+ 'tagAlias' => 'CustomTagAlias',
+ 'taggedAlias' => 'CustomTaggedAlias',
+ 'tagClass' => 'Tags.CustomTag',
+ 'taggedClass' => 'Tags.CustomTagged',
+ ),
+ );
+
+/**
+ * Run test cases multiple times with different behavior settings
+ *
+ * @param PHPUnit_Framework_TestResult $result The test result object
+ * @return PHPUnit_Framework_TestResult
+ */
+ public function run(PHPUnit_Framework_TestResult $result = null) {
+ foreach ($this->behaviorSettings as $behaviorSettings) {
+ $this->behaviorSettings = $behaviorSettings;
+ $result = parent::run($result);
+ }
+
+ return $result;
+ }
/**
* Method executed before each test
@@ -102,7 +171,7 @@ public function setUp() {
parent::setUp();
$this->Article = ClassRegistry::init('Article');
Configure::write('Config.language', 'eng');
- $this->Article->Behaviors->attach('Tags.Taggable', array());
+ $this->Article->Behaviors->attach('Tags.Taggable', $this->behaviorSettings);
}
/**
@@ -122,31 +191,39 @@ public function tearDown() {
* @return void
*/
public function testOccurrenceCache() {
- $resultBefore = $this->Article->Tag->find('first', array(
+ $tagAlias = $this->Article->Behaviors->Taggable->settings['Article']['tagAlias'];
+
+ $resultBefore = $this->Article->{$tagAlias}->find('first', array(
'contain' => array(),
'conditions' => array(
- 'Tag.keyname' => 'cakephp')));
+ $tagAlias . '.keyname' => 'cakephp'
+ )
+ ));
// adding a new record with the cakephp tag to increase the occurrence
$data = array('title' => 'Test Article', 'tags' => 'cakephp, php');
$this->Article->create();
$this->Article->save($data, false);
- $resultAfter = $this->Article->Tag->find('first', array(
+ $resultAfter = $this->Article->{$tagAlias}->find('first', array(
'contain' => array(),
'conditions' => array(
- 'Tag.keyname' => 'cakephp')));
+ $tagAlias . '.keyname' => 'cakephp'
+ )
+ ));
- $this->assertEquals($resultAfter['Tag']['occurrence'] - $resultBefore['Tag']['occurrence'], 1);
+ $this->assertEquals($resultAfter[$tagAlias]['occurrence'] - $resultBefore[$tagAlias]['occurrence'], 1);
// updating the record to not have the cakephp tag anymore, decreases the occurrence
$data = array('id' => $this->Article->id, 'title' => 'Test Article', 'tags' => 'php, something, else');
$this->Article->save($data, false);
- $resultAfter = $this->Article->Tag->find('first', array(
+ $resultAfter = $this->Article->{$tagAlias}->find('first', array(
'contain' => array(),
'conditions' => array(
- 'Tag.keyname' => 'cakephp')));
- $this->assertEquals($resultAfter['Tag']['occurrence'], 1);
+ $tagAlias . '.keyname' => 'cakephp'
+ )
+ ));
+ $this->assertEquals($resultAfter[$tagAlias]['occurrence'], 1);
}
/**
@@ -160,7 +237,9 @@ public function testTagSaving() {
$this->Article->save($data, false);
$result = $this->Article->find('first', array(
'conditions' => array(
- 'id' => 'article-1')));
+ 'id' => 'article-1'
+ )
+ ));
$this->assertTrue(!empty($result['Article']['tags']));
$data['tags'] = 'foo, developer, developer, php';
@@ -168,23 +247,27 @@ public function testTagSaving() {
$result = $this->Article->find('first', array(
'contain' => array('Tag'),
'conditions' => array(
- 'id' => 'article-1')));
+ 'id' => 'article-1'
+ )
+ ));
$this->assertTrue(!empty($result['Article']['tags']));
$this->assertEquals(3, count($result['Tag']));
-
$data['tags'] = 'cakephp:foo, developer, cakephp:developer, cakephp:php';
$this->Article->save($data, false);
$result = $this->Article->Tag->find('all', array(
'recursive' => -1,
'order' => 'Tag.identifier DESC, Tag.name ASC',
'conditions' => array(
- 'Tag.identifier' => 'cakephp')));
+ 'Tag.identifier' => 'cakephp'
+ )
+ ));
$result = Set::extract($result, '{n}.Tag.keyname');
$this->assertEquals($result, array(
- 'developer', 'foo', 'php'));
+ 'developer', 'foo', 'php'
+ ));
$this->assertFalse($this->Article->saveTags('foo, bar', null));
$this->assertFalse($this->Article->saveTags(array('foo', 'bar'), 'something'));
@@ -226,7 +309,9 @@ public function testTagArrayToString() {
$this->Article->save($data, false);
$result = $this->Article->find('first', array(
'conditions' => array(
- 'id' => 'article-1')));
+ 'id' => 'article-1'
+ )
+ ));
$result = $this->Article->tagArrayToString($result['Tag']);
$this->assertTrue(!empty($result));
$this->assertInternalType('string', $result);
@@ -240,7 +325,9 @@ public function testTagArrayToString() {
$this->Article->save($data, false);
$result = $this->Article->find('first', array(
'conditions' => array(
- 'id' => 'article-1')));
+ 'id' => 'article-1'
+ )
+ ));
$result = $this->Article->tagArrayToString($result['Tag']);
$this->assertTrue(!empty($result));
@@ -267,20 +354,26 @@ public function testMultibyteKey() {
* @return void
*/
public function testAfterFind() {
+ $tagAlias = $this->Article->Behaviors->Taggable->settings['Article']['tagAlias'];
+
$data['id'] = 'article-1';
$data['tags'] = 'foo, bar, test';
$this->Article->save($data, false);
$result = $this->Article->find('first', array(
'conditions' => array(
- 'id' => 'article-1')));
- $this->assertTrue(isset($result['Tag']));
+ 'id' => 'article-1'
+ )
+ ));
+ $this->assertTrue(isset($result[$tagAlias]));
$this->Article->Behaviors->Taggable->settings['Article']['unsetInAfterFind'] = true;
$result = $this->Article->find('first', array(
'conditions' => array(
- 'id' => 'article-1')));
- $this->assertTrue(!isset($result['Tag']));
+ 'id' => 'article-1'
+ )
+ ));
+ $this->assertTrue(!isset($result[$tagAlias]));
}
/**
@@ -292,7 +385,8 @@ public function testAfterFindFields() {
$this->Article->Behaviors->detach('Taggable');
$results = $this->Article->find('first', array(
'recursive' => -1,
- 'fields' => array('id')));
+ 'fields' => array('id')
+ ));
$expected = array($this->Article->alias => array('id' => 'article-1'));
$this->assertIdentical($results, $expected);
}
@@ -361,7 +455,8 @@ public function testSavingTagsDoesNotCreateEmptyRecords() {
$this->Article->save($data, false);
$result = $this->Article->find('first', array(
'conditions' => array(
- 'id' => 'article-1')
+ 'id' => 'article-1'
+ )
));
$count = $this->Article->Tag->find('count', array(
@@ -384,6 +479,60 @@ public function testSavingTagsWithDifferentIdentifier() {
$this->Article->save($data);
$data = $this->Article->findById('article-1');
$this->assertEquals('bar:cakephp, foo:cakephp', $data['Article']['tags']);
+ }
+/**
+ * testDeletingMoreThanOneTagAtATime
+ *
+ * @link https://github.com/CakeDC/tags/issues/86
+ * @return void
+ */
+ public function testDeletingMoreThanOneTagAtATime() {
+ // Adding five tags for testing
+ $data = array(
+ 'Article' => array(
+ 'id' => 'article-test-delete-tags',
+ 'tags' => 'foo, bar, test, second, third',
+ )
+ );
+ $this->Article->create();
+ $this->Article->save($data, false);
+ $result = $this->Article->find('first', array(
+ 'conditions' => array(
+ 'id' => 'article-test-delete-tags'
+ )
+ ));
+ $this->assertEquals($result['Article']['tags'], 'third, second, test, bar, foo');
+ // Removing three of the five previously added tags
+ $result['Article']['tags'] = 'third, second';
+ $this->Article->save($result, false);
+ $result = $this->Article->find('first', array(
+ 'conditions' => array(
+ 'id' => 'article-test-delete-tags'
+ )
+ ));
+ $this->assertEquals($result['Article']['tags'], 'second, third');
+ // Removing all tags, empty string - WON'T work as expected because of deleteTagsOnEmptyField
+ $result['Article']['tags'] = '';
+ $this->Article->save($result, false);
+ $result = $this->Article->find('first', array(
+ 'conditions' => array(
+ 'id' => 'article-test-delete-tags'
+ )
+ ));
+ $this->assertEquals($result['Article']['tags'], 'third, second');
+ // Now with deleteTagsOnEmptyField
+ $this->Article->Behaviors->load('Tags.Taggable', array(
+ 'deleteTagsOnEmptyField' => true
+ ));
+ $result['Article']['tags'] = '';
+ $this->Article->save($result, false);
+ $result = $this->Article->find('first', array(
+ 'conditions' => array(
+ 'id' => 'article-test-delete-tags'
+ )
+ ));
+ $this->assertEquals($result['Article']['tags'], '');
}
+
}
diff --git a/Test/Case/Model/TagTest.php b/Test/Case/Model/TagTest.php
index 042c4e3..43ca44f 100644
--- a/Test/Case/Model/TagTest.php
+++ b/Test/Case/Model/TagTest.php
@@ -76,14 +76,16 @@ public function testTagFind() {
$expected = array(
'Tag' => array(
- 'id' => 'tag-1',
- 'identifier' => null,
- 'name' => 'CakePHP',
- 'keyname' => 'cakephp',
+ 'id' => 'tag-1',
+ 'identifier' => null,
+ 'name' => 'CakePHP',
+ 'keyname' => 'cakephp',
'occurrence' => 1,
'article_occurrence' => 1,
- 'created' => '2008-06-02 18:18:11',
- 'modified' => '2008-06-02 18:18:37'));
+ 'created' => '2008-06-02 18:18:11',
+ 'modified' => '2008-06-02 18:18:37'
+ )
+ );
$this->assertEquals($results, $expected);
}
@@ -107,23 +109,29 @@ public function testView() {
* @return void
*/
public function testAdd() {
- $result = $this->Tag->add(
- array('Tag' => array(
- 'tags' => 'tag1, tag2, tag3')));
+ $result = $this->Tag->add(array(
+ 'Tag' => array(
+ 'tags' => 'tag1, tag2, tag3'
+ )
+ ));
$this->assertTrue($result);
$result = $this->Tag->find('all', array(
'recursive' => -1,
'fields' => array(
- 'Tag.name')));
+ 'Tag.name'
+ )
+ ));
$result = Set::extract($result, '{n}.Tag.name');
$this->assertTrue(in_array('tag1', $result));
$this->assertTrue(in_array('tag2', $result));
$this->assertTrue(in_array('tag3', $result));
// adding same tags again.
- $result = $this->Tag->add(
- array('Tag' => array(
- 'tags' => 'tag1, tag2, tag3')));
+ $result = $this->Tag->add(array(
+ 'Tag' => array(
+ 'tags' => 'tag1, tag2, tag3'
+ )
+ ));
$this->assertTrue($result);
}
@@ -139,20 +147,26 @@ public function testEdit() {
$data = array(
'Tag' => array(
'id' => 'tag-1',
- 'name' => 'CAKEPHP'));
+ 'name' => 'CAKEPHP'
+ )
+ );
$this->assertTrue($this->Tag->edit('tag-1', $data));
$data = array(
'Tag' => array(
'id' => 'tag-1',
- 'name' => 'CAKEPHP111'));
+ 'name' => 'CAKEPHP111'
+ )
+ );
$this->assertFalse($this->Tag->edit('tag-1', $data));
$data = array(
'Tag' => array(
'id' => 'tag-1',
'name' => 'CAKEPHP',
- 'keyname' => ''));
+ 'keyname' => ''
+ )
+ );
$this->assertEquals($this->Tag->edit('tag-1', $data), $data);
$this->expectException('CakeException');
diff --git a/Test/Case/Model/TaggedTest.php b/Test/Case/Model/TaggedTest.php
index b2cae29..b8c35f3 100644
--- a/Test/Case/Model/TaggedTest.php
+++ b/Test/Case/Model/TaggedTest.php
@@ -105,7 +105,9 @@ public function testTaggedFind() {
'language' => 'eng',
'times_tagged' => 1,
'created' => '2008-12-02 12:32:31',
- 'modified' => '2008-12-02 12:32:31'));
+ 'modified' => '2008-12-02 12:32:31'
+ )
+ );
$this->assertEquals($result, $expected);
}
@@ -117,7 +119,8 @@ public function testTaggedFind() {
*/
public function testFindCloud() {
$result = $this->Tagged->find('cloud', array(
- 'model' => 'Article'));
+ 'model' => 'Article'
+ ));
$this->assertEquals(count($result), 3);
$this->assertTrue(isset($result[0][0]['occurrence']));
@@ -127,7 +130,8 @@ public function testFindCloud() {
$this->assertTrue(is_array($result) && !empty($result));
$result = $this->Tagged->find('cloud', array(
- 'limit' => 1));
+ 'limit' => 1
+ ));
$this->assertEquals(count($result), 1);
}
@@ -140,17 +144,20 @@ public function testFindTagged() {
$this->Tagged->recursive = -1;
$result = $this->Tagged->find('tagged', array(
'by' => 'cakephp',
- 'model' => 'Article'));
+ 'model' => 'Article'
+ ));
$this->assertEquals(count($result), 1);
$this->assertEquals($result[0]['Article']['id'], 'article-1');
$result = $this->Tagged->find('tagged', array(
- 'model' => 'Article'));
+ 'model' => 'Article'
+ ));
$this->assertEquals(count($result), 2);
// Test call to paginateCount by Controller::pagination()
$result = $this->Tagged->paginateCount(array(), 1, array(
'model' => 'Article',
- 'type' => 'tagged'));
+ 'type' => 'tagged'
+ ));
$this->assertEquals($result, 2);
}
@@ -164,13 +171,15 @@ public function testFindTaggedWithConditions() {
$result = $this->Tagged->find('tagged', array(
'by' => 'cakephp',
'model' => 'Article',
- 'conditions' => array('Article.title LIKE' => 'Second %')));
+ 'conditions' => array('Article.title LIKE' => 'Second %')
+ ));
$this->assertEquals(count($result), 0);
$result = $this->Tagged->find('tagged', array(
'by' => 'cakephp',
'model' => 'Article',
- 'conditions' => array('Article.title LIKE' => 'First %')));
+ 'conditions' => array('Article.title LIKE' => 'First %')
+ ));
$this->assertEquals(count($result), 1);
$this->assertEquals($result[0]['Article']['id'], 'article-1');
}
@@ -186,16 +195,24 @@ public function testDeepAssociationsHasOne() {
'belongsTo' => array(
'Article' => array(
'className' => 'TaggedArticle',
- 'foreignKey' => 'foreign_key'))));
+ 'foreignKey' => 'foreign_key'
+ )
+ )
+ ));
$this->Tagged->Article->bindModel(array(
'hasOne' => array(
- 'User' => array())));
+ 'User' => array()
+ )
+ ));
$result = $this->Tagged->find('all', array(
'contain' => array(
'Article' => array(
- 'User'))));
+ 'User'
+ )
+ )
+ ));
$this->assertEquals($result[0]['Article']['User']['name'], 'CakePHP');
}
@@ -211,16 +228,24 @@ public function testDeepAssociationsBelongsTo() {
'belongsTo' => array(
'Article' => array(
'className' => 'TaggedArticle',
- 'foreignKey' => 'foreign_key'))));
+ 'foreignKey' => 'foreign_key'
+ )
+ )
+ ));
$this->Tagged->Article->bindModel(array(
'belongsTo' => array(
- 'User' => array())));
+ 'User' => array()
+ )
+ ));
$result = $this->Tagged->find('all', array(
'contain' => array(
'Article' => array(
- 'User'))));
+ 'User'
+ )
+ )
+ ));
$this->assertEquals($result[0]['Article']['User']['name'], 'CakePHP');
}
diff --git a/Test/Case/View/Helper/TagCloudHelperTest.php b/Test/Case/View/Helper/TagCloudHelperTest.php
index 7786c16..bd8e73d 100644
--- a/Test/Case/View/Helper/TagCloudHelperTest.php
+++ b/Test/Case/View/Helper/TagCloudHelperTest.php
@@ -35,7 +35,9 @@ class TagCloudHelperTest extends CakeTestCase {
'keyname' => 'cakephp',
'weight' => 2,
'created' => '2008-06-02 18:18:11',
- 'modified' => '2008-06-02 18:18:37')),
+ 'modified' => '2008-06-02 18:18:37'
+ )
+ ),
array(
'Tag' => array(
'id' => 2,
@@ -44,7 +46,9 @@ class TagCloudHelperTest extends CakeTestCase {
'keyname' => 'cakedc',
'weight' => 2,
'created' => '2008-06-01 18:18:15',
- 'modified' => '2008-06-01 18:18:15')),
+ 'modified' => '2008-06-01 18:18:15'
+ )
+ ),
);
/**
@@ -55,8 +59,9 @@ class TagCloudHelperTest extends CakeTestCase {
public $TagCloud;
/**
- * (non-PHPdoc)
- * @see cake/tests/lib/CakeTestCase#setUp($method)
+ * Setup the test case
+ *
+ * @return void
*/
public function setUp() {
parent::setUp();
@@ -76,7 +81,8 @@ public function testDisplay() {
// Test tags shuffling
$options = array(
- 'shuffle' => true);
+ 'shuffle' => true
+ );
$expected = 'CakePHP CakeDC ';
$i = 100;
do {
@@ -87,7 +93,8 @@ public function testDisplay() {
// Test normal display
$options = array(
- 'shuffle' => false);
+ 'shuffle' => false
+ );
$result = $this->TagCloud->display($this->sampleTags, $options);
$this->assertEquals($result, $expected);
@@ -101,18 +108,23 @@ public function testDisplay() {
'named' => 'query'
));
$result = $this->TagCloud->display($this->sampleTags, $options);
- $expected = 'CakePHP '.
+ $expected = 'CakePHP ' .
'CakeDC ';
$this->assertEquals($result, $expected);
$tags = $this->sampleTags;
$tags[1]['Tag']['weight'] = 1;
$result = $this->TagCloud->display($tags, $options);
- $expected = 'CakePHP '.
+ $expected = 'CakePHP ' .
'CakeDC ';
$this->assertEquals($result, $expected);
}
+/**
+ * Test that display method defines correct size when using custom weight fields
+ *
+ * @return void
+ */
public function testDisplayShouldDefineCorrectSizeWhenCustomWeightField() {
$tags = $this->sampleTags;
$tags[0]['Tag']['custom_weight'] = 6;
@@ -125,14 +137,37 @@ public function testDisplayShouldDefineCorrectSizeWhenCustomWeightField() {
);
$result = $this->TagCloud->display($tags, $options);
- $expected = 'CakePHP '.
+ $expected = 'CakePHP ' .
'CakeDC ';
$this->assertEquals($result, $expected);
}
/**
- * (non-PHPdoc)
- * @see cake/tests/lib/CakeTestCase#tearDown($method)
+ * Test query string param type
+ *
+ * @return void
+ */
+ public function testQueryStringUrlParams() {
+ $tags = $this->sampleTags;
+ $tags[0]['Tag']['custom_weight'] = 6;
+ $tags[1]['Tag']['custom_weight'] = 3;
+
+ $options = array(
+ 'shuffle' => false,
+ 'extract' => '{n}.Tag.custom_weight',
+ 'paramType' => 'querystring'
+ );
+
+ $result = $this->TagCloud->display($tags, $options);
+ $expected = 'CakePHP ' .
+ 'CakeDC ';
+ $this->assertEquals($result, $expected);
+ }
+
+/**
+ * Tear down the test case
+ *
+ * @return void
*/
public function tearDown() {
parent::tearDown();
diff --git a/Test/Fixture/ArticleFixture.php b/Test/Fixture/ArticleFixture.php
index 2edfe6d..c7a094d 100644
--- a/Test/Fixture/ArticleFixture.php
+++ b/Test/Fixture/ArticleFixture.php
@@ -37,11 +37,13 @@ class ArticleFixture extends CakeTestFixture {
array(
'id' => 'article-1',
'title' => 'First Article',
- 'user_id' => 'user-1'),
+ 'user_id' => 'user-1'
+ ),
array(
'id' => 'article-2',
'title' => 'Second Article',
- 'user_id' => 'user-2'),
+ 'user_id' => 'user-2'
+ ),
array(
'id' => 'article-3',
'title' => 'Third Article',
diff --git a/Test/Fixture/TagFixture.php b/Test/Fixture/TagFixture.php
index 75159b4..132154f 100644
--- a/Test/Fixture/TagFixture.php
+++ b/Test/Fixture/TagFixture.php
@@ -58,7 +58,8 @@ class TagFixture extends CakeTestFixture {
'occurrence' => 1,
'article_occurrence' => 1,
'created' => '2008-06-02 18:18:11',
- 'modified' => '2008-06-02 18:18:37'),
+ 'modified' => '2008-06-02 18:18:37'
+ ),
array(
'id' => 'tag-2',
'identifier' => null,
@@ -67,7 +68,8 @@ class TagFixture extends CakeTestFixture {
'occurrence' => 1,
'article_occurrence' => 1,
'created' => '2008-06-01 18:18:15',
- 'modified' => '2008-06-01 18:18:15'),
+ 'modified' => '2008-06-01 18:18:15'
+ ),
array(
'id' => 'tag-3',
'identifier' => null,
diff --git a/Test/Fixture/UserFixture.php b/Test/Fixture/UserFixture.php
index 386c26b..f225186 100644
--- a/Test/Fixture/UserFixture.php
+++ b/Test/Fixture/UserFixture.php
@@ -23,9 +23,10 @@ class UserFixture extends CakeTestFixture {
* @var array
*/
public $fields = array(
- 'id' => array('type' => 'string', 'null' => false, 'default' => NULL, 'length' => 36),
+ 'id' => array('type' => 'string', 'null' => false, 'default' => null, 'length' => 36),
'name' => array('type' => 'string', 'null' => false),
- 'article_id' => array('type' => 'string', 'null' => false, 'default' => NULL, 'length' => 36));
+ 'article_id' => array('type' => 'string', 'null' => false, 'default' => null, 'length' => 36)
+ );
/**
* records property
@@ -36,14 +37,18 @@ class UserFixture extends CakeTestFixture {
array(
'id' => 'user-1',
'name' => 'CakePHP',
- 'article_id' => 'article-1'),
+ 'article_id' => 'article-1'
+ ),
array(
'id' => 'user-2',
'name' => 'Second User',
- 'article_id' => 'article-2'),
+ 'article_id' => 'article-2'
+ ),
array(
'id' => 'user-3',
'name' => 'Third User',
- 'article_id' => 'article-3'));
+ 'article_id' => 'article-3'
+ )
+ );
}
diff --git a/View/Helper/TagCloudHelper.php b/View/Helper/TagCloudHelper.php
index 5af8daa..c5caf04 100644
--- a/View/Helper/TagCloudHelper.php
+++ b/View/Helper/TagCloudHelper.php
@@ -29,7 +29,7 @@ class TagCloudHelper extends AppHelper {
/**
* Method to output a tag-cloud formatted based on the weight of the tags
*
- * @param array $tags
+ * @param array $tags Tag data array
* @param array $options Display options. Valid keys are:
* - shuffle: true to shuffle the tag list, false to display them in the same order than passed [default: true]
* - extract: Set::extract() compatible format string. Path to extract weight values from the $tags array [default: {n}.Tag.weight]
@@ -37,8 +37,9 @@ class TagCloudHelper extends AppHelper {
* - after: string to be displayed after each generated link. "%size%" will be replaced with tag size calculated from the weight [default: empty]
* - maxSize: size of the heaviest tag [default: 160]
* - minSize: size of the lightest tag [default: 80]
- * - url: an array containing the default url
+ * - url: an array containing the default URL
* - named: the named parameter used to send the tag [default: by]
+ * - paramType: the type of URL parameters used (named or querystring) [default: named]
* @return string
*/
public function display($tags = null, $options = array()) {
@@ -56,7 +57,8 @@ public function display($tags = null, $options = array()) {
'url' => array(
'controller' => 'search'
),
- 'named' => 'by'
+ 'named' => 'by',
+ 'paramType' => 'named'
);
$options = array_merge($defaults, $options);
@@ -93,20 +95,25 @@ public function display($tags = null, $options = array()) {
/**
* Generates the URL for a tag
*
- * @param array
- * @param array
+ * @param array $tag Tag data array
+ * @param array $options Display options
* @return array|string
*/
protected function _tagUrl($tag, $options) {
- $options['url'][$options['named']] = $tag[$options['tagModel']]['keyname'];
+ if ($options['paramType'] === 'named') {
+ $options['url'][$options['named']] = $tag[$options['tagModel']]['keyname'];
+ } else {
+ $options['url']['?'][$options['named']] = $tag[$options['tagModel']]['keyname'];
+ }
+
return $options['url'];
}
/**
* Replaces %size% in strings with the calculated "size" of the tag
*
- * @param string
- * @param float
+ * @param string $string Before or after string
+ * @param float $size Calculated size
* @return string
*/
protected function _replace($string, $size) {