Skip to content

Commit 89f38f7

Browse files
author
Benjamin Wilson Friedman
authored
ParseObject encode/decode (#351)
* Initial working for encode/decode functionality * Changed markup for PHP * Adjust encode/decode methods * Modified ParseRelation for proper encoding, intended for usage in encode/decode for ParseObject * Later fetch to pass on travis * Checking formatted dates to avoid issues with microseconds having 6 digits natively in php and 3 digits for parse * Removed redundant code path for ACL data, is always handled & removed in advance * Removed redundant check & fixed exception message typo * removed additional redundant check & upped tests * Use 'operationSet' instead of estimatedData for a more accurate snapshot * lint * Using dates formatted for parse server
1 parent 9ecd520 commit 89f38f7

File tree

6 files changed

+446
-17
lines changed

6 files changed

+446
-17
lines changed

README.md

+4-3
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,13 @@ ParseClient::initialize( $app_id, null, $master_key );
5959
ParseClient::setServerURL('https://my-parse-server.com:port','parse');
6060
```
6161

62-
Notice
63-
Parse server's default port is `1337` and the second parameter `parse` is the route prefix of your parse server.
62+
Notice Parse server's default port is `1337` and the second parameter `parse` is the route prefix of your parse server.
6463

6564
For example if your parse server's url is `http://example.com:1337/parse` then you can set the server url using the following snippet
6665

67-
`ParseClient::setServerURL('https://example.com:1337','parse');`
66+
```php
67+
ParseClient::setServerURL('https://example.com:1337','parse');
68+
```
6869

6970
Getting Started
7071
---------------

src/Parse/Internal/ParseRelationOperation.php

+1-4
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,6 @@ private function addObjects($objects, &$container)
117117
*/
118118
private function removeObjects($objects, &$container)
119119
{
120-
if (!is_array($objects)) {
121-
$objects = [$objects];
122-
}
123120
$nullObjects = [];
124121
foreach ($objects as $object) {
125122
if ($object->getObjectId() == null) {
@@ -186,7 +183,7 @@ public function _mergeWithPrevious($previous)
186183
&& $previous->targetClassName != $this->targetClassName
187184
) {
188185
throw new Exception(
189-
'Related object object must be of class '
186+
'Related object must be of class '
190187
.$this->targetClassName.', but '.$previous->targetClassName
191188
.' was passed in.',
192189
103

src/Parse/ParseObject.php

+161-8
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use Parse\Internal\Encodable;
1313
use Parse\Internal\FieldOperation;
1414
use Parse\Internal\IncrementOperation;
15+
use Parse\Internal\ParseRelationOperation;
1516
use Parse\Internal\RemoveOperation;
1617
use Parse\Internal\SetOperation;
1718

@@ -673,9 +674,6 @@ private function mergeFromServer($data, $completeData = true)
673674
$decodedValue = new ParseRelation($this, $key, $className);
674675
}
675676
}
676-
if ($key == 'ACL') {
677-
$decodedValue = ParseACL::_createACLFromJSON($decodedValue);
678-
}
679677
}
680678
$this->serverData[$key] = $decodedValue;
681679
$this->dataAvailability[$key] = true;
@@ -688,13 +686,10 @@ private function mergeFromServer($data, $completeData = true)
688686
/**
689687
* Merge data from other object.
690688
*
691-
* @param ParseObject $other
689+
* @param ParseObject $other Other object to merge data from
692690
*/
693691
private function mergeFromObject($other)
694692
{
695-
if (!$other) {
696-
return;
697-
}
698693
$this->objectId = $other->getObjectId();
699694
$this->createdAt = $other->getCreatedAt();
700695
$this->updatedAt = $other->getUpdatedAt();
@@ -726,6 +721,7 @@ public function _mergeMagicFields(&$data)
726721
if (isset($data['ACL'])) {
727722
$acl = ParseACL::_createACLFromJSON($data['ACL']);
728723
$this->serverData['ACL'] = $acl;
724+
$this->dataAvailability['ACL'] = true;
729725
unset($data['ACL']);
730726
}
731727
}
@@ -952,10 +948,167 @@ public function _encode()
952948
$out[$key] = $value;
953949
}
954950
}
955-
956951
return json_encode($out);
957952
}
958953

954+
/**
955+
* Returns a JSON encoded value of a ParseObject,
956+
* defers to encodeObject internally
957+
*
958+
* @return string
959+
*/
960+
public function encode()
961+
{
962+
$encoded = [
963+
'className' => $this->className,
964+
'serverData' => [],
965+
'operationSet' => []
966+
];
967+
968+
// add special fields
969+
if (isset($this->objectId)) {
970+
$encoded['objectId'] = $this->objectId;
971+
}
972+
if (isset($this->createdAt)) {
973+
$encoded['serverData']['createdAt'] = ParseClient::_encode(
974+
$this->createdAt,
975+
false
976+
);
977+
}
978+
if (isset($this->updatedAt)) {
979+
$encoded['serverData']['updatedAt'] = ParseClient::_encode(
980+
$this->updatedAt,
981+
false
982+
);
983+
}
984+
985+
// add server data
986+
foreach ($this->serverData as $key => $value) {
987+
$encoded['serverData'][$key] = ParseClient::_encode($value, true);
988+
}
989+
990+
// add pending ops
991+
foreach ($this->operationSet as $key => $op) {
992+
$encoded['operationSet'][$key] = $op->_encode();
993+
}
994+
995+
return json_encode($encoded);
996+
}
997+
998+
/**
999+
* Decodes and returns an encoded ParseObject
1000+
*
1001+
* @param string|array $encoded Encoded ParseObject to decode
1002+
* @return ParseObject
1003+
* @throws ParseException
1004+
*/
1005+
public static function decode($encoded)
1006+
{
1007+
if (!is_array($encoded)) {
1008+
// decode this string
1009+
$encoded = json_decode($encoded, true);
1010+
}
1011+
1012+
// pull out objectId, if set
1013+
$objectId = isset($encoded['objectId']) ? $encoded['objectId'] : null;
1014+
1015+
// recreate this object
1016+
$obj = ParseObject::create($encoded['className'], $objectId, !isset($objectId));
1017+
1018+
if (isset($encoded['serverData']['createdAt'])) {
1019+
$encoded['serverData']['createdAt'] = ParseClient::getProperDateFormat(
1020+
ParseClient::_decode($encoded['serverData']['createdAt'])
1021+
);
1022+
}
1023+
if (isset($encoded['serverData']['updatedAt'])) {
1024+
$encoded['serverData']['updatedAt'] = ParseClient::getProperDateFormat(
1025+
ParseClient::_decode($encoded['serverData']['updatedAt'])
1026+
);
1027+
}
1028+
1029+
// unset className
1030+
unset($encoded['className']);
1031+
1032+
// set server data
1033+
$obj->_mergeAfterFetch($encoded['serverData']);
1034+
1035+
// reinstate op set
1036+
foreach ($encoded['operationSet'] as $key => $value) {
1037+
if (is_array($value)) {
1038+
if (isset($value['__op'])) {
1039+
$op = $value['__op'];
1040+
1041+
if ($op === 'Add') {
1042+
$obj->_performOperation(
1043+
$key,
1044+
new AddOperation(ParseClient::_decode($value['objects']))
1045+
);
1046+
} elseif ($op === 'AddUnique') {
1047+
$obj->_performOperation(
1048+
$key,
1049+
new AddUniqueOperation(ParseClient::_decode($value['objects']))
1050+
);
1051+
} elseif ($op === 'Delete') {
1052+
$obj->_performOperation($key, new DeleteOperation());
1053+
} elseif ($op === 'Increment') {
1054+
$obj->_performOperation(
1055+
$key,
1056+
new IncrementOperation($value['amount'])
1057+
);
1058+
} elseif ($op === 'AddRelation') {
1059+
$obj->_performOperation(
1060+
$key,
1061+
new ParseRelationOperation(ParseClient::_decode($value['objects']), null)
1062+
);
1063+
} elseif ($op === 'RemoveRelation') {
1064+
$obj->_performOperation(
1065+
$key,
1066+
new ParseRelationOperation(null, ParseClient::_decode($value['objects']))
1067+
);
1068+
} elseif ($op === 'Batch') {
1069+
$ops = $value['ops'];
1070+
$obj->_performOperation(
1071+
$key,
1072+
new ParseRelationOperation(
1073+
ParseClient::_decode($ops[0]['objects']),
1074+
ParseClient::_decode($ops[1]['objects'])
1075+
)
1076+
);
1077+
} elseif ($op === 'Remove') {
1078+
$obj->_performOperation(
1079+
$key,
1080+
new RemoveOperation(ParseClient::_decode($value['objects']))
1081+
);
1082+
} else {
1083+
throw new ParseException("Unrecognized op '{$op}' found during decode.");
1084+
}
1085+
} else {
1086+
if (isset($value['__type'])) {
1087+
// encoded object
1088+
$obj->_performOperation($key, new SetOperation(ParseClient::_decode($value)));
1089+
} elseif ($key === 'ACL') {
1090+
// encoded ACL
1091+
$obj->_performOperation($key, new SetOperation(ParseACL::_createACLFromJSON($value)));
1092+
} else {
1093+
// array
1094+
if (count(array_filter(array_keys($value), 'is_string')) > 0) {
1095+
// associative
1096+
$obj->_performOperation($key, new SetOperation($value, true));
1097+
} else {
1098+
// sequential
1099+
$obj->_performOperation($key, new SetOperation($value));
1100+
}
1101+
}
1102+
}
1103+
} else {
1104+
// set op (not an associative array)
1105+
$obj->_performOperation($key, new SetOperation($value));
1106+
}
1107+
}
1108+
1109+
return $obj;
1110+
}
1111+
9591112
/**
9601113
* Returns JSON object of the unsaved operations.
9611114
*

src/Parse/ParseRelation.php

+15-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
namespace Parse;
77

8+
use Parse\Internal\Encodable;
89
use Parse\Internal\ParseRelationOperation;
910

1011
/**
@@ -14,7 +15,7 @@
1415
* @author Mohamed Madbouli <[email protected]>
1516
* @package Parse
1617
*/
17-
class ParseRelation
18+
class ParseRelation implements Encodable
1819
{
1920
/**
2021
* The parent of this relation.
@@ -124,4 +125,17 @@ public function getQuery()
124125

125126
return $query;
126127
}
128+
129+
/**
130+
* Return an encoded array of this relation.
131+
*
132+
* @return array
133+
*/
134+
public function _encode()
135+
{
136+
return [
137+
'__type' => 'Relation',
138+
'className' => $this->targetClassName
139+
];
140+
}
127141
}

0 commit comments

Comments
 (0)