We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

How can I access related attributes for a user by the attribute name?

Hi guys I'm new to phalcon, loving it so far, but just having an issue getting information I need in volt.

If you could help out that would be great, I've posted a question in detail on Stackoverflow.

https://stackoverflow.com/questions/24713954/getting-related-user-attributes-in-phalcon

Thanks in advance



98.9k
edited Jul '14

The relationship is called UsersAttributes so instead of:

{{ user.userAttributes.profileImage }}

you have to use:

{{ user.usersAttributes.profileImage }}

@Phalcon still getting an undefined property error...

In my controller for example if I dump the following:

    var_dump($user->usersAttributes->toArray());

I get:

array (size=3)
    0 => 
        array (size=4)
        'id' => string '1' (length=1)
        'userId' => string '1' (length=1)
        'attributeId' => string '1' (length=1)
        'attributeValue' => string '/profile/83/jocelyn.jpg' (length=23)

If I do

var_dump($user->attributes->toArray());

If get:

    array (size=3)
        0 => 
         array (size=3)
            'id' => string '1' (length=1)
            'name' => string 'profileImage' (length=12)
            'defaultValue' => string '/profile/placeholder.jpg' (length=24)

So I can do {{ user.attributes.profileImage }} but I get undefined property exception but If i do say {{ user.attributes.name }} I get "profileImage" returned which isn't exactly what I want, question is I guess, am i missing something and shoudl the attribute anem get mapped to the value in the usersAttributes or do I have to get the value another way by say manually mapping them and setting a view property?



6.2k
edited Jul '14

@andrefigueira

What I can see is that in Users model in method initialize you have got

$this->hasMany('id', 'UsersAttributes', 'userId');
$this->hasManyToMany(
        'id',
        'UsersAttributes',
        'userId', 'attributeId',
        'Attributes',
        'id'
);

so you actually defining relation for UsersAttributes twice. Firstly think which relation you want to use, if you want to have One To Many you should got just hasMany(), if you want to have Many To Many you should got hasManyToMany()...not both together on the same table and field.

I've tried removing the first one but still doesn't map the key of the attribute to the related value.



98.9k

When you use $this->hasMany('id', 'UsersAttributes', 'userId'); you're defining a 1-n relationship, it means by accessing user.usersAttributes you're accessing one or more user's attributes, so you can't directly access "profileImage" there:

{{ for attribute in user.usersAttributes }}
 {{ attribute.profileImage }}
{{ endfor }}


12.6k
Accepted
answer

Understood, thanks very much for the clarification, what I've ended up doing is within the Users model is create a specific mapper method and do an afterFetch to append the attributes to the user result, would this be ok? It does work, just wondering if not a cleaner way to do it.

public static function fetchUserAttributes($userId)
{

    $modelsManager = Phalcon\DI::getDefault()->getModelsManager();

    $phql = '
    SELECT name, attributeValue
    FROM Attributes
    LEFT JOIN UsersAttributes
    ON UsersAttributes.userId = :userId:
    AND Attributes.id = UsersAttributes.attributeId
    ';

    $rows = $modelsManager->executeQuery($phql, array('userId' => $userId));

    $attributesObj = new \stdClass();

    foreach($rows as $row)
    {

        $attributesObj->{$row['name']} = $row['attributeValue'];

    }

    return $attributesObj;

}

public function afterFetch()
{

    //Attach user attributes
    $this->attributes = Users::fetchUserAttributes($this->id);

}