mirror of
https://github.com/humhub/humhub.git
synced 2025-01-16 21:58:17 +01:00
Enh: Added ContentTag
concept for creating content categories/filter on module level
This commit is contained in:
parent
2872d2aa9d
commit
14009c6195
@ -88,7 +88,7 @@ abstract class SocialActivity extends \yii\base\Object implements rendering\View
|
||||
* Static initializer should be prefered over new initialization, since it makes use
|
||||
* of Yii::createObject dependency injection/configuration.
|
||||
*
|
||||
* @return \humhub\components\SocialActivity
|
||||
* @return static
|
||||
*/
|
||||
public static function instance($options = [])
|
||||
{
|
||||
@ -110,8 +110,8 @@ abstract class SocialActivity extends \yii\base\Object implements rendering\View
|
||||
|
||||
/**
|
||||
* Builder function for the source.
|
||||
* @param type $source
|
||||
* @return \humhub\components\SocialActivity
|
||||
* @param \yii\db\ActiveRecord $source
|
||||
* @return $this
|
||||
*/
|
||||
public function about($source)
|
||||
{
|
||||
|
@ -45,6 +45,7 @@ HumHub Change Log
|
||||
- Fix: Reset modal dialog size + add `size` option
|
||||
- Enh: Added `size` option `ui.modal.Modal.set()`
|
||||
- Enh: Use `ContentActiveRecord::getUrl()` for content perma links (if given)
|
||||
- Enh: Added `ContentTag` concept for creating content categories/filter on module level
|
||||
|
||||
1.2.1 (June 17, 2017)
|
||||
- Fix: Invite error in french language
|
||||
|
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*
|
||||
*/
|
||||
|
||||
use yii\db\Migration;
|
||||
|
||||
class m170723_133337_content_tag extends Migration
|
||||
{
|
||||
public function safeUp()
|
||||
{
|
||||
$this->createTable('content_tag', [
|
||||
'id' => 'pk',
|
||||
'name' => $this->string(100)->notNull(),
|
||||
'module_id' => $this->string(100)->notNull(),
|
||||
'contentcontainer_id' => $this->integer()->null(),
|
||||
'type' => $this->string(100)->null(),
|
||||
'parent_id' => $this->integer()->null(),
|
||||
'color' => $this->string(7)->null()
|
||||
]);
|
||||
|
||||
$this->createIndex('idx-content-tag', 'content_tag', [
|
||||
'module_id', 'contentcontainer_id', 'name'
|
||||
]);
|
||||
|
||||
$this->addForeignKey('fk-content-tag-container-id', 'content_tag', 'contentcontainer_id', 'contentcontainer', 'id', 'CASCADE');
|
||||
$this->addForeignKey('fk-content-tag-parent-id', 'content_tag', 'parent_id', 'content_tag', 'id', 'SET NULL');
|
||||
|
||||
$this->createTable('content_tag_relation', [
|
||||
'id' => 'pk',
|
||||
'content_id' => $this->integer()->notNull(),
|
||||
'tag_id' => $this->integer()->notNull(),
|
||||
]);
|
||||
|
||||
$this->addForeignKey('fk-content-tag-rel-content-id', 'content_tag_relation', 'content_id', 'content', 'id', 'CASCADE');
|
||||
$this->addForeignKey('fk-content-tag-rel-tag-id', 'content_tag_relation', 'tag_id', 'content_tag', 'id', 'CASCADE');
|
||||
}
|
||||
|
||||
public function safeDown()
|
||||
{
|
||||
echo "m170723_133337_content_filter cannot be reverted.\n";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
// Use up()/down() to run migration code without a transaction.
|
||||
public function up()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
echo "m170723_133337_content_filter cannot be reverted.\n";
|
||||
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
}
|
@ -11,6 +11,7 @@ namespace humhub\modules\content\models;
|
||||
use Yii;
|
||||
use humhub\modules\user\components\PermissionManager;
|
||||
use yii\base\Exception;
|
||||
use yii\base\InvalidParamException;
|
||||
use yii\helpers\Url;
|
||||
use humhub\modules\user\models\User;
|
||||
use humhub\modules\space\models\Space;
|
||||
@ -419,6 +420,52 @@ class Content extends ContentDeprecated
|
||||
return $this->hasOne(ContentContainer::className(), ['id' => 'contentcontainer_id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ContentTagRelation query.
|
||||
*
|
||||
* @since 1.2.2
|
||||
* @return \yii\db\ActiveQuery
|
||||
*/
|
||||
public function getTagRelations()
|
||||
{
|
||||
return $this->hasMany(ContentTagRelation::className(), ['content_id' => 'id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all content related tags ContentTags related to this content.
|
||||
*
|
||||
* @since 1.2.2
|
||||
* @return \yii\db\ActiveQuery
|
||||
*/
|
||||
public function getTags()
|
||||
{
|
||||
return $this->hasMany(ContentTag::class, ['id' => 'tag_id'])->via('tagRelations');
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new ContentTagRelation for this content and the given $tag instance.
|
||||
*
|
||||
* @since 1.2.2
|
||||
* @throws InvalidParamException if the provided tag is part of another ContentContainer
|
||||
* @return boolean true if tag relation could be saved or is already assigned otherwise false
|
||||
*/
|
||||
public function addTag(ContentTag $tag)
|
||||
{
|
||||
if(!empty($tag->contentcontainer_id) && $tag->contentcontainer_id != $this->contentcontainer_id) {
|
||||
throw new InvalidParamException(Yii::t('ContentModule.base', 'Content Tag with invalid contentcontainer_id assigned.'));
|
||||
}
|
||||
|
||||
if(ContentTagRelation::findBy($this, $tag)->count()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
unset($this->tags);
|
||||
|
||||
$contentRelation = new ContentTagRelation($this, $tag);
|
||||
return $contentRelation->save();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks if the given user can edit this content.
|
||||
*
|
||||
|
421
protected/humhub/modules/content/models/ContentTag.php
Normal file
421
protected/humhub/modules/content/models/ContentTag.php
Normal file
@ -0,0 +1,421 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: buddha
|
||||
* Date: 23.07.2017
|
||||
* Time: 15:47
|
||||
*/
|
||||
|
||||
namespace humhub\modules\content\models;
|
||||
|
||||
|
||||
use humhub\components\ActiveRecord;
|
||||
use humhub\modules\content\components\ContentActiveRecord;
|
||||
use humhub\modules\content\components\ContentContainerActiveRecord;
|
||||
use Yii;
|
||||
use yii\db\ActiveQuery;
|
||||
|
||||
/**
|
||||
* ContentTags are a concept to categorize content on module and ContentContainer level.
|
||||
* By means of ContentTags a module is able to create own category concepts as for example event types (calendar) or
|
||||
* task related tags, in which the module itself is responsible for managing and the usage of it's tags.
|
||||
*
|
||||
* Module implementing own an own category concept should extend the ContentTag class as follows:
|
||||
*
|
||||
* ```php
|
||||
* class MyModuleCategory extends ContentTag
|
||||
* {
|
||||
* public $moduleId = 'myModule';
|
||||
*
|
||||
* public static getLabel()
|
||||
* {
|
||||
* return 'MyCategory'
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* All MyModuleCategory will be assigned with the given `$moduleId` as `$module_id` and the class name as `$type`.
|
||||
* Calls to `MyModuleCategory::find()` will always include `$module_id` filters, the same goes for other query methods as `findByCotnainer` etc.
|
||||
*
|
||||
* If a subclass sets `$includeTypeQuery` to true queries will also include a $type filter. This is required if a module provides more than one
|
||||
* tag type.
|
||||
*
|
||||
* If you require to select untyped tags use `ContentTag::find()` instead.
|
||||
*
|
||||
* If the contentcontainer_id of a given ContentTag is null, the ContentTag is meant to be module global and therefore not bound to a ContentContainer instance.
|
||||
*
|
||||
* In some cases a ContentTag has to be related with some further settigns, this can be achieved by extending the `ContentTagAddition` class and
|
||||
* setting the ContentTags `$additioNClass`.
|
||||
*
|
||||
* An instance of this class will automatically be created by calling `$tag->addition`
|
||||
*
|
||||
* @property integer $id
|
||||
* @property string name
|
||||
* @property string module_id
|
||||
* @property integer contentcontainer_id
|
||||
* @property string type
|
||||
* @property integer parent_id
|
||||
*
|
||||
* @package humhub\modules\content\models
|
||||
* @since 1.2.2
|
||||
* @author buddha
|
||||
*/
|
||||
class ContentTag extends ActiveRecord
|
||||
{
|
||||
public $moduleId;
|
||||
|
||||
public $additionClass;
|
||||
|
||||
protected $_container;
|
||||
|
||||
public $includeTypeQuery = false;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static function tableName()
|
||||
{
|
||||
return 'content_tag';
|
||||
}
|
||||
|
||||
public function __construct($contentContainer = [], $name = null, $config = [])
|
||||
{
|
||||
if (is_array($contentContainer)) {
|
||||
parent::__construct($contentContainer);
|
||||
} else if ($contentContainer instanceof ContentContainerActiveRecord) {
|
||||
$this->contentcontainer_id = $contentContainer->contentcontainer_id;
|
||||
parent::__construct($config);
|
||||
} else {
|
||||
parent::__construct([]);
|
||||
}
|
||||
|
||||
if(!empty($name)) {
|
||||
$this->name = $name;
|
||||
}
|
||||
}
|
||||
|
||||
public static function getLabel()
|
||||
{
|
||||
return Yii::t('ContentModule.models_ContentTag', 'Tag');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the module_id as and type.
|
||||
* Subclasses overwriting this method have to make sure to call parent::init() at the end.
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->module_id = $this->moduleId;
|
||||
if (!$this->type) {
|
||||
$this->type = static::class;
|
||||
}
|
||||
parent::init();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
[['name', 'module_id'], 'required'],
|
||||
[['name', 'module_id', 'type'], 'string', 'max' => '100'],
|
||||
['color', 'string', 'max' => '7'],
|
||||
[['parent_id'], 'integer'],
|
||||
[['name'], 'validateUnique']
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates
|
||||
* @param $attribute
|
||||
* @param $params
|
||||
* @param $validator
|
||||
*/
|
||||
public function validateUnique($attribute, $params, $validator)
|
||||
{
|
||||
if (empty($this->contentcontainer_id)) {
|
||||
$query = self::find()->andWhere('contentcontainer_id IS NULL');
|
||||
} else {
|
||||
$query = self::findByContainer($this->contentcontainer_id);
|
||||
}
|
||||
|
||||
$query->andWhere(['name' => $this->name]);
|
||||
|
||||
if (!$this->isNewRecord) {
|
||||
$query->andWhere(['<>', 'id', $this->id]);
|
||||
}
|
||||
|
||||
if ($query->count() > 0) {
|
||||
$this->addError('name', Yii::t('ContentModule.models_ContentTag', 'The given name is already in use.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
/**
|
||||
* Ensure there is always a corresponding Content record
|
||||
* @see ContentTagAddition
|
||||
*/
|
||||
if ($name == 'addition' && $this->additionClass) {
|
||||
$addition = parent::__get('addition');
|
||||
if (!$this->isRelationPopulated('addition') || $addition === null) {
|
||||
$addition = Yii::createObject($this->additionClass);
|
||||
$this->populateRelation('addition', $addition);
|
||||
$addition->setTag($this);
|
||||
}
|
||||
return $addition;
|
||||
}
|
||||
return parent::__get($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function validate($attributeNames = null, $clearErrors = true)
|
||||
{
|
||||
$result = parent::validate($attributeNames, $clearErrors);
|
||||
if($attributeNames === null || in_array('addition', $attributeNames)) {
|
||||
// the addition will only be validated if $tag->addition has been called
|
||||
if($this->hasAddition() && !$this->addition->validate()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ContentContainer relation as ActiveQuery to this tag or null if this is a global tag.
|
||||
*
|
||||
* Note: In order to retrieve the actual Cotnainer (Space/User) use `getContainer()`.
|
||||
* @return \yii\db\ActiveQuery
|
||||
*/
|
||||
public function getContentContainer()
|
||||
{
|
||||
if ($this->contentcontainer_id === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->hasOne(ContentContainer::className(), ['id' => 'contentcontainer_id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the actual Container (Space/User) related to this tag or null if this is a global tag.
|
||||
* This function will cache the container instance once loaded.
|
||||
*
|
||||
* @return null|ContentContainerActiveRecord
|
||||
*/
|
||||
public function getContainer()
|
||||
{
|
||||
if ($this->contentcontainer_id === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->_container === null) {
|
||||
$this->_container = $this->contentContainer->getPolymorphicRelation();
|
||||
}
|
||||
|
||||
return $this->_container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parent tag relation.
|
||||
*
|
||||
* @return \yii\db\ActiveQuery
|
||||
*/
|
||||
public function getParent()
|
||||
{
|
||||
if ($this->parent_id === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->hasOne(ContentTag::className(), ['id' => 'parent_id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ActiveRecord|\yii\db\ActiveQuery
|
||||
*/
|
||||
public function getAddition()
|
||||
{
|
||||
if (!$this->additionClass) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->hasOne($this->additionClass, ['tag_id' => 'id']);
|
||||
}
|
||||
|
||||
public function hasAddition()
|
||||
{
|
||||
return $this->additionClass != null && $this->isRelationPopulated('addition');
|
||||
}
|
||||
|
||||
public function setAddition(ContentTagAddition $addition)
|
||||
{
|
||||
$addition->setTag($this);
|
||||
}
|
||||
|
||||
public function afterSave($insert, $changedAttributes)
|
||||
{
|
||||
$addition = $this->addition;
|
||||
parent::afterSave($insert, $changedAttributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this content tag is of the given $type.
|
||||
*
|
||||
* @param ContentTag $tag
|
||||
* @return bool
|
||||
*/
|
||||
public function is($type)
|
||||
{
|
||||
return $this->type === $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds instances and filters by module_id if a static module_id is given.
|
||||
*
|
||||
* @return \yii\db\ActiveQuery
|
||||
*/
|
||||
public static function find()
|
||||
{
|
||||
$query = parent::find();
|
||||
self::moduleQuery($query);
|
||||
return self::typeQuery($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an type filter query to the given $query instance in case $includeTypeQuery of the subclass is set to true and the
|
||||
* calling class is not ContentTag class itself.
|
||||
*
|
||||
* @param $query ActiveQuery
|
||||
* @param bool $force
|
||||
* @return mixed
|
||||
*/
|
||||
protected static function typeQuery($query)
|
||||
{
|
||||
$instance = new static;
|
||||
if($instance->includeTypeQuery && static::class != ContentTag::class) {
|
||||
$query->andWhere(['content_tag.type' => static::class]);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an module id filter query to the given $query instance in case a subclass has set the $moduleId.
|
||||
*
|
||||
* @param $query ActiveQuery
|
||||
* @return mixed
|
||||
*/
|
||||
protected static function moduleQuery($query)
|
||||
{
|
||||
$instance = new static;
|
||||
if (!empty($instance->moduleId)) {
|
||||
$query->andWhere(['content_tag.module_id' => $instance->moduleId]);
|
||||
}
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param $moduleId
|
||||
* @return \yii\db\ActiveQuery
|
||||
*/
|
||||
public static function findByModule($moduleId)
|
||||
{
|
||||
return parent::find()->where(['module_id' => $moduleId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds instances by given $type.
|
||||
*
|
||||
* @param string $type
|
||||
* @return \yii\db\ActiveQuery
|
||||
*/
|
||||
public static function findByType($type)
|
||||
{
|
||||
$query = parent::find();
|
||||
self::moduleQuery($query)->andWhere(['content_tag.type' => $type]);
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Content related tags.
|
||||
*
|
||||
* @param Content $content
|
||||
* @param null $type
|
||||
* @return ActiveQuery
|
||||
*/
|
||||
public static function findByContent(Content $content)
|
||||
{
|
||||
$query = $content->getTags();
|
||||
self::moduleQuery($query);
|
||||
$instance = new static;
|
||||
|
||||
if (!empty($instance->moduleId)) {
|
||||
$query->andWhere(['content_tag.module_id' => $instance->moduleId]);
|
||||
}
|
||||
|
||||
return self::typeQuery($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all tag relations of the given type for the given $content.
|
||||
*
|
||||
* @param Content $content
|
||||
* @return ContentTagRelation[]
|
||||
*/
|
||||
public static function getTagContentRelations(Content $content)
|
||||
{
|
||||
$query = $content->getTagRelations()->innerJoin('content_tag', 'content_tag_relation.tag_id = content_tag.id');
|
||||
|
||||
$instance = new static;
|
||||
if (!empty($instance->moduleId)) {
|
||||
$query->andWhere(['content_tag.module_id' => $instance->moduleId]);
|
||||
}
|
||||
|
||||
if (static::class != ContentTag::class) {
|
||||
$query->andWhere(['content_tag.type' => static::class]);
|
||||
}
|
||||
|
||||
return $query->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all tag relations of the given type for the given $content.
|
||||
*
|
||||
* @param Content $content
|
||||
*/
|
||||
public static function deleteContentRelations(Content $content)
|
||||
{
|
||||
$relations = self::getTagContentRelations($content);
|
||||
foreach ($relations as $relation) {
|
||||
$relation->delete();
|
||||
}
|
||||
|
||||
unset($content->tags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds instances by ContentContainerActiveRecord and optional type.
|
||||
*
|
||||
* @param ContentContainerActiveRecord|integer $record Container instance or contentcontainer_id
|
||||
* @param null $type
|
||||
* @return \yii\db\ActiveQuery
|
||||
*/
|
||||
public static function findByContainer($container)
|
||||
{
|
||||
$container_id = $container instanceof ContentContainerActiveRecord ? $container->contentcontainer_id : $container;
|
||||
return self::find()->andWhere(['content_tag.contentcontainer_id' => $container_id]);
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: buddha
|
||||
* Date: 23.07.2017
|
||||
* Time: 21:38
|
||||
*/
|
||||
|
||||
namespace humhub\modules\content\models;
|
||||
|
||||
|
||||
use yii\db\ActiveRecord;
|
||||
|
||||
/**
|
||||
* Class ContentTagAddition
|
||||
*
|
||||
* @property integer $id
|
||||
* @perperty integer $tag_id
|
||||
*
|
||||
* @since 1.2.2
|
||||
* @author buddha
|
||||
*/
|
||||
class ContentTagAddition extends ActiveRecord
|
||||
{
|
||||
|
||||
public function setTag(ContentTag $tag)
|
||||
{
|
||||
$this->tag_id = $tag->id;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: buddha
|
||||
* Date: 23.07.2017
|
||||
* Time: 22:06
|
||||
*/
|
||||
|
||||
namespace humhub\modules\content\models;
|
||||
|
||||
|
||||
use humhub\components\ActiveRecord;
|
||||
use yii\base\InvalidParamException;
|
||||
|
||||
/**
|
||||
* Class ContentTagRelation
|
||||
*
|
||||
* @property integer $id
|
||||
* @property integer $content_id
|
||||
* @property integer $tag_id
|
||||
*
|
||||
* @since 1.2.2
|
||||
* @author buddha
|
||||
*/
|
||||
class ContentTagRelation extends ActiveRecord
|
||||
{
|
||||
public static function tableName()
|
||||
{
|
||||
return "content_tag_relation";
|
||||
}
|
||||
|
||||
/**
|
||||
* ContentTagRelation constructor.
|
||||
* @param array $content
|
||||
* @param ContentTag|null $tag
|
||||
* @param array $config
|
||||
*/
|
||||
public function __construct($content = [], $tag = null, $config = [])
|
||||
{
|
||||
if(is_array($content)) {
|
||||
parent::__construct($content);
|
||||
} else if($content instanceof Content) {
|
||||
$this->setContent($content);
|
||||
|
||||
if($tag !== null && $tag->isNewRecord) {
|
||||
throw new InvalidParamException('ContentTag was not saved before creating ContentTagRelation');
|
||||
}
|
||||
|
||||
if($tag !== null) {
|
||||
$this->setTag($tag);
|
||||
}
|
||||
parent::__construct($config);
|
||||
} else {
|
||||
parent::__construct([]);
|
||||
}
|
||||
}
|
||||
|
||||
public static function findBy($contentId, $tagId) {
|
||||
$contentId = ($contentId instanceof Content) ? $contentId->id : $contentId;
|
||||
$tagId = ($tagId instanceof ContentTag) ? $tagId->id : $tagId;
|
||||
|
||||
return self::find()->where(['content_id' => $contentId])->andWhere(['tag_id' => $tagId]);
|
||||
}
|
||||
|
||||
public function getTag()
|
||||
{
|
||||
return $this->hasOne(ContentTagAddition::class, ['id' => 'tag_id']);
|
||||
}
|
||||
|
||||
public function getContent()
|
||||
{
|
||||
return $this->hasOne(Content::class, ['id' => 'content_id']);
|
||||
}
|
||||
|
||||
public function setContent(Content $content)
|
||||
{
|
||||
$this->content_id = $content->id;
|
||||
}
|
||||
|
||||
public function setTag(ContentTag $tag)
|
||||
{
|
||||
$this->tag_id = $tag->id;
|
||||
}
|
||||
}
|
@ -18,6 +18,8 @@ class ContentFixture extends ActiveFixture
|
||||
|
||||
public $depends = [
|
||||
'humhub\modules\content\tests\codeception\fixtures\ContentContainerFixture',
|
||||
'humhub\modules\content\tests\codeception\fixtures\ContentTagFixture',
|
||||
'humhub\modules\content\tests\codeception\fixtures\ContentTagRelationFixture',
|
||||
'humhub\modules\post\tests\codeception\fixtures\PostFixture',
|
||||
'humhub\modules\comment\tests\codeception\fixtures\CommentFixture',
|
||||
'humhub\modules\like\tests\codeception\fixtures\LikeFixture'
|
||||
|
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*
|
||||
*/
|
||||
|
||||
namespace humhub\modules\content\tests\codeception\fixtures;
|
||||
|
||||
use humhub\modules\content\models\ContentTag;
|
||||
use yii\test\ActiveFixture;
|
||||
|
||||
class ContentTagFixture extends ActiveFixture
|
||||
{
|
||||
public $modelClass = ContentTag::class;
|
||||
public $dataFile = '@modules/content/tests/codeception/fixtures/data/content_tag.php';
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*
|
||||
*/
|
||||
|
||||
namespace humhub\modules\content\tests\codeception\fixtures;
|
||||
|
||||
use humhub\modules\content\models\ContentTag;
|
||||
use humhub\modules\content\models\ContentTagRelation;
|
||||
use yii\test\ActiveFixture;
|
||||
|
||||
class ContentTagRelationFixture extends ActiveFixture
|
||||
{
|
||||
public $modelClass = ContentTagRelation::class;
|
||||
public $dataFile = '@modules/content/tests/codeception/fixtures/data/content_tag_relation.php';
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*
|
||||
*/
|
||||
return [];
|
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*
|
||||
*/
|
||||
return [];
|
@ -0,0 +1,217 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: buddha
|
||||
* Date: 24.07.2017
|
||||
* Time: 15:56
|
||||
*/
|
||||
|
||||
namespace humhub\modules\content\tests\codeception\unit;
|
||||
|
||||
|
||||
use humhub\modules\content\models\Content;
|
||||
use humhub\modules\content\models\ContentTag;
|
||||
use humhub\modules\content\models\ContentTagRelation;
|
||||
use humhub\modules\space\models\Space;
|
||||
use tests\codeception\_support\HumHubDbTestCase;
|
||||
use yii\base\InvalidParamException;
|
||||
|
||||
class ContentTagTest extends HumHubDbTestCase
|
||||
{
|
||||
public $space;
|
||||
|
||||
public function testCreation()
|
||||
{
|
||||
// Test Tag validation/constructor
|
||||
$this->assertTrue($this->createTestTag('testTag1'));
|
||||
|
||||
// Test Tag db attributes
|
||||
$tag = TestTag::findOne(1);
|
||||
$this->assertEquals('testTag1', $tag->name);
|
||||
$this->assertEquals($this->space->contentcontainer_id, $tag->contentcontainer_id);
|
||||
$this->assertEquals('test', $tag->moduleId);
|
||||
$this->assertEquals(TestTag::class, $tag->type);
|
||||
|
||||
// Test unique module/container/name
|
||||
$this->assertFalse($this->createTestTag('testTag1'));
|
||||
|
||||
// Other types should be able to use the same name
|
||||
$this->assertTrue($this->createOtherTestTag('testTag1'));
|
||||
|
||||
// Other modules should be able to use the same name
|
||||
$this->assertTrue($this->createOtherModuleTestTag('testTag1'));
|
||||
|
||||
// Other contentcontainer should be able to use the same name
|
||||
$space2 = Space::findOne(2);
|
||||
$this->assertTrue($this->createTestTag('testTag1', $space2));
|
||||
|
||||
// Global tag should be able to use the same name
|
||||
$tag = new TestTagOtherModule(null, 'testTag1');
|
||||
$this->assertTrue($tag->save());
|
||||
}
|
||||
|
||||
public function testFindByContainer()
|
||||
{
|
||||
$space2 = Space::findOne(2);
|
||||
$this->assertTrue($this->createTestTag('testTag1'));
|
||||
$this->assertTrue($this->createTestTag('testTag2'));
|
||||
$this->assertTrue($this->createTestTag('testTag3', $space2));
|
||||
|
||||
$this->assertTrue($this->createOtherTestTag('testTagA'));
|
||||
$this->assertTrue($this->createOtherTestTag('testTagB'));
|
||||
$this->assertTrue($this->createOtherTestTag('testTagC', $space2));
|
||||
|
||||
$this->assertTrue($this->createOtherModuleTestTag('testTagX'));
|
||||
$this->assertTrue($this->createOtherModuleTestTag('testTagY'));
|
||||
$this->assertTrue($this->createOtherModuleTestTag('testTagZ', $space2));
|
||||
|
||||
$allSpace1Tags = ContentTag::findByContainer($this->space)->all();
|
||||
$this->assertEquals(6, count($allSpace1Tags));
|
||||
|
||||
$allSpace2Tags = ContentTag::findByContainer($space2)->all();
|
||||
$this->assertEquals(3, count($allSpace2Tags));
|
||||
|
||||
$typedSpace1Tags = TestTag::findByContainer($this->space)->all();
|
||||
$this->assertEquals(2, count($typedSpace1Tags));
|
||||
|
||||
$typedSpace2Tags = TestTag::findByContainer($space2)->all();
|
||||
$this->assertEquals(1, count($typedSpace2Tags));
|
||||
|
||||
$otherModuleTags = TestTagOtherModule::findByContainer($this->space)->all();
|
||||
$this->assertEquals(2, count($otherModuleTags));
|
||||
|
||||
$otherModuleTagsS2 = TestTagOtherModule::findByContainer($space2)->all();
|
||||
$this->assertEquals(1, count($otherModuleTagsS2));
|
||||
|
||||
}
|
||||
|
||||
public function testTagDeletion()
|
||||
{
|
||||
$content = Content::findOne(1);
|
||||
$tag2 = new TestTagSameModule($content->getContainer(), 'test2');
|
||||
$tag2->save();
|
||||
$content->addTag($tag2);
|
||||
$this->assertEquals(1, count($content->tagRelations));
|
||||
|
||||
$tag2->delete();
|
||||
$content->refresh();
|
||||
$this->assertEquals(0, count($content->tagRelations));
|
||||
|
||||
}
|
||||
|
||||
public function testContentDeletion()
|
||||
{
|
||||
$content = Content::findOne(1);
|
||||
$tag2 = new TestTagSameModule($content->getContainer(), 'test2');
|
||||
$tag2->save();
|
||||
$content->addTag($tag2);
|
||||
$this->assertEquals(1, ContentTagRelation::find()->count());
|
||||
|
||||
$content->delete();
|
||||
$this->assertEquals(0, ContentTagRelation::find()->count());
|
||||
|
||||
}
|
||||
|
||||
public function testTagContentRelation()
|
||||
{
|
||||
$this->space = Space::findOne(['id' => 3]);
|
||||
$tag = new TestTag($this->space, 'test');
|
||||
$content = Content::findOne(1);
|
||||
|
||||
try {
|
||||
$content->addTag($tag);
|
||||
$this->assertTrue(false);
|
||||
} catch(InvalidParamException $e) {
|
||||
// Tag was not saved
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
|
||||
$this->assertTrue($tag->save());
|
||||
|
||||
try {
|
||||
$content->addTag($tag);
|
||||
$this->assertTrue(false);
|
||||
} catch(InvalidParamException $e) {
|
||||
// Tag assigned with invalid container_id
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
|
||||
$tag->contentcontainer_id = $content->contentcontainer_id;
|
||||
|
||||
$this->assertTrue($content->addTag($tag));
|
||||
$this->assertEquals(1, count($content->tags));
|
||||
|
||||
$this->assertTrue($content->addTag($tag));
|
||||
$this->assertEquals(1, count($content->tags));
|
||||
|
||||
|
||||
$tag2 = new TestTagSameModule($content->getContainer(), 'test2');
|
||||
$tag2->save();
|
||||
$content->addTag($tag2);
|
||||
$this->assertEquals(2, count($content->tags));
|
||||
|
||||
$tag3 = new TestTagOtherModule($content->getContainer(), 'test3');
|
||||
$tag3->save();
|
||||
$content->addTag($tag3);
|
||||
$this->assertEquals(3, count($content->tags));
|
||||
|
||||
$sameModuleTags = TestTagSameModule::findByContent($content)->all();
|
||||
$this->assertEquals(1, count($sameModuleTags));
|
||||
|
||||
$tags = TestTag::findByContent($content)->all();
|
||||
$this->assertEquals(1, count($tags));
|
||||
|
||||
TestTagSameModule::deleteContentRelations($content);
|
||||
$sameModuleTags = TestTagSameModule::findByContent($content)->all();
|
||||
$this->assertEquals(0, count($sameModuleTags));
|
||||
$this->assertEquals(2, count($content->tags));
|
||||
|
||||
ContentTag::deleteContentRelations($content);
|
||||
$this->assertEquals(0, count($content->tags));
|
||||
}
|
||||
|
||||
protected function createTestTag($name, $container = null)
|
||||
{
|
||||
$container = (!$container) ? $this->space : $container;
|
||||
|
||||
if(!$container) {
|
||||
$container = $this->space = Space::findOne(['id' => 3]);
|
||||
}
|
||||
|
||||
$tag = new TestTag($container, $name);
|
||||
return $tag->save();
|
||||
}
|
||||
|
||||
protected function createOtherTestTag($name, $container = null)
|
||||
{
|
||||
$container = (!$container) ? $this->space : $container;
|
||||
|
||||
if(!$container) {
|
||||
$container = $this->space = Space::findOne(['id' => 3]);
|
||||
}
|
||||
|
||||
$tag = new TestTagSameModule($container, $name);
|
||||
return $tag->save();
|
||||
}
|
||||
|
||||
protected function createOtherModuleTestTag($name, $container = null)
|
||||
{
|
||||
$container = (!$container) ? $this->space : $container;
|
||||
|
||||
if(!$container) {
|
||||
$container = $this->space = Space::findOne(['id' => 3]);
|
||||
}
|
||||
|
||||
$tag = new TestTagOtherModule($container, $name);
|
||||
return $tag->save();
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: buddha
|
||||
* Date: 24.07.2017
|
||||
* Time: 15:56
|
||||
*/
|
||||
|
||||
namespace humhub\modules\content\tests\codeception\unit;
|
||||
|
||||
|
||||
use humhub\modules\content\models\ContentTag;
|
||||
|
||||
class TestTag extends ContentTag
|
||||
{
|
||||
public $moduleId = 'test';
|
||||
|
||||
public $includeTypeQuery = true;
|
||||
|
||||
public static function getLabel()
|
||||
{
|
||||
return 'testCategory';
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: buddha
|
||||
* Date: 24.07.2017
|
||||
* Time: 15:56
|
||||
*/
|
||||
|
||||
namespace humhub\modules\content\tests\codeception\unit;
|
||||
|
||||
|
||||
use humhub\modules\content\models\ContentTag;
|
||||
|
||||
class TestTagOtherModule extends ContentTag
|
||||
{
|
||||
public $moduleId = 'otherTest';
|
||||
|
||||
public static function getLabel()
|
||||
{
|
||||
return 'testCategory';
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: buddha
|
||||
* Date: 24.07.2017
|
||||
* Time: 15:56
|
||||
*/
|
||||
|
||||
namespace humhub\modules\content\tests\codeception\unit;
|
||||
|
||||
|
||||
use humhub\modules\content\models\ContentTag;
|
||||
|
||||
class TestTagSameModule extends ContentTag
|
||||
{
|
||||
public $moduleId = 'test';
|
||||
|
||||
public $includeTypeQuery = true;
|
||||
|
||||
public static function getLabel()
|
||||
{
|
||||
return 'testCategory';
|
||||
}
|
||||
|
||||
}
|
115
protected/humhub/widgets/ContentTagDropDown.php
Normal file
115
protected/humhub/widgets/ContentTagDropDown.php
Normal file
@ -0,0 +1,115 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: buddha
|
||||
* Date: 23.07.2017
|
||||
* Time: 17:36
|
||||
*/
|
||||
|
||||
namespace humhub\widgets;
|
||||
|
||||
|
||||
use humhub\libs\Html;
|
||||
use humhub\modules\content\models\ContentTag;
|
||||
|
||||
class ContentTagDropDown extends InputWidget
|
||||
{
|
||||
/**
|
||||
* @var string tagClass
|
||||
*/
|
||||
public $tagClass;
|
||||
public $query;
|
||||
public $contentContainer;
|
||||
public $type = true;
|
||||
public $prompt = false;
|
||||
public $promptValue = 0;
|
||||
|
||||
public $items;
|
||||
private $_itemOptions = [];
|
||||
|
||||
public function int() {
|
||||
if(!$this->tagClass) {
|
||||
$this->tagClass = ContentTag::class;
|
||||
// Reset default behavior inf no specific tagClass is given
|
||||
if($this->type === true) {
|
||||
$this->type = null;
|
||||
}
|
||||
}
|
||||
|
||||
if(!$this->none && !$this->noneLabel) {
|
||||
$this->noneLabel = Yii::t('ContentModule.widgets_ContentTagDropDown', 'None');
|
||||
}
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
$items = $this->getItems();
|
||||
|
||||
if(empty($items)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$options = $this->getOptions();
|
||||
unset($options['id']);
|
||||
|
||||
if($this->form && $this->hasModel()) {
|
||||
return $this->form->field($this->model, $this->attribute)->dropDownList($items, $options);
|
||||
} else if($this->hasModel()) {
|
||||
return Html::activeDropDownList($this->model, $this->attribute, $items, $options);
|
||||
} else {
|
||||
return Html::dropDownList($this->name, $this->value, $items, $options);
|
||||
}
|
||||
}
|
||||
|
||||
public function getAttributes()
|
||||
{
|
||||
$result = [
|
||||
'class' => 'form-control',
|
||||
'options' => $this->_itemOptions
|
||||
];
|
||||
|
||||
if($this->prompt) {
|
||||
$result['prompt'] = $this->prompt;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getItems()
|
||||
{
|
||||
if($this->items) {
|
||||
return $this->items;
|
||||
}
|
||||
|
||||
if(!$this->query) {
|
||||
if($this->contentContainer) {
|
||||
$this->query = call_user_func($this->tagClass .'::findByContainer', $this->contentContainer);
|
||||
} elseif(!empty($this->type)){
|
||||
$type = ($this->type === true) ? $this->tagClass : $this->type;
|
||||
$this->query = call_user_func($this->tagClass .'::findByType', [$type]);
|
||||
} else {
|
||||
$this->query = call_user_func($this->tagClass .'::find');
|
||||
}
|
||||
}
|
||||
|
||||
$tags = $this->items = $this->query->all();
|
||||
|
||||
$result = [];
|
||||
foreach ($tags as $tag) {
|
||||
$result[$tag->id] = $tag->name;
|
||||
$this->_itemOptions[$tag->id] = [
|
||||
'data-type-color' => $tag->color
|
||||
];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user