SitePoint Sponsor

User Tag List

Page 1 of 3 123 LastLast
Results 1 to 25 of 68
  1. #1
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,194
    Mentioned
    17 Post(s)
    Tagged
    5 Thread(s)

    Active Record Save (insert/update) And destroy Feature

    I've been thinking about this for a while and would like some others opinions on this matter. This thread is discusses the ideas related to this post and somewhat continuation. However, everything discussed in that post is working perfectly. Now what I need to do is decide the features and aesthetics for updating and destroying that should be supported.

    The obvious idea and one that most other similar patterns have to explicitly pull and object in to memory and set the property. Then call the save method. This seems like its the bare bones of a update though and I would like something more rich and user friendly which I'll discuss below.

    PHP Code:
    $post = new Post(2);
    $post->message 'Updated message';
    $post->save(); 
    The above code would simply update the message column where the id = 2 on the posts table to the new message. Nothing extraordinary or unique.

    Upon look at Luke Bakers save system I thought it was a nice featured to actually be able to pass in a related object in a belongs to association. So something I feel would be highly worth implementing is something along the line of the following.

    PHP Code:
    $thread = new Thread(2);
    $post = new Post(345);
    $post->thread $thread;
    $post->save(); 
    So rather then needing to pass in the actually id you could pass in the object. The advantages of this should be obvious when you look at the same idea in this code:

    PHP Code:
    $thread = new Thread(2);
    $post = new Post(345);
    $post->thread_id $thread->id;
    $post->save(); 
    In this example you would explicitly need to pass in the data type which seems a little incorrect. In that the thread should exists before you relate it to the post. Using the previous method forces you to create a instance which means it does in deed exists. That seems like logically the more concrete and useful approach.

    Now, the other thing I was wondering is whether or not I could make this even more rich in that a ActiveRecord that has something included could be saved in a hierarchical manor. Take the following code:

    PHP Code:

    $user 
    = new User(3);

    $thread = new Thread();

    $thread->message 'whatever';

    $user->threads $thread;

    $user->save(); 
    Do you think something like that would be useful? Where you could essentially add several threads to a user then call save. The save method would essentially then insert those new threads records. So this could take the place of needing to do this:

    PHP Code:

    $user 
    = new User(2);

    $thread = new Thread();

    $thread->message 'message';
    $thread->user $user;

    $thread->save(); 
    This code would essentially insert the new thread with the appropriate user foreign key. However, in the previous example we could essentially accomplish a multiple insert or update (depending on whether a primary key exists)

    PHP Code:

    $user 
    = new User(2);

    $thread1 = new Thread();
    $thread2 = new Thread();
    $thread3 = new Thread();

    $thread1->message 'thread 1 message';
    $thread2->message 'thread 2 message';
    $thread3->message 'thread 3 message';

    $user->threads $thread1;
    $user->threads $thread2
    $user
    ->threads $thread3;

    $user->save(); 
    This code would essentially create a multiple insert statement and bind the user to each thread. If this weren't possible then you would need to generate each thread individually and and save it which would result in 3 separate queries.

    Do you think this is a neat and useful feature to integrate? Have you seen it in other ActiveRecord implementations before?

    Any other ideas or concepts worth integrating for a save?

    Now to talk about the destroy featured. To delete a record is relatively simple since everything within the system is uniquely identified by one primary key. Therefore, a straight forward way of deleting one record would be to just delete it where the primary key is equal and limit by one.

    PHP Code:

    $thread 
    = new Thread(3);
    $thread->destroy(); 
    The above code would simply delete from threads where the primary key equals 2. That is simple enough.

    However, the idea I really liked and found useful when I came upon it was the ability to remove all dependencies along with a record. For example, if a thread is deleted then its post should be taken along with it. However, the previous example doesn't allow that. Do you think this is a useful feature? Have you seen it in any other Activerecord implementations?

    I also thought it would be useful to remove included items. For example, if you pulled in a thread and afew posts. Then destroyed the thread the included items would go along with the thread. I'll give you an example.

    PHP Code:

    $thread 

    Thread::find(

       
    'one'
       
    ,array(
          
    'include'=>'posts'
          
    ,'id'=>3
       
    )
       ,array(
         
    'id'=>array('? OR Post.id = ? OR Post.id = ?',1,4,87)
         ,
    'require'=>false
       
    )


    In this example we are simply bringing in a thread with a primary key of 3 and its posts. However, we are only bringing in posts with a primary key of 1,4 or 87 for that thread. Now, what I thought would be interesting is the ability to destroy the thread and when the thread is destroyed take only the related posts that have been included. So you could destroy related items by including them all in one shot.

    PHP Code:

    $thread
    ->destroy(true); 
    That code coupled coupled with the previous would first remove the dependencies where id is equal to 1,4 or 87. Then upon deleting those it would remove itself. However, if the situation were reversed and a post was the root element then the the post then thread it relates to would be deleted. Dpeneding on other passed arguments that threads other dependencies would also be destroyed. Does this sound like a good / useful way to implement the destroy mechanism for the Activerecord? Have you seen the same idea or similar used else were for a Activerecord?

    Any other possible ways to make the update,insert and destroy more rich and useful? Perhaps any possible problems I overlooked or may run into that are worth mentioning that you see?

    thanks
    Last edited by oddz; Apr 3, 2009 at 01:11.

  2. #2
    SitePoint Guru
    Join Date
    Jun 2006
    Posts
    638
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hey

    I have similar functionality built into my library, but it ended up using to much CPU/memory and I took it out...

    I like your idea, up to a point:
    PHP Code:
    $user = new User(2);

    $thread1 = new Thread();
    $thread2 = new Thread();
    $thread3 = new Thread();

    $thread1->message 'thread 1 message';
    $thread2->message 'thread 2 message';
    $thread3->message 'thread 3 message';

    $user->threads $thread1;
    $user->threads $thread2;
    $user->threads $thread3;

    $user->save(); 
    That code is misleading.

    PHP Code:
    $user->threads $thread1;
    $user->threads $thread2
    That to me means that I replace the "threads" from "$user" with "$thread1", and then "$thread2".

    For one to many or many to one relationships, I would use "function calls" instead.

    Example:
    PHP Code:
    // Load the user
    $user = new User(2);

    // New threads for our example
    $thread1 = new Thread();
    $thread2 = new Thread();
    $thread3 = new Thread();

    $thread1->message 'thread 1 message';
    $thread2->message 'thread 2 message';
    $thread3->message 'thread 3 message';

    // Add threads to my user (end of list)
    $user->addThread($thread1);
    $user->addThread($thread2);
    $user->addThread($thread3);

    // Another way to add threads (this one might be more specific to my framework, set at predefined index, overwrite the one already there at that index)
    # $user->setThread( [index], [object]);
    $user->setThread(1$thread1);
    $user->setThread(2$thread2);
    $user->setThread(3$thread3);


    // Save the user
    $user->save(); 

    // Access threads from the user.
    foreach ($user->threads as $thread) {
        echo 
    $thread->message;

    And another way to add threads in my system:
    PHP Code:
    // Create an array of threads.
    $threads = array ($thread1$thread2$thread3);

    // Set the threads to my user (overwriting threads)
    $user->threads $threads

    The second part of your post, delete is easier to implement.

    Basically, in your data map where you define the relationships, you can add a new flag: cascadeDelete.

    If you delete an object, you check it's data map and see if it has the "cascadeDelete" flag set for each relationship, and if it does, you also delete the objects linking to/from it.

    Now, be careful here, since those objects might also have other relationships using the cascadeDelete flag, and you want to delete those also.

    Another problem will be "infinite loops". If A cascadeDeletes B, B cascadeDeletes C and C cascadeDeletes A, your code will end up in an infinite loop:
    Code:
    - Delete A
    -- should I cascadeDelete B?
    --- yes, should I cascadeDelete C?
    ---- yes, should I cascadeDelete A? (back at the start)
    Hope this helps.

  3. #3
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,194
    Mentioned
    17 Post(s)
    Tagged
    5 Thread(s)
    Well I was thinking that if the item was a array then it would replace otherwise it would add. If the property is plural then I think it can be assumed that the property is an array. If that property can be resolved in a singular form to a model.

    In the below circumstance what would actually happen is that since the item is a ActiveRecord it would be pushed onto the threads array(). However, if the item where an array then it would replace the threads array. Sound good?

    PHP Code:

    // pushes: $user->addThread($threads);
    $user->threads $thread1;

    // replaces threads
    $user->threads = array($threads); 
    Although, I haven't thought of using a dynamic getter and setters for included active records. That may be worth while implementing.

  4. #4
    SitePoint Guru
    Join Date
    Jun 2006
    Posts
    638
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by oddz View Post
    PHP Code:

    // pushes: $user->addThread($threads);
    $user->threads $thread1;

    // replaces threads
    $user->threads = array($threads); 
    That's hard to see,example:
    PHP Code:

    $user
    ->news $news
    What did I do there?

  5. #5
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,194
    Mentioned
    17 Post(s)
    Tagged
    5 Thread(s)
    Yeah, after thinking about it I agree. I went ahead and actually integrated that into the active record class because its a good idea. However, you can pass any number of arguments as long as the types match the model. I thought that would be a nice little enhancement.

    PHP Code:

    $user 
    = new User(2);

    $user->addThread(
      new 
    Thread(array('title'=>'hello 1'))
      ,new 
    Thread(array('title'=>'hello 2'))
       ,new 
    Thread(array('title'=>'hello 3'))
    );

    $user->save(); 
    It isn't functioning yet but aesthetically that seems like the most user friendly way.

  6. #6
    SitePoint Guru
    Join Date
    Jun 2006
    Posts
    638
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    That works.

    Now, problem (code wise) will be making it work for new records. (add a link between a new record and an existing record )

  7. #7
    SitePoint Addict chestertondevelopment's Avatar
    Join Date
    Dec 2005
    Location
    Essex, UK
    Posts
    241
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    The syntax problem:
    PHP Code:
    $user = new User(2); 

    $thread1 = new Thread(); 
    $thread2 = new Thread(); 
    $thread3 = new Thread(); 

    $thread1->message 'thread 1 message'
    $thread2->message 'thread 2 message'
    $thread3->message 'thread 3 message'

    $user->threads $thread1
    $user->threads $thread2
    $user->threads $thread3

    $user->save(); 
    Why not just have $user->threads as a normal array so:
    PHP Code:
    $user = new User(2); 

    $thread1 = new Thread(); 
    $thread2 = new Thread(); 
    $thread3 = new Thread(); 

    $thread1->message 'thread 1 message'
    $thread2->message 'thread 2 message'
    $thread3->message 'thread 3 message'

    $user->threads[] = $thread1
    $user->threads[] = $thread2
    $user->threads[] = $thread3

    $user->save(); 
    That's how I've seen it done before. Look at the Doctrine library and its syntax for more help, it has all the features you've discussed.

  8. #8
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,194
    Mentioned
    17 Post(s)
    Tagged
    5 Thread(s)
    threads is a array in that context. However, pushing a element onto it like that results in a indirect modification of a overloaded property warning.

    Vali wrote:
    Now, problem (code wise) will be making it work for new records. (add a link between a new record and an existing record )
    Yeah, the implementation is proving to be a struggle.

  9. #9
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,194
    Mentioned
    17 Post(s)
    Tagged
    5 Thread(s)
    Not exactly sure how to handle this yet but here is the scenario.

    The save class creates two objects: ActiveRecordInsert and ActiveRecordUpdate. The Save class is in part responsible for routing a ActiveRecord to update or insert.

    The problem that i have run into is how to determine whether the object needs to be inserted or updated. Previously I was thinking that if the primary key wasn't present it could be assumed the object needs to be inserted. However, this assumption fails on the basis that the primary key is a string rather then a auto incrementing id.

    However, if the primary key is a string and check for that what would might be the best way to determine if the record needs to be updated or inserted? Under this circumstance it doesn't seem as if its possible to know unless I first run a find for it? That doesn't seem right considering it is possible to add any number of items to save.

    thanks

    Rough draft of the ActiveRecordSave class… really rough:

    PHP Code:
    class ActiveRecordSave {

        protected 
    $insert;
        protected 
    $update;

        public function 
    __construct() {    
        
            
    $this->_init();
        
        }
        
        protected function 
    _init() {
        
            
    $this->insert = new ActiveRecordInsert();
            
    $this->update = new ActiveRecordUpdate();
        
        }
        
        public function 
    addInsert(ActiveRecord $pRecord) {
        
            
    $this->insert->add($pRecord);
        
        }
        
        public function 
    addUpdate(ActiveRecord $pRecord) {
        
            
    $this->update->add($pRecord);
        
        }
        
        public function 
    add(ActiveRecord $pRecord) {
            
            
    // may be instances were primary key needs to be defined?
            
    $config ActiveRecordModelConfig::getModelConfig(get_class($pRecord));    
            
    $primaryKey $config->getPrimaryKey();
            
            if() {
            
            
            } else {
            
            
            }
        
        }



  10. #10
    SitePoint Evangelist
    Join Date
    Mar 2006
    Location
    Sweden
    Posts
    451
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    oddz:
    The way I do it is to have a method isPersisted() to determine whether to update or insert. Nine times out of then, the isPersisted() just checks if a primary key is there, and that it's numeric (that's the default implementation), and when I have objects that doesn't have one numeric primary key, I just override isPersisted().

  11. #11
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,194
    Mentioned
    17 Post(s)
    Tagged
    5 Thread(s)
    So how would you determine in a generic circumstance whether the entity already exists in the database?

    PHP Code:
    $user = new User();

    $user->id 'oddz';

    $user->save() 
    In that circumstance how would you determine in a generic fashion whether that record needs to inserted or updated?

    Its not enough to say if the the primary key is a string and is present the record should be inserted, because the same conditions could be true for a update if the primary key is not auto generated.

    A solution that doesn't seem perfect was to check whether anything has been changed. If anything has been changed then the system could defaut to updating the record. However, in the circumstance below that methodology breaks.

    PHP Code:
    $user = new User();

    $user->id 'oddz';
    $user->id 'changed_our_mind';

    $user->save() 
    In that circumstance the $user->hasChanged('id') would evaluate to true and the record would be updated rather then inserted, which would break the system.

    I could use that method and just never do the above, but that seems flawed. Although I also have a flatten method that takes all the properties in memory and removes all but the first. So then the record wouldn't have any changes.

    PHP Code:
    $user = new User();

    $user->id 'oddz';
    $user->id 'changed_our_mind';

    $user->flatten();
    $user->save() 
    Again, though seems flawed.

  12. #12
    SitePoint Evangelist
    Join Date
    Mar 2006
    Location
    Sweden
    Posts
    451
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    In that specific circumstance, I would forward it to an update, because the primary key has a value. That's the generic approach, because most of the times, my primary keys are generated, I don't create them "manually". If I have one table where I'd use a string primary key that I create in PHP before the record get's inserted, I'd change that DAO-class to do a select query based on the given id to see if it already exists in the database.

    You could even make that generic, if you find yourself in the string-primary-key-situation a lot. Something like:
    PHP Code:
    <?php
    GenericDAO
    ::save() {
      if(
    is_numeric($this->id)) {
        
    $this->update();
      } else {
        
    $this->insert();
      }
    }

    StringPkDAO::save() {
      if(
    $this->recordExists('id='$this->id)) {
        
    $this->update();
      } else {
        
    $this->insert();
      }
    }
    ?>

  13. #13
    SitePoint Addict Mastodont's Avatar
    Join Date
    Mar 2007
    Location
    Czech Republic
    Posts
    375
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    how to determine whether the object needs to be inserted or updated
    Well, this is set by some parent object, isn't it? You probably do not want to create objects without purpose.
    PHP Code:
    $parent->NewUser();
    $parent->EditUser($id); 
    You can set any flag inside.

  14. #14
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,194
    Mentioned
    17 Post(s)
    Tagged
    5 Thread(s)
    Well yes you can force it, but in the same instance I would like to be able to decide automatically. That is one of the responsibilities of the ActiveRecordSave class.

    PHP Code:
    $user = new User();
    $user->id 'oddz';

    $save = new ActiveRecordSave();
    $save->addInsert($user);
    $save->query($db); 
    This would essentially be the code necessary to save the record that would reside inside the save() method inside the ActiveRecord class.

    PHP Code:
    $save = new ActiveRecordSave();
    $save->add($this);
    return 
    $save->query(self::$db); 

  15. #15
    SitePoint Evangelist
    Join Date
    Mar 2006
    Location
    Sweden
    Posts
    451
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Mastodont:
    Good point. You do need to be a little careful there though, because if you do:
    PHP Code:
    <?php
    $user 
    = new User();
    $user->id $other_user->id;
    $user->name $other_user->name;
    $userdao->save($user);
    ?>
    You might be fooled to believe that this would lead to an update, but since no internal flag is set from the DAO, the DAO tries to insert the record and fails because a record with that id already exists. Of course, you wouldn't copy object properties like that a lot, but by doing the saving that way, you imply that the object is more of a live representation of the database record, and then you're headed down the ORM road.

  16. #16
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,194
    Mentioned
    17 Post(s)
    Tagged
    5 Thread(s)
    I'm just using separate classes so I can avoid stuffing everything in one place. The ActiveRecordInsert and ActiveRecordUpdate are both intelligent Linked Lists. It wouldn't seem right to place that code inside the ActiveRecord itself.

  17. #17
    SitePoint Addict Mastodont's Avatar
    Join Date
    Mar 2007
    Location
    Czech Republic
    Posts
    375
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by wysiwyg View Post
    ... because if you do:
    PHP Code:
    <?php
    ...
    $userdao->save($user);
    ?>
    But I would never do it You need to retain context and call
    PHP Code:
    $userdao->insert($user);
    //or
    $userdao->update($user); 

  18. #18
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,194
    Mentioned
    17 Post(s)
    Tagged
    5 Thread(s)
    So your saying there shouldn't be a router that makes the decision? I should require people either call insert or update directly?

    That would be possible, but the problem is that the system supports a hierarchical save. For example, you could find a user and include that users posts and further include the user for each post. Anything that is modified needs to be saved. its the same for adding elements. Its possible to use the system in a way similar to a gateway as previously discussed. So in that circumstance the children would need to inserted. However, everything is automatic and its rare that the save itself will only be dealing with one element but several.

    PHP Code:
    $user User::find('one',array('id'=>1,'include'=>'posts'));
    $user->addPost(new Post(),new Post());
    $user->status 2;
    $user->posts[1]->message 'changed message';
    $user->save() 
    In that circumstance what would result is twos inserts,and two update statements. The system decides whether of not to insert or update elements in the tree based on the primary key. However, when the primary key is directly defined that would break unless the root element where that item so you could send the flag.

  19. #19
    SitePoint Addict Mastodont's Avatar
    Join Date
    Mar 2007
    Location
    Czech Republic
    Posts
    375
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    If you really need common "save" method, why not to use simple approach?
    - method sends insert
    - if db returns error, then method sends update

  20. #20
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,194
    Mentioned
    17 Post(s)
    Tagged
    5 Thread(s)
    Well I can't do that either because the single insert statement could consist of multiple items to be inserted. In that circumstance I end up not knowing which one actually failed. The standard idea behind the Insert class is that when a item is added it checks to see if that item is compatible with any other nodes in the list. If it is compatible then it gets added as a child. If not then it moves on to the next item in the list or becomes the leaf. So unless I were to restructure that it wouldn't work. For example, if 8 items have been passed to the insert and they of the same class and have the same fields they are inserted together not individually. Now if that eight item insert fails how do I determine which item(s) was actually the one that failed without running each one individually in the find or something based on the primary key if present?

  21. #21
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,194
    Mentioned
    17 Post(s)
    Tagged
    5 Thread(s)
    Maybe a better example would be to show it:

    PHP Code:
    $user User::find('one',array('id'=>2,'include'=>'threads'));

    $user->threads[0]->title 'changed_this_title';
    $user->access 2;
    $user->addThread(
        new 
    Thread(
            array(
                
    'title'=>'Thread 1'
                
    ,'created'=>time()
                ,
    'status'=>0
            
    )
        )
        ,new 
    Thread(
            array(
                
    'title'=>'Thread 2'
                
    ,'created'=>time()
                ,
    'status'=>0
                
    ,'posts'=>array(
                    new 
    Post(
                        array(
                            
    'message'=>'thread 2 message'
                            
    ,'created'=>time()
                        )
                    )
                )
            )
        )
        ,new 
    Thread(
            array(
                
    'title'=>'Thread 3'
                
    ,'created'=>time()
                ,
    'posts'=>array(
                    new 
    Post(
                        array(
                            
    'message'=>'thread 3 message'
                            
    ,'created'=>time()
                        )
                    )
                )
            )
        )
    );
    $user->save(); 
    HTML Code:
    INSERT INTO threads (title,status,created) VALUES (?,?,FROM_UNIXTIME(?)),(?,?,FROM_UNIXTIME(?))
    
    Array
    (
        [0] => Array
            (
                [0] => Thread 2
                [1] => 0
                [2] => 1239102490
            )
    
        [1] => Array
            (
                [0] => Thread 1
                [1] => 0
                [2] => 1239102490
            )
    
    )
    1
    
    INSERT INTO threads (title,created) VALUES (?,FROM_UNIXTIME(?))
    
    Array
    (
        [0] => Array
            (
                [0] => Thread 3
                [1] => 1239102490
            )
    
    )
    1
    
    INSERT INTO posts (message,created) VALUES (?,?),(?,?)
    
    Array
    (
        [0] => Array
            (
                [0] => thread 3 message
                [1] => 1239102490
            )
    
        [1] => Array
            (
                [0] => thread 2 message
                [1] => 1239102490
            )
    
    )
    1
    
    UPDATE users SET access = ? WHERE id = ? LIMIT 1
    
    Array
    (
        [0] => 2
        [1] => 2
    )
    1
    
    UPDATE threads SET title = ? WHERE id = ? LIMIT 1
    
    Array
    (
        [0] => changed_this_title
        [1] => 2
    )
    1
    The foreign key binding isn't functioning yet but you should be able to grasp the problem from that example. There is no way to logically pass a flag to the inner elements of the tree here. There needs to be some way of automatically determining whether to save or insert that can hold up in both numerical or string based primary key scenarios without a flag.

  22. #22
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,194
    Mentioned
    17 Post(s)
    Tagged
    5 Thread(s)
    Neat feature? - have you seen this before?

    The idea that if the the parent item(at any level) is not active and needs to be inserted it will be inserted in isolation to grab the relation key after the insert if its the primary key so that it can be automatically applied to the dependencies.

    In this example the project root element hasn't been created yet. However, the system knows to isolate it regardless of whether it wa sa child or the root if it has items. In this case the project has bids that need the primary key. So system will automatically insert that item in isolation and bind the foreign key to the bids at any level.

    PHP Code:
    $project = new Project(
        array(
            
    'created'=>time()
            ,
    'user'=>new User(2)
            ,
    'range'=>new Range(4)
            ,
    'category'=>new Category(6)
            ,
    'title'=>'My new project'
            
    ,'message'=>'hello'
            
    ,'status'=>1
            
    ,'bids'=>array(
                new 
    Bid(array(
                    
    'user'=>new User(3)
                    ,
    'message'=>'blah'
                    
    ,'status'=>1
                    
    ,'created'=>time()
                    ,
    'price'=>480
                
    ))
                ,new 
    Bid(array(
                    
    'user'=>new User(4)
                    ,
    'message'=>'blah 2'
                    
    ,'status'=>1
                    
    ,'created'=>time()
                    ,
    'price'=>1300
                
    ))
            )
        )
    ); 
    HTML Code:
    INSERT INTO projects (user_id,category_id,range_id,title,message,status,created) VALUES (?,?,?,?,?,?,FROM_UNIXTIME(?))1
    
    Array
    (
        [0] => Array
            (
                [0] => 2
                [1] => 6
                [2] => 4
                [3] => My new project
                [4] => hello
                [5] => 1
                [6] => 1239182499
            )
    
    )
    1
    
    INSERT INTO bids (user_id,project_id,price,message,status,created) VALUES (?,?,?,?,?,FROM_UNIXTIME(?)),(?,?,?,?,?,FROM_UNIXTIME(?))
    
    Array
    (
        [0] => Array
            (
                [0] => 4
                [1] => 300
                [2] => 1300
                [3] => blah 2
                [4] => 1
            )
    
        [1] => Array
            (
                [0] => 3
                [1] => 300
                [2] => 480
                [3] => blah
                [4] => 1
            )
    
    )
    1
    
    Array
    (
    )
    1

  23. #23
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,194
    Mentioned
    17 Post(s)
    Tagged
    5 Thread(s)
    Maybe a better example would be saving through the user and also changing the user state.

    PHP Code:
    $user User::find('one',array('id'=>2,'include'=>'projects'));

    $user->pwd '67JkHyuI';
    $user['projects'][] = new Project(
        array(
            
    'created'=>time()
            ,
    'range'=>new Range(4)
            ,
    'category'=>new Category(6)
            ,
    'title'=>'My new project'
            
    ,'message'=>'hello'
            
    ,'status'=>1
            
    ,'bids'=>array(
                new 
    Bid(array(
                    
    'user'=>new User(3)
                    ,
    'message'=>'blah'
                    
    ,'status'=>1
                    
    ,'created'=>time()
                    ,
    'price'=>480
                
    ))
                ,new 
    Bid(array(
                    
    'user'=>new User(4)
                    ,
    'message'=>'blah 2'
                    
    ,'status'=>1
                    
    ,'created'=>time()
                    ,
    'price'=>1300
                
    ))
            )
        )
    );

    $user->save(); 
    HTML Code:
    INSERT INTO projects (user_id,category_id,range_id,title,message,status,created) VALUES (?,?,?,?,?,?,FROM_UNIXTIME(?))1
    
    Array
    (
        [0] => Array
            (
                [0] => 2
                [1] => 6
                [2] => 4
                [3] => My new project
                [4] => hello
                [5] => 1
                [6] => 1239183247
            )
    
    )
    1
    
    INSERT INTO bids (user_id,project_id,price,message,status,created) VALUES (?,?,?,?,?,FROM_UNIXTIME(?)),(?,?,?,?,?,FROM_UNIXTIME(?))
    
    Array
    (
        [0] => Array
            (
                [0] => 4
                [1] => 300
                [2] => 1300
                [3] => blah 2
                [4] => 1
            )
    
        [1] => Array
            (
                [0] => 3
                [1] => 300
                [2] => 480
                [3] => blah
                [4] => 1
            )
    
    )
    1
    
    UPDATE users SET pwd = AES_ENCRYPT(?,SHA1(CONCAT(?,FROM_UNIXTIME(created)))) WHERE id = ? LIMIT 1
    
    Array
    (
        [0] => 67JkHyuI
        [1] => zmysalt
        [2] => 2
    )
    1

  24. #24
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,194
    Mentioned
    17 Post(s)
    Tagged
    5 Thread(s)
    Another feature:

    Scenario: A user needs to hidden along with their posts, projects, threads and bids.

    PHP Code:
    $user User::find(
        
    'one'
        
    ,array(
            
    'id'=>1
            
    ,'include'=>array('projects','bids','threads','posts')
        )
        ,array(
    'require'=>false)
        ,array(
    'require'=>false)
        ,array(
    'require'=>false)
        ,array(
    'require'=>false)
    );

    $user['status'] = 0;
    if(
    $user->projects) {
        foreach(
    $user['projects'] as $project) {
            
    $project['status'] = 0;
        }
    }

    if(
    $user->bids) {
        foreach(
    $user['bids'] as $bid) {
            
    $bid['status'] = 0;
        }
    }

    if(
    $user->threads) {
        foreach(
    $user['threads'] as $thread) {
            
    $thread['status'] = 0;
        }
    }

    if(
    $user->posts) {
        foreach(
    $user['posts'] as $post) {
            
    $post['status'] = 0;
        }
    }

    $user->save(); 
    output:
    HTML Code:
    UPDATE users SET status = ? WHERE id = ? LIMIT 1
    
    Array
    (
        [0] => 0
        [1] => 1
    )
    1
    
    UPDATE projects SET status = ? WHERE id = ? OR id = ? OR id = ? LIMIT 3
    
    Array
    (
        [0] => 0
        [1] => 5
        [2] => 13
        [3] => 4
    )
    1
    
    UPDATE bids SET status = ? WHERE id = ? OR id = ? OR id = ? OR id = ? LIMIT 4
    
    Array
    (
        [0] => 0
        [1] => 5
        [2] => 8
        [3] => 9
        [4] => 4
    )
    1
    
    UPDATE threads SET status = ? WHERE id = ? LIMIT 1
    
    Array
    (
        [0] => 0
        [1] => 1
    )
    1
    
    UPDATE posts SET status = ? WHERE id = ? OR id = ? OR id = ? LIMIT 3
    
    Array
    (
        [0] => 0
        [1] => 2
        [2] => 3
        [3] => 1
    )
    1

  25. #25
    Spirit Coder allspiritseve's Avatar
    Join Date
    Dec 2002
    Location
    Ann Arbor, MI (USA)
    Posts
    648
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    What exactly is the appeal of ActiveRecord? It just seems so much cleaner to me to separate out database code into a Gateway or Mapper.


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •