xpdoobjectvehicle.class.php 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. <?php
  2. /*
  3. * Copyright 2010-2015 by MODX, LLC.
  4. *
  5. * This file is part of xPDO.
  6. *
  7. * xPDO is free software; you can redistribute it and/or modify it under the
  8. * terms of the GNU General Public License as published by the Free Software
  9. * Foundation; either version 2 of the License, or (at your option) any later
  10. * version.
  11. *
  12. * xPDO is distributed in the hope that it will be useful, but WITHOUT ANY
  13. * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  14. * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License along with
  17. * xPDO; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
  18. * Suite 330, Boston, MA 02111-1307 USA
  19. */
  20. /**
  21. * Defines a class that represents an xPDOObject within a transportable package.
  22. *
  23. * @package xpdo
  24. * @subpackage transport
  25. */
  26. /**
  27. * Represents an xPDOObject within an {@link xPDOTransport} package.
  28. *
  29. * @package xpdo
  30. * @subpackage transport
  31. */
  32. class xPDOObjectVehicle extends xPDOVehicle {
  33. public $class = 'xPDOObjectVehicle';
  34. /**
  35. * Retrieve an xPDOObject instance represented in this vehicle.
  36. *
  37. * This method returns the main object contained in the payload, but you can optionally specify
  38. * a related_objects node within the payload to retrieve a specific dependent object.
  39. */
  40. public function get(& $transport, $options = array (), $element = null) {
  41. $object = null;
  42. $element = parent :: get($transport, $options, $element);
  43. if (isset ($element['class']) && isset ($element['object'])) {
  44. $vClass = $element['class'];
  45. if (!empty ($element['package'])) {
  46. $pkgPrefix = $element['package'];
  47. $pkgKeys = array_keys($transport->xpdo->packages);
  48. if ($pkgFound = in_array($pkgPrefix, $pkgKeys)) {
  49. $pkgPrefix = '';
  50. }
  51. elseif ($pos = strpos($pkgPrefix, '.')) {
  52. $prefixParts = explode('.', $pkgPrefix);
  53. $prefix = '';
  54. foreach ($prefixParts as $prefixPart) {
  55. $prefix .= $prefixPart;
  56. $pkgPrefix = substr($pkgPrefix, $pos +1);
  57. if ($pkgFound = in_array($prefix, $pkgKeys))
  58. break;
  59. $prefix .= '.';
  60. $pos = strpos($pkgPrefix, '.');
  61. }
  62. if (!$pkgFound)
  63. $pkgPrefix = $element['package'];
  64. }
  65. $vClass = (!empty ($pkgPrefix) ? $pkgPrefix . '.' : '') . $vClass;
  66. }
  67. $object = $transport->xpdo->newObject($vClass);
  68. if (is_object($object) && $object instanceof xPDOObject) {
  69. $options = array_merge($options, $element);
  70. $setKeys = false;
  71. if (isset ($options[xPDOTransport::PRESERVE_KEYS])) {
  72. $setKeys = (boolean) $options[xPDOTransport::PRESERVE_KEYS];
  73. }
  74. $object->fromJSON($element['object'], '', $setKeys, true);
  75. }
  76. }
  77. return $object;
  78. }
  79. /**
  80. * Install the xPDOObjects represented by vehicle into the transport host.
  81. */
  82. public function install(& $transport, $options) {
  83. $parentObj = null;
  84. $parentMeta = null;
  85. $installed = $this->_installObject($transport, $options, $this->payload, $parentObj, $parentMeta);
  86. return $installed;
  87. }
  88. /**
  89. * Install a single xPDOObject from the vehicle payload.
  90. *
  91. * @param xPDOTransport $transport The host xPDOTransport instance.
  92. * @param array $options Any optional attributes to apply to the installation.
  93. * @param array $element A node of the payload representing the object to install.
  94. * @param xPDOObject &$parentObject A reference to the object serving as a parent to the one
  95. * being installed.
  96. * @param array $fkMeta The foreign key relationship data that defines the relationship with the
  97. * parentObject.
  98. */
  99. protected function _installObject(& $transport, $options, $element, & $parentObject, $fkMeta) {
  100. $saved = false;
  101. $preExistingMode = xPDOTransport::PRESERVE_PREEXISTING;
  102. $upgrade = false;
  103. $exists = false;
  104. /** @var xPDOObject $object */
  105. $object = $this->get($transport, $options, $element);
  106. if (is_object($object) && $object instanceof xPDOObject) {
  107. $vOptions = array_merge($options, $element);
  108. $vClass = $vOptions['class'];
  109. if ($transport->xpdo->getDebug() === true)
  110. $transport->xpdo->log(xPDO::LOG_LEVEL_DEBUG, "Installing Vehicle: " . print_r($vOptions, true));
  111. if ($parentObject !== null && $fkMeta !== null) {
  112. if ($fkMeta['owner'] == 'local') {
  113. if ($object->get($fkMeta['foreign']) !== $parentObject->get($fkMeta['local'])) {
  114. $object->set($fkMeta['foreign'], $parentObject->get($fkMeta['local']));
  115. }
  116. }
  117. }
  118. $preserveKeys = !empty ($vOptions[xPDOTransport::PRESERVE_KEYS]);
  119. $upgrade = !empty ($vOptions[xPDOTransport::UPDATE_OBJECT]);
  120. if (!empty ($vOptions[xPDOTransport::UNIQUE_KEY])) {
  121. $uniqueKey = $object->get($vOptions[xPDOTransport::UNIQUE_KEY]);
  122. if (is_array($uniqueKey)) {
  123. $criteria = array_combine($vOptions[xPDOTransport::UNIQUE_KEY], $uniqueKey);
  124. } else {
  125. $criteria = array (
  126. $vOptions[xPDOTransport::UNIQUE_KEY] => $uniqueKey
  127. );
  128. }
  129. }
  130. elseif (isset ($vOptions['key_expr']) && isset ($vOptions['key_format'])) {
  131. //TODO: implement ability to generate new keys
  132. } else {
  133. $pk = $object->getPK();
  134. $nativeKey = $vOptions[xPDOTransport::NATIVE_KEY];
  135. if (is_array($pk) && is_array($nativeKey)) {
  136. $criteria = array_combine($pk, $nativeKey);
  137. } elseif (is_string($pk) && is_scalar($nativeKey)) {
  138. $criteria = array($pk => $nativeKey);
  139. } else {
  140. $criteria = $nativeKey;
  141. $transport->xpdo->log(xPDO::LOG_LEVEL_WARN, 'The native key provided in the vehicle does not match the primary key field(s) for the object: ' . print_r($nativeKey, true));
  142. }
  143. }
  144. if (!empty ($vOptions[xPDOTransport::PREEXISTING_MODE])) {
  145. $preExistingMode = intval($vOptions[xPDOTransport::PREEXISTING_MODE]);
  146. }
  147. if ($this->validate($transport, $object, $vOptions)) {
  148. if (!$this->_installRelated($transport, $object, $element, $options, 'foreign')) {
  149. $transport->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Could not install related objects with foreign owned keys for vehicle object of class {$vClass}; criteria: " . print_r($criteria, true));
  150. if ($transport->xpdo->getDebug() === true) $transport->xpdo->log(xPDO::LOG_LEVEL_DEBUG, 'Could not install related objects for vehicle: ' . print_r($vOptions, true));
  151. } elseif (!empty($vOptions[xPDOTransport::UNIQUE_KEY])) {
  152. $uniqueKey = $object->get($vOptions[xPDOTransport::UNIQUE_KEY]);
  153. if (is_array($uniqueKey)) {
  154. $criteria = array_combine($vOptions[xPDOTransport::UNIQUE_KEY], $uniqueKey);
  155. } else {
  156. $criteria = array (
  157. $vOptions[xPDOTransport::UNIQUE_KEY] => $uniqueKey
  158. );
  159. }
  160. } else {
  161. $pk = $object->getPK();
  162. $nativeKey = $object->get($pk);
  163. if (is_array($pk) && is_array($nativeKey)) {
  164. $criteria = array_combine($pk, $nativeKey);
  165. } elseif (is_string($pk) && is_scalar($nativeKey)) {
  166. $criteria = array($pk => $nativeKey);
  167. } else {
  168. $criteria = $nativeKey;
  169. $transport->xpdo->log(xPDO::LOG_LEVEL_WARN, 'The native key provided in the vehicle does not match the primary key field(s) for the object: ' . print_r($nativeKey, true));
  170. }
  171. }
  172. /** @var xPDOObject $obj */
  173. if ($obj = $transport->xpdo->getObject($vClass, $criteria)) {
  174. $exists = true;
  175. if ($preExistingMode !== xPDOTransport::REMOVE_PREEXISTING) {
  176. $transport->_preserved[$vOptions['guid']] = array (
  177. 'criteria' => $criteria,
  178. 'object' => $obj->toArray('', true)
  179. );
  180. }
  181. if ($upgrade) {
  182. $obj->fromArray($object->toArray('', true), '', false, true);
  183. $object = $obj;
  184. } else {
  185. if (is_array($criteria)) {
  186. $obj->fromArray($criteria, '', true);
  187. }
  188. $object = $obj;
  189. }
  190. }
  191. elseif ($transport->xpdo->getDebug() === true) {
  192. $transport->xpdo->log(xPDO::LOG_LEVEL_DEBUG, "Object for class {$vClass} not found; criteria: " . print_r($criteria, true));
  193. }
  194. if (!$exists || ($exists && $upgrade)) {
  195. if ($transport->xpdo->getOption('dbtype') === 'sqlsrv' && !$exists && $preserveKeys) {
  196. $transport->xpdo->exec("SET IDENTITY_INSERT {$transport->xpdo->getTableName($vClass)} ON");
  197. }
  198. $saved = $object->save();
  199. if ($transport->xpdo->getOption('dbtype') === 'sqlsrv' && !$exists && $preserveKeys) {
  200. $transport->xpdo->exec("SET IDENTITY_INSERT {$transport->xpdo->getTableName($vClass)} OFF");
  201. }
  202. if (!$saved) {
  203. $transport->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Error saving vehicle object of class {$vClass}; criteria: " . print_r($criteria, true));
  204. if ($transport->xpdo->getDebug() === true) $transport->xpdo->log(xPDO::LOG_LEVEL_DEBUG, "Error saving vehicle object: " . print_r($vOptions, true));
  205. }
  206. } else {
  207. $transport->xpdo->log(xPDO::LOG_LEVEL_INFO, "Skipping vehicle object of class {$vClass} (data object exists and cannot be upgraded); criteria: " . print_r($criteria, true));
  208. if ($transport->xpdo->getDebug() === true) $transport->xpdo->log(xPDO::LOG_LEVEL_DEBUG, 'Skipping vehicle object (data object exists and cannot be upgraded): ' . print_r($vOptions, true));
  209. }
  210. if (($saved || $exists)) {
  211. if ($parentObject !== null && $fkMeta !== null) {
  212. if ($fkMeta['owner'] == 'foreign') {
  213. if ($object->get($fkMeta['foreign']) !== $parentObject->get($fkMeta['local'])) {
  214. $parentObject->set($fkMeta['local'], $object->get($fkMeta['foreign']));
  215. }
  216. }
  217. }
  218. }
  219. if (($saved || $exists) && !$this->_installRelated($transport, $object, $element, $options, 'local')) {
  220. $transport->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Could not install related objects with locally owned keys for vehicle object of class {$vClass}; criteria: " . print_r($criteria, true));
  221. if ($transport->xpdo->getDebug() === true) $transport->xpdo->log(xPDO::LOG_LEVEL_DEBUG, 'Could not install related objects for vehicle: ' . print_r($vOptions, true));
  222. }
  223. if ($parentObject === null && !$this->resolve($transport, $object, $vOptions)) {
  224. $transport->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Could not resolve vehicle for object of class {$vClass}; criteria: " . print_r($criteria, true));
  225. if ($transport->xpdo->getDebug() === true) $transport->xpdo->log(xPDO::LOG_LEVEL_DEBUG, 'Could not resolve vehicle: ' . print_r($vOptions, true));
  226. }
  227. } else {
  228. //$transport->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Could not validate vehicle object of class {$vClass}; criteria: " . print_r($criteria, true));
  229. if ($transport->xpdo->getDebug() === true) $transport->xpdo->log(xPDO::LOG_LEVEL_DEBUG, 'Could not validate vehicle object: ' . print_r($vOptions, true));
  230. }
  231. } else {
  232. $transport->xpdo->log(xPDO::LOG_LEVEL_ERROR, 'Could not load vehicle!');
  233. }
  234. return ($saved || ($exists && !$upgrade));
  235. }
  236. /**
  237. * Installs a related object from the vehicle.
  238. *
  239. * @param xPDOTransport &$transport
  240. * @param xPDOObject &$parent
  241. * @param array $element
  242. * @param array $options
  243. * @return bool
  244. */
  245. public function _installRelated(& $transport, & $parent, $element, $options, $owner = '') {
  246. $installed = true;
  247. if (is_object($parent) && isset ($element[xPDOTransport::RELATED_OBJECTS]) && is_array($element[xPDOTransport::RELATED_OBJECTS])) {
  248. foreach ($element[xPDOTransport::RELATED_OBJECTS] as $rAlias => $rVehicles) {
  249. $rMeta = $parent->getFKDefinition($rAlias);
  250. if ($rMeta) {
  251. if (!empty($owner) && $owner !== $rMeta['owner']) continue;
  252. $rOptions = $options;
  253. if (isset($element[xPDOTransport::RELATED_OBJECT_ATTRIBUTES])) {
  254. if (isset($element[xPDOTransport::RELATED_OBJECT_ATTRIBUTES][$rAlias])) {
  255. $rOptions = array_merge($rOptions, $element[xPDOTransport::RELATED_OBJECT_ATTRIBUTES][$rAlias]);
  256. } elseif (isset($element[xPDOTransport::RELATED_OBJECT_ATTRIBUTES][$rMeta['class']])) {
  257. $rOptions = array_merge($rOptions, $element[xPDOTransport::RELATED_OBJECT_ATTRIBUTES][$rMeta['class']]);
  258. }
  259. }
  260. foreach ($rVehicles as $rKey => $rVehicle) {
  261. $installed = $this->_installObject($transport, $rOptions, $rVehicle, $parent, $rMeta);
  262. }
  263. }
  264. }
  265. }
  266. return $installed;
  267. }
  268. /**
  269. * Uninstalls vehicle artifacts from the transport host.
  270. */
  271. public function uninstall(& $transport, $options) {
  272. $parentObj = null;
  273. $parentMeta = null;
  274. return $this->_uninstallObject($transport, $options, $this->payload, $parentObj, $parentMeta);
  275. }
  276. /**
  277. * Uninstall the xPDOObjects represented by a vehicle element from the transport host.
  278. */
  279. public function _uninstallObject(& $transport, $options, $element, & $parentObject, $fkMeta) {
  280. $uninstalled = false;
  281. $removed = false;
  282. $uninstallObject = true;
  283. $upgrade = false;
  284. $preExistingMode = xPDOTransport::PRESERVE_PREEXISTING;
  285. $object = $this->get($transport, $options, $element);
  286. if (is_object($object) && $object instanceof xPDOObject) {
  287. $vOptions = array_merge($options, $element);
  288. $vClass = $vOptions['class'];
  289. $upgrade = !empty($vOptions[xPDOTransport::UPDATE_OBJECT]);
  290. $preserveKeys = !empty ($vOptions[xPDOTransport::PRESERVE_KEYS]);
  291. if (!empty ($vOptions[xPDOTransport::UNIQUE_KEY])) {
  292. $uniqueKey = $object->get($vOptions[xPDOTransport::UNIQUE_KEY]);
  293. if (is_array($uniqueKey)) {
  294. $criteria = array_combine($vOptions[xPDOTransport::UNIQUE_KEY], $uniqueKey);
  295. } else {
  296. $criteria = array (
  297. $vOptions[xPDOTransport::UNIQUE_KEY] => $uniqueKey
  298. );
  299. }
  300. } else {
  301. $criteria = $vOptions[xPDOTransport::NATIVE_KEY];
  302. }
  303. if (!empty ($vOptions[xPDOTransport::PREEXISTING_MODE])) {
  304. $preExistingMode = intval($vOptions[xPDOTransport::PREEXISTING_MODE]);
  305. }
  306. if ($this->validate($transport, $object, $vOptions)) {
  307. $uninstalled = true;
  308. if (isset($vOptions[xPDOTransport::UNINSTALL_OBJECT])) {
  309. $uninstallObject = !empty($vOptions[xPDOTransport::UNINSTALL_OBJECT]);
  310. }
  311. $exists = false;
  312. if ($obj = $transport->xpdo->getObject($vClass, $criteria)) {
  313. $exists = true;
  314. $object = $obj;
  315. }
  316. if ($exists) {
  317. if ($uninstallObject && $upgrade && (!isset ($transport->_preserved[$vOptions['guid']]) || $preExistingMode === xPDOTransport::REMOVE_PREEXISTING)) {
  318. $removed = $object->remove();
  319. if (!$removed) {
  320. $uninstalled = false;
  321. $transport->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Error removing vehicle object of class {$vClass}; criteria: " . print_r($criteria, true));
  322. if ($transport->xpdo->getDebug() === true) $transport->xpdo->log(xPDO::LOG_LEVEL_DEBUG, 'Error removing vehicle object: ' . print_r($vOptions, true));
  323. }
  324. }
  325. if ($upgrade && $preExistingMode === xPDOTransport::RESTORE_PREEXISTING) {
  326. if (isset ($transport->_preserved[$vOptions['guid']])) {
  327. $preserved = $transport->_preserved[$vOptions['guid']]['object'];
  328. $object->fromArray($preserved, '', true, true);
  329. $restored = $object->save();
  330. if (!$restored) {
  331. $transport->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Error restoring preserved object of class {$vClass}: " . print_r($transport->_preserved[$vOptions['guid']], true));
  332. }
  333. }
  334. }
  335. } else {
  336. $transport->xpdo->log(xPDO::LOG_LEVEL_WARN, 'Skipping ' . $vClass . ' object (data object does not exist and cannot be removed): ' . print_r($criteria, true));
  337. }
  338. if (!$this->_uninstallRelated($transport, $object, $element, $options)) {
  339. $transport->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Could not uninstall related objects for vehicle object of class {$vClass}; criteria: " . print_r($criteria, true));
  340. if ($transport->xpdo->getDebug() === true) $transport->xpdo->log(xPDO::LOG_LEVEL_DEBUG, 'Could not uninstall related objects for vehicle: ' . print_r($vOptions, true));
  341. }
  342. if ($parentObject === null && !$this->resolve($transport, $object, $vOptions)) {
  343. $transport->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Could not resolve vehicle for object of class {$vClass}; criteria: " . print_r($criteria, true));
  344. if ($transport->xpdo->getDebug() === true) $transport->xpdo->log(xPDO::LOG_LEVEL_DEBUG, 'Could not resolve vehicle: ' . print_r($vOptions, true));
  345. }
  346. } else {
  347. //$transport->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Could not validate vehicle object of class {$vClass}; criteria: " . print_r($criteria, true));
  348. if ($transport->xpdo->getDebug() === true) $transport->xpdo->log(xPDO::LOG_LEVEL_DEBUG, 'Could not validate vehicle object: ' . print_r($vOptions, true));
  349. }
  350. } else {
  351. $transport->xpdo->log(xPDO::LOG_LEVEL_ERROR, 'Problem instantiating object from vehicle');
  352. if ($transport->xpdo->getDebug() === true) $transport->xpdo->log(xPDO::LOG_LEVEL_DEBUG, 'Problem instantiating object from vehicle: ' . print_r(array_merge($options, $element), true));
  353. }
  354. return $uninstalled;
  355. }
  356. /**
  357. * Uninstalls related objects from the vehicle.
  358. */
  359. public function _uninstallRelated(& $transport, & $parent, $element, $options) {
  360. $uninstalled = true;
  361. if (is_object($parent) && isset ($element[xPDOTransport::RELATED_OBJECTS]) && is_array($element[xPDOTransport::RELATED_OBJECTS])) {
  362. $uninstalled = false;
  363. foreach ($element[xPDOTransport::RELATED_OBJECTS] as $rAlias => $rVehicles) {
  364. $parentClass = $parent->_class;
  365. $rMeta = $transport->xpdo->getFKDefinition($parentClass, $rAlias);
  366. if ($rMeta) {
  367. $results = array();
  368. foreach ($rVehicles as $rKey => $rVehicle) {
  369. $results[] = $this->_uninstallObject($transport, $options, $rVehicle, $parent, $rMeta);
  370. }
  371. $uninstalled = (array_search(false, $results) === false);
  372. }
  373. }
  374. }
  375. return $uninstalled;
  376. }
  377. /**
  378. * Put an xPDOObject representation into a transport package.
  379. *
  380. * This implementation supports the inclusion of related objects. Simply instantiate the related
  381. * objects that you want to include in the vehicle on the main object, and set
  382. * xPDOTransport::RELATED_OBJECTS => true in your attributes.
  383. */
  384. public function put(& $transport, & $object, $attributes = array ()) {
  385. parent :: put($transport, $object, $attributes);
  386. if (is_object($object)) {
  387. if (!isset ($this->payload['package'])) {
  388. if ($object instanceof xPDOObject) {
  389. $packageName = $object->_package;
  390. } else {
  391. $packageName = '';
  392. }
  393. $this->payload['package'] = $packageName;
  394. }
  395. if ($object instanceof xPDOObject) {
  396. $nativeKey = $object->getPrimaryKey();
  397. $this->payload['object'] = $object->toJSON('', true);
  398. $this->payload['native_key'] = $nativeKey;
  399. $this->payload['signature'] = md5($this->payload['class'] . '_' . $this->payload['guid']);
  400. if (isset ($this->payload[xPDOTransport::RELATED_OBJECTS]) && !empty ($this->payload[xPDOTransport::RELATED_OBJECTS])) {
  401. $relatedObjects = array ();
  402. foreach ($object->_relatedObjects as $rAlias => $related) {
  403. if (is_array($related)) {
  404. foreach ($related as $rKey => $rObj) {
  405. if (!isset ($relatedObjects[$rAlias]))
  406. $relatedObjects[$rAlias] = array ();
  407. $guid = md5(uniqid(rand(), true));
  408. $relatedObjects[$rAlias][$guid] = array ();
  409. $this->_putRelated($transport, $rAlias, $rObj, $relatedObjects[$rAlias][$guid]);
  410. }
  411. }
  412. elseif (is_object($related)) {
  413. if (!isset ($relatedObjects[$rAlias]))
  414. $relatedObjects[$rAlias] = array ();
  415. $guid = md5(uniqid(rand(), true));
  416. $relatedObjects[$rAlias][$guid] = array ();
  417. $this->_putRelated($transport, $rAlias, $related, $relatedObjects[$rAlias][$guid]);
  418. }
  419. }
  420. if (!empty ($relatedObjects))
  421. $this->payload['related_objects'] = $relatedObjects;
  422. }
  423. }
  424. elseif (is_object($object)) {
  425. $this->payload['object'] = $transport->xpdo->toJSON(get_object_vars($object));
  426. $this->payload['native_key'] = $this->payload['guid'];
  427. $this->payload['signature'] = md5($this->payload['class'] . '_' . $this->payload['guid']);
  428. }
  429. }
  430. }
  431. /**
  432. * Recursively put related objects into the vehicle.
  433. *
  434. * @access protected
  435. * @param xPDOTransport $transport The host xPDOTransport instance.
  436. * @param string $alias The alias representing the relation to the parent object.
  437. * @param xPDOObject &$object A reference to the dependent object being added into the vehicle.
  438. * @param array $payloadElement An element of the payload to place the dependent object in.
  439. */
  440. protected function _putRelated(& $transport, $alias, & $object, & $payloadElement) {
  441. if (is_array($payloadElement)) {
  442. if (is_object($object) && $object instanceof xPDOObject) {
  443. if (isset ($this->payload['related_object_attributes'][$alias]) && is_array($this->payload['related_object_attributes'][$alias])) {
  444. $payloadElement = array_merge($payloadElement, $this->payload['related_object_attributes'][$alias]);
  445. }
  446. elseif (isset ($this->payload['related_object_attributes'][$object->_class]) && is_array($this->payload['related_object_attributes'][$object->_class])) {
  447. $payloadElement = array_merge($payloadElement, $this->payload['related_object_attributes'][$object->_class]);
  448. }
  449. $payloadElement['class'] = $object->_class;
  450. $nativeKey = $object->getPrimaryKey();
  451. $payloadElement['object'] = $object->toJSON('', true);
  452. $payloadElement['guid'] = md5(uniqid(rand(), true));
  453. $payloadElement['native_key'] = $nativeKey;
  454. $payloadElement['signature'] = md5($object->_class . '_' . $payloadElement['guid']);
  455. $relatedObjects = array ();
  456. foreach ($object->_relatedObjects as $rAlias => $related) {
  457. if (is_array($related)) {
  458. foreach ($related as $rKey => $rObj) {
  459. if (!isset ($relatedObjects[$rAlias]))
  460. $relatedObjects[$rAlias] = array ();
  461. $guid = md5(uniqid(rand(), true));
  462. $relatedObjects[$rAlias][$guid] = array ();
  463. $this->_putRelated($transport, $rAlias, $rObj, $relatedObjects[$rAlias][$guid]);
  464. }
  465. }
  466. elseif (is_object($related)) {
  467. if (!isset ($relatedObjects[$rAlias]))
  468. $relatedObjects[$rAlias] = array ();
  469. $guid = md5(uniqid(rand(), true));
  470. $relatedObjects[$rAlias][$guid] = array ();
  471. $this->_putRelated($transport, $rAlias, $related, $relatedObjects[$rAlias][$guid]);
  472. }
  473. }
  474. if (!empty ($relatedObjects))
  475. $payloadElement['related_objects'] = $relatedObjects;
  476. }
  477. }
  478. }
  479. }