Dynamic Yii Table Controller/modell

Hey,

i have to create the following Application:

A CRUD Design to dynamically create a whole Table / Controller Model. So that i can create a Profile with dynamic Fields ( For Example Name, Surname, Telephone etc) and on another Copy of the Application i also want to have the field Telefax or other Stuff).

I Already have written a controller and Model for that, so on each change, this change will also be applied to the linked table.

Now my question is how to generate the Controller & Modell (All CRUD options) to read each field from the Database Table or from the describing table.

Cheers

Lugaru

I might suggest looking at how Gii or Giix generate CRUD and Models.

I have done such a thing in my application.

I have a ‘User’ table (actually more than a User table) in which each user has ‘Properties’.

These properties are for most of them in a ‘Properties’ table.

The User model has overloaded ‘__get’ and ‘__set’ methods to automatically get these properties from the properties table. The rest of the application does not even have to know that these properties are in another table.

I had to move one of the properties from the property table to the User table for performance reasons (the name of the user) - with a migration that change went pretty smooth.

There is some complexity in writing this up because one has to cope with new properties for an existing record or for a new record and only save them when the User is saved to make the object and its properties look as a single object.

Hey le top,

sounds interesting. Could you maybe post a bit of code or send me some code per PM? i would really appreciate that!

thanks!

Ok, I’ll share some of the code. There are still some print instructions in branches that should never be reached, which is not a priority to improve in my project.

The class defines a relation ‘properties’ representing the properties. It is prefixed with '’ because it is intended to be used internally only.

This will give you an idea of what has to be done.




class Entity extends CActiveRecord {

  // ...


    /* (non-PHPdoc)

     * @see CActiveRecord::__get()

    *

    * Extend getter to retrieve generic properties for the entity.

    */

    public function __get($name) {

        if(!parent::__isset($name)) {

            return $this->getProperty($name);

        }

        // Default case:

        return parent::__get($name);

    }


    public function __set($name,$value) {

        try {

            parent::__set($name, $value);

        } catch(Exception $e) {

            $this->setProperty($name, $value);

        }

    }







    /**

     * Scope to limit selection to entities that have the given property.

     * @param string $property

     * @return Entity

     */

    public function property($property) {

        $this->getDbCriteria()->compare('_properties.property_identifier',$property);

        return $this;

    }




    /**

     * Scope to constrain the entity to have a specific property value.

     *

     * @param string $property

     * @param string $value

     */

    public function property_equals($property,$value) {

        $relationAlias=$this->aliasId();

        $this->getDbCriteria()->mergeWith(

                array(

                        'with'=>array(

                                '_properties'=>array(

                                        'alias'=>$relationAlias,

                                        'condition'=>"`$relationAlias`.`property_identifier`=:property and `$relationAlias`.`property_value`=:value",

                                        'params'=>array(':property'=>$property, ':value'=>$value),

                                ),

                        ),

                )

        );

        return $this;

    }




    private $propertiesToSet=array();

    private $propertiesType=array();


    /**

     * Gets a property for the Entity.

     *

     * Looks for the given property amongst available properties (usually from EntityProperties).

     *

     * @param string $property

    */

    public function getProperty($property) {

        if(array_key_exists($property, $this->propertiesToSet)) {

            return $this->propertiesToSet[$property];

        } else {

            $props=parent::__get('properties');

            if(array_key_exists($property, $props)) {

                return $this->properties[$property]->property_value;

            } else {

                return null;

            }

        }

    }




    /**

     * Set an entity property.

     * @param string $property

     * @param mixed $value

     * @param integer $type  The type of the property {@link EntityProperties::TYPE_STRING}

     */

    public function setProperty($property,$value,$type=EntityProperties::TYPE_STRING) {

        if($this->isNewRecord) {

   	        $this->propertiesType[$property]=$type;

   	        $this->propertiesToSet[$property]=$value;

        } else {

            $param=self::PARAM_PREFIX.self::$paramCount++;

            $alias=self::TBL_PREFIX.self::$paramCount++;

            $found=array();

            if($this->hasRelated('properties')) {

                foreach($this->properties as $p) {

                    if($p->property_identifier===$property) {

                        $found[] = $p;

                        break;

                    }

                }

            } else {

                $found=$this->properties(

                        array(

                                'alias'=>$alias,

                                'condition'=>"`$alias`.`property_identifier`=$param",

                                'params'=>array($param=>$property),

                                'joinType'=>'INNER JOIN', // Links through entity_property_link which is left outer join.

                        ));

            }

            if(empty($found)) {

                $this->addNewProperty($property,$value,$type,$this->isAttributeSafe($property));

            } else {

                foreach($found as /* @var $p EntityProperties */ $p) {

                    $p->property_value = $value;

                    if(!$p->save()) {

                        print "Saving $property $value failed";

                        print CHtml::errorSummary($p);

                    }

                }

            }

        }

        return $value;

    }




    /**

     * (non-PHPdoc)

     * @see CActiveRecord::save()

     */

    public function save($runValidation=true,$attributes=null) {

        $this->getAttributes(array('is_active'));

        if($result=parent::save($runValidation, $attributes)) {

[size=2]            if(!empty($this->properties)) {[/size]

                $result_i=true;

                foreach($this->properties as $p) {

                    $result_i&=$p->save();

                    if(!$result_i) {

                        $this->addErrors($p->getErrors());

                    }

                    $result&=$result_i;

                }

            }

            //print $result?"ok":"nok";

            if(!empty($this->propertiesToSet)) {

                $lresult=true;

                foreach($this->propertiesToSet as $property=>$value) {

                    $result&=$this->addNewProperty($property,$value,$this->propertiesType[$property],true);

                }

                if($lresult) {

                    $this->propertiesToSet = array();

                    $this->propertiesType = array();

                }

                $result&=$lresult;

            }

            //print $result?"ok":"nok";

        } else {

            echo Yii::trace("Skip1:".CVarDumper::dumpAsString($this),'vardump');

        }

        return $result;

    }