Tools (a behavior and a console command) to track and store validation progress as well as proofreading and approval progress on a field-by-field basis. Created for content management systems to aid tracking completion progress of publishing workflows such as creation, draft, review, approval, proofreading, translation etc.
- Automatically sets the current item status (such as Temporary, Draft, Reviewable and Publishable) based on validation rules
- Supplies a convenient place to store the current overall status as well as approval and proofreading flags for attributes that are part of the content creation process
- Methods to calculate and read the current validation, approval and proofreading progress
- Stores the current progress of any validation scenarios, so that content items can be listed/filtered based on how close/far to completion they are
- Leverages Yii validation logic as the fundamental method of validating the fields
- Leverages Gii code generation to provide CRUD operations to set and change flags
- Console command automatically creates migrations for the necessary database changes
- (Optional) Leverages Yii extension i18n-columns to provide individual quality assurance states for each translation language
- Yii 1.1 or above
- Use of Yii console
- Use of Gii (preferably Gtc) and/or giic
- MySQL 5.1.10+, SQL Server 2012 or similarly recent database (For the console command. The behavior itself works with any Yii-supported database)
Ensure that you have the following in your composer.json:
"repositories":[
{
"type": "vcs",
"url": "https://github.com/neam/yii-qa-state"
},
...
],
"require":{
"neam/yii-qa-state":"dev-develop",
...
},
Then install through composer:
php composer.php update neam/yii-qa-state
If you don't use composer, clone or download this project into /path/to/your/app/vendor/neam/yii-qa-state
'aliases' => array(
...
'vendor' => dirname(__FILE__) . '/../../vendor',
'qa-state' => 'vendor.neam.yii-qa-state',
...
),
'import' => array(
...
'qa-state.behaviors.QaStateBehavior',
...
),
'commandMap' => array(
...
'qa-state' => array(
'class' => 'qa-state.commands.QaStateCommand',
),
...
),
1. Set up validation rules in your model, stating what fields are required for draft, reviewable and publishable scenarios.
Example:
// Chapter.php
class Chapter extends BaseChapter
{
...
public function rules()
{
return array_merge(
parent::rules(), array(
array('title, slug', 'required', 'on' => 'draft,reviewable,publishable'),
array('thumbnail, about, video, teachers_guide, exercises, snapshots, credits', 'required', 'on' => 'publishable'),
)
);
}
...
}
This example only uses the validation rule "required", but of course any validation rules can be used. The attributes can be ordinary model attributes, relations or virtual attributes that use custom validation rules etc. The important part is that they are applied on the scenarios that the behavior is configured to use (default: draft,reviewable,publishable).
public function behaviors()
{
return array(
'qa-state' => array(
'class' => 'QaStateBehavior',
'scenarios' => array(
'draft',
'reviewable',
'publishable',
/* Example: tracking translation progress through language-specific validation scenarios - add the scenarios through configuration:
'translate_into_es',
'translate_into_de',
'translate_into_fr',
'translate_into_sv',
*/
),
'manualFlags' => array(
'allow_review',
'allow_publish'
),
),
);
}
./yiic qa-state process
Run with --verbose
to see more details.
./yiic migrate
This will add the relevant tables, relations and fields to be able to track the qa state of the configured models.
The schema has this general structure:
{table}_qa_state
id
foreach scenario: {scenario}_validation_progress
approval_progress
proofing_progress
foreach manualFlag: {manualFlag}
foreach attribute: {attribute}_approved - boolean (with null)
foreach attribute: {attribute}_proofed - boolean (with null)
created
modified
Each progress field are integers between 0 and 100, reflecting percentage of total progress. Total progress is measured as all attributes under validation either validates, are approved, proofread or translated respectively.
Sample migration file:
<?php
class m131017_120644_qa_attributes extends CDbMigration
{
public function up()
{
$this->createTable('chapter_qa_state', array(
'id' => 'BIGINT NOT NULL AUTO_INCREMENT',
'PRIMARY KEY (`id`)',
));
$this->addColumn('chapter', 'chapter_qa_state_id', 'BIGINT NULL');
$this->addForeignKey('chapter_qa_state_id_fk', 'chapter', 'chapter_qa_state_id', 'chapter_qa_state', 'id', 'SET NULL', 'SET NULL');
$this->addColumn('chapter_qa_state', 'status', 'VARCHAR(255) NULL');
$this->addColumn('chapter_qa_state', 'draft_validation_progress', 'BOOLEAN NULL');
$this->addColumn('chapter_qa_state', 'reviewable_validation_progress', 'BOOLEAN NULL');
$this->addColumn('chapter_qa_state', 'publishable_validation_progress', 'BOOLEAN NULL');
$this->addColumn('chapter_qa_state', 'approval_progress', 'INT NULL');
$this->addColumn('chapter_qa_state', 'proofing_progress', 'INT NULL');
$this->addColumn('chapter_qa_state', 'allow_review', 'BOOLEAN NULL');
$this->addColumn('chapter_qa_state', 'allow_publish', 'BOOLEAN NULL');
$this->addColumn('chapter_qa_state', 'title_approved', 'BOOLEAN NULL');
$this->addColumn('chapter_qa_state', 'slug_approved', 'BOOLEAN NULL');
$this->addColumn('chapter_qa_state', 'thumbnail_approved', 'BOOLEAN NULL');
$this->addColumn('chapter_qa_state', 'about_approved', 'BOOLEAN NULL');
$this->addColumn('chapter_qa_state', 'video_approved', 'BOOLEAN NULL');
$this->addColumn('chapter_qa_state', 'teachers_guide_approved', 'BOOLEAN NULL');
$this->addColumn('chapter_qa_state', 'exercises_approved', 'BOOLEAN NULL');
$this->addColumn('chapter_qa_state', 'snapshots_approved', 'BOOLEAN NULL');
$this->addColumn('chapter_qa_state', 'credits_approved', 'BOOLEAN NULL');
$this->addColumn('chapter_qa_state', 'title_proofed', 'BOOLEAN NULL');
$this->addColumn('chapter_qa_state', 'slug_proofed', 'BOOLEAN NULL');
$this->addColumn('chapter_qa_state', 'thumbnail_proofed', 'BOOLEAN NULL');
$this->addColumn('chapter_qa_state', 'about_proofed', 'BOOLEAN NULL');
$this->addColumn('chapter_qa_state', 'video_proofed', 'BOOLEAN NULL');
$this->addColumn('chapter_qa_state', 'teachers_guide_proofed', 'BOOLEAN NULL');
$this->addColumn('chapter_qa_state', 'exercises_proofed', 'BOOLEAN NULL');
$this->addColumn('chapter_qa_state', 'snapshots_proofed', 'BOOLEAN NULL');
$this->addColumn('chapter_qa_state', 'credits_proofed', 'BOOLEAN NULL');
// {...example file shortened...}
$this->createTable('video_file_qa_state', array(
'id' => 'BIGINT NOT NULL AUTO_INCREMENT',
'PRIMARY KEY (`id`)',
));
$this->addColumn('video_file', 'video_file_qa_state_id', 'BIGINT NULL');
$this->addForeignKey('video_file_qa_state_id_fk', 'video_file', 'video_file_qa_state_id', 'video_file_qa_state', 'id', 'SET NULL', 'SET NULL');
$this->addColumn('video_file_qa_state', 'status', 'VARCHAR(255) NULL');
$this->addColumn('video_file_qa_state', 'draft_validation_progress', 'BOOLEAN NULL');
$this->addColumn('video_file_qa_state', 'reviewable_validation_progress', 'BOOLEAN NULL');
$this->addColumn('video_file_qa_state', 'publishable_validation_progress', 'BOOLEAN NULL');
$this->addColumn('video_file_qa_state', 'approval_progress', 'INT NULL');
$this->addColumn('video_file_qa_state', 'proofing_progress', 'INT NULL');
$this->addColumn('video_file_qa_state', 'allow_review', 'BOOLEAN NULL');
$this->addColumn('video_file_qa_state', 'allow_publish', 'BOOLEAN NULL');
$this->addColumn('video_file_qa_state', 'title_approved', 'BOOLEAN NULL');
$this->addColumn('video_file_qa_state', 'slug_approved', 'BOOLEAN NULL');
$this->addColumn('video_file_qa_state', 'clip_approved', 'BOOLEAN NULL');
$this->addColumn('video_file_qa_state', 'about_approved', 'BOOLEAN NULL');
$this->addColumn('video_file_qa_state', 'thumbnail_approved', 'BOOLEAN NULL');
$this->addColumn('video_file_qa_state', 'subtitles_approved', 'BOOLEAN NULL');
$this->addColumn('video_file_qa_state', 'title_proofed', 'BOOLEAN NULL');
$this->addColumn('video_file_qa_state', 'slug_proofed', 'BOOLEAN NULL');
$this->addColumn('video_file_qa_state', 'clip_proofed', 'BOOLEAN NULL');
$this->addColumn('video_file_qa_state', 'about_proofed', 'BOOLEAN NULL');
$this->addColumn('video_file_qa_state', 'thumbnail_proofed', 'BOOLEAN NULL');
$this->addColumn('video_file_qa_state', 'subtitles_proofed', 'BOOLEAN NULL');
}
public function down()
{
$this->dropForeignKey('chapter_qa_state_id_fk', 'chapter');
$this->dropColumn('chapter', 'chapter_qa_state_id');
$this->dropTable('chapter_qa_state');
$this->dropColumn('chapter_qa_state', 'status');
$this->dropColumn('chapter_qa_state', 'draft_validation_progress');
$this->dropColumn('chapter_qa_state', 'reviewable_validation_progress');
$this->dropColumn('chapter_qa_state', 'publishable_validation_progress');
$this->dropColumn('chapter_qa_state', 'approval_progress');
$this->dropColumn('chapter_qa_state', 'proofing_progress');
$this->dropColumn('chapter_qa_state', 'allow_review');
$this->dropColumn('chapter_qa_state', 'allow_publish');
$this->dropColumn('chapter_qa_state', 'title_approved');
$this->dropColumn('chapter_qa_state', 'slug_approved');
$this->dropColumn('chapter_qa_state', 'thumbnail_approved');
$this->dropColumn('chapter_qa_state', 'about_approved');
$this->dropColumn('chapter_qa_state', 'video_approved');
$this->dropColumn('chapter_qa_state', 'teachers_guide_approved');
$this->dropColumn('chapter_qa_state', 'exercises_approved');
$this->dropColumn('chapter_qa_state', 'snapshots_approved');
$this->dropColumn('chapter_qa_state', 'credits_approved');
$this->dropColumn('chapter_qa_state', 'title_proofed');
$this->dropColumn('chapter_qa_state', 'slug_proofed');
$this->dropColumn('chapter_qa_state', 'thumbnail_proofed');
$this->dropColumn('chapter_qa_state', 'about_proofed');
$this->dropColumn('chapter_qa_state', 'video_proofed');
$this->dropColumn('chapter_qa_state', 'teachers_guide_proofed');
$this->dropColumn('chapter_qa_state', 'exercises_proofed');
$this->dropColumn('chapter_qa_state', 'snapshots_proofed');
$this->dropColumn('chapter_qa_state', 'credits_proofed');
// {...example file shortened...}
$this->dropForeignKey('video_file_qa_state_id_fk', 'video_file');
$this->dropColumn('video_file', 'video_file_qa_state_id');
$this->dropTable('video_file_qa_state');
$this->dropColumn('video_file_qa_state', 'status');
$this->dropColumn('video_file_qa_state', 'draft_validation_progress');
$this->dropColumn('video_file_qa_state', 'reviewable_validation_progress');
$this->dropColumn('video_file_qa_state', 'publishable_validation_progress');
$this->dropColumn('video_file_qa_state', 'approval_progress');
$this->dropColumn('video_file_qa_state', 'proofing_progress');
$this->dropColumn('video_file_qa_state', 'allow_review');
$this->dropColumn('video_file_qa_state', 'allow_publish');
$this->dropColumn('video_file_qa_state', 'title_approved');
$this->dropColumn('video_file_qa_state', 'slug_approved');
$this->dropColumn('video_file_qa_state', 'clip_approved');
$this->dropColumn('video_file_qa_state', 'about_approved');
$this->dropColumn('video_file_qa_state', 'thumbnail_approved');
$this->dropColumn('video_file_qa_state', 'subtitles_approved');
$this->dropColumn('video_file_qa_state', 'title_proofed');
$this->dropColumn('video_file_qa_state', 'slug_proofed');
$this->dropColumn('video_file_qa_state', 'clip_proofed');
$this->dropColumn('video_file_qa_state', 'about_proofed');
$this->dropColumn('video_file_qa_state', 'thumbnail_proofed');
$this->dropColumn('video_file_qa_state', 'subtitles_proofed');
}
}
Use Gii as per the official documentation. After this, you have a convenient place to store the approval and proofreading flags for attributes that are part of the content creation process.
The manual flags as well as the approval and proofreading flags are meant to be altered by relevant users/editors in your application. The behavior updates the total validation, approval and proofreading progress on afterSave.
- Initial release
- Automatically sets the current item status (such as Temporary, Draft, Reviewable and Publishable) based on validation rules
- Supplies a convenient place to store the approval and proofreading flags for attributes that are part of the content creation process
- Methods to calculate and read the current validation, approval and proofreading progress
- Transparent qa state records creation
- Leverages Yii validation logic as the fundamental method of validating the fields
- Leverages Gii code generation to provide CRUD operations to set and change flags
- Optional: Leverages Yii extension i18n-columns to provide individual quality assurance states for each translation language
- Console command automatically creates migrations for the necessary database changes
How do I update the schema after having updated my datamodel or the list of attributes that are part of the qa process?
- Generate the necessary schema migration using the command
./yiic qa-state process
- Apply the migration using
./yiic migrate
- Generate crud for the new schema
Before generating the crud you might want to remove any fields that are no longer configured to be part of the qa process. This is however optional since the behavior will only take into consideration the currently configured attributes. To help out with this task, the action resetAttributes can be used.
Instructions on how to reset and re-populate the attributes in the qa state tables:
- Run
./yiic qa-state process
- Apply the migration using
./yiic migrate
- Follow the steps 1-3 above