0

I've got two tables: step and links joined 1:n. I'm aiming to maintain the links through the step objects. I retrieve all steps from the database and populate the relation with the links table. I persist the step object containing a collection of links to JSON and return it to the front end using REST.

That means that if a step is linked or unlinked to another step in the front end I send the entire step back to the backend including a collection of links. In the back end I use the following code:

public function put($processStep) {
        if (isset($processStep['Processesid']) && isset($processStep['Coordx']) && isset($processStep['Coordy'])) {
            $p = $this->query->findPK($processStep['Id']);

            $p->setId($processStep['Id']);
            $p->setProcessesid($processStep['Processesid']);
            if (isset($processStep['Flowid'])) $p->setFlowid($processStep['Flowid']);
            if (isset($processStep['Applicationid'])) $p->setApplicationid($processStep['Applicationid']);
            $p->setCoordx($processStep['Coordx']);
            $p->setCoordy($processStep['Coordy']);

            $links = $p->getLinksRelatedByFromstep();
            $links->clear();

            foreach ($processStep['Links'] as $link) {
                if (!isset($link['Linkid'])) {
                    $newLink = new \Link();

                    $newLink->setFromstep($link['Fromstep']);
                    $newLink->setTostep($link['Tostep']);

                    $links->prepend($newLink);
                }
            }

            $p->save();

            return $p;
        } else {
            throw new Exceptions\ProcessStepException("Missing mandatory fields.", 1);
        }
    }

I'm basically deleting every link from a step and based upon the request object I recreate the links. This saves me the effort to compare what links are deleted and added. The insert work like a charm Propel automatically creates the new links. Thing is it doesn't delete like it inserts. I've checked the object that is being persisted ($p) and I see the link being deleted but in the MySQL log there is absolutely no action being performed by Propel. It looks like a missing member from the link collection doesn't trigger a dirty flag or something like that.

Maybe I'm going about this the wrong way, I hope someone can offer some advice.

Thanks

Remco
  • 172
  • 9
  • I don; t see any calls to delete() anywehere in your code. I only see you using clear(). clear() clears any criteria / filters you applied to the collection, it will not actually delete anything. – chocochaos Mar 03 '17 at 14:08
  • The $links var is an instance of an ObjectCollection, the clear function removes the links from the collection (according to the API docs) breaking the relations between a step and its links, at least that was my reasoning :). By breaking the relation I was hoping that Propel would trigger an implicit delete for the missing link objects just like it triggers an insert for links that are added to the collection. If I'm to use explicit delete calls I need to start comparing links from the step posted to the backend and the one in the database what I was hoping to prevent. Thanks for the input! – Remco Mar 03 '17 at 15:40

2 Answers2

1

To delete records, you absolutely always have to use delete. The diff method on the collection is extremely helpful when determining which entities need added, updated, and deleted.

Ben
  • 713
  • 4
  • 12
  • Thanks Ben, that's all I needed to know. Shame though I was hoping it was intuïtive enough to handle deletes like inserts – Remco Mar 05 '17 at 12:34
0

Thanks to Ben I got on the right track, an explicit call for a delete is not needed. I came across a function called: setRelatedBy(ObjectCollection o) I use this function to provide a list of related objects, new objects are interpreted as inserts and omissions are interpreted as deletes.

I didn't find any relevant documentation regarding the problem so here's my code:

$p = $this->query->findPK($processStep['Id']);

            $p->setId($processStep['Id']);
            $p->setProcessesid($processStep['Processesid']);
            $p->setCoordx($processStep['Coordx']);
            $p->setCoordy($processStep['Coordy']);
            if (isset($processStep['Flowid'])) $p->setFlowid($processStep['Flowid']);
            if (isset($processStep['Applicationid'])) $p->setApplicationid($processStep['Applicationid']);

            //Get related records, same as populaterelation
            $currentLinks = $p->getLinksRelatedByFromstep();
            $links =  new \Propel\Runtime\Collection\ObjectCollection();

            //Check for still existing links add to new collection if so.
            //This is because creating a new Link instance and setting columns marks the object as dirty creating an exception due to duplicate keys
            foreach ($currentLinks as $currentLink) {
                foreach ($processStep['Links'] as $link) {
                    if (isset($link['Linkid']) && $currentLink->getLinkid() == $link['Linkid']) {
                        $links->prepend($currentLink);

                        break;
                    }
                }
            }

            //Add new link objects
            foreach ($processStep['Links'] as $link) {
                if (!isset($link['Linkid'])) {
                    $newLink = new \Link();

                    $newLink->setFromstep($link['Fromstep']);
                    $newLink->setTostep($link['Tostep']);

                    $links->prepend($newLink);
                }

            }

            //Replace the collection and save the processstep.
            $p->setLinksRelatedByFromstep($links);
            $p->save();
Remco
  • 172
  • 9