Skip to content

Commit ead1f76

Browse files
committed
Merge pull request #1 from harm-less/improved-variables
Improved variables and child functionalities
2 parents 59dcae2 + 0228c6c commit ead1f76

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+2079
-1721
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
## About
88

99
This library will allow you to save a snapshot of your PHP object in various formats like XML or JSON (encoding).
10-
When your project has been setup properly you can reuse this by decoding the snapshot. It will return the
11-
same PHP object.
10+
When your project has been setup properly you can reuse the snapshot by decoding it. The decoding process will return
11+
the same PHP object you started with.
1212

1313
This library is useful for you if you want to quickly find a way to save a state of your PHP object. Think about a
1414
configurator that allows you to customize a certain product in various ways for example.

src/PE/Encoder.php

Lines changed: 116 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
use PE\Enums\ActionVariable;
1212
use PE\Exceptions\EncoderException;
1313
use PE\Options\EncoderOptions;
14+
use PE\Variables\Types\NodeAccessor;
15+
use PE\Variables\Types\ObjectAccessor;
1416

1517
/**
1618
* Class Encoder
@@ -59,10 +61,11 @@ protected function decodeRawToArray($nodeName, $node, $array) {
5961
foreach ($decodedData as $decodedName => $data) {
6062
// if data belongs to a child
6163
if ($nodeType->childNodeExists($decodedName)) {
64+
$childNodeSetter = $nodeType->getChild($decodedName)->getSetter();
6265
// decode it, unset it and add it back into the array at the correct place
6366
$childArrDecoded = $this->decodeRawToArray($decodedName, $nodeChildData, $array);
6467
unset($decodedData[$decodedName]);
65-
$decodedData = $nodeType->getChild($decodedName)->setAfterChildren() === false ? array($decodedName => $childArrDecoded) + $decodedData : array_merge($decodedData, array($decodedName => $childArrDecoded));
68+
$decodedData = $childNodeSetter->setAfterChildren() === false ? array($decodedName => $childArrDecoded) + $decodedData : array_merge($decodedData, array($decodedName => $childArrDecoded));
6669
}
6770
// if data belongs to an attribute simply
6871
else if (is_array($data)) {
@@ -116,8 +119,10 @@ protected function _decodeNode($nodeName, $nodeData, EncoderOptions $options, En
116119
$addAfterAttributes = true;
117120
if ($parentNode) {
118121
$childNode = $parentNode->getChild($nodeName);
119-
$addAfterDecode = $childNode->setAfterChildren();
120-
$addAfterAttributes = $childNode->setAfterAttributes();
122+
123+
$childNodeSetter = $childNode->getSetter();
124+
$addAfterDecode = $childNodeSetter->setAfterChildren();
125+
$addAfterAttributes = $childNodeSetter->setAfterAttributes();
121126
}
122127

123128
$objects = array();
@@ -129,6 +134,7 @@ protected function _decodeNode($nodeName, $nodeData, EncoderOptions $options, En
129134
$nodeChildType = $proxyNode->getObjectType($parentObject, $nodeDataItem);
130135
$nodeType = ($nodeChildType !== null && !empty($nodeChildType) ? $nodeChildType : $proxyNode->getDefaultType());
131136
$type = $proxyNode->getType($nodeType);
137+
$variableCollection = $type->getVariableCollection();
132138

133139
// make sure the variables are all dashed as this is the default
134140
foreach ($nodeDataItem as $nodeDataName => $nodeDataValue) {
@@ -139,18 +145,24 @@ protected function _decodeNode($nodeName, $nodeData, EncoderOptions $options, En
139145
}
140146
}
141147

148+
$preNodeStaticOptions = array(
149+
NodeAccessor::VARIABLE_NODE => $type,
150+
NodeAccessor::VARIABLE_PARENT => $parentObject
151+
);
142152
// call node methods. It can be useful when you want to change the outcome of the node data in the node
143153
// that does not have a certain setter but is used in other ways
144-
$nodeMethodVariables = $type->getVariablesSetterActionByType(EncoderNodeVariable::ACTION_TYPE_NODE);
145-
foreach ($nodeMethodVariables as $variableId => $nodeMethodVariable) {
146-
if (isset($nodeDataItem[$variableId])) {
147-
$setterOptions = array(
148-
ActionVariable::SETTER_NODE_DATA => $nodeDataItem,
149-
ActionVariable::SETTER_NAME => $variableId,
150-
ActionVariable::SETTER_PARENT => $parentObject,
151-
ActionVariable::SETTER_VALUE => $nodeDataItem[$variableId]
152-
);
153-
if ($newNode = $nodeMethodVariable->callNodeSetterAction($type, $setterOptions)) {
154+
$preNodeSetterVariables = $variableCollection->getPreNodeSetterVariables();
155+
foreach ($preNodeSetterVariables as $preNodeSetterVariable) {
156+
$variableId = $preNodeSetterVariable->getId();
157+
$variableIsset = isset($nodeDataItem[$variableId]);
158+
$preNodeSetter = $preNodeSetterVariable->getPreNodeSetter();
159+
if (isset($nodeDataItem[$variableId]) || $preNodeSetter->alwaysExecute()) {
160+
$setterOptions = array_merge($preNodeStaticOptions, array(
161+
NodeAccessor::VARIABLE_NODE_DATA => $nodeDataItem,
162+
NodeAccessor::VARIABLE_NAME => $variableId,
163+
NodeAccessor::VARIABLE_VALUE => $variableIsset ? $nodeDataItem[$variableId] : null
164+
));
165+
if ($newNode = $preNodeSetter->apply($setterOptions)) {
154166
$nodeDataItem = $newNode;
155167
}
156168
}
@@ -183,12 +195,15 @@ protected function _decodeNode($nodeName, $nodeData, EncoderOptions $options, En
183195
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"', $processedVariable, $nodeClassName, $nodeName, $type->getNodeName(), $nodeIndex));
184196
}
185197
$requiredValue = $nodeDataItem[$processedVariable];
186-
$processedRequiredValue = $type->processValue($processedVariable, $requiredValue);
187-
if ($processedRequiredValue === null) {
188-
throw new EncoderException(sprintf('Variable "%s" for "%s" cannot process its value (%s). Presumably because the NodeType does not recognize the variable', $processedVariable, $nodeClassName, $requiredValue));
198+
$objectSetterVariable = $variableCollection->getVariableById($processedVariable);
199+
if (!$objectSetterVariable) {
200+
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".', $processedVariable, $nodeClassName, $nodeName, $type->getNodeName(), $nodeIndex));
189201
}
190202

191-
array_push($requiredVariableValues, $processedRequiredValue);
203+
$objectSetter = $objectSetterVariable->getObjectSetter();
204+
$processedRequiredValue = $objectSetter->processValue($requiredValue);
205+
206+
$requiredVariableValues[$processedVariable] = $processedRequiredValue;
192207
unset($nodeDataItem[$processedVariable]);
193208
}
194209

@@ -203,14 +218,40 @@ protected function _decodeNode($nodeName, $nodeData, EncoderOptions $options, En
203218
$parentNode->addChildrenToObject($nodeName, $parentObject, array($nodeInstance));
204219
}
205220

206-
foreach ($nodeDataItem as $name => $value) {
207-
$type->applyToVariable($name, array(
208-
ActionVariable::SETTER_NODE_DATA => $nodeDataItem,
209-
ActionVariable::SETTER_OBJECT => $nodeInstance,
210-
ActionVariable::SETTER_PARENT => $parentObject,
211-
ActionVariable::SETTER_NAME => $name,
212-
ActionVariable::SETTER_VALUE => $value
213-
));
221+
// run the post setter variable types
222+
$postNodeStaticOptions = array_merge($preNodeStaticOptions, array(
223+
ObjectAccessor::VARIABLE_OBJECT => $nodeInstance,
224+
));
225+
$postNodeSetterVariables = $variableCollection->getPostNodeSetterVariables();
226+
foreach ($postNodeSetterVariables as $postNodeSetterVariable) {
227+
$variableId = $postNodeSetterVariable->getId();
228+
$variableIsset = isset($nodeDataItem[$variableId]);
229+
$postNodeSetter = $postNodeSetterVariable->getPostNodeSetter();
230+
if ($variableIsset || $postNodeSetter->alwaysExecute()) {
231+
$setterOptions = array_merge($postNodeStaticOptions, array(
232+
NodeAccessor::VARIABLE_NODE_DATA => $nodeDataItem,
233+
NodeAccessor::VARIABLE_NAME => $variableId,
234+
NodeAccessor::VARIABLE_VALUE => $variableIsset ? $nodeDataItem[$variableId] : null
235+
));
236+
if ($newNode = $postNodeSetter->apply($setterOptions)) {
237+
$nodeDataItem = $newNode;
238+
}
239+
}
240+
}
241+
242+
// run the optional object setter variable types
243+
$objectSetterVariables = $variableCollection->getObjectSetterVariables();
244+
foreach ($objectSetterVariables as $objectSetterVariable) {
245+
$variableId = $objectSetterVariable->getId();
246+
if (array_key_exists($variableId, $requiredVariableValues)) {
247+
// if the variable was an required variable do not try to set it again
248+
continue;
249+
}
250+
$variableIsset = isset($nodeDataItem[$variableId]);
251+
$objectSetter = $objectSetterVariable->getObjectSetter();
252+
if ($variableIsset || $objectSetter->alwaysExecute()) {
253+
$objectSetter->apply($nodeInstance, $variableIsset ? $nodeDataItem[$variableId] : null);
254+
}
214255
}
215256

216257
if (!$addAfterDecode && $addAfterAttributes) {
@@ -222,7 +263,7 @@ protected function _decodeNode($nodeName, $nodeData, EncoderOptions $options, En
222263
if ($type->childNodeExists($childName)) {
223264
$children = $this->_decodeNode($childName, $nodeDataItem, $options, $type, $nodeInstance, $nodeDataItem);
224265

225-
if ($type->getChild($childName)->setAfterChildren()) {
266+
if ($type->getChild($childName)->getSetter()->setAfterChildren()) {
226267
$isSingleChildNode = $type->isSingleNode($childName);
227268
$type->addChildrenToObject($childName, $nodeInstance, $isSingleChildNode ? array($children) : $children);
228269
}
@@ -232,7 +273,7 @@ protected function _decodeNode($nodeName, $nodeData, EncoderOptions $options, En
232273

233274
$nodeIndex++;
234275
}
235-
$proxyNode->variablesAreValid($decodedChildren, true);
276+
$variableCollection->objectVariablesAreValidWithData($decodedChildren, true);
236277

237278
if ($isSingleNode) {
238279
return $objects[0];
@@ -295,38 +336,64 @@ public function encode($object, EncoderOptions $options = null) {
295336
}
296337

297338
protected function _encode($object, EncoderNode $node, EncoderOptions $options, $parent = null, $nodeIterationIndex = null, $childObjectIterationIndex = null) {
298-
$variables = $node->getVariables();
339+
$variableCollection = $node->getVariableCollection();
340+
$objectGetterVariables = $variableCollection->getObjectGetterVariables();
299341

300342
$optionNodeIndex = $node->getNodeName() . '[' . $childObjectIterationIndex . ']';
301343

302344
$attributesRaw = array();
303-
foreach ($variables as $variable) {
304-
if (!$variable->hasGetterAction() || $variable->alwaysExecute()) {
305345

306-
$variableId = $variable->getId();
346+
$postNodeStaticOptions = array(
347+
NodeAccessor::VARIABLE_NODE => $node,
348+
NodeAccessor::VARIABLE_OBJECT => $object,
349+
NodeAccessor::VARIABLE_PARENT => $parent,
350+
NodeAccessor::VARIABLE_OPTIONS => $options,
351+
NodeAccessor::VARIABLE_NODE_ITERATION_INDEX => $nodeIterationIndex,
352+
NodeAccessor::VARIABLE_CHILD_OBJECT_ITERATION_INDEX => $childObjectIterationIndex,
353+
);
307354

308-
$attributeValue = null;
309-
$getAttributeMethod = $variable->getGetterMethod();
310-
if (method_exists($object, $getAttributeMethod)) {
311-
$attributeValue = $object->$getAttributeMethod();
312-
} else {
313-
throw new EncoderException(sprintf('Getter method "%s" does not exist in object "%s" for node type "%s" (%s) and variable with id "%s".', $getAttributeMethod, get_class($object), $node->getNodeTypeName(), get_class($node), $variableId));
355+
$preNodeGetterVariables = $variableCollection->getPreNodeGetterVariables();
356+
foreach ($preNodeGetterVariables as $preNodeGetterVariable) {
357+
$variableId = $preNodeGetterVariable->getId();
358+
$postNodeGetter = $preNodeGetterVariable->getPreNodeGetter();
359+
$actionOptions = array_merge($postNodeStaticOptions, array(
360+
NodeAccessor::VARIABLE_NODE_DATA => $attributesRaw,
361+
NodeAccessor::VARIABLE_NAME => $variableId,
362+
));
363+
if ($newAttributeData = $postNodeGetter->apply($actionOptions)) {
364+
if (is_array($newAttributeData)) {
365+
$attributesRaw = $newAttributeData;
314366
}
315-
316-
$attributesRaw[$variableId] = $attributeValue;
317367
}
318368
}
319369

320-
$actionVariables = array(
321-
ActionVariable::GETTER_OBJECT => $object,
322-
ActionVariable::GETTER_PARENT => $parent,
323-
ActionVariable::GETTER_OPTIONS => $options,
324-
ActionVariable::GETTER_NODE_ITERATION_INDEX => $nodeIterationIndex,
325-
ActionVariable::GETTER_CHILD_OBJECT_ITERATION_INDEX => $childObjectIterationIndex,
326-
);
370+
// get all the variables values from the object
371+
foreach ($objectGetterVariables as $objectGetterVariable) {
372+
$variableId = $objectGetterVariable->getId();
373+
374+
$objectGetter = $objectGetterVariable->getObjectGetter();
375+
$attributesRaw[$variableId] = $objectGetter->apply($object);
376+
}
377+
378+
$postNodeGetterVariables = $variableCollection->getPostNodeGetterVariables();
379+
foreach ($postNodeGetterVariables as $postNodeGetterVariable) {
380+
$variableId = $postNodeGetterVariable->getId();
381+
$hasVariable = array_key_exists($variableId, $attributesRaw);
382+
$postNodeGetter = $postNodeGetterVariable->getPostNodeGetter();
383+
if ($hasVariable || $postNodeGetter->alwaysExecute()) {
384+
$actionOptions = array_merge($postNodeStaticOptions, array(
385+
NodeAccessor::VARIABLE_NODE_DATA => $attributesRaw,
386+
NodeAccessor::VARIABLE_NAME => $variableId,
387+
NodeAccessor::VARIABLE_VALUE => $hasVariable ? $attributesRaw[$variableId] : null,
388+
));
389+
if ($newAttributeData = $postNodeGetter->apply($actionOptions)) {
390+
if (is_array($newAttributeData)) {
391+
$attributesRaw = $newAttributeData;
392+
}
393+
}
394+
}
395+
}
327396

328-
$nodeMethodVariables = $node->getVariablesGetterActionByType(EncoderNodeVariable::ACTION_TYPE_NODE);
329-
$attributesRaw = $this->loopNodeVariables($node, $nodeMethodVariables, $attributesRaw, $actionVariables);
330397

331398
$optionNodeKey = $options->option('key', $node);
332399
$optionNodeValue = $options->option('value', $node);
@@ -367,7 +434,7 @@ protected function _encode($object, EncoderNode $node, EncoderOptions $options,
367434
$isIterated = $optionChildIteration !== null;
368435
$childIteration = $optionChildIteration === null ? 1 : $optionChildIteration;
369436

370-
$getChildObjectsMethod = $child->getGetterMethod();
437+
$getChildObjectsMethod = $child->getGetter()->getMethod();
371438
if (!method_exists($object, $getChildObjectsMethod)) {
372439
throw new EncoderException(sprintf('Getter method "%s" for node "%s" does not exist in class "%s"', $getChildObjectsMethod, $childNodeName, get_class($object)));
373440
}
@@ -473,25 +540,4 @@ protected function encodeNodeChildren(EncoderNode $node, $nodeName, EncoderNodeC
473540
protected function encodeAttributes($attributes) {
474541
return $attributes;
475542
}
476-
477-
478-
protected function loopNodeVariables($node, $variables, $data, $actionOptions) {
479-
$temp = $data;
480-
foreach ($variables as $variableId => $nodeMethodVariable) {
481-
$hasVariable = array_key_exists($variableId, $data);
482-
if ($hasVariable || $nodeMethodVariable->alwaysExecute()) {
483-
$actionOptions = array_merge(array(
484-
ActionVariable::GETTER_NODE_DATA => $data,
485-
ActionVariable::GETTER_NAME => $variableId,
486-
ActionVariable::GETTER_VALUE => $hasVariable ? $data[$variableId] : null,
487-
), $actionOptions);
488-
if ($newAttributeData = $nodeMethodVariable->callNodeGetterAction($node, $actionOptions)) {
489-
if (is_array($newAttributeData)) {
490-
$temp = $newAttributeData;
491-
}
492-
}
493-
}
494-
}
495-
return $temp;
496-
}
497543
}

src/PE/Enums/ActionVariable.php

Lines changed: 0 additions & 24 deletions
This file was deleted.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
namespace PE\Exceptions;
4+
5+
use RuntimeException;
6+
7+
class EncoderNodeVariableCollectionException extends RuntimeException implements PEExceptionInterface
8+
{
9+
}

src/PE/Exceptions/VariableCollectionException.php

Lines changed: 0 additions & 9 deletions
This file was deleted.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
namespace PE\Exceptions;
4+
5+
use RuntimeException;
6+
7+
class VariableTypeException extends RuntimeException implements PEExceptionInterface
8+
{
9+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
namespace PE\Nodes\Children;
4+
5+
abstract class NodeChildAccessor {
6+
7+
private $method;
8+
9+
function __construct($method) {
10+
$this->method = $method;
11+
}
12+
13+
public function getMethod() {
14+
return $this->method;
15+
}
16+
17+
}
18+
19+
?>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace PE\Nodes\Children;
4+
5+
final class NodeChildGetter extends NodeChildAccessor {
6+
7+
function __construct($method) {
8+
parent::__construct($method);
9+
}
10+
11+
}
12+
13+
?>

0 commit comments

Comments
 (0)