简体   繁体   中英

append a related Model in Phalcon

I wrote a vcard class with Phalcon in PHP. The vCard Model is initialized like this.

// Inside the BS_VCard class
public function initialize(){
    $this->hasMany("id","BS_VCardElement","vCardId",array(
        "alias" => "elements",
        'foreignKey' => array(
            'action' => Phalcon\Mvc\Model\Relation::ACTION_CASCADE
        )
    ));
}

Its elements are initialized like this

// Inside the BS_VCardElement class
public function initialize(){
    $this->belongsTo("vCardId","BS_VCard","id",array("alias" => "vCard"));
    ...
}

If a user reads a vCard and adds another element, it doesn't work as expected. To simplify the use I added some fascade methods like this

public function addDateOfBirth($date){
    $element = new BS_VCardElement();
    $element->setName("BDAY");
    $element->addValue($date);
    // This doesn't work
    $this->elements[] = $element;
}

The Docs/Storing related records do not explain how to append fresh data like this to the related table.

I also tried this

$this->elements[] = array_merge($this->elements,array($element));

But the save method seems to ignore the added element. Save() returns true.

This question has been asked a couple of months ago but since I ran into a similar issue I decided to share my results anyway.

And here's what I found. Lower case aliases ('elements') don't seem to work whereas upper case aliases ('Elements') do.

To add one element you can do this;

$this->Elements = $element;

To add multiple elements you can do this;

$elements = array($element1, $element2);
$this->Elements = $elements;

After that you have to save the vcard before accessing the elements again. If you don't, phalcon will just return a result set with only the elements already in the database. (Not sure if this can be changed somehow.)

And here's the documentation (where all this is not mentioned): http://docs.phalconphp.com/en/latest/reference/models.html#storing-related-records

According to the Phalcon source code , the Resultset object is immutible.

/**
 * Resultsets cannot be changed. It has only been implemented to 
 * meet the definition of the ArrayAccess interface
 *
 * @param int index
 * @param \Phalcon\Mvc\ModelInterface value
 */
public function offsetSet(var index, var value)
{
    throw new Exception("Cursor is an immutable ArrayAccess object");
}

It appears that replacing the element with an array is the only way to implement an "append" or modification of the resultset (other than delete which IS supported).

Of course this breaks the \\Phalcon\\Mvc\\Model::_preSaveRelatedRecords() because the function ignores the class properties and refetches the related from the Model Manager (and resets the model::$element attribute at the end).

I feel frustrated by this because appending objects to a collection seems like a very common task and not having a clear method in which to add new items to a parent seems like a design flaw.

I think related elements might have some magic functionality invoked when you set the properties, so simply using $this->elements[] (evidently) doesn't work. Perhaps try re-setting the entire variable:

public function addDateOfBirth($date){
    $element = new BS_VCardElement();
    $element->setName("BDAY");
    $element->addValue($date);

    $elements = $this->elements;
    $elements[] = $element;
    $this->elements = $elements;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM