Taggable Extension Or-Ing Tags

I want to do the following.


$tagged = Os:: model() -> withTags("windows, windows7, windowsXp")-> find();

I want to retrieve records from the databse that contain any of the 3 tags. By default internally conditions ar AND-ed and must meet all 3 tags. I want to OR the tags.

Anyone have any clues?

I’d modified the ETaggableBehavior.php in the extension folder.

the getFindByTagsCriteria() now looks like this.


/**

	 * Get criteria to limit query by tags.

	 * @access private

	 * @param array $tags

	 * @return CDbCriteria

	 */

	protected function getFindByTagsCriteria($tags) {

		$criteria = new CDbCriteria();


		$pk = $this->getOwner()->tableSchema->primaryKey;


		if(!empty($tags)){

			$conn = $this->getConnection();

			$criteria->select = 't.*';

			

			if(count($tags) >0){

				$criteria -> join .= "

                                        JOIN {$this->getTagBindingTableName()} bt 

					ON t.{$pk} = bt.{$this->getModelTableFkName()}

					

					JOIN {$this->tagTable} tag0 

					ON tag0.{$this->tagTablePk} = bt.{$this->tagBindingTableTagId} AND (";

			

			

				for($i = 0, $count = count($tags); $i < $count; $i++){

					$tag = $conn->quoteValue($tags[$i]);

					$criteria->join .= " tag0.`{$this->tagTableName}` = $tag OR";

				}

				$criteria -> join = rtrim($criteria -> join, "OR");

				$criteria -> join .= ")";

			}

		}


		if($this->getScopeCriteria()){

			$criteria->mergeWith($this->getScopeCriteria());

		}


		return $criteria;

	}

I can now OR conditions. I have no idea what impact this would have on the whole plugin flow. Tell me what do you think?

Thanks to samdark’s great will to help, I’d been suggested to add these methods to the extension if i want to OR tags.


/**

 * Get criteria to limit query to match any of tags specified

 * @access private

 * @param array $tags

 * @return CDbCriteria

 */

protected function getFindByAnyTagsCriteria($tags) {

	$criteria = new CDbCriteria();


	$pk = $this->getOwner()->tableSchema->primaryKey;


	if(!empty($tags)){

		$conn = $this->getConnection();

		foreach($tags as &$tag) {

			$tag = $conn->quoteValue($tag);

		}

		unset($tag);

		$tags = implode(', ', $tags);


		$criteria->select = 't.*';

		$criteria->join .=

			"JOIN {$this->getTagBindingTableName()} bt ON t.{$pk} = bt.{$this->getModelTableFkName()}

			JOIN {$this->tagTable} tag ON tag.{$this->tagTablePk} = bt.{$this->tagBindingTableTagId} AND tag.`{$this->tagTableName}` IN ($tags)";

		}

	}


	if($this->getScopeCriteria()){

		$criteria->mergeWith($this->getScopeCriteria());

	}


	return $criteria;

}


/**

 * Limit current AR query to have any of tags specified.

 * @param string|array $tags

 * @return CActiveRecord

 */

public function taggedWithAnyOf($tags) {

	$tags = $this->toTagsArray($tags);


	if(!empty($tags)){

		$criteria = $this->getFindByAnyTagsCriteria($tags);

		$this->getOwner()->getDbCriteria()->mergeWith($criteria);

	}


	return $this->getOwner();

}

Source:

https://gist.github.com/3826070

by samdark