Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

initial commit

  • Loading branch information...
commit 06978072e901aea0dd704cf3e1c4892d2939df49 0 parents
Cameron Jacobson authored
21 LICENSE
@@ -0,0 +1,21 @@
+Phreezer - my take on php-object-freezer by Sebastian Bergmann
+
+Copyright (C) 2013 Cameron Jacobson
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------
+
+* Please note, some files within this project may
+ contain other license / copyright notices
7 README.md
@@ -0,0 +1,7 @@
+# Phreezer
+
+My take on sebastianbergmann/php-object-freezer. Currently with only slight modifications.
+
+## see examples in:
+
+examples/*
7 composer.json
@@ -0,0 +1,7 @@
+{
+ "autoload": {
+ "psr-0": {
+ "Phreezer": "src/"
+ }
+ }
+}
24 examples/example1.php
@@ -0,0 +1,24 @@
+<?php
+
+require_once(dirname(__DIR__).'/vendor/autoload.php');
+
+use Phreezer\Phreezer;
+use Phreezer\Storage\CouchDB;
+use Phreezer\Cache;
+use Phreezer\IdGenerator\UUID;
+use Phreezer\HashGenerator\NonRecursiveSHA1;
+
+$lazyProxy = false;
+$blacklist = array();
+$useAutoload = true;
+
+$freezer = new Phreezer(
+ new UUID(),
+ new NonRecursiveSHA1(new UUID()),
+ $blacklist,
+ $useAutoload
+);
+
+$a = new CouchDB('mydb', $freezer, new Cache(), $lazyProxy, 'localhost', 5984);
+
+var_dump($a);
25 phpunit.xml.dist
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<phpunit backupGlobals="false"
+ backupStaticAttributes="false"
+ colors="true"
+ convertErrorsToExceptions="true"
+ convertNoticesToExceptions="true"
+ convertWarningsToExceptions="true"
+ processIsolation="false"
+ stopOnFailure="false"
+ syntaxCheck="false"
+ bootstrap="tests/bootstrap.php"
+>
+ <testsuites>
+ <testsuite name="Phreezer Test Suite">
+ <directory>./tests/Phreezer/</directory>
+ </testsuite>
+ </testsuites>
+
+ <filter>
+ <whitelist>
+ <directory>./src/</directory>
+ </whitelist>
+ </filter>
+</phpunit>
80 src/Phreezer/Cache.php
@@ -0,0 +1,80 @@
+<?php
+
+/**
+ * Object_Freezer
+ *
+ * Copyright (c) 2008-2012, Sebastian Bergmann <sb@sebastian-bergmann.de>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Sebastian Bergmann nor the names of his
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package Object_Freezer
+ * @author Sebastian Bergmann <sb@sebastian-bergmann.de>
+ * @copyright 2008-2012 Sebastian Bergmann <sb@sebastian-bergmann.de>
+ * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
+ * @since File available since Release 1.0.0
+ */
+
+
+namespace Phreezer;
+
+class Cache
+{
+ /**
+ * @var array
+ */
+ protected $objects = array();
+
+ /**
+ * Retrieves an object from the object cache.
+ *
+ * @param string $id
+ * @return object
+ */
+ public function get($id)
+ {
+ if (isset($this->objects[$id])) {
+ return $this->objects[$id];
+ } else {
+ return FALSE;
+ }
+ }
+
+ /**
+ * Puts an object into the object cache.
+ *
+ * @param string $id
+ * @param object $object
+ */
+ public function put($id, $object)
+ {
+ $this->objects[$id] = $object;
+ }
+}
57 src/Phreezer/HashGenerator.php
@@ -0,0 +1,57 @@
+<?php
+
+/**
+ * Object_Freezer
+ *
+ * Copyright (c) 2008-2012, Sebastian Bergmann <sb@sebastian-bergmann.de>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Sebastian Bergmann nor the names of his
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package Object_Freezer
+ * @author Sebastian Bergmann <sb@sebastian-bergmann.de>
+ * @copyright 2008-2012 Sebastian Bergmann <sb@sebastian-bergmann.de>
+ * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
+ * @since File available since Release 1.0.0
+ */
+
+
+namespace Phreezer;
+
+interface HashGenerator
+{
+ /**
+ * Returns a hash for an object.
+ *
+ * @param object $object The object that is to be hashed.
+ * @return string
+ */
+ public function getHash($object);
+}
113 src/Phreezer/HashGenerator/NonRecursiveSHA1.php
@@ -0,0 +1,113 @@
+<?php
+
+/**
+ * Object_Freezer
+ *
+ * Copyright (c) 2008-2012, Sebastian Bergmann <sb@sebastian-bergmann.de>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Sebastian Bergmann nor the names of his
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package Object_Freezer
+ * @author Sebastian Bergmann <sb@sebastian-bergmann.de>
+ * @copyright 2008-2012 Sebastian Bergmann <sb@sebastian-bergmann.de>
+ * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
+ * @since File available since Release 1.0.0
+ */
+
+
+namespace Phreezer\HashGenerator;
+
+use Phreezer\HashGenerator;
+use Phreezer\Util;
+use Phreezer\IdGenerator;
+
+class NonRecursiveSHA1 implements HashGenerator
+{
+ /**
+ * @var Phreezer\IdGenerator
+ */
+ protected $idGenerator;
+
+ /**
+ * Constructor.
+ *
+ * @param Phreezer\IdGenerator $idGenerator
+ */
+ public function __construct(IdGenerator $idGenerator)
+ {
+ $this->idGenerator = $idGenerator;
+ }
+
+ /**
+ * Implementation of Phreezer\HashGenerator that uses the SHA1
+ * hashing function on the attribute values of an object without recursing
+ * into aggregated arrays or objects.
+ *
+ * @param object $object The object that is to be hashed.
+ * @return string
+ * @throws InvalidArgumentException
+ */
+ public function getHash($object)
+ {
+ // Bail out if a non-object was passed.
+ if (!is_object($object)) {
+ throw Util::getInvalidArgumentException(1, 'object');
+ }
+
+ $attributes = Util::readAttributes($object);
+ ksort($attributes);
+
+ if (isset($attributes['__phreezer_hash'])) {
+ unset($attributes['__phreezer_hash']);
+ }
+
+ foreach ($attributes as $key => $value) {
+ if (is_array($value)) {
+ $attributes[$key] = '<array>';
+ }
+
+ else if (is_object($value)) {
+ if (!isset($value->__phreezer_uuid)) {
+ $value->__phreezer_uuid =
+ $this->idGenerator->getId();
+ }
+
+ $attributes[$key] = $value->__phreezer_uuid;
+ }
+
+ else if (is_resource($value)) {
+ $attributes[$key] = NULL;
+ }
+ }
+
+ return sha1(get_class($object) . join(':', $attributes));
+ }
+}
56 src/Phreezer/IdGenerator.php
@@ -0,0 +1,56 @@
+<?php
+
+/**
+ * Object_Freezer
+ *
+ * Copyright (c) 2008-2012, Sebastian Bergmann <sb@sebastian-bergmann.de>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Sebastian Bergmann nor the names of his
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package Object_Freezer
+ * @author Sebastian Bergmann <sb@sebastian-bergmann.de>
+ * @copyright 2008-2012 Sebastian Bergmann <sb@sebastian-bergmann.de>
+ * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
+ * @since File available since Release 1.0.0
+ */
+
+
+namespace Phreezer;
+
+interface IdGenerator
+{
+ /**
+ * Returns a new object identifier.
+ *
+ * @return string The new object identifier
+ */
+ public function getId();
+}
69 src/Phreezer/IdGenerator/UUID.php
@@ -0,0 +1,69 @@
+<?php
+
+/**
+ * Object_Freezer
+ *
+ * Copyright (c) 2008-2012, Sebastian Bergmann <sb@sebastian-bergmann.de>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Sebastian Bergmann nor the names of his
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package Object_Freezer
+ * @author Sebastian Bergmann <sb@sebastian-bergmann.de>
+ * @copyright 2008-2012 Sebastian Bergmann <sb@sebastian-bergmann.de>
+ * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
+ * @since File available since Release 1.0.0
+ */
+
+
+namespace Phreezer\IdGenerator;
+
+use Phreezer\IdGenerator;
+
+class UUID implements IdGenerator
+{
+ /**
+ * This implementation of UUID generation is based on code from a note
+ * made on the PHP documentation.
+ *
+ * @return string
+ * @link http://de3.php.net/manual/en/function.uniqid.php#69164
+ */
+ public function getId()
+ {
+ return sprintf(
+ '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
+ mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff),
+ mt_rand(0, 0x0fff) | 0x4000,
+ mt_rand(0, 0x3fff) | 0x8000,
+ mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
+ );
+ }
+}
176 src/Phreezer/LazyProxy.php
@@ -0,0 +1,176 @@
+<?php
+
+/**
+ * Object_Freezer
+ *
+ * Copyright (c) 2008-2012, Sebastian Bergmann <sb@sebastian-bergmann.de>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Sebastian Bergmann nor the names of his
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package Object_Freezer
+ * @author Sebastian Bergmann <sb@sebastian-bergmann.de>
+ * @copyright 2008-2012 Sebastian Bergmann <sb@sebastian-bergmann.de>
+ * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
+ * @since File available since Release 1.0.0
+ */
+
+
+namespace Phreezer;
+
+use Phreezer\Storage;
+
+class LazyProxy
+{
+ /**
+ * @var Phreezer\Storage
+ */
+ protected $storage;
+
+ /**
+ * @var string
+ */
+ protected $uuid;
+
+ /**
+ * @var object
+ */
+ protected $thawedObject;
+
+ /**
+ * Constructor.
+ *
+ * @param Phreezer\Storage $storage
+ * @param string $uuid
+ */
+ public function __construct(Storage $storage, $uuid)
+ {
+ $this->storage = $storage;
+ $this->uuid = $uuid;
+ }
+
+ /**
+ * Returns the real object.
+ *
+ * @return object
+ */
+ public function getObject()
+ {
+ if ($this->thawedObject === NULL) {
+ $this->thawedObject = $this->storage->fetch($this->uuid);
+ }
+
+ return $this->thawedObject;
+ }
+
+ /**
+ * Delegates the attribute read access to the real object and
+ * tries to replace the lazy proxy object with it.
+ *
+ * @param string $name
+ * @return mixed
+ */
+ public function __get($name)
+ {
+ $object = $this->replaceProxy(2);
+ $attribute = new ReflectionProperty($object, $name);
+ $attribute->setAccessible(TRUE);
+
+ return $attribute->getValue($object);
+ }
+
+ /**
+ * Delegates the attribute write access to the real object and
+ * tries to replace the lazy proxy object with it.
+ *
+ * @param string $name
+ * @param mixed $value
+ */
+ public function __set($name, $value)
+ {
+ $object = $this->replaceProxy(2);
+ $attribute = new ReflectionProperty($object, $name);
+ $attribute->setAccessible(TRUE);
+
+ $attribute->setValue($object, $value);
+ }
+
+ /**
+ * Delegates the message to the real object and
+ * tries to replace the lazy proxy object with it.
+ *
+ * @param string $name
+ * @param array $arguments
+ * @return mixed
+ */
+ public function __call($name, array $arguments)
+ {
+ $object = $this->replaceProxy(3);
+ $reflector = new ReflectionMethod($object, $name);
+
+ return $reflector->invokeArgs($object, $arguments);
+ }
+
+ /**
+ * Tries to replace the lazy proxy object with the real object.
+ *
+ * @param integer $offset
+ * @return object
+ */
+ protected function replaceProxy($offset)
+ {
+ $object = $this->getObject();
+
+ /**
+ * 0: LazyProxy::replaceProxy()
+ * 1: LazyProxy::__get($name) / LazyProxy::__set($name, $value)
+ * 2: Frame that accesses $name
+ * 1: LazyProxy::__call($method, $arguments)
+ * 2: LazyProxy::$method()
+ * 3: Frame that invokes $method
+ */
+ $trace = debug_backtrace();
+
+ if (isset($trace[$offset]['object'])) {
+ $reflector = new ReflectionObject($trace[$offset]['object']);
+
+ foreach ($reflector->getProperties() as $attribute) {
+ $attribute->setAccessible(TRUE);
+
+ if ($attribute->getValue($trace[$offset]['object']) === $this) {
+ $attribute->setValue($trace[$offset]['object'], $object);
+ break;
+ }
+ }
+ }
+
+ return $object;
+ }
+}
398 src/Phreezer/Phreezer.php
@@ -0,0 +1,398 @@
+<?php
+
+/**
+ * Object_Freezer
+ *
+ * Copyright (c) 2008-2012, Sebastian Bergmann <sb@sebastian-bergmann.de>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Sebastian Bergmann nor the names of his
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package Object_Freezer
+ * @author Sebastian Bergmann <sb@sebastian-bergmann.de>
+ * @copyright 2008-2012 Sebastian Bergmann <sb@sebastian-bergmann.de>
+ * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
+ * @since File available since Release 1.0.0
+ */
+
+
+namespace Phreezer;
+
+use Phreezer\NonRecursiveSHA1;
+use Phreezer\IdGenerator\UUID;
+use Phreezer\Util;
+use Phreezer\IdGenerator;
+use Phreezer\HashGenerator;
+
+class Phreezer
+{
+ /**
+ * @var boolean
+ */
+ protected $autoload = TRUE;
+
+ /**
+ * @var array
+ */
+ protected $blacklist = array();
+
+ /**
+ * @var Phreezer\IdGenerator
+ */
+ protected $idGenerator;
+
+ /**
+ * @var Phreezer\HashGenerator
+ */
+ protected $hashGenerator;
+
+ /**
+ * Constructor.
+ *
+ * @param Phreezer\IdGenerator $idGenerator
+ * @param Phreezer\HashGenerator $hashGenerator
+ * @param array $blacklist
+ * @param boolean $useAutoload
+ * @throws InvalidArgumentException
+ */
+ public function __construct(IdGenerator $idGenerator = NULL, HashGenerator $hashGenerator = NULL, array $blacklist = array(), $useAutoload = TRUE)
+ {
+ // Use Phreezer\IdGenerator\UUID by default.
+ if ($idGenerator === NULL) {
+ $idGenerator = new Phreezer\IdGenerator_UUID;
+ }
+
+ // Use Phreezer\HashGenerator\NonRecursiveSHA1 by default.
+ if ($hashGenerator === NULL) {
+ $hashGenerator = new NonRecursiveSHA1(
+ $idGenerator
+ );
+ }
+
+ $this->setIdGenerator($idGenerator);
+ $this->setHashGenerator($hashGenerator);
+ $this->setBlacklist($blacklist);
+ $this->setUseAutoload($useAutoload);
+ }
+
+ public function freeze($object, array &$objects = array())
+ {
+ // Bail out if a non-object was passed.
+ if (!is_object($object)) {
+ throw Util::getInvalidArgumentException(1, 'object');
+ }
+
+ // The object has not been frozen before, generate a new UUID and
+ // store it in the "special" __phreezer_uuid attribute.
+ if (!isset($object->__phreezer_uuid)) {
+ $object->__phreezer_uuid = $this->idGenerator->getId();
+ }
+
+ $isDirty = $this->isDirty($object, TRUE);
+ $uuid = $object->__phreezer_uuid;
+
+ if (!isset($objects[$uuid])) {
+ $objects[$uuid] = array(
+ 'className' => get_class($object),
+ 'isDirty' => $isDirty,
+ 'state' => array()
+ );
+
+ // Iterate over the attributes of the object.
+ foreach (Util::readAttributes($object) as $k => $v) {
+ if ($k !== '__phreezer_uuid') {
+ if (is_array($v)) {
+ $this->freezeArray($v, $objects);
+ }
+
+ else if (is_object($v) &&
+ !in_array(get_class($v), $this->blacklist)) {
+ // Freeze the aggregated object.
+ $this->freeze($v, $objects);
+
+ // Replace $v with the aggregated object's UUID.
+ $v = '__phreezer_' .
+ $v->__phreezer_uuid;
+ }
+
+ else if (is_resource($v)) {
+ $v = NULL;
+ }
+
+ // Store the attribute in the object's state array.
+ $objects[$uuid]['state'][$k] = $v;
+ }
+ }
+ }
+
+ return array('root' => $uuid, 'objects' => $objects);
+ }
+
+ /**
+ * Freezes an array.
+ *
+ * @param array $array The array that is to be frozen.
+ * @param array $objects Only used internally.
+ */
+ protected function freezeArray(array &$array, array &$objects)
+ {
+ foreach ($array as &$value) {
+ if (is_array($value)) {
+ $this->freezeArray($value, $objects);
+ }
+
+ else if (is_object($value)) {
+ $tmp = $this->freeze($value, $objects);
+ $value = '__phreezer_' . $tmp['root'];
+ unset($tmp);
+ }
+ }
+ }
+
+ public function thaw(array $frozenObject, $root = NULL, array &$objects = array())
+ {
+ // Bail out if one of the required classes cannot be found.
+ foreach ($frozenObject['objects'] as $object) {
+ if (!class_exists($object['className'], $this->useAutoload)) {
+ throw new RuntimeException(
+ sprintf(
+ 'Class "%s" could not be found.', $object['className']
+ )
+ );
+ }
+ }
+
+ // By default, we thaw the root object and (recursively)
+ // its aggregated objects.
+ if ($root === NULL) {
+ $root = $frozenObject['root'];
+ }
+
+ // Thaw object (if it has not been thawed before).
+ if (!isset($objects[$root])) {
+ $className = $frozenObject['objects'][$root]['className'];
+ $state = $frozenObject['objects'][$root]['state'];
+ $reflector = new ReflectionClass($className);
+ $objects[$root] = $reflector->newInstanceWithoutConstructor();
+
+ // Handle aggregated objects.
+ $this->thawArray($state, $frozenObject, $objects);
+
+ $reflector = new ReflectionObject($objects[$root]);
+
+ foreach ($state as $name => $value) {
+ if (strpos($name, '__phreezer') !== 0) {
+ if ($reflector->hasProperty($name)) {
+ $attribute = $reflector->getProperty($name);
+ $attribute->setAccessible(TRUE);
+ $attribute->setValue($objects[$root], $value);
+ } else {
+ $objects[$root]->$name = $value;
+ }
+ }
+ }
+
+ // Store UUID.
+ $objects[$root]->__phreezer_uuid = $root;
+
+ // Store hash.
+ if (isset($state['__phreezer_hash'])) {
+ $objects[$root]->__phreezer_hash =
+ $state['__phreezer_hash'];
+ }
+ }
+
+ return $objects[$root];
+ }
+
+ /**
+ * Thaws an array.
+ *
+ * @param array $array The array that is to be thawed.
+ * @param array $frozenObject The frozen object structure from which to thaw.
+ * @param array $objects Only used internally.
+ */
+ protected function thawArray(array &$array, array $frozenObject, array &$objects)
+ {
+ foreach ($array as &$value) {
+ if (is_array($value)) {
+ $this->thawArray($value, $frozenObject, $objects);
+ }
+
+ else if (is_string($value) &&
+ strpos($value, '__phreezer') === 0) {
+ $aggregatedObjectId = str_replace(
+ '__phreezer_', '', $value
+ );
+
+ if (isset($frozenObject['objects'][$aggregatedObjectId])) {
+ $value = $this->thaw(
+ $frozenObject, $aggregatedObjectId, $objects
+ );
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns the Phreezer\IdGenerator implementation used
+ * to generate object identifiers.
+ *
+ * @return Phreezer\IdGenerator
+ */
+ public function getIdGenerator()
+ {
+ return $this->idGenerator;
+ }
+
+ /**
+ * Sets the Phreezer\IdGenerator implementation used
+ * to generate object identifiers.
+ *
+ * @param Phreezer\IdGenerator $idGenerator
+ */
+ public function setIdGenerator(IdGenerator $idGenerator)
+ {
+ $this->idGenerator = $idGenerator;
+ }
+
+ /**
+ * Returns the Phreezer\HashGenerator implementation used
+ * to generate hash objects.
+ *
+ * @return Phreezer\HashGenerator
+ */
+ public function getHashGenerator()
+ {
+ return $this->hashGenerator;
+ }
+
+ /**
+ * Sets the Phreezer\HashGenerator implementation used
+ * to generate hash objects.
+ *
+ * @param Phreezer\HashGenerator $hashGenerator
+ */
+ public function setHashGenerator(HashGenerator $hashGenerator)
+ {
+ $this->hashGenerator = $hashGenerator;
+ }
+
+ /**
+ * Returns the blacklist of class names for which aggregates objects are
+ * not frozen.
+ *
+ * @return array
+ */
+ public function getBlacklist()
+ {
+ return $this->blacklist;
+ }
+
+ /**
+ * Sets the blacklist of class names for which aggregates objects are
+ * not frozen.
+ *
+ * @param array $blacklist
+ * @throws InvalidArgumentException
+ */
+ public function setBlacklist(array $blacklist)
+ {
+ $this->blacklist = $blacklist;
+ }
+
+ /**
+ * Returns the flag that controls whether or not __autoload()
+ * should be invoked.
+ *
+ * @return boolean
+ */
+ public function getUseAutoload()
+ {
+ return $this->useAutoload;
+ }
+
+ /**
+ * Sets the flag that controls whether or not __autoload()
+ * should be invoked.
+ *
+ * @param boolean $flag
+ * @throws InvalidArgumentException
+ */
+ public function setUseAutoload($flag)
+ {
+ // Bail out if a non-boolean was passed.
+ if (!is_bool($flag)) {
+ throw Util::getInvalidArgumentException(1, 'boolean');
+ }
+
+ $this->useAutoload = $flag;
+ }
+
+ /**
+ * Checks whether an object is dirty, ie. if its SHA1 hash is still valid.
+ *
+ * Returns TRUE when the object's __phreezer_hash attribute is no
+ * longer valid or does not exist.
+ * Returns FALSE when the object's __phreezer_hash attribute is
+ * still valid.
+ *
+ * @param object $object The object that is to be checked.
+ * @param boolean $rehash Whether or not to rehash dirty objects.
+ * @return boolean
+ * @throws InvalidArgumentException
+ */
+ public function isDirty($object, $rehash = FALSE)
+ {
+ // Bail out if a non-object was passed.
+ if (!is_object($object)) {
+ throw Util::getInvalidArgumentException(1, 'object');
+ }
+
+ // Bail out if a non-boolean was passed.
+ if (!is_bool($rehash)) {
+ throw Util::getInvalidArgumentException(2, 'boolean');
+ }
+
+ $isDirty = TRUE;
+ $hash = $this->hashGenerator->getHash($object);
+
+ if (isset($object->__phreezer_hash) &&
+ $object->__phreezer_hash == $hash) {
+ $isDirty = FALSE;
+ }
+
+ if ($isDirty && $rehash) {
+ $object->__phreezer_hash = $hash;
+ }
+
+ return $isDirty;
+ }
+}
196 src/Phreezer/Storage.php
@@ -0,0 +1,196 @@
+<?php
+
+/**
+ * Object_Freezer
+ *
+ * Copyright (c) 2008-2012, Sebastian Bergmann <sb@sebastian-bergmann.de>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Sebastian Bergmann nor the names of his
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package Object_Freezer
+ * @author Sebastian Bergmann <sb@sebastian-bergmann.de>
+ * @copyright 2008-2012 Sebastian Bergmann <sb@sebastian-bergmann.de>
+ * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
+ * @since File available since Release 1.0.0
+ */
+
+
+namespace Phreezer;
+
+use Phreezer\Phreezer;
+use Phreezer\Cache;
+use Phreezer\LazyProxy;
+use Phreezer\Util;
+
+abstract class Storage
+{
+ /**
+ * @var Phreezer\Cache
+ */
+ protected $cache;
+
+ /**
+ * @var Phreezer
+ */
+ protected $freezer;
+
+ /**
+ * @var boolean
+ */
+ protected $lazyLoad = FALSE;
+
+ /**
+ * Constructor.
+ *
+ * @param Phreezer $freezer Phreezer instance to be used
+ * @param Phreezer\Cache $cache Phreezer\Cache instance to be used
+ * @param boolean $useLazyLoad Flag that controls whether objects are fetched using lazy load or not
+ */
+ public function __construct(Phreezer $freezer = NULL, Cache $cache = NULL, $useLazyLoad = FALSE)
+ {
+ if ($freezer === NULL) {
+ $freezer = new Phreezer;
+ }
+
+ if ($cache === NULL) {
+ $cache = new Cache;
+ }
+
+ $this->freezer = $freezer;
+ $this->cache = $cache;
+
+ $this->setUseLazyLoad($useLazyLoad);
+ }
+
+ /**
+ * Sets the flag that controls whether objects are fetched using lazy load.
+ *
+ * @param boolean $flag
+ * @throws InvalidArgumentException
+ */
+ public function setUseLazyLoad($flag)
+ {
+ // Bail out if a non-boolean was passed.
+ if (!is_bool($flag)) {
+ throw Util::getInvalidArgumentException(1, 'boolean');
+ }
+
+ $this->lazyLoad = $flag;
+ }
+
+ /**
+ * Freezes an object and stores it in the object storage.
+ *
+ * @param object $object The object that is to be stored.
+ * @return string
+ */
+ public function store($object)
+ {
+ // Bail out if a non-object was passed.
+ if (!is_object($object)) {
+ throw Util::getInvalidArgumentException(1, 'object');
+ }
+
+ $this->doStore($this->freezer->freeze($object));
+
+ return $object->__phreezer_uuid;
+ }
+
+ /**
+ * Fetches a frozen object from the object storage and thaws it.
+ *
+ * @param string $id The ID of the object that is to be fetched.
+ * @return object
+ */
+ public function fetch($id)
+ {
+ // Bail out if a non-string was passed.
+ if (!is_string($id)) {
+ throw Util::getInvalidArgumentException(1, 'string');
+ }
+
+ // Try to retrieve object from the object cache.
+ $object = $this->cache->get($id);
+
+ if (!$object) {
+ // Retrieve object from the object storage.
+ $frozenObject = $this->doFetch($id);
+ $this->fetchArray($frozenObject['objects'][$id]['state']);
+ $object = $this->freezer->thaw($frozenObject);
+
+ // Put object into the object cache.
+ $this->cache->put($id, $object);
+ }
+
+ return $object;
+ }
+
+ /**
+ * Fetches a frozen array from the object storage and thaws it.
+ *
+ * @param array $array
+ * @param array $objects
+ */
+ protected function fetchArray(array &$array, array &$objects = array())
+ {
+ foreach ($array as &$value) {
+ if (is_array($value)) {
+ $this->fetchArray($value, $objects);
+ }
+
+ else if (is_string($value) &&
+ strpos($value, '__phreezer_') === 0) {
+ $uuid = str_replace('__phreezer_', '', $value);
+
+ if (!$this->lazyLoad) {
+ $this->doFetch($uuid, $objects);
+ } else {
+ $value = new LazyProxy($this, $uuid);
+ }
+ }
+ }
+ }
+
+ /**
+ * Freezes an object and stores it in the object storage.
+ *
+ * @param array $frozenObject
+ */
+ abstract protected function doStore(array $frozenObject);
+
+ /**
+ * Fetches a frozen object from the object storage and thaws it.
+ *
+ * @param string $id The ID of the object that is to be fetched.
+ * @return object
+ */
+ abstract protected function doFetch($id);
+}
287 src/Phreezer/Storage/CouchDB.php
@@ -0,0 +1,287 @@
+<?php
+
+/**
+ * Object_Freezer
+ *
+ * Copyright (c) 2008-2012, Sebastian Bergmann <sb@sebastian-bergmann.de>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Sebastian Bergmann nor the names of his
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package Object_Freezer
+ * @author Sebastian Bergmann <sb@sebastian-bergmann.de>
+ * @copyright 2008-2012 Sebastian Bergmann <sb@sebastian-bergmann.de>
+ * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
+ * @since File available since Release 1.0.0
+ */
+
+
+namespace Phreezer\Storage;
+
+use Phreezer\Phreezer;
+use Phreezer\Storage;
+use Phreezer\Util;
+use Phreezer\Cache;
+
+class CouchDB extends Storage
+{
+ /**
+ * @var string
+ */
+ protected $database;
+
+ /**
+ * @var string
+ */
+ protected $host;
+
+ /**
+ * @var int
+ */
+ protected $port;
+
+ /**
+ * @var array
+ */
+ protected $revisions = array();
+
+ /**
+ * @var boolean
+ */
+ protected $debug = FALSE;
+
+ /**
+ * Constructor.
+ *
+ * @param string $database Name of the database to be used
+ * @param Phreezer $freezer Phreezer instance to be used
+ * @param Phreezer\Cache $cache Phreezer\Cache instance to be used
+ * @param boolean $useLazyLoad Flag that controls whether objects are fetched using lazy load or not
+ * @param string $host Hostname of the CouchDB instance to be used
+ * @param int $port Port of the CouchDB instance to be used
+ * @throws InvalidArgumentException
+ */
+ public function __construct($database, Phreezer $freezer = NULL, Cache $cache = NULL, $useLazyLoad = FALSE, $host = 'localhost', $port = 5984)
+ {
+ parent::__construct($freezer, $cache, $useLazyLoad);
+
+ if (!is_string($database)) {
+ throw Util::getInvalidArgumentException(1, 'string');
+ }
+
+ if (!is_string($host)) {
+ throw Util::getInvalidArgumentException(4, 'string');
+ }
+
+ if (!is_int($port)) {
+ throw Util::getInvalidArgumentException(5, 'integer');
+ }
+
+ $this->database = $database;
+ $this->host = $host;
+ $this->port = $port;
+ }
+
+ /**
+ * Freezes an object and stores it in the object storage.
+ *
+ * @param array $frozenObject
+ */
+ protected function doStore(array $frozenObject)
+ {
+ $payload = array('docs' => array());
+
+ foreach ($frozenObject['objects'] as $id => $object) {
+ if ($object['isDirty'] !== FALSE) {
+ $revision = NULL;
+
+ if (isset($this->revisions[$id])) {
+ $revision = $this->revisions[$id];
+ }
+
+ $data = array(
+ '_id' => $id,
+ '_rev' => $revision,
+ 'class' => $object['className'],
+ 'state' => $object['state']
+ );
+
+ if (!$data['_rev']) {
+ unset($data['_rev']);
+ }
+
+ $payload['docs'][] = $data;
+ }
+ }
+
+ if (!empty($payload['docs'])) {
+ $response = $this->send(
+ 'POST',
+ '/' . $this->database . '/_bulk_docs',
+ json_encode($payload)
+ );
+
+ if (strpos($response['headers'], 'HTTP/1.1 201 Created') !== 0) {
+ // @codeCoverageIgnoreStart
+ throw new RuntimeException('Could not save objects.');
+ // @codeCoverageIgnoreEnd
+ }
+
+ $data = json_decode($response['body'], TRUE);
+
+ foreach ($data as $state) {
+ if (isset($state['error'])) {
+ // @codeCoverageIgnoreStart
+ throw new RuntimeException(
+ sprintf(
+ 'Could not save object "%s": %s - %s',
+ $state['id'],
+ $state['error'],
+ $state['reason']
+ )
+ );
+ // @codeCoverageIgnoreEnd
+ } else {
+ $this->revisions[$state['id']] = $state['rev'];
+ }
+ }
+ }
+ }
+
+ /**
+ * Fetches a frozen object from the object storage and thaws it.
+ *
+ * @param string $id The ID of the object that is to be fetched.
+ * @param array $objects Only used internally.
+ * @return object
+ * @throws InvalidArgumentException
+ * @throws RuntimeException
+ */
+ protected function doFetch($id, array &$objects = array())
+ {
+ $isRoot = empty($objects);
+
+ if (!isset($objects[$id])) {
+ $response = $this->send(
+ 'GET', '/' . $this->database . '/' . urlencode($id)
+ );
+
+ if (strpos($response['headers'], 'HTTP/1.1 200 OK') !== 0) {
+ throw new RuntimeException(
+ sprintf('Object with id "%s" could not be fetched.', $id)
+ );
+ }
+
+ $object = json_decode($response['body'], TRUE);
+ $this->revisions[$object['_id']] = $object['_rev'];
+
+ $objects[$id] = array(
+ 'className' => $object['class'],
+ 'isDirty' => FALSE,
+ 'state' => $object['state']
+ );
+
+ if (!$this->lazyLoad) {
+ $this->fetchArray($object['state'], $objects);
+ }
+ }
+
+ if ($isRoot) {
+ return array('root' => $id, 'objects' => $objects);
+ }
+ }
+
+ /**
+ * Sends an HTTP request to the CouchDB server.
+ *
+ * @param string $method
+ * @param string $url
+ * @param string $payload
+ * @return array
+ * @throws RuntimeException
+ */
+ public function send($method, $url, $payload = NULL)
+ {
+ $socket = @fsockopen($this->host, $this->port, $errno, $errstr);
+
+ if (!$socket) {
+ throw new RuntimeException($errno . ': ' . $errstr);
+ }
+
+ $request = sprintf(
+ "%s %s HTTP/1.1\r\nHost: %s:%d\r\nContent-Type: application/json\r\nConnection: close\r\n",
+ $method,
+ $url,
+ $this->host,
+ $this->port
+ );
+
+ if ($payload !== NULL) {
+ $request .= 'Content-Length: ' . strlen($payload) . "\r\n\r\n" .
+ $payload;
+ }
+
+ $request .= "\r\n";
+
+ // @codeCoverageIgnoreStart
+ if ($this->debug) {
+ print $request;
+ }
+ // @codeCoverageIgnoreEnd
+
+ fwrite($socket, $request);
+
+ $buffer = '';
+
+ while (!feof($socket)) {
+ $buffer .= fgets($socket);
+ }
+
+ list($headers, $body) = explode("\r\n\r\n", $buffer);
+
+ return array('headers' => $headers, 'body' => $body);
+ }
+
+ /**
+ * Sets the flag that controls whether or not debug messages are printed.
+ *
+ * @param boolean $flag
+ * @throws InvalidArgumentException
+ */
+ public function setDebug($flag)
+ {
+ // Bail out if a non-boolean was passed.
+ if (!is_bool($flag)) {
+ throw Util::getInvalidArgumentException(1, 'boolean');
+ }
+
+ $this->debug = $flag;
+ }
+}
100 src/Phreezer/Util.php
@@ -0,0 +1,100 @@
+<?php
+
+/**
+ * Object_Freezer
+ *
+ * Copyright (c) 2008-2012, Sebastian Bergmann <sb@sebastian-bergmann.de>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Sebastian Bergmann nor the names of his
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package Object_Freezer
+ * @author Sebastian Bergmann <sb@sebastian-bergmann.de>
+ * @copyright 2008-2012 Sebastian Bergmann <sb@sebastian-bergmann.de>
+ * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
+ * @since File available since Release 1.0.0
+ */
+
+
+namespace Phreezer;
+
+use Phreezer\Util;
+
+class Util
+{
+ /**
+ * Returns an associative array of all attributes of an object,
+ * including those declared as protected or private.
+ *
+ * @param object $object The object for which all attributes are returned.
+ * @return array
+ * @throws InvalidArgumentException
+ */
+ public static function readAttributes($object)
+ {
+ // Bail out if a non-object was passed.
+ if (!is_object($object)) {
+ throw Util::getInvalidArgumentException(1, 'object');
+ }
+
+ $reflector = new \ReflectionObject($object);
+ $result = array();
+
+ // Iterate over the attributes of the object.
+ foreach ($reflector->getProperties() as $attribute) {
+ $attribute->setAccessible(TRUE);
+ $result[$attribute->getName()] = $attribute->getValue($object);
+ }
+
+ return $result;
+ }
+
+ /**
+ * Only used internally.
+ *
+ * @param integer $argument
+ * @param string $type
+ * @return InvalidArgumentException
+ */
+ public static function getInvalidArgumentException($argument, $type)
+ {
+ $stack = debug_backtrace(FALSE);
+
+ return new \InvalidArgumentException(
+ sprintf(
+ 'Argument #%d of %s::%s() is no %s',
+ $argument,
+ $stack[1]['class'],
+ $stack[1]['function'],
+ $type
+ )
+ );
+ }
+}
10 tests/Phreezer/PhreezerTest.php
@@ -0,0 +1,10 @@
+<?php
+
+namespace Phreezer\Tests;
+
+class PhreezerTest extends \PHPUnit_Framework_TestCase
+{
+ public function setUp(){}
+
+ public function testPhreezer(){}
+}
4 tests/bootstrap.php
@@ -0,0 +1,4 @@
+<?php
+
+$loader = require dirname(__DIR__).'/vendor/autoload.php';
+$loader->add('Phreezer\Tests', __DIR__);
Please sign in to comment.
Something went wrong with that request. Please try again.