예제 #1
0
 public function testStaticGetNode()
 {
     $node = $this->node();
     EncoderNode::addNode($node);
     $this->assertEquals($node, EncoderNode::getNode('nodes'));
     $this->assertEquals($node, EncoderNode::getNode('node'));
     $this->assertNull(EncoderNode::getNode('unknown'));
 }
예제 #2
0
 /**
  * @param string $nodeName
  * @param array $nodeData
  * @param EncoderOptions $options
  * @param EncoderNode|null $parentNode
  * @param object $parentObject
  * @param array $parentNodeData
  * @return array[]
  */
 protected function _decodeNode($nodeName, $nodeData, EncoderOptions $options, EncoderNode $parentNode = null, $parentObject = null, $parentNodeData = null)
 {
     $proxyNode = EncoderNode::getNode($nodeName);
     $isSingleNode = EncoderNode::isSingleNode($nodeName);
     $nodeDataChild = $nodeData[$nodeName];
     if ($isSingleNode) {
         $nodeDataChild = array($nodeDataChild);
     }
     $addAfterDecode = true;
     $addAfterAttributes = true;
     if ($parentNode) {
         $childNode = $parentNode->getChild($nodeName);
         $childNodeSetter = $childNode->getSetter();
         $addAfterDecode = $childNodeSetter->setAfterChildren();
         $addAfterAttributes = $childNodeSetter->setAfterAttributes();
     }
     $objects = array();
     $decodedChildren = array();
     $nodeIndex = 0;
     foreach ($nodeDataChild as $nodeDataItem) {
         $nodeChildType = $proxyNode->getObjectType($parentObject, $nodeDataItem);
         $nodeType = $nodeChildType !== null && !empty($nodeChildType) ? $nodeChildType : $proxyNode->getDefaultType();
         $type = $proxyNode->getType($nodeType);
         $variableCollection = $type->getVariableCollection();
         $preNodeStaticOptions = array(NodeAccessor::VARIABLE_NODE => $type, NodeAccessor::VARIABLE_PARENT => $parentObject);
         // call node methods. It can be useful when you want to change the outcome of the node data in the node
         // that does not have a certain setter but is used in other ways
         $preNodeSetterVariables = $variableCollection->getPreNodeSetterVariables();
         foreach ($preNodeSetterVariables as $preNodeSetterVariable) {
             $variableId = $preNodeSetterVariable->getId();
             $variableIsset = isset($nodeDataItem[$variableId]);
             $preNodeSetter = $preNodeSetterVariable->getPreNodeSetter();
             if (isset($nodeDataItem[$variableId]) || $preNodeSetter->alwaysExecute()) {
                 $setterOptions = array_merge($preNodeStaticOptions, array(NodeAccessor::VARIABLE_NODE_DATA => $nodeDataItem, NodeAccessor::VARIABLE_NAME => $variableId, NodeAccessor::VARIABLE_VALUE => $variableIsset ? $nodeDataItem[$variableId] : null));
                 if ($newNode = $preNodeSetter->apply($setterOptions)) {
                     $nodeDataItem = $newNode;
                 }
             }
         }
         // add the full decoded node data to a node array
         $decodedChildren[] = $nodeDataItem;
         // if the node needs to create a new object
         if ($type->needsObject()) {
             $nodeClassName = $type->getObjectClassName();
             // load the class object this node should decode into
             if (!class_exists($nodeClassName)) {
                 $type->loadObject();
                 if (!class_exists($nodeClassName)) {
                     throw new EncoderException(sprintf('Tried loading class "%s" so it can be decoded, this failed however because it\'s not available. You either mistyped the name of the class in the node or the "loadObject()" method didn\'t load the correct file with the class', $nodeClassName));
                 }
             }
             $requiredVariables = $this->getRequiredConstructorVariables($nodeClassName);
             $requiredVariableValues = array();
             foreach ($requiredVariables as $variable) {
                 if (!array_key_exists($variable, $nodeDataItem)) {
                     throw new EncoderException(sprintf('Variable "%s" for "%s" does not exist but is required to create an object for node "%s" (Node type: "%s") at index "%s"', $variable, $nodeClassName, $nodeName, $type->getNodeName(), $nodeIndex));
                 }
                 $requiredValue = $nodeDataItem[$variable];
                 $objectSetterVariable = $variableCollection->getVariableById($variable);
                 if (!$objectSetterVariable) {
                     throw new EncoderException(sprintf('Variable "%s" for "%s" is required but there is no EncoderNodeVariable available to retrieve the value for node "%s" (Node type: "%s") at index "%s".', $variable, $nodeClassName, $nodeName, $type->getNodeName(), $nodeIndex));
                 }
                 $objectSetter = $objectSetterVariable->getObjectSetter();
                 $processedRequiredValue = $objectSetter->processValue($requiredValue);
                 $requiredVariableValues[$variable] = $processedRequiredValue;
                 unset($nodeDataItem[$variable]);
             }
             // create a new instance of the class
             $rc = new \ReflectionClass($nodeClassName);
             $nodeInstance = $rc->newInstanceArgs($requiredVariableValues);
             // add the new object to the children array
             array_push($objects, $nodeInstance);
             if (!$addAfterDecode && !$addAfterAttributes) {
                 $parentNode->addChildrenToObject($nodeName, $parentObject, array($nodeInstance));
             }
             // run the post setter variable types
             $postNodeStaticOptions = array_merge($preNodeStaticOptions, array(ObjectAccessor::VARIABLE_OBJECT => $nodeInstance));
             $postNodeSetterVariables = $variableCollection->getPostNodeSetterVariables();
             foreach ($postNodeSetterVariables as $postNodeSetterVariable) {
                 $variableId = $postNodeSetterVariable->getId();
                 $variableIsset = isset($nodeDataItem[$variableId]);
                 $postNodeSetter = $postNodeSetterVariable->getPostNodeSetter();
                 if ($variableIsset || $postNodeSetter->alwaysExecute()) {
                     $setterOptions = array_merge($postNodeStaticOptions, array(NodeAccessor::VARIABLE_NODE_DATA => $nodeDataItem, NodeAccessor::VARIABLE_NAME => $variableId, NodeAccessor::VARIABLE_VALUE => $variableIsset ? $nodeDataItem[$variableId] : null));
                     if ($newNode = $postNodeSetter->apply($setterOptions)) {
                         $nodeDataItem = $newNode;
                     }
                 }
             }
             // run the optional object setter variable types
             $objectSetterVariables = $variableCollection->getObjectSetterVariables();
             foreach ($objectSetterVariables as $objectSetterVariable) {
                 $variableId = $objectSetterVariable->getId();
                 if (array_key_exists($variableId, $requiredVariableValues)) {
                     // if the variable was an required variable do not try to set it again
                     continue;
                 }
                 $variableIsset = isset($nodeDataItem[$variableId]);
                 $objectSetter = $objectSetterVariable->getObjectSetter();
                 if ($objectSetter->required() && !$variableIsset) {
                     throw new EncoderException(sprintf('Decoding failed because variable "%s" for node "%s" is required but isn\'t present in the node data.', $variableId, $nodeName));
                 }
                 if ($variableIsset || $objectSetter->alwaysExecute()) {
                     $objectSetter->apply($nodeInstance, $variableIsset ? $nodeDataItem[$variableId] : null);
                 }
             }
             if (!$addAfterDecode && $addAfterAttributes) {
                 $parentNode->addChildrenToObject($nodeName, $parentObject, array($nodeInstance));
             }
             // set node children if they exist
             foreach ($nodeDataItem as $childName => $value) {
                 if ($type->childNodeExists($childName)) {
                     $children = $this->_decodeNode($childName, $nodeDataItem, $options, $type, $nodeInstance, $nodeDataItem);
                     if ($type->getChild($childName)->getSetter()->setAfterChildren()) {
                         $isSingleChildNode = $type->isSingleNode($childName);
                         $type->addChildrenToObject($childName, $nodeInstance, $isSingleChildNode ? array($children) : $children);
                     }
                 }
             }
         }
         $nodeIndex++;
     }
     $proxyNode->getVariableCollection()->objectVariablesAreValidWithData($decodedChildren, true);
     if ($isSingleNode) {
         return $objects[0];
     }
     return $objects;
 }