/** * Push all recorded changes to the backend. * * The order is important to avoid conflicts * 1. remove nodes * 2. move nodes * 3. add new nodes * 4. commit any other changes * * @return void */ public function save() { // TODO: start transaction // remove nodes/properties foreach ($this->itemsRemove as $path => $dummy) { $this->transport->deleteNode($path); } // move nodes/properties foreach ($this->nodesMove as $src => $dst) { $this->transport->moveNode($src, $dst); } // filter out sub-nodes and sub-properties since the top-most nodes that are // added will create all sub-nodes and sub-properties at once $nodesToCreate = $this->itemsAdd; foreach ($nodesToCreate as $path => $dummy) { foreach ($nodesToCreate as $path2 => $dummy) { if (strpos($path2, $path . '/') === 0) { unset($nodesToCreate[$path2]); } } } // create new nodes foreach ($nodesToCreate as $path => $dummy) { $item = $this->getNodeByPath($path); if ($item instanceof \PHPCR\NodeInterface) { $this->transport->storeNode($path, $item->getProperties(), $item->getNodes()); } elseif ($item instanceof \PHPCR\PropertyInterface) { $this->transport->storeProperty($path, $item); } else { throw new \UnexpectedValueException('Unknown type ' . get_class($item)); } } // loop through cached nodes and commit all dirty and set them to clean. if (isset($this->objectsByPath['Node'])) { foreach ($this->objectsByPath['Node'] as $path => $item) { if ($item->isModified()) { if ($item instanceof \PHPCR\NodeInterface) { foreach ($item->getProperties() as $propertyName => $property) { if ($property->isModified()) { $this->transport->storeProperty($property->getPath(), $property); } } } elseif ($item instanceof \PHPCR\PropertyInterface) { if ($item->getNativeValue() === null) { $this->transport->deleteProperty($path); } else { $this->transport->storeProperty($path, $item); } } else { throw new \UnexpectedValueException('Unknown type ' . get_class($item)); } } } } // TODO: have a davex client method to commit transaction // commit changes to the local state foreach ($this->itemsRemove as $path => $dummy) { unset($this->objectsByPath['Node'][$path]); } /* local state is already updated in moveNode foreach ($this->nodesMove as $src => $dst) { $this->objectsByPath[$dst] = $this->objectsByPath[$src]; unset($this->objectsByPath[$src]); } */ foreach ($this->itemsAdd as $path => $dummy) { $item = $this->getNodeByPath($path); $item->confirmSaved(); } if (isset($this->objectsByPath['Node'])) { foreach ($this->objectsByPath['Node'] as $path => $item) { if ($item->isModified()) { $item->confirmSaved(); } } } $this->itemsRemove = array(); $this->nodesMove = array(); $this->itemsAdd = array(); }