Вход Регистрация
Файл: silawar.ru/protected/extensions/CAdvancedArBehavior/CAdvancedArBehavior.php
Строк: 295
<?php
/**
 * CAdvancedArBehavior class file.
 *
 * @author Herbert Maschke <thyseus@gmail.com>
 * @link http://www.yiiframework.com/
 * @version 0.3
 */

/* The CAdvancedArBehavior extension adds up some functionality to the default
 * possibilites of yii´s ActiveRecord implementation.
 *
 * To use this extension, just copy this file to your extensions/ directory,
 * add 'import' => 'application.extensions.CAdvancedArBehavior', [...] to your 
 * config/main.php and add this behavior to each model you would like to
 * inherit the new possibilities:
 *
 * public function behaviors(){
 *         return array( 'CAdvancedArBehavior' => array(
 *             'class' => 'application.extensions.CAdvancedArBehavior')); 
 *         }                                  
 *
 *
 * Automatically sync your Database Schema when setting new fields by
 * activating $syncdb
 *
 * Better support of MANY_TO_MANY relations:
 *
 * When we have defined a MANY_MANY relation in our relations() function, we
 * are now able to add up instances of the foreign Model on the fly while
 * saving our Model to the Database. Let´s assume the following Relation:
 *
 * Post has:
 *  'categories'=>array(self::MANY_MANY, 'Category',
 *                  'tbl_post_category(post_id, category_id)')
 *
 * Category has:
 * 'posts'=>array(self::MANY_MANY, 'Post',
 *                  'tbl_post_category(category_id, post_id)')
 *
 * Now we can use the attribute 'categories' of our Post model to add up new
 * rows to our MANY_MANY connection Table:
 *
 * $post = new Post();
 * $post->categories = Category::model()->findAll();
 * $post->save();
 *
 * This will save our new Post in the table Post, and in addition to this it
 * updates our N:M-Table with every Category available in the Database.
 * 
 * We can further limit the Objects given to the attribute, and can also go 
 * the other Way around:
 *
 * $category = new Category();
 * $category->posts = array(5, 6, 7, 10);
 * $caregory->save(); 
 *
 * We can pass Object instances like in the first example, or a list of
 * integers that representates the Primary key of the Foreign Table, so that
 * the Posts with the id 5, 6, 7 and 10 get´s added up to our new Category.
 *
 * 5 Queries will be performed here, one for the Category-Model and four for
 * the N:M-Table tbl_post_category. Note that this behavior could be tuned
 * further in the future, so only one query get´s executed for the MANY_MANY
 * Table.
 *
 * We can also pass a _single_ object or an single integer:
 *
 * $category = new Category();
 * $category->posts = Post::model()->findByPk(12);
 * $category->posts = 12;
 * $category->save();
 * 
 * Assign -1 to a attribute to let it be untouched by the behavior.
 */


class CAdvancedArbehavior extends CActiveRecordBehavior
{
    
// Set this to false to disable tracing of changes
    
public $trace true;

    
// If you want to ignore some relations, set them here.
    
public $ignoreRelations = array();

    
// After the save process of the model this behavior is attached to 
    // is finished, we begin saving our MANY_MANY related data 
    
public function afterSave($event
    {
        if(!
is_array($this->ignoreRelations))
            throw new 
CException('ignoreRelations of CAdvancedArBehavior needs to be an array');

        
$this->writeManyManyTables();
        return 
parent::afterSave($event);

    }

    protected function 
writeManyManyTables() 
    {
        if(
$this->trace)
            
Yii::trace('writing MANY_MANY data for '.get_class($this->owner),
                    
'system.db.ar.CActiveRecord');

        foreach(
$this->getRelations() as $relation
        {
            
$this->cleanRelation($relation);
            
$this->writeRelation($relation);
        }
    }

    
/* A relation will have the following format:
     $relation['m2mTable'] = the tablename of the foreign object
     $relation['m2mThisField'] = the column in the many2many table that represents the primary Key of the object that this behavior is attached to
     $relation['m2mForeignField'] = the column in the many2many table that represents the foreign object. 

  Written in Yii relation syntax, it would be like this
        'relationname' => array('foreignobject', 'column', 'm2mTable(m2mThisField, m2mForeignField) */
    
protected function getRelations()
    {
        
$relations = array();

        foreach (
$this->owner->relations() as $key => $relation
        {
            if (
$relation[0] == CActiveRecord::MANY_MANY && 
                    !
in_array($key$this->ignoreRelations) &&
                    
$this->owner->hasRelated($key) && 
                    
$this->owner->$key != -1)
            {
                
$info = array();
                
$info['key'] = $key;
                
$info['foreignTable'] = $relation[1];

                    if (
preg_match('/^(.+)((.+)s*,s*(.+))$/s'$relation[2], $pocks)) 
                    {
                        
$info['m2mTable'] = $pocks[1];
                        
$info['m2mThisField'] = $pocks[2];
                        
$info['m2mForeignField'] = $pocks[3];
                    }
                    else 
                    {
                        
$info['m2mTable'] = $relation[2];
                        
$info['m2mThisField'] = $this->owner->tableSchema->PrimaryKey;
                        
$info['m2mForeignField'] = CActiveRecord::model($relation[1])->tableSchema->primaryKey;
                    }
                
$relations[$key] = $info;
            }
        }
        return 
$relations;
    }

    
/** writeRelation's job is to check if the user has given an array or an 
     * single Object, and executes the needed query */
    
protected function writeRelation($relation
    {
        
$key $relation['key'];

        
// Only an object or primary key id is given
        
if(!is_array($this->owner->$key) && $this->owner->$key != array())         
            
$this->owner->$key = array($this->owner->$key);

        
// An array of objects is given
        
foreach((array)$this->owner->$key as $foreignobject)
        {
            if(empty(
$foreignobject)) continue; // если выбрали пустое поле - не пишем
            
if(!is_numeric($foreignobject) && is_object($foreignobject))
                
$foreignobject $foreignobject->{$foreignobject->$relation['m2mForeignField']};
            
$this->execute(
                    
$this->makeManyManyInsertCommand($relation$foreignobject));
        }
    }

    
/* before saving our relation data, we need to clean up exsting relations so
     * they are synchronized */
    
protected function cleanRelation($relation)
    {
        
$this->execute($this->makeManyManyDeleteCommand($relation));    
    }

    
// A wrapper function for execution of SQL queries
    
public function execute($query) {
        return 
Yii::app()->db->createCommand($query)->execute();
    }

    public function 
makeManyManyInsertCommand($relation$value) {
        return 
sprintf("insert into %s (%s, %s) values ('%s', '%s')",
                
$relation['m2mTable'],
                
$relation['m2mThisField'],
                
$relation['m2mForeignField'],
                
$this->owner->{$this->owner->tableSchema->primaryKey},
                
$value);
    }

    public function 
makeManyManyDeleteCommand($relation) {
        return 
sprintf("delete ignore from %s where %s = '%s'",
                
$relation['m2mTable'],
                
$relation['m2mThisField'],
                
$this->owner->{$this->owner->tableSchema->primaryKey}
                );
    }
}
Онлайн: 1
Реклама