Jackalope\Transport\DoctrineDBAL\Client::syncReferences PHP Method

syncReferences() private method

private syncReferences ( array $referencesToUpdate )
$referencesToUpdate array
    private function syncReferences(array $referencesToUpdate)
    {
        if ($referencesToUpdate) {
            // do not update references that are going to be deleted anyways
            $toUpdate = array_diff(array_keys($referencesToUpdate), array_keys($this->referencesToDelete));
            try {
                foreach ($this->referenceTables as $table) {
                    $query = "DELETE FROM {$table} WHERE source_id IN (?)";
                    $this->executeChunkedUpdate($query, $toUpdate);
                }
            } catch (DBALException $e) {
                throw new RepositoryException('Unexpected exception while cleaning up after saving', $e->getCode(), $e);
            }
            $updates = array();
            foreach ($toUpdate as $nodeId) {
                $references = $referencesToUpdate[$nodeId];
                foreach ($references['properties'] as $name => $data) {
                    foreach ($data['values'] as $value) {
                        $targetId = $this->getSystemIdForNode($value);
                        if (false === $targetId) {
                            if (PropertyType::REFERENCE === $data['type']) {
                                throw new ReferentialIntegrityException(sprintf('Trying to store reference to non-existant node with path "%s" in node "%s" "%s"', $value, $references['path'], $name));
                            }
                            continue;
                        }
                        $key = $targetId . '-' . $nodeId . '-' . $name;
                        // it is valid to have multiple references to the same node in a multivalue
                        // but it is not desired to store duplicates in the database
                        $updates[$key] = array('type' => $data['type'], 'data' => array('source_id' => $nodeId, 'source_property_name' => $name, 'target_id' => $targetId));
                    }
                }
            }
            foreach ($updates as $update) {
                $this->getConnection()->insert($this->referenceTables[$update['type']], $update['data']);
            }
        }
        // TODO on RDBMS that support deferred FKs we could skip this step
        if ($this->referencesToDelete) {
            $params = array_keys($this->referencesToDelete);
            // remove all PropertyType::REFERENCE with a source_id on a deleted node
            try {
                $query = "DELETE FROM phpcr_nodes_references WHERE source_id IN (?)";
                $this->executeChunkedUpdate($query, $params);
            } catch (DBALException $e) {
                throw new RepositoryException('Unexpected exception while cleaning up deleted nodes', $e->getCode(), $e);
            }
            // ensure that there are no PropertyType::REFERENCE pointing to nodes that will be deleted
            // Note: due to the outer join we cannot filter on workspace_name, but this is ok
            // since within a transaction there can never be missing referenced nodes within the current workspace
            // make sure the target node is not in the list of nodes being deleted, to allow deletion in same request
            $query = 'SELECT DISTINCT r.target_id
            FROM phpcr_nodes_references r
                LEFT OUTER JOIN phpcr_nodes n ON r.target_id = n.id
            WHERE r.target_id IN (?)';
            if ($this->getConnection()->getDatabasePlatform() instanceof SqlitePlatform) {
                $missingTargets = array();
                foreach (array_chunk($params, self::SQLITE_MAXIMUM_IN_PARAM_COUNT) as $chunk) {
                    $stmt = $this->getConnection()->executeQuery($query, array($chunk), array(Connection::PARAM_INT_ARRAY));
                    $missingTargets = array_merge($missingTargets, $stmt->fetchAll(\PDO::FETCH_COLUMN));
                }
            } else {
                $stmt = $this->getConnection()->executeQuery($query, array($params), array(Connection::PARAM_INT_ARRAY));
                $missingTargets = $stmt->fetchAll(\PDO::FETCH_COLUMN);
            }
            if ($missingTargets) {
                $paths = array();
                foreach ($missingTargets as $id) {
                    if (isset($this->referencesToDelete[$id])) {
                        $paths[] = $this->referencesToDelete[$id];
                    }
                }
                throw new ReferentialIntegrityException("Cannot delete '" . implode("', '", $paths) . "': A reference points to this node or a subnode");
            }
            // clean up all references
            try {
                foreach ($this->referenceTables as $table) {
                    $query = "DELETE FROM {$table} WHERE target_id IN (?)";
                    $this->executeChunkedUpdate($query, $params);
                }
            } catch (DBALException $e) {
                throw new RepositoryException('Unexpected exception while cleaning up deleted nodes', $e->getCode(), $e);
            }
        }
    }