Jackalope\Node::parseData PHP Метод

parseData() приватный Метод

Initialize or update this object with raw data from backend.
См. также: Node::__construct()
См. также: Node::refresh()
private parseData ( array $rawData, boolean $update, boolean $keepChanges = false )
$rawData array in the format as returned from Jackalope\Transport\TransportInterface
$update boolean whether to initialize this object or update
$keepChanges boolean only used if $update is true, same as $keepChanges in refresh()
    private function parseData($rawData, $update, $keepChanges = false)
    {
        //TODO: refactor to use hash array instead of stdClass struct
        if ($update) {
            // keep backup of old state so we can remove what needs to be removed
            $oldNodes = array_flip(array_values($this->nodes));
            $oldProperties = $this->properties;
        }
        /*
         * we collect all nodes coming from the backend. if we update with
         * $keepChanges, we use this to update the node list rather than losing
         * reorders
         *
         * properties are easy as they are not ordered.
         */
        $nodesInBackend = array();
        foreach ($rawData as $key => $value) {
            $node = false;
            // reset to avoid trouble
            if (is_object($value)) {
                // this is a node. add it if
                if (!$update || !$keepChanges || isset($oldNodes[$key]) || !($node = $this->objectManager->getCachedNode($this->path . '/' . $key))) {
                    // for all those cases, if the node was moved away or is deleted in current session, we do not add it
                    if (!$this->objectManager->isNodeMoved($this->path . '/' . $key) && !$this->objectManager->isNodeDeleted($this->path . '/' . $key)) {
                        // otherwise we (re)load a node from backend but a child has been moved away already
                        $nodesInBackend[] = $key;
                    }
                }
                if ($update) {
                    unset($oldNodes[$key]);
                }
            } else {
                //property or meta information
                /* Property type declarations start with :, the value then is
                 * the type string from the NodeType constants. We skip that and
                 * look at the type when we encounter the value of the property.
                 *
                 * If its a binary data, we only get the type declaration and
                 * no data. Then the $value of the type declaration is not the
                 * type string for binary, but the number of bytes of the
                 * property - resp. array of number of bytes.
                 *
                 * The magic property ::NodeIteratorSize tells this node has no
                 * children. Ignore that info for now. We might optimize with
                 * this info once we do prefetch nodes.
                 */
                if (0 === strpos($key, ':')) {
                    if ((is_int($value) || is_array($value)) && $key != '::NodeIteratorSize') {
                        // This is a binary property and we just got its length with no data
                        $key = substr($key, 1);
                        if (!isset($rawData->{$key})) {
                            $binaries[$key] = $value;
                            if ($update) {
                                unset($oldProperties[$key]);
                            }
                            if (isset($this->properties[$key])) {
                                // refresh existing binary, this will only happen in update
                                // only update length
                                if (!($keepChanges && $this->properties[$key]->isModified())) {
                                    $this->properties[$key]->_setLength($value);
                                    if ($this->properties[$key]->isDirty()) {
                                        $this->properties[$key]->setClean();
                                    }
                                }
                            } else {
                                // this will always fall into the creation mode
                                $this->_setProperty($key, $value, PropertyType::BINARY, true);
                            }
                        }
                    }
                    //else this is a type declaration
                    //skip this entry (if its binary, its already processed
                    continue;
                }
                if ($update && array_key_exists($key, $this->properties)) {
                    unset($oldProperties[$key]);
                    $prop = $this->properties[$key];
                    if ($keepChanges && $prop->isModified()) {
                        continue;
                    }
                } elseif ($update && array_key_exists($key, $this->deletedProperties)) {
                    if ($keepChanges) {
                        // keep the delete
                        continue;
                    } else {
                        // restore the property
                        $this->properties[$key] = $this->deletedProperties[$key];
                        $this->properties[$key]->setClean();
                        // now let the loop update the value. no need to talk to ObjectManager as it
                        // does not store property deletions
                    }
                }
                switch ($key) {
                    case 'jcr:index':
                        $this->index = $value;
                        break;
                    case 'jcr:primaryType':
                        $this->primaryType = $value;
                        // type information is exposed as property too,
                        // although there exist more specific methods
                        $this->_setProperty('jcr:primaryType', $value, PropertyType::NAME, true);
                        break;
                    case 'jcr:mixinTypes':
                        // type information is exposed as property too,
                        // although there exist more specific methods
                        $this->_setProperty($key, $value, PropertyType::NAME, true);
                        break;
                        // OPTIMIZE: do not instantiate properties until needed
                    // OPTIMIZE: do not instantiate properties until needed
                    default:
                        if (isset($rawData->{':' . $key})) {
                            /*
                             * this is an inconsistency between jackrabbit and
                             * dbal transport: jackrabbit has type name, dbal
                             * delivers numeric type.
                             * we should eventually fix the format returned by
                             * transport and either have jackrabbit transport
                             * do the conversion or let dbal store a string
                             * value instead of numerical.
                             */
                            $type = is_numeric($rawData->{':' . $key}) ? $rawData->{':' . $key} : PropertyType::valueFromName($rawData->{':' . $key});
                        } else {
                            $type = $this->valueConverter->determineType($value);
                        }
                        $this->_setProperty($key, $value, $type, true);
                        break;
                }
            }
        }
        if ($update) {
            if ($keepChanges) {
                // we keep changes. merge new nodes to the right place
                $previous = null;
                $newFromBackend = array_diff($nodesInBackend, array_intersect($this->nodes, $nodesInBackend));
                foreach ($newFromBackend as $name) {
                    $pos = array_search($name, $nodesInBackend);
                    if (is_array($this->originalNodesOrder)) {
                        // update original order to send the correct reorderings
                        array_splice($this->originalNodesOrder, $pos, 0, $name);
                    }
                    if ($pos === 0) {
                        array_unshift($this->nodes, $name);
                    } else {
                        // do we find the predecessor of the new node in the list?
                        $insert = array_search($nodesInBackend[$pos - 1], $this->nodes);
                        if (false !== $insert) {
                            array_splice($this->nodes, $insert + 1, 0, $name);
                        } else {
                            // failed to find predecessor, add to the end
                            $this->nodes[] = $name;
                        }
                    }
                }
            } else {
                // discard changes, just overwrite node list
                $this->nodes = $nodesInBackend;
                $this->originalNodesOrder = null;
            }
            foreach ($oldProperties as $name => $property) {
                if (!($keepChanges && $property->isNew())) {
                    // may not call remove(), we don't want another delete with
                    // the backend to be attempted
                    $this->properties[$name]->setDeleted();
                    unset($this->properties[$name]);
                }
            }
            // notify nodes that where not received again that they disappeared
            foreach ($oldNodes as $name => $index) {
                if ($this->objectManager->purgeDisappearedNode($this->path . '/' . $name, $keepChanges)) {
                    // drop, it was not a new child
                    if ($keepChanges) {
                        // otherwise we overwrote $this->nodes with the backend
                        $id = array_search($name, $this->nodes);
                        if (false !== $id) {
                            unset($this->nodes[$id]);
                        }
                    }
                }
            }
        } else {
            // new node loaded from backend
            $this->nodes = $nodesInBackend;
        }
    }