[Module] Ycm - Yii Content Management Module

http://www.yiiframework.com/extension/ycm/

Post questions here.

Hi!

Interesting project!

Could you add once more widget - "Autocomplete Ajax Filed"?

Also can I disable widgets in individual Action?

What do you mean by individual Action? Create and Update?

I added the bootstrap typehead widget.

Usage:




	public function attributeWidgets()

	{

		return array(

			array('myfield','typeHead'),

		);

	}



or if you wish to limit the list




	public function attributeWidgets()

	{

		return array(

			array('myfield','typeHead','options'=>array('items'=>5)),

		);

	}



and




	public function myfieldChoices()

	{

		return array('Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorado', 'Connecticut', 'Delaware');

	}



Hi,

Janisto: this is brillant. Usefull, nice widgets and good piece of code. Thank you also for typeHead feature.

Is there a feature for setting in the model class the displayed fields in create and update form views as it is in index (grid) view ?

If you wish to hide some fields from the create and update action, you should just remove them from customized attribute labels array.




	public function attributeLabels()

	{

		return array(

			'id' => 'ID',

			//'field0' => 'Field 0',

			//'field1' => 'Field 1',

			'field2' => 'Field 2',

			...

		);

	}



YCM uses attributeLabels() for fields and field order, so you can also change the order of the fields in attributeLabels().

how simple !

thks

I added a Google Analytics statistics page to the development version of YCM. Grab it from GitHub and let me know how it works for you.

New version is out.

Really great tool! But better documentation is needed, or at least reference manual.

I would like to see two news widgets, that looks like ‘chosenMultiple’, but first one stores data in json_encode() format (i.e. multiple email addresses), and second one stores each as the new entry in another table (i. e. tags).

Ability to configure that new one can be added to dropdown lists via module config, would be great too. Something like button "Add" with modal window popping out, that has "Create" form inside with one button "Save", that saves and closes modal, then adds it to mentioned dropdown list, and activates it.

Possibility to drag’n’drop sort while in list view, would be great too!

I will try to code those in time given to me, but it would be great, if such function would be included in YCM. :)

And one bug report. When database field type is text, YCM detects it and in editor shows it as wysiwyg widget, bet that in turn causes error in YcmModule.php (line 273). Because attributeWidgets method in YcmModule.php (line 564) in YcmModule.php can return null, array_slice can fail. The solution is either to change attributeWidgets output to return array in any case. Otherwise, it can be solved by adding to model attributeWidgets that db field and add wysiwyg widged to it.

Regards,

Deele

I’ll try to add proper documentation later.

For tags, you could use https://github.com/yiiext/taggable-behavior and chosenMultiple.

I also use https://github.com/yiiext/status-behavior quite often.

But then all models should have order field of some sort, right?

Fixed. Thanks for noticing that one :)

I need to learn behaviors a bit more, newbie to yii, was not able to test them string away.

I will look forward to learn those resources, thanks!

Not all models, but the ones configured to have. I guess, there should be some adminSearch/TbGridView option, that would add hidden column/field with ordering number, that is passed via ajax, to server, that stores change of order. Like in jquery ui sortable, it should feel good, to do sort. :)

What would you suggest to do, if I want to deploy some sort of easy interface for client, to manage different entries from different/single model in one page. Like configuration page, with different values, positioned in some containers. Is there any faster way to handle data saving, than coding everything by hand? If I will give this model/table view for clients, they will shoot me in the arm :D

Is there a way to rearrange columns in list, and fields in create?

To modify the order in form, just change the order in attributeWidgets(). You can also hide fields by removing them from attributeWidgets().

In list view, just add, change order or remove items from adminSearch().

I just added proper support for taggable behavior to the development version of ycm.

Download it from https://github.com/janisto/yii-ycm/

Download https://github.com/yiiext/taggable-behavior/ to extensions folder.

To test the feature, use this SQL:




CREATE TABLE `work`

(

  `id` INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,

  `title` VARCHAR(128),

  `content` TEXT

) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;


CREATE TABLE `tag`

(

  `id` INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,

  `name` VARCHAR(255) NOT NULL,

  `count` INTEGER NOT NULL DEFAULT '0',

  UNIQUE KEY `tag_name` (`name`)

) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;


CREATE TABLE `work_tag`

(

  `work_id` INTEGER NOT NULL,

  `tag_id` INTEGER NOT NULL,

  PRIMARY KEY (`work_id`,`tag_id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;



Then add Work model:





<?php


/**

 * This is the model class for table "work".

 *

 * The followings are the available columns in table 'work':

 * @property integer $id

 * @property string $title

 * @property string $content

 */

class Work extends CActiveRecord

{

	/**

	 * Behaviors.

	 * @return array

	 */

	function behaviors() {

		return array(

			'tags' => array(

				'class' => 'ext.taggable.ETaggableBehavior',

				// Table where tags are stored

				'tagTable' => 'tag',

				// Tag table PK field

				'tagTablePk' => 'id',

				// Tag name field

				'tagTableName' => 'name',

				// Tag counter field. If null (default) does not write tag counts to DB.

				'tagTableCount' => 'count',

				// Cross-table that stores tag-model connections. By default it's your_model_tableTag.

				'tagBindingTable' => 'work_tag',

				// Tag binding table tag ID

				'tagBindingTableTagId' => 'tag_id',

				// Foreign key in cross-table. By default it's your_model_tableId.

				'modelTableFk' => 'work_id',

			),

		);

	}


	/**

	 * Returns the static model of the specified AR class.

	 * @param string $className active record class name.

	 * @return Work the static model class

	 */

	public static function model($className=__CLASS__)

	{

		return parent::model($className);

	}


	/**

	 * @return string the associated database table name

	 */

	public function tableName()

	{

		return 'work';

	}


	/**

	 * @return array validation rules for model attributes.

	 */

	public function rules()

	{

		// NOTE: you should only define rules for those attributes that

		// will receive user inputs.

		return array(

			array('title', 'length', 'max'=>128),

			array('content', 'safe'),

			// The following rule is used by search().

			// Please remove those attributes that should not be searched.

			array('id, title, content', 'safe', 'on'=>'search'),

		);

	}


	/**

	 * @return array customized attribute labels (name=>label)

	 */

	public function attributeLabels()

	{

		return array(

			'id' => 'ID',

			'title' => 'Title',

			'content' => 'Content',

			'tags' => 'Tags',

		);

	}


	/**

	 * Retrieves a list of models based on the current search/filter conditions.

	 * @return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.

	 */

	public function search()

	{

		// Warning: Please modify the following code to remove attributes that

		// should not be searched.


		$criteria=new CDbCriteria;


		$criteria->compare('id',$this->id);

		$criteria->compare('title',$this->title,true);

		$criteria->compare('content',$this->content,true);


		return new CActiveDataProvider($this, array(

			'criteria'=>$criteria,

		));

	}


	/**

	 * Config for attribute widgets (ycm module)

	 *

	 * @return array

	 */

	public function attributeWidgets()

	{

		return array(

			array('tags','taggable'),

		);

	}


	/**

	 * Config for TbGridView class (ycm module)

	 *

	 * @return array

	 */

	public function adminSearch()

	{

		return array(

			'columns'=>array(

				'id',

				'title',

			),

		);

	}

}



And Tag model:





<?php


/**

 * This is the model class for table "tag".

 *

 * The followings are the available columns in table 'tag':

 * @property integer $id

 * @property string $name

 * @property integer $count

 */

class Tag extends CActiveRecord

{

	/**

	 * Returns the static model of the specified AR class.

	 * @param string $className active record class name.

	 * @return Tag the static model class

	 */

	public static function model($className=__CLASS__)

	{

		return parent::model($className);

	}


	/**

	 * @return string the associated database table name

	 */

	public function tableName()

	{

		return 'tag';

	}


	/**

	 * @return array validation rules for model attributes.

	 */

	public function rules()

	{

		// NOTE: you should only define rules for those attributes that

		// will receive user inputs.

		return array(

			array('name', 'required'),

			array('count', 'numerical', 'integerOnly'=>true),

			array('name', 'length', 'max'=>255),

			// The following rule is used by search().

			// Please remove those attributes that should not be searched.

			array('id, name, count', 'safe', 'on'=>'search'),

		);

	}


	/**

	 * @return array customized attribute labels (name=>label)

	 */

	public function attributeLabels()

	{

		return array(

			'id' => 'ID',

			'name' => 'Name',

			'count' => 'Count',

		);

	}


	/**

	 * Retrieves a list of models based on the current search/filter conditions.

	 * @return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.

	 */

	public function search()

	{

		// Warning: Please modify the following code to remove attributes that

		// should not be searched.


		$criteria=new CDbCriteria;


		$criteria->compare('id',$this->id);

		$criteria->compare('name',$this->name,true);

		$criteria->compare('count',$this->count);


		return new CActiveDataProvider($this, array(

			'criteria'=>$criteria,

		));

	}


	/**

	 * Config for TbGridView class (ycm module)

	 *

	 * @return array

	 */

	public function adminSearch()

	{

		return array(

			'columns'=>array(

				'id',

				'name',

				'count',

			),

		);

	}

}



Let me know if this feature suits your needs.

Another bug. I have an "Image" model (name, caption, url (required, image), thumbnail_url (image), category_id (required, dropdown)). When I edit existing entry, to change, for example, name of image, with no "new" images selected, and saving afterwards, it throws an error, saying that "Image" (url) is required, and no more "Preview" buttons avilable, even thou, that field is not empty in database.

That is because input of type file, can’t have a value pre-set. You should create special case for file/image types of fields/widgets, so they would obey “required” flag, and would not overwrite file name in database, if nothing is selected and in addition, there should be “delete file/image” togglable button (checkbox or something fancier, like button with trash icon), right next to field, so user could set that field to empty, only when needed, that would delete local file from server.

Before I start working with tags, I need to find a way to automatically resize to some specific bounds, and genereate thumbnail(-s) if it is required by config. Because right now, I’m requesting thumbnail from user. I have pretty extensive class created for another project, that does all of these jobs, and even allows to overlay images and set up watermarks, but I don’t know for now, where to put that code, where that upload process is processed, where I need to put hooks inside. It would be great, if that could be configured via attributeWidgets().

Thanks for your feedback janisto, I really appreciate such authors :wub:

EDIT: I guess, I just found to solutions for problem that I posted as a bug. That was lack of documentation in fault. There was a need to add couple of additional rules for attributes that receive user inputs.


array('url', 'length', 'max'=>255),

array('url', 'unsafe'),

array('url', 'file', 'on'=>'insert', 'allowEmpty'=>true, 'types'=>'jpg,jpeg,gif,png', 'maxSize'=>1024*1024*6),

array('url', 'file', 'on'=>'update', 'allowEmpty'=>true, 'types'=>'jpg,jpeg,gif,png', 'maxSize'=>1024*1024*6),

Even thou, "Delete attached file" option is required.

No, that doesn’t work, and removing them from attributeWidgets(), doesn’t work either. It automatically displays field during update, if it exists within model.

In addition, I noticed, that wysiwyg editor is messing up HTML code during display of update, that I enter in html code view. It adds many "<p></p>" in places, where they are not needed.

Uups. I created a bug while fixing another. Now you can do this in the development version:




	public function attributeWidgets()

	{

		return array(

			array('fieldName','hide'),

		);

	}



See my latest commit: https://github.com/janisto/yii-ycm/commit/dd8e3831c93a57450cbedc5b6677a88620b74231

Then it’s a bug in Redactor js. For me it’s working ok.

Argh. My bad again. You should remove items or change the order in attributeLabels() :)

From my point of view, that is wrong. Labels has nothing to do with display of update/new item.

Given solution with specific field type inside attributeWidgets() is much better, it isnt invading Yii structure.

The next question is about ability to use bootstrap’s field attributes: “placeholder”, “disabled” and “required”.

And another problem I noticed just now: pager links are broken. It is showing "http://mydomain/ycm/model/list/ycm%2Fmodel%2Flist%2Fname%2FArticle//name/Article/Article_page/2" while inside "http://mydomain/ycm/model/list/name/Article". Dunno where to start looking for problem…

EDIT: In reponse to clicking on pager page with mentioned url, there is an error, that ModelController in line 130 received an empty string from $_GET[get_class($model)], that can’t be iterated with foreach. If I add “&& !empty($_GET[get_class($model)])”, it still doesn’t work, it returns partial render of that table in response, but client side JS/Ajax can’t handle it.

EDIT2: Pager and column header links broken. Only edit/delete and filter fields usable.

Checkout the development version: https://github.com/janisto/yii-ycm/

Now you can override options in all form widgets.

For example:




	public function attributeWidgets()

	{

		return array(

			array('fieldName','textField','class'=>'span6','placeholder'=>'Type something…','hint'=>'Lorem Ipsum','disabled'=>'disabled'),


		);

	}



If you want a required field, then you must define that in the rules:




	public function rules()

	{

		// NOTE: you should only define rules for those attributes that

		// will receive user inputs.

		return array(

			array('fieldName', 'required'),

		);

	}



"image" and "file" type fields must be defined "unsafe" in the rules. Then update should work properly.