ExpressionEngine CMS
Open, Free, Amazing

Thread

This is an archived forum and the content is probably no longer relevant, but is provided here for posterity.

The active forums are here.

Gas ORM 2

March 16, 2012 11:36pm

Subscribe [39]
  • #16 / Mar 19, 2012 7:29pm

    Khrome83

    22 posts

    So last_id() is not working?

    I get this error.

    An Error Was Encountered
    
    Unknown method.
    
    
      Function  : last_id
      File      : /home/guildwar/public_html/application/models/skills.php
      Line      : 82
      Snapshot  : 
    80   // Record ID
    81   $id = $this->last_id();
    82
    83   // _races
  • #17 / Mar 20, 2012 12:10pm

    toopay

    1583 posts

    @DerLola,

    Thanks for the report. I’ve just updated the spark, both for the previous issue(which throw a warning on autogenerate model) and your issue with base_url. Update your spark using this command via CLI :

    $ php tools/spark reinstall gas -f
  • #18 / Mar 20, 2012 12:30pm

    toopay

    1583 posts

    The other thing to note, is that for ‘recast’, ‘skill_points’, ‘activation_time’ it has them set to AUTO as opposed to INT, even tough they are in in DB without the Auto Increment flag associated with them.

    What database and dbdriver you use? I’ve just try them, and they generate numeric for INT or TINYINT.

    Is there a better way when inserting data with a pivot table?

    You already doing it right, theres no shortcut for create an intermediate record, only cascade delete supported (i’ve never heard about cascade insert anyway). But perhaps, try playing with Gas\Data in your model. I am more convinience to wrap some data into it, instead adding more method just to set-up some property. Gas\Data works this way :

    $some_property = new \Gas\Data();
    
    // To set something
    // Set some array
    $some_property->set('data', array('foo' => 'bar', 'else' => 'thing'));
    // Or…similar with above
    $some_property->set('data.foo', 'bar');
    $some_property->set('data.else', 'thing');
    
    // To get something
    var_dump($some_property->get('data')); // will outputing array('foo' => 'bar', 'else' => 'thing')
    var_dump($some_property->get('nothing')); // will outputing NULL
    var_dump($some_property->get('nothing', 'default value')); // will outputing 'default value'
    var_dump($some_property->get('data.foo')); // will outputing 'bar'
    var_dump($some_property->get('data.else')); // will outputing 'thing'

    So last_id() is not working?

    Yes, i change it to insert_id which inherit from CI query builder. Also, just in case you need the whole created resource, you could use :

    // Right after create a record…
    if ($new_user->save())
    {
       // This will return the last created record in standard Gas instance
       $last_created = Model\User::last_created();
    }
  • #19 / Mar 20, 2012 3:45pm

    Khrome83

    22 posts

    @toopay

    Thanks for the response. That clears a lot of stuff up for me.

    I am assuming you are suggesting to use set function to build a collection, and then follow the standard format for inserting it into the database? This gets rid of the custom methods in the model, as well as the private variables? Is that correct?

    Is something that I create in the view or controller, accessible in the model than this way through _after_save()?

    So instead of calling a function set_types, I could just set a collection of ‘types’ with the array of data I need. Then when _after_save() is called, insert that information to the correct table?

    I am sorry, but I am coming back to PHP and web development after my career with Game Design didn’t go anywhere after a few years. OOP PHP 5 is new to me entirely, as well as frameworks like CI, so it’s been a little slow for me grasping things.

    Ruby on Rails actually has a cascade insert. I only played with ROR for a few weeks using the CodeSchool Zombies for Rails and some side project, but I could so something like this (provided in my limited knowledge I understood what was going on).

    This is my best PHP interpretation for mythical GAS ORM with cascade insert -

    $data = array(
    'name' => 'Bob',
    'email' => '[email protected]',
    'job' => find_by_name('M$'),
    'pay' => array('amount' => '2000', 'frequency' => '2 weeks'),
    );
    
    Model\User::make($data);

    I imagine additional arrays would be new record for table Pay, and would insert into User_Pay the correct IDs, while find_by_name would look in table Job for the existing record and make the correct IDs in User_Job.

    This could be super far off plausible, like I said I am just getting back into this so my knowledge is super limited.

    This is everything I have on my Database setup. I just switched to a new host that uses CPanel so still learning where all the info is listed. I hope this answers your question about my database.

    Server: Localhost via UNIX socket
    Server version: 5.1.56-log
    Protocol version: 10
    User: guildwar@localhost
    MySQL charset: UTF-8 Unicode (utf8)
    Web server
    
    cpsrvd 11.30.4.6
    MySQL client version: 5.1.56
    PHP extension: mysql
  • #20 / Mar 20, 2012 4:41pm

    toopay

    1583 posts

    I am assuming you are suggesting to use set function to build a collection, and then follow the standard format for inserting it into the database? This gets rid of the custom methods in the model, as well as the private variables? Is that correct?

    Is something that I create in the view or controller, accessible in the model than this way through _after_save()?

    So instead of calling a function set_types, I could just set a collection of ‘types’ with the array of data I need. Then when _after_save() is called, insert that information to the correct table?

    Correct, and yes that property should be accesible.

    Regarding your database, it all seems ok. But again, i could not replicate those behaviour. From here, everything generated in appropriate datatype. I will check that a little while, and wait to see if someone else have same issue.

    This is my best PHP interpretation for mythical GAS ORM with cascade insert -

    $data = array(
    'name' => 'Bob',
    'email' => '[email protected]',
    'job' => find_by_name('M$'),
    'pay' => array('amount' => '2000', 'frequency' => '2 weeks'),
    );
    
    Model\User::make($data);

    I imagine additional arrays would be new record for table Pay, and would insert into User_Pay the correct IDs, while find_by_name would look in table Job for the existing record and make the correct IDs in User_Job.

    In case you still dont realize, the new relationship method within this version. You could have, for example, something like this in your relationship configuration :

    'role' => ORM::has_many('\\Model\\Acl\\User => \\Model\\Acl <= \\Model\\Acl\\Role => \\Model\\Role'),

    So new relationship method could be more than 2 level deep, not like the old one. So, this thing adding some complexity, to apply something like ‘cascade_insert’.

    In the past, someone is already asking the same. And for me, the callback which available for that point (after_save) most likely resolving the need to create and linked the last created record to some many-to-many relationship with other entity. And so far, i dont have any difficulty to set up that way.

    But i will consider this idea, and i may include this behaviour in next minor release. Maybe something like this :

    // Perhaps, this only works for 2 level deep relationship
    $new_user = Model\User::with_job($jobdata)->create($userdata)->save();
    // So it slightly "uniformal" with cascade delete :
    // Model\User::with('job')->delete(1);
  • #21 / Mar 20, 2012 7:05pm

    Khrome83

    22 posts

    Thanks toopay for all the feedback and information. I really appreciate it.

  • #22 / Mar 21, 2012 10:32am

    Jazmo

    13 posts

    I have to say that i really hate escaping table references \\table within has_many declaration or in other strings :(

  • #23 / Mar 21, 2012 11:06am

    toopay

    1583 posts

    Setting up your model relationship is one-time set-up, unless in the future, you need to change your table schema 😊

  • #24 / Mar 21, 2012 12:11pm

    Khrome83

    22 posts

    @toopay - I could not get the properties to be accessible in the model when set in the view. So I was not able to use Gas\Data(). I did however spend a few hours playing around and figured this out. I think this is a more elegant way to set up the pivot tables, as it’s universal for all my pivot tables and did not require a custom method per pivot table, or a separate entry for each addition.

    I still need to do some testing, and I need to add validation to make sure _pivot contains data.

    So when creating a record, call function on the model set_pivot. This takes all the table names (lowercase) and the ID if the associated record. Also pass the name of the model, this was just to make the code easier to copy and paste from model to model.

    $contents = array(
         'name' => 'Heal as One',
         'description' => 'Heal yourself and your pet',
         'recast' => '20'
        );
    
       $newrecord = Model\Skills::make($contents);
       $newrecord->set_pivot(array(
         'types' => '3',
         'pets' => '1',
         'weapons' => '1',
         'professions' => '3'
        ), 'skills');
    
    
       if($newrecord->save()) {
        echo 'New Record Saved';
       } else {
        echo 'Foo not saved. Error were '.$foo->errors('', '');
       }

    Then in the model add these private fields -

    private $_pivot;
        private $_model;

    The set_pivot function -

    function set_pivot($collection, $model) {
      $this->_pivot = $collection;
      $this->_model = $model;
      return $this;
     }

    Then add this into _after_save() -

    if ($this->empty) {
       // Record Id
       $id = $this->insert_id();
    
       // Insert Into Appropriate Pivot Tables
       foreach ($this->_pivot as $key => $value) {
        $contents[$key.'_id'] = $value;
        $contents[$this->_model.'_id'] = $id;
        $class = 'Model\\'.ucfirst($this->_model).'\\'.ucfirst($key);
        $class::make($contents)->save(TRUE);
        unset($contents);
       } 
    
      }

    Calling make dynamically could not be done without eval before, but thanks to PHP 5.3 this is now valid.

    So now it will insert a new entry for any relations that are provided. Obviously this works for me because I follow the default conventions for naming the pivot table foreign keys. I am sure there is a better way to make this worth with the scheme overrides included in the models.

  • #25 / Mar 21, 2012 3:07pm

    Khrome83

    22 posts

    A few questions on finder?

    What is the difference between

    $skills = Model\Skills::all();

    and

    $skills = Model\Skills::with('types','professions')->all();

    When I use either, i still get access to the information regardless if I include With().

    I am printing everything as such -

    foreach ($skills as $s) {
        echo $s->name.'
    ';
        foreach ($s->types() as $t){
         echo $t->name.'
    ';
        }
        foreach ($s->professions() as $p) {
         echo $p->name.'
    ';
        }
        foreach ($s->weapons() as $w) {
         echo $w->name.'
    ';
        }    
       }

    So even if weapons are not included, I can still access them? So what does with get me?

    Also when I do -

    $skills = Model\Skills::find(1);

    I can no access any of the relationships (types, professions, weapons, etc).

  • #26 / Mar 21, 2012 3:31pm

    toopay

    1583 posts

    A few questions on finder?

    What is the difference between

    $skills = Model\Skills::all();

    and

    $skills = Model\Skills::with('types','professions')->all();

    When I use either, i still get access to the information regardless if I include With().

    Yes, you will still get access to the related entity without eager load (with method). The different is on the executed queries. With the first one, you actually will generate SELECT statement as many as your records, but with eager load it minimize the query. To find out, try adding this line :

    $this->output->enable_profiler(TRUE);

    And try to access the related entity with eager load, and try without it. You will see the different.

    Also when I do -

    $skills = Model\Skills::find(1);

    I can no access any of the relationships (types, professions, weapons, etc).

    What you mean “no access” here?

  • #27 / Mar 21, 2012 6:33pm

    Khrome83

    22 posts

    So it took it down from 220 queries to 7. That is pretty cool.

    To answer your question, if I use this code, where the only thing that changed is that all() is replaced with find(1), i get errors.

    Code -

    $skills = Model\Skills::find(1);
       $this->output->enable_profiler(TRUE); 
    
       foreach ($skills as $s) {
        echo $s->name.'
    ';
        foreach ($s->types() as $t){
         echo $t->name.'
    ';
        }
        foreach ($s->professions() as $p) {
         echo $p->name.'
    ';
        }
        foreach ($s->weapons() as $w) {
         echo $w->name.'
    ';
        }    
        //wtf($s);
    
       }

    Outputs -

    A PHP Error was encountered
    
    Severity: Notice
    
    Message: Trying to get property of non-object
    
    Filename: views/welcome.php
    
    Line Number: 69
    
    
    
    Fatal error: Call to a member function types() on a non-object in /home/guildwar/public_html/application/views/welcome.php on line 70

     

  • #28 / Mar 21, 2012 8:42pm

    Dan Tdr

    20 posts

    Hey toopay,

    I searched for this info but with no luck, how can i use Gas ORM 2 with HMCV (Modular Extension) i want to put my models in my modules and not keep them in a folder models in my application folder. How can i do that?

    Thank you,
    Dan

  • #29 / Mar 21, 2012 9:04pm

    Khrome83

    22 posts

    On the documentation it lists how to change the folder path for modules.

    Not sure if this helps you…

    http://gasorm-doc.taufanaditya.com/configuration.html

    $config['models_path'] = array('Model' => APPPATH.'models');

    toopay would know better

  • #30 / Mar 22, 2012 4:18am

    indCI

    11 posts

    I have a database with tables that have underscores ( _ ) in the name.
    In Gas 2 this is apparently interpreted as namespace_tablename, which is fine here, I guess.
    But I’m having a bit of a problem with these tables.

    For example there is service table which has relationships set up like this:

    'resource'     => ORM::has_many('\\Model\\Resource'),
    'service_type' => ORM::belongs_to('\\Model\\Service\\Type'),

    Now, if I try

    $service->resource()

    I get the resources for that service, but if I try

    $service->service_type()

    I get error

    You have an error in your SQL syntax
    SELECT * FROM `service_type` WHERE `service_type`.`id` IN (%s)

    so somewhere it bypasses the sprintf().

    Am I doing something wrong here?
    Should I edit the auto-generated models by hand and make them like \Model\Service_type instead of \\Model\\Service\\Type, or is there something I can do to fix this the way it is now?

    I have tried following the User Guide but it doesn’t explicitly tell how to deal with tables like this.

    EDIT: It doesn’t work even if I make that change by hand, so the problem is somewhere else. I’m probably doing something stupid here, but it did work with the previous Gas ORM version.

    EDIT2: Am I supposed to somehow define the foreign key here? service_type table has a column called id and service has type_id. Is this what breaks it? Why did it work in the previous version though?
    I’m actually quite new to databases and ORM, so bear with me here.

.(JavaScript must be enabled to view this email address)

ExpressionEngine News!

#eecms, #events, #releases