Skip to content

Commit

Permalink
ParseObject encode/decode (#351)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
Benjamin Wilson Friedman authored Sep 8, 2017
1 parent 9ecd520 commit 89f38f7
Show file tree
Hide file tree
Showing 6 changed files with 446 additions and 17 deletions.
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,13 @@ ParseClient::initialize( $app_id, null, $master_key );
ParseClient::setServerURL('https://my-parse-server.com:port','parse');
```

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

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

`ParseClient::setServerURL('https://example.com:1337','parse');`
```php
ParseClient::setServerURL('https://example.com:1337','parse');
```

Getting Started
---------------
Expand Down
5 changes: 1 addition & 4 deletions src/Parse/Internal/ParseRelationOperation.php
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,6 @@ private function addObjects($objects, &$container)
*/
private function removeObjects($objects, &$container)
{
if (!is_array($objects)) {
$objects = [$objects];
}
$nullObjects = [];
foreach ($objects as $object) {
if ($object->getObjectId() == null) {
Expand Down Expand Up @@ -186,7 +183,7 @@ public function _mergeWithPrevious($previous)
&& $previous->targetClassName != $this->targetClassName
) {
throw new Exception(
'Related object object must be of class '
'Related object must be of class '
.$this->targetClassName.', but '.$previous->targetClassName
.' was passed in.',
103
Expand Down
169 changes: 161 additions & 8 deletions src/Parse/ParseObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use Parse\Internal\Encodable;
use Parse\Internal\FieldOperation;
use Parse\Internal\IncrementOperation;
use Parse\Internal\ParseRelationOperation;
use Parse\Internal\RemoveOperation;
use Parse\Internal\SetOperation;

Expand Down Expand Up @@ -673,9 +674,6 @@ private function mergeFromServer($data, $completeData = true)
$decodedValue = new ParseRelation($this, $key, $className);
}
}
if ($key == 'ACL') {
$decodedValue = ParseACL::_createACLFromJSON($decodedValue);
}
}
$this->serverData[$key] = $decodedValue;
$this->dataAvailability[$key] = true;
Expand All @@ -688,13 +686,10 @@ private function mergeFromServer($data, $completeData = true)
/**
* Merge data from other object.
*
* @param ParseObject $other
* @param ParseObject $other Other object to merge data from
*/
private function mergeFromObject($other)
{
if (!$other) {
return;
}
$this->objectId = $other->getObjectId();
$this->createdAt = $other->getCreatedAt();
$this->updatedAt = $other->getUpdatedAt();
Expand Down Expand Up @@ -726,6 +721,7 @@ public function _mergeMagicFields(&$data)
if (isset($data['ACL'])) {
$acl = ParseACL::_createACLFromJSON($data['ACL']);
$this->serverData['ACL'] = $acl;
$this->dataAvailability['ACL'] = true;
unset($data['ACL']);
}
}
Expand Down Expand Up @@ -952,10 +948,167 @@ public function _encode()
$out[$key] = $value;
}
}

return json_encode($out);
}

/**
* Returns a JSON encoded value of a ParseObject,
* defers to encodeObject internally
*
* @return string
*/
public function encode()
{
$encoded = [
'className' => $this->className,
'serverData' => [],
'operationSet' => []
];

// add special fields
if (isset($this->objectId)) {
$encoded['objectId'] = $this->objectId;
}
if (isset($this->createdAt)) {
$encoded['serverData']['createdAt'] = ParseClient::_encode(
$this->createdAt,
false
);
}
if (isset($this->updatedAt)) {
$encoded['serverData']['updatedAt'] = ParseClient::_encode(
$this->updatedAt,
false
);
}

// add server data
foreach ($this->serverData as $key => $value) {
$encoded['serverData'][$key] = ParseClient::_encode($value, true);
}

// add pending ops
foreach ($this->operationSet as $key => $op) {
$encoded['operationSet'][$key] = $op->_encode();
}

return json_encode($encoded);
}

/**
* Decodes and returns an encoded ParseObject
*
* @param string|array $encoded Encoded ParseObject to decode
* @return ParseObject
* @throws ParseException
*/
public static function decode($encoded)
{
if (!is_array($encoded)) {
// decode this string
$encoded = json_decode($encoded, true);
}

// pull out objectId, if set
$objectId = isset($encoded['objectId']) ? $encoded['objectId'] : null;

// recreate this object
$obj = ParseObject::create($encoded['className'], $objectId, !isset($objectId));

if (isset($encoded['serverData']['createdAt'])) {
$encoded['serverData']['createdAt'] = ParseClient::getProperDateFormat(
ParseClient::_decode($encoded['serverData']['createdAt'])
);
}
if (isset($encoded['serverData']['updatedAt'])) {
$encoded['serverData']['updatedAt'] = ParseClient::getProperDateFormat(
ParseClient::_decode($encoded['serverData']['updatedAt'])
);
}

// unset className
unset($encoded['className']);

// set server data
$obj->_mergeAfterFetch($encoded['serverData']);

// reinstate op set
foreach ($encoded['operationSet'] as $key => $value) {
if (is_array($value)) {
if (isset($value['__op'])) {
$op = $value['__op'];

if ($op === 'Add') {
$obj->_performOperation(
$key,
new AddOperation(ParseClient::_decode($value['objects']))
);
} elseif ($op === 'AddUnique') {
$obj->_performOperation(
$key,
new AddUniqueOperation(ParseClient::_decode($value['objects']))
);
} elseif ($op === 'Delete') {
$obj->_performOperation($key, new DeleteOperation());
} elseif ($op === 'Increment') {
$obj->_performOperation(
$key,
new IncrementOperation($value['amount'])
);
} elseif ($op === 'AddRelation') {
$obj->_performOperation(
$key,
new ParseRelationOperation(ParseClient::_decode($value['objects']), null)
);
} elseif ($op === 'RemoveRelation') {
$obj->_performOperation(
$key,
new ParseRelationOperation(null, ParseClient::_decode($value['objects']))
);
} elseif ($op === 'Batch') {
$ops = $value['ops'];
$obj->_performOperation(
$key,
new ParseRelationOperation(
ParseClient::_decode($ops[0]['objects']),
ParseClient::_decode($ops[1]['objects'])
)
);
} elseif ($op === 'Remove') {
$obj->_performOperation(
$key,
new RemoveOperation(ParseClient::_decode($value['objects']))
);
} else {
throw new ParseException("Unrecognized op '{$op}' found during decode.");
}
} else {
if (isset($value['__type'])) {
// encoded object
$obj->_performOperation($key, new SetOperation(ParseClient::_decode($value)));
} elseif ($key === 'ACL') {
// encoded ACL
$obj->_performOperation($key, new SetOperation(ParseACL::_createACLFromJSON($value)));
} else {
// array
if (count(array_filter(array_keys($value), 'is_string')) > 0) {
// associative
$obj->_performOperation($key, new SetOperation($value, true));
} else {
// sequential
$obj->_performOperation($key, new SetOperation($value));
}
}
}
} else {
// set op (not an associative array)
$obj->_performOperation($key, new SetOperation($value));
}
}

return $obj;
}

/**
* Returns JSON object of the unsaved operations.
*
Expand Down
16 changes: 15 additions & 1 deletion src/Parse/ParseRelation.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

namespace Parse;

use Parse\Internal\Encodable;
use Parse\Internal\ParseRelationOperation;

/**
Expand All @@ -14,7 +15,7 @@
* @author Mohamed Madbouli <[email protected]>
* @package Parse
*/
class ParseRelation
class ParseRelation implements Encodable
{
/**
* The parent of this relation.
Expand Down Expand Up @@ -124,4 +125,17 @@ public function getQuery()

return $query;
}

/**
* Return an encoded array of this relation.
*
* @return array
*/
public function _encode()
{
return [
'__type' => 'Relation',
'className' => $this->targetClassName
];
}
}
Loading

0 comments on commit 89f38f7

Please sign in to comment.