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

Many to many - one record exists

Hi,

I haven't been able to find a nicer way to do this yet and don't think i'm trying to do anything rediculous. My situation is that I have many users and many users can be linked to many objects and when viewing an object I would like to display certain objects if the link between them exists.

At the moment I have only been able to do it via the __get magic method like so:

<?php
$object->getUsers([
    'user_id = :user_id:'
    'bind' => [
        'user_id' => 1, //as an example
    ]
]);
$exists = $object->count() === 1;

Is there a nicer way to do this? Or at least get one record back instead of a record set?

Thanks, Gary

You shouldn't have to pass in those paramets to the magic method if your models are defined right.

$object->getUsers(); shoudl be plently. Or even better yet you coudl alias the relationshit then its not a method you just access them via the alias. $object->aliasUsers

that being said you are simply trying to determine if there exists a non 0 value?

count($object->aliasUsers) > 0 or i suppose $object->aliasUsers->count()

quick follow up..

you say you have a many to many relationship, but code

$object->getUsers([
    'user_id = :user_id:'
    'bind' => [
        'user_id' => 1, //as an example
    ]
]);

would by definition only ever return 1 record...

It is a many-to-many relationship with the following setup:

<?php
// User model
$this->hasManyToMany('id', 'ObjectUser', 'user_id', 'object_id', 'Object', 'id', [
    'alias' => 'objects',
]);

// Object model
$this->hasManyToMany('id', 'ObjectUser', 'object_id', 'user_id', 'User', 'id', [
    'alias' => 'users',
]);

// ObjectUser model
$this->belongsTo('object_id', 'Object', 'id', [
    'alias' => 'object',
]);
$this->belongsTo('user_id', 'User', 'id', [
    'alias' => 'user',
]);

So with that I can call:

<?php
$object->getUsers();

But that returns me all users as Phalcon\Mvc\Model\Resultset\Simple and count() can be greater than one. According to https://docs.phalcon.io/en/latest/reference/models.html#taking-advantage-of-relationships I can match on conditions:

<?php
// Or using bound parameters
$robotsParts = $robot->getRobotsParts(
  array(
    "created_at = :date:",
    "bind" => array(
        "date" => "2015-03-15"
    )
  )
);

But that still returns a result set and I am left with using count().

Gary

The other option I can think of is using an ACL, but not sure how to make it object specific. I guess I need to register the ACL as a shared service so I can make use of isAllowed() as at the moment it's within my security plugin.

edited Jun '16

I mean your implemenation works, but i would put it in the model method instead so you can call it form anywhere. Instantiating and ACL for this is super overkill.. and esentiall does the same exact thing but adds another play of unnecesarry complexity.

    public function canAccess($id){
        $ct = $this->getUsers([
        'conditions' => 'user_id = :user_id:',
        'bind' => [
            'user_id' => $id ]]);
        return ( count($ct) > 0) ? true : false; // any non 0 value woudl mean your user has access in case your usersobjects table gets messy for whatever reason. 
    }

Then wherever you are calling it from controller, helpers etc its available and consistant.

$object = Object::findFirstById( 10 );

$object->canAccess( 24 ); // user ID we are checking has access.

Yeah, this was something I was thinking of implementing but was just hoping there was a slightly nicer way of doing it.