Welcome Guest, Not a member yet? Register   Sign In
Gas ORM
#21

[eluser]bretticus[/eluser]
So I'm basically new to ORM's. I've decided to give it a spin and see if it actually does "... remove all hassle and ... seriously reduce [my] development time..." I like what I see so far. Just having a hard time wrapping my brain around how to do CRUD with pivot tables.

I have two tables: user and role.

They have a pivot table called site_user for a many-to-many relationship.

The user model starts with...

Code:
class User extends Gas {

    public $table = 'user';
    public $primary_key = 'user_id';
    public $relations = array(
        'has_and_belongs_to' => array('site' => array())
    );

and the site model starts with ...

Code:
class Site extends Gas {

    public $table = 'site';
    public $primary_key = 'site_id';
    public $relations = array(
        'has_many' => array('host' => array()),
        //... more has_many relationships...
        'has_and_belongs_to' => array('user' => array())
    );

So I was thinking perhaps, I could do something like...

Code:
$user = Gas::factory('user')->find_where(array('email' => '[email protected]'));
$user->role=1;
$user->save();

Of course that throws an undefined method error. How is this supposed to work?

I'd really appreciate pointers.

Thanks
#22

[eluser]toopay[/eluser]
@bretticus,

There are enough hooks point to do extra things within your task.

has_and_belongs_to property was intend to works with some schema like
Code:
# Note that job_user not contain any extra collumn(s) other than user_id and job_id

  +--------+   +--------------+   +------------+
  | user   |   | job_user     |   | job        |
  +--------+   +--------------+   +------------+
  | id     |<->| user _id     |   |            |
  | name   |   | job_id       |<->| id         |
  | ...    |   |              |   | description|
  +--------+   +--------------+   | .........  |
                                  +------------+

If this is the case, then you could have, in your user model :
Code:
class User extends Gas {
    // Model definition and relationship property here...
    // ...
    
    // This to hold the job value modifier
    private $_job;

    // ... Some methods...
    // ...

    // This one, to change the job property
    public function set_job($job)
    {
       $this->_job = array('job_id' => $job);

       return $this;
    }

    // Then in your _after_save callback
    function _after_save()
    {
       // This will triggered whenever INSERT event occurs
       if ($this->empty)
       {
          // Executed when _job contain something...
          if (is_array($this->_job))
          {
             $this->_job['user_id'] = $this->last_id();
          
             // Since we use 'has_and_belongs_to' property
             // this mean, there is no 'job_user' model.
             // So we write it directly here, using query builder method
             // below is analog of : $this->db->insert('table', $values)
             $this->db()->insert('job_user', $this->_job);
          }
       }
    }
This way, it will automatically save user with its job whenever you want it,
Code:
// Somewhere within your application scripts
// let say we want save Foo with its job
$data = array('name' => 'Mr.Foo', 'username' => 'foo', 'email' => '[email protected]');
$foo  = Gas::factory('user')->fill($data);
$foo->set_job(1);

if ($foo->save())
{
   echo 'Foo and its job saved';
}
else
{
   echo 'Foo not saved. Error were '.$foo->errors('<p class="error">', '</p>');
}
If, the case are your pivot table contain more collumns, i will suggest to setup other relationship than '_has_and_belongs_to' and use 'through' model option (this mean, your pivot table will need a model contain abstraction about it).
#23

[eluser]mecharius[/eluser]
Hi Toopay,
First of all - I came across GAS a little while ago and think it looks great. I've already built one basic app off it (Electrical Parts Inventory Manager) and I'm working at converting another Doctrine based app to it.

The application I am converting has about 20 tables with some complicated relationships between them. I've been looking at these for quite a while and when I read the code everything seems to be ok, but I keep getting an error " Model XXXX located, but missing relationship properties."

Do you have any tips for debugging complex relationships? Is there any way we can get a bit more detail out of where the error is occurring? I'm not looking for you to debug my code, more just interested if there is a way I can get more information out of the GAS error!

Keep up the great work,

Thanks,
Will
#24

[eluser]mecharius[/eluser]
OK, I tracked it down by going to line 3032 or thereabouts in the GAS library and just echoing every variable in the Gas::generate_child() function.

Strangely enough it looked as though Gas was assuming relationships I hadn't defined? i.e. I had a has_and_belongs_to relationship between Users table and Permissions table which I had deliberately not defined through Gas (i.e. the tables existed but I was manually managing it in code), but Gas seemed to be looking for it?
#25

[eluser]toopay[/eluser]
[quote author="mecharius" date="1328443182"]
Strangely enough it looked as though Gas was assuming relationships I hadn't defined? i.e. I had a has_and_belongs_to relationship between Users table and Permissions table which I had deliberately not defined through Gas (i.e. the tables existed but I was manually managing it in code), but Gas seemed to be looking for it?[/quote]
Thats true. When the first time core abstraction of Gas loaded, it save all of your model(s) and its properties, into some global entity repository.

Thus, if you try to reach unexisted property(es) within your model, eg:
Code:
$user = Gas::factory('user')->find(1);

// Here, accidentally you try to reach some property
// which had same name with one of your model
$permission = $user->permission;
then it assume you are trying to load some related entity. And because you has not define any relationship between them, some error occurs. If this is the case, then the solution is quite obvious. Either change your model name or the used property. Your model could have different name than your factual table name.

If you still have some issue on setting up relationship, after read the documentation, feel free to share your schema here, and we could try to resolve it together.
#26

[eluser]mecharius[/eluser]
Thanks,
Yeah the relationship is for a nested ACL so it can be a little confusing... I can manage this outside of GAS quite easily and currently have the Users<<HABTM>>Permissions working. I'm just managing the Permissions<<>>Permissions relationship in my code.

Code:
USER         USER_PERMISSION           PERMISSION
====         ===============           ==========
id   <------ user_id               /-- id          <-|
             permission_id <------|    parent_id   --/




Another interesting relationship that Doctrine supports is linking a table to another table twice by alias... e.g. for private messaging - you can track from_user and to_user both linked by separate IDs based on the schema below. Does that make sense?

Code:
USER        MESSAGE            USER
====        =======            ====
            id
id <------- from_user_id
            to_user_id ------&gt; id

Is it possible to implement this kind of relationship? e.g.
Code:
#USER_GAS.PHP#
public $relations = array(
    'has_many' => array(
        'received_messages'=>(array('foreign_table'=>'messages', 'foreign_key'=>'to_user_id')),
        'sent_messages' =>( array('foreign_table'=>'messages', 'foreign_key'=>'from_user_id'))
    )
);


#MESSAGES_GAS.PHP#
public $relations = array(
    'belongs_to' => array(
        // What do I put here???? e.g.
        'from_user'=>array('foreign_table'=>'users', 'foreign_key'=>'id'),
        'to_user'=>array('foreign_table'=>'users', 'foreign_key'=>'id')
    )
);



#Could then access in a controller like
echo "Message sent from " . $message->from_user->username . "<br/>";
echo "Message sent to " . $message->to_user->username;

## OR ##
foreach($user->sent_messages as $msg)
{
    echo $msg->subject;
}

Anyway, just some thoughts / questions... Thanks for all your work on this library, its great!
#27

[eluser]toopay[/eluser]
@mecharius,

You could set up self-referential for the first case, play around with it.

Regarding your second case/though, aliasing, while within current version it was impossible(mean you will need to adding extra method by yourself within some model, to handle that), the next version will be far more flexible and set up something like that will be a breeze. Because each relationship no longer based by per-table/model mindset, but based by "path" of entities tuple(s) you defined, something like : http://goo.gl/VVUob (look around line 101-105).
#28

[eluser]mecharius[/eluser]
Ah ok, thanks again for your help! :cheese:
#29

[eluser]Lunaman[/eluser]
Hey Toopay,

Trying to use Gas ORM I stumbled upon something I miss from CI form validation.
With standard form validation usage there is the possibility to add a readable name to a field for the end-user.
I can't seem to find this functionality when using Gas ORM.

Is there a way I can get field names replaced with readable names for the end-user?

Thanks
#30

[eluser]toopay[/eluser]
@Lunaman,

The validator within Gas, already replace your table's collumn name into human-readable name. But if necessary you could also get the raw error(s) and process it by yourself, by accessing 'errors' property. Eg :
Code:
$data     = array('name' => 'Mr.Foo', 'username' => 'foo', 'email' => 'notvalidemail');
$new_user = Gas::factory('user')->fill($data);

if ($new_user->save(TRUE))
{
   echo 'New user saved';
}
else
{
   echo 'Failed. Raw errors were :';
   echo '<pre>';
   // Here you could get the array of errors,
   // and you could process it furthermore to fit your needs
   print_r($new_user->errors);
   echo '</pre>';
}




Theme © iAndrew 2016 - Forum software by © MyBB