4.8. Creating, Modifying, and Saving Relateds

Let's say you fetch a blog record and want to work with its related records and collections. All you need to do is attempt to get or set the related property; if it exists at the database, it will be populate for you, but if it does not, you will get a fresh new record or collection to work with.

<?php
/**
 * @var Solar_Sql_Model_Catalog $model
 */

// get the blog item
$item = $model->blogs->fetch(1);

// look at its related summary record. this will
// create a new summary record on-the-fly if one
// does not already exist.
echo htmlspecialchars($item->summary->last_comment_at);

// loop through its comments collection. this will
// create a new empty collection if one does not
// already exist.
if ($item->comments->isEmpty()) {
    echo "No comments.";
} else {
    foreach ($item->comments as $n => $comment) {
        echo "Comment $n is by "
           . htmlspecialchars($comment->author)
           . "<br />";
    }
}

However, a belongs-to related will *not* automatically populate itself. Because the related record is the superior one, and the native record is subordinate, you will need to create and attach the belongs-to on your own.

<?php
/**
 * @var Solar_Sql_Model_Catalog $model
 */

// get the blog item
$item = $model->blogs->fetch(1);

// blog belongsTo author ... do we have an author here?
if (! $item->author) {
    $author = $model->authors->fetchByHandle('pmjones');
    $item->author = $author;
}

For has-many collections, you can append to them directly instead of fetching a new record from the related model and attaching it.

<?php
/**
 * @var Solar_Sql_Model_Catalog $model
 * @var Acme_Model_Blog_Record $item
 */
if (! $item->comments) {
    $item->setNewRelated('comments');
}

// you could do this to add a new comment:
$comment = $model->comments->fetchNew();
$comment->body = "A new comment.";
$item->comments[] = $comment;

// but this may be easier:
$comment = $item->comments->appendNew(array(
    'body' => "A new comment.",
));

To save a record and all its subordinate records and collections, invoke the save() method on that record. This will *not* save superior belongs-to records; those, you must save on your own.

<?php
/**
 * @var Acme_Model_Blog_Record $item
 */

// set a value on the related summary record
$item->summary->last_comment_at = date('Y-m-d H:i:s');

// save the blog record, including all subordinate
// has-one, has-many, and has-many-through relateds
$item->save();

// the $item->author property will not be saved;
// it is a superior belongs-to related, not a subordinate

4.8.1. Automatic Foreign Key Management

For has-one and has-many relateds, the Solar model system will automatically set the proper foreign keys in the related records and collections for you when you save the record.

However, when you have a new belongs-to related, you must save it yourself before you attempt to save the subordinate record. This is because the superior record to which the subordinate record belongs does not have a primary key yet. If you try to save a record where the record it belongs to does not exist in the database, it will throw an exception.

Finally, for has-many-through relationships, the Solar model system manages the association mapping table for you. All you need to do is add to the foreign collection on the record. New items in the collection that don't exist yet will be created if necessary. Items removed from the collection will be removed from the mapping, but not from the foreign table.

<?php
/**
 * @var Solar_Sql_Model_Catalog $model
 * @var Acme_Model_Blog_Record $item
 */

// get all the existing tags
$tags = $model->tags->fetchAll();

// add the first three tags in the tags table
// to the blog item
$item->tags[0] = $tags[0];
$item->tags[1] = $tags[1];
$item->tags[2] = $tags[2];

// save the blog item; solar will manage the taggings table
// for you automatically, adding and removing mappings in
// that table as needed.
$item->save();

4.8.2. Independent Operation

You don't have to operate on relateds through the record if you don't want to. You can always do a model fetch on your own and work with that record or collection independently. However, you will need to manage foreign keys yourself.

<?php
/**
 * @var Solar_Sql_Model_Catalog $model
 */

// the blog ID to work with
$blog_id = 1;

// get the comments on the blog ID
$comments = $model->comments->fetchAll(array(
    'where' => array(
        'blog_id = ?' => $blog_id,
    ),
));

// add a new comment
$comments->appendNew(array(
    'body' => 'This is my new comment.',
    'blog_id' => $blog_id,
));

// save the collection
$comments->save();


Local