User Properties

Hi

I am trying to implement user properties and make them flexible and easy to modify.

I have 3 tables and corresponding ActiveRecords:

Property (the one with property definitions)

(name, caption, constrained, multiple)

For example:


aboutMe	            About me	        0	0

country	            Country	        1	0

accessGroup	    Access Groups	1	1

PropertyValue (available property values)

( propertyId, value, caption)

For example:


3	1	USA

3	2	Barbados

4	1	First group

4	2	Second group

And the mapping table UserProperty:

( userId, propertyId, value)


1	1	About me value

1	3	3

1	4	["1","3"]

I want to pass an array of UserProperty models to the view along with User model and render it.

If properties is already in the table it is easy to do with relations:

In User class:


    /**

     * @return \yii\db\ActiveQuery

     */

    public function getUserProperty()

    {

        return $this->hasMany(UserProperty::className(), ['userId' => 'id'])

            ->indexBy('id')

            ->inverseOf('user');

    }

But is there a way to create a list of empty UserProperties if it is not set yet?

In other words i want UserProperty model to be created for every Property available.

Some stuff to get you started.


    private $propertiesToSet=array();


    /**

     * Gets a property for the Entity.

     *

     * Looks for the given property amongst available properties.

     *

     * @param string $property

     */

    public function getProperty($property,$defaultValue=null) {

        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 $defaultValue;

            }

        }

    }




// In save() there is some code like this:

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

	//...

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

                $lresult=true;

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

		    // addNewProperty creates a new property instance and links it, with DB operations.

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

                }

                if($lresult) {

                    $this->propertiesToSet = array();

                }

                $result&=$lresult;

            }

	//...


// And I also have a scope


    public function property_equals($property,$value) {

        $relationAlias=$this->aliasId();

        $property_iden=$this->getDbConnection()->getSchema()->quoteColumnName("$relationAlias.property_identifier");

        $property_value=$this->getDbConnection()->getSchema()->quoteColumnName("$relationAlias.property_value");


        $this->getDbCriteria()->mergeWith(

                array(

                        'with'=>array(

                                '_properties'=>array(

                                        'select'=>array(),

                                        'alias'=>$relationAlias,

                                        'condition'=>"$property_iden=\"$property\" and $property_value=:value",

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

                                ),

                        ),

                )

        );

        return $this;

    }


// ... plus other methods that are too complex to share ...// Anyway, this should give you some ideas.

Thank you!

I want to pass an array of UserProperty models to the view along with User model and render it.

If properties is already in the table it is easy to do with relations: