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

Model relation using namespaces

Hi all,

I'm implementing Phalcon ORM and have an issue with relations between models. To be accurate, I had a test code working with staticly included classes. Then I've started using namespaces, added an autoloader and it doesn't work anymore.

My test code:

  //includes model class and return a new UsersModel
  $oUser = $this->_getModel('users');   

  $aoUsers = $oUser::find(array('order' => 'id ASC'));
  foreach($aoUsers as $oUser)
  {
     dump($oUser->id);
     dump($oUser->profiles);
  }

As expected the resultset was containing the user & profile data. Now I've changed the relation declarations with Namespaces, the resultset only contains the user data. My Models:

namespace Phalcon\Mvc\Model;
class Users extends \Phalcon\Mvc\Model\ModelBase
{   
    namespace Phalcon\Mvc\Model;
    public function initialize()
    {
        $this->useDynamicUpdate(true);
        $this->hasOne("id", "\Phalcon\Mvc\Model\Profiles", "id");
    }

    public function metaData()
    {
        //generating my own meta here.
    }
}

Second model:

  namespace Phalcon\Mvc\Model;
  class Profiles extends \Phalcon\Mvc\Model\ModelBase
  { 
      namespace Phalcon\Mvc\Model;
      public function initialize()
      {
          $this->useDynamicUpdate(true);
          $this->belongsTo("id", "\Phalcon\Mvc\Model\Users", "id");
      }

      public function metaData()
      {
          //generating my own meta here.
      }
  }

If I dump the ModelManager, I see it's set up properly:


$oManager = $oUser->getModelsManager();         
dump($oManager);

dump('relations ?');
$oRelation = $oManager->getRelations("profiles");           
dump($oRelation);

//Outputs:

Object(Phalcon\Mvc\Model\Manager) => 
array(24) {
  ["*_dependencyInjector"]=>
  string(24) " *** Phalcon object *** "
  ["*_eventsManager"]=>
  NULL
  ["*_customEventsManager"]=>
  NULL
  ["*_readConnectionServices"]=>
  NULL
  ["*_writeConnectionServices"]=>
  NULL
  ["*_aliases"]=>
  array(1) {
    ["phalcon\mvc\model\users$\phalcon\mvc\model\profiles"]=>
    array(8) {
      ["*_type"]=>
      int(2)
      ["*_referencedModel"]=>
      string(27) "\Phalcon\Mvc\Model\Profiles"
      ["*_fields"]=>
      string(2) "id"
      ["*_referencedFields"]=>
      string(2) "id"
      ["*_intermediateModel"]=>
      NULL
      ["*_intermediateFields"]=>
      NULL
      ["*_intermediateReferencedFields"]=>
      NULL
      ["*_options"]=>
      NULL
    }
  }
  ["*_hasMany"]=>
  array(1) {
    ["phalcon\mvc\model\users$\phalcon\mvc\model\profiles"]=>
    array(1) {
      [0]=>
      [...]

//And relations:
array (
  0 => 
  Phalcon\Mvc\Model\Relation::__set_state(array(
     '_type' => 2,
     '_referencedModel' => '\\Phalcon\\Mvc\\Model\\Profiles',
     '_fields' => 'id',
     '_referencedFields' => 'id',
     '_intermediateModel' => NULL,
     '_intermediateFields' => NULL,
     '_intermediateReferencedFields' => NULL,
     '_options' => NULL,
  )),
)

What is wrong ?

Well, as a last hope I tried to use aliases, and it works.

if I declare the relation as

    $this->hasMany("id", "\Phalcon\Mvc\Model\Profiles", "user_id",  array('alias' => 'uprofiles'));

The query result let let me access the profile data calling

    dump($oUser->uprofiles);

That shows my config is ok, but that's a bit painful to use. Any way to have the ModelManager to interprete the namespace "\Phalcon\Mvc\Model\Profiles" to let me access the model with $oUser->profiles ?

(aka instanciate the model using \Phalcon\Mvc\Model\Profiles()" but including it in the resultset as "Profiles)

Cheers

Maybe remove the first \ in the model name would help:

namespace Phalcon\Mvc\Model; // use the framework namespace sounds like a really bad idea
  class Profiles extends \Phalcon\Mvc\Model\ModelBase
  { 
      namespace Phalcon\Mvc\Model; /// < not sure how this works for you
      public function initialize()
      {
          $this->useDynamicUpdate(true);
          $this->belongsTo("id", "Phalcon\Mvc\Model\Users", "id");
      }

      public function metaData()
      {
          //generating my own meta here.
      }
  }

Thanks for the reply Andres...

  1. Using Phalcon namespace: it's just a proof of concept for now, that won't stay like this for sure, it's to avoid any possible namespace issue as I build my first ORM. Based on your answer I understand that the ORM should convert "Phalcon\Mvc\Model\Users" ==> $oUser->profiles

    • Do you think using phalcon namespace could explain why it's not working ?
  2. "namespace Phalcon\Mvc\Model;" in the middle, copy/paste issue, that is not in my actual code.

  3. Leading slash or not, it doesn't work without aliases.
edited Jul '15

Update: I've cleaned up my namespaces, moved all the models to \Phapp\Model\ModelName and it sadly still doesn't work without aliases.


// Model:
$this->hasMany("id", "\Phapp\Model\Profiles", "user_id");  

// Controller:
$oUser->profiles->toArray()
// Notice: Access to undefined property Phapp\Model\Users::profiles in [...] 

// Model:
$this->hasMany("id", "\Phapp\Model\Profiles", "user_id",  array('alias' => 'profiles'));
// Controller: works
$oUser->profiles->toArray()

Is there anything else I could/should do ? Is there a default namespace to set somewhere ? Best,

What's the problem of having aliases?