• 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
ActiveRecord for CodeIgniter: Rails-style model interactions

#31
[eluser]Michael Wales[/eluser]
I think each has it's merits. If you know SQL well, want total control of your queries which will better your ability to scale if your application all of a sudden becomes extremely popular, then CI's Active Record class offers much more flexibility in that regard.

If you are wanting to develop your application very quickly and think you will have a difficult time handling the relationships between multiple tables, this RoR-clone is great.

Ultimately, I think the CI route is the best way to go for beginners, unless they have a firm grasp of Ruby on Rails already. You will definitely learn much more and be more involved in the development process rather than relying on the "magic" that occurs behind the scenes in this library (as well as in RoR).

#32
[eluser]sophistry[/eluser]
@ralf57 - i have to agree with walesmd. i've been using CI Active Record for a year now and it's just great for most everything.

but, this class is an advancement I was ready to make - i am just lazy about writing lots of redundant code.

but, you can see from my struggles above, it's not a path for a beginner - especially if you are still on PHP4.

EDIT... HEY! it must be karma. I just noticed I became a "Senior Member" with this post. 300 posts in a little over a year.

#33
[eluser]sophistry[/eluser]
ok maurice, more PHP4 migration problems maybe you can help me with. as you know i am trying to get PHP4 to work with this code. i've got the find functions working but i wanted to try the other techniques listed in the wiki. specifically this technique of combining columns for output:

EDIT... added entire code to make sure I wasn't leaving anything out.
Code:
// this is the Controller extended
// the p() function is a debugging function i use to print vars
<?php

class Addresses extends Controller {

    var $Address;
    
    function Addresses()
    {
        parent::Controller();
        $Address =& $this->load->model('Address');
    }
    
    function index()
    {
        echo "Welcome to my address list!";
        //$addresses = $this->Address->find(ALL);
        $data = array('host_domain'=>'domain.com');
        $addresses = $this->Address->find_and_limit_by(2,0,array($data));
        //p($addresses);
        foreach ($addresses as $obj)
        {
            //p($obj);
            // addressing the objects from outside the class works
                        // no errors in this one
            $full_email = ($obj->mailbox . '@' . $obj->host_domain);
            // relying on a class function that uses $this-> doesn't work
                        // errors on every iteration except the first in this one
            $full_email_too = $obj->emailaddress();

            p($full_email); // prints all email addresses fine
            p($full_email_too); // prints only the first and then stops
            
            
        }
    }
    
}
?>

// and the model

<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');

class Address extends ActiveRecord {


    function Address()
    {
        parent::ActiveRecord();
        $this->_class_name = strtolower(get_class($this));
        $this->_table = 'address';
        $this->_columns = $this->discover_table_columns();
    }

    
    // this kind of function is like a calculation field
    function emailaddress()
    {
        return $this->mailbox . '@' . $this->host_domain;
    }
}

?>

when i put that in my address model, php complains about undefined property:
Code:
A PHP Error was encountered
Severity: Notice
Message: Undefined property: mailbox
Filename: models/address.php
Line Number: 19

so, i'm thinking it has to do with the different way that PHP4 handles "overloaded" class properties and somehow there isn't support for that in the PHP4 version of overloading. i tried implementing the __get and __set magic functions but to no avail - they just cause the rest of the class properties to vanish!

tell me, am i missing something obvious?

#34
[eluser]ralf57[/eluser]
[quote author="walesmd" date="1190686480"]I think each has it's merits. If you know SQL well, want total control of your queries which will better your ability to scale if your application all of a sudden becomes extremely popular, then CI's Active Record class offers much more flexibility in that regard.

If you are wanting to develop your application very quickly and think you will have a difficult time handling the relationships between multiple tables, this RoR-clone is great.

Ultimately, I think the CI route is the best way to go for beginners, unless they have a firm grasp of Ruby on Rails already. You will definitely learn much more and be more involved in the development process rather than relying on the "magic" that occurs behind the scenes in this library (as well as in RoR).[/quote]

Thank you walesmd,
now it's all more clear

#35
[eluser]Maurice Calhoun[/eluser]
[quote author="sophistry" date="1190711240"]ok maurice, more PHP4 migration problems maybe you can help me with. as you know i am trying to get PHP4 to work with this code. i've got the find functions working but i wanted to try the other techniques listed in the wiki. specifically this technique of combining columns for output:

EDIT... added entire code to make sure I wasn't leaving anything out.
Code:
// this is the Controller extended
// the p() function is a debugging function i use to print vars
<?php

class Addresses extends Controller {

    var $Address;
    
    function Addresses()
    {
        parent::Controller();
        $Address =& $this->load->model('Address');
    }
    
    function index()
    {
        echo "Welcome to my address list!";
        //$addresses = $this->Address->find(ALL);
        $data = array('host_domain'=>'domain.com');
        $addresses = $this->Address->find_and_limit_by(2,0,array($data));
        //p($addresses);
        foreach ($addresses as $obj)
        {
            //p($obj);
            // addressing the objects from outside the class works
                        // no errors in this one
            $full_email = ($obj->mailbox . '@' . $obj->host_domain);
            // relying on a class function that uses $this-> doesn't work
                        // errors on every iteration except the first in this one
            $full_email_too = $obj->emailaddress();

            p($full_email); // prints all email addresses fine
            p($full_email_too); // prints only the first and then stops
            
            
        }
    }
    
}
?>

// and the model

<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');

class Address extends ActiveRecord {


    function Address()
    {
        parent::ActiveRecord();
        $this->_class_name = strtolower(get_class($this));
        $this->_table = 'address';
        $this->_columns = $this->discover_table_columns();
    }

    
    // this kind of function is like a calculation field
    function emailaddress()
    {
        return $this->mailbox . '@' . $this->host_domain;
    }
}

?>

when i put that in my address model, php complains about undefined property:
Code:
A PHP Error was encountered
Severity: Notice
Message: Undefined property: mailbox
Filename: models/address.php
Line Number: 19

so, i'm thinking it has to do with the different way that PHP4 handles "overloaded" class properties and somehow there isn't support for that in the PHP4 version of overloading. i tried implementing the __get and __set magic functions but to no avail - they just cause the rest of the class properties to vanish!

tell me, am i missing something obvious?[/quote]

Message: Undefined property: mailbox

To be able to use the $this->mailbox property in your Address model it has to be assign. I think that you can do this inside of your foreach loop in your controller like this

Code:
$this->Address->mailbox = $obj->mailbox;

I think this should work.

#36
[eluser]sophistry[/eluser]
yes, but that is what i am trying to avoid by using this whole set up in the first place. isn't the point of this activerecord class that you don't have to define the columns as properties - they just "magically" appear based on the column names. at least that's what it looks like what's happening over at the PHP5 party. ;-)

BTW, thanks for the reply. i think there is something fundamentally flawed with trying to get this set up fully working in PHP4. there are a host of comments in the overload() function at php.net that say don't use inheritance and overload() together. basically they end up where you just pointed me which is, you have to hard code it if you want dynamic properties in PHP4. unless i'm missing something...

#37
[eluser]chrisj[/eluser]
Any more luck with other relations (has_many, has_one, belongs_to)? Using the suggestion before, I've been hacking a little bit, but would like input.

Here's my new _fetch_related:
Code:
function _fetch_related($table, $inflected)
{
  $inflected = ($inflected) ? $inflected[0] : substr($table, 0, -1);

  if( array_search($table, $this->_belongs_to) ) {
        $foreign_key = $table . '_id';
        $query = $this->db->query('SELECT * FROM ' . $inflected . ' WHERE id = ' . $this->$foreign_key);
    }
  else if( array_search($table, $this->_has_many) || array_search($table, $this->_has_one) ) {
      $query = $this->db->query('SELECT * FROM ' . $table . ' WHERE '. $this->_table .'_id = ' . $this->id);
  }
  else if( array_search($table, $this->_has_and_belongs_to_many) ) {
    $relationship_table = ($this->_table < $table) ? $this->_table . '_' . $table : $table . '_' . $this->_table;
    $query = $this->db->query('
        SELECT
        ' . $table . '.*
        FROM
        ' . $table . '
        LEFT JOIN
        ' . $relationship_table . '
        ON
        ' . $table . '.id = ' . $inflected . '_id
        LEFT JOIN
        ' . $this->_table . '
        ON
        ' . $this->_table . '.id = ' . $this->_class_name . '_id
        WHERE
        ' . $this->_table . '.id = ' . $this->id
        );
  }

  eval('$this->' . $table . ' = $query->result();');            
}

And then add this to the ActiveRecord constructor to prevent errors if you don't specify relations in the child class:
Code:
$this->_belongs_to = array();
$this->_has_many = array();
$this->_has_one = array();
$this->_has_and_belongs_to_many = array();

So then the model looks like this (traditional blog example):
Code:
class Post extends ActiveRecord {
    function __construct()
    {
        parent::ActiveRecord();
        $this->_class_name = strtolower(get_class($this));
        $this->_table = get_class($this).'s';
        $this->_columns = $this->discover_table_columns();

        $this->_belongs_to = array('blog','category','post_type','user');
        $this->_has_many = array('comments','images');
        $this->_has_and_belongs_to_many = array('tags');
    }
}

And then in my controller I can do this:
Code:
$post = $this->Post->find($id);
$post->fetch_related_blog();
$post->fetch_related_category();
$post->fetch_related_post_type();
$post->fetch_related_user();
$post->fetch_related_comments();
$post->fetch_related_images();
$post->fetch_related_tags();

This seems to work okay.

I haven't tackled create_relationship yet.

I've also been working on putting the CI validation procedures into the model (ala RoR) but that's another issue.

#38
[eluser]nmweb[/eluser]
Nice work! I will probably give it a shot somewhere in this weekend. I'm also curious after you validation procedures into the model.

#39
[eluser]Matthew Pennell[/eluser]
[quote author="chrisj" date="1191016759"]Any more luck with other relations (has_many, has_one, belongs_to)? Using the suggestion before, I've been hacking a little bit, but would like input.

<snip>[/quote]
That looks perfect, nice work Chris! Smile The create_relationship changes should be pretty simple too.

#40
[eluser]chrisj[/eluser]
Thanks BB & NM.

I found some major bugs with my _fetch_related function, however. Here's the new and improved version:
Code:
function _fetch_related($table, $inflected)
    {
        $inflected = ($inflected) ? $inflected[0] : substr($table, 0, -1);

        if( array_search($table, $this->_belongs_to) !== false ) {
            $foreign_key = $table . '_id';
            $query = $this->db->query('SELECT * FROM ' . $inflected . ' WHERE id = ' . $this->$foreign_key);
        }
        else if( array_search($table, $this->_has_many) !== false || array_search($table, $this->_has_one) !== false ) {    
            $query = $this->db->query('SELECT * FROM ' . $table . ' WHERE '. $this->_class_name .'_id = id');
        }                    
        else if( array_search($table, $this->_has_and_belongs_to_many) !== false ) {
            $relationship_table = ($this->_table < $table) ? $this->_table . '_' . $table : $table . '_' . $this->_table;
            $query = $this->db->query('
                SELECT
                    ' . $table . '.*
                FROM
                    ' . $table . '
                LEFT JOIN
                    ' . $relationship_table . '
                ON
                    ' . $table . '.id = ' . $inflected . '_id
                LEFT JOIN
                    ' . $this->_table . '
                ON
                    ' . $this->_table . '.id = ' . $this->_class_name . '_id
                WHERE
                    ' . $this->_table . '.id = ' . $this->id
            );
        }
        else {
            return false;
        }

        eval('$this->' . $table . ' = $query->result();');            
    }


Digg   Delicious   Reddit   Facebook   Twitter   StumbleUpon  


  Theme © 2014 iAndrew  
Powered By MyBB, © 2002-2021 MyBB Group.