From 5984bc88f61afcd39921fc9ff7254ca6d4c2f7c0 Mon Sep 17 00:00:00 2001 From: anton Date: Tue, 4 Jul 2017 00:09:21 +0300 Subject: [PATCH 1/2] reflection class --- src/DBAL.php | 59 +++++++++-- src/Document/Document.php | 19 ++++ src/DocumentMapper/DataMapper.php | 127 ++++++++++++++++------- src/DocumentMapper/DataMapperFactory.php | 12 ++- src/Instantiator/Instantiator.php | 24 +++++ 5 files changed, 196 insertions(+), 45 deletions(-) create mode 100644 src/Instantiator/Instantiator.php diff --git a/src/DBAL.php b/src/DBAL.php index 8a4f861..aef52d8 100644 --- a/src/DBAL.php +++ b/src/DBAL.php @@ -8,42 +8,85 @@ class DBAL { private $db; - public function __construct($host, $port, $db_name) + /** + * DBAL constructor. + * @param string $host + * @param string $port + * @param string $db_name + */ + public function __construct(string $host, string $port, string $db_name) { $this->db = (new Client("mongodb://$host:$port"))->$db_name; } - public function insert($table_name, array $data) + /** + * @param string $table_name + * @param array $data + * @return \MongoDB\InsertOneResult + */ + public function insert(string $table_name, array $data) { return $this->db->$table_name->insertOne($data); } - public function insertMany($table_name, array $data) + /** + * @param string $table_name + * @param array $data + * @return \MongoDB\InsertManyResult + */ + public function insertMany(string $table_name, array $data) { return $this->db->$table_name->insertMany($data); } - public function update($table_name, array $filter, array $data) + /** + * @param string $table_name + * @param array $filter + * @param array $data + * @return \MongoDB\UpdateResult + */ + public function update(string $table_name, array $filter, array $data) { return $this->db->$table_name->updateOne($filter, ['$set' => $data]); } - public function delete($table_name, array $filter) + /** + * @param string $table_name + * @param array $filter + * @return \MongoDB\DeleteResult + */ + public function delete(string $table_name, array $filter) { return $this->db->$table_name->deleteOne($filter); } - public function find($table_name, array $filter, array $options = []) + /** + * @param string $table_name + * @param array $filter + * @param array $options + * @return \MongoDB\Driver\Cursor + */ + public function find(string $table_name, array $filter, array $options = []) { return $this->db->$table_name->find($filter, $options); } - public function findOne($table_name, array $filter, array $options = []) + /** + * @param string $table_name + * @param array $filter + * @param array $options + * @return array|null|object + */ + public function findOne(string $table_name, array $filter, array $options = []) { return $this->db->$table_name->findOne($filter, $options); } - public function drop($table_name) + /** + * @param string $table_name + * @return array|object + */ + public function drop(string $table_name) { return $this->db->$table_name->drop(); } diff --git a/src/Document/Document.php b/src/Document/Document.php index eaea05f..418a681 100644 --- a/src/Document/Document.php +++ b/src/Document/Document.php @@ -4,5 +4,24 @@ class Document { + private $id; + /** + * @return mixed + */ + public function getId() + { + return (string)$this->id; + } + + /** + * @param $id + * @return $this + */ + public function setId(string $id) + { + $this->id = $id; + + return $this; + } } \ No newline at end of file diff --git a/src/DocumentMapper/DataMapper.php b/src/DocumentMapper/DataMapper.php index 1098aa8..6a2605f 100644 --- a/src/DocumentMapper/DataMapper.php +++ b/src/DocumentMapper/DataMapper.php @@ -4,31 +4,43 @@ use ODM\DBAL; use ODM\Document\Document; +use ODM\Instantiator\Instantiator; class DataMapper { private $dbal; private $table_name; - private $class; + private $class_name; + private $instantiator; const MONGO_ID = '_id'; const ID = 'id'; - public function __construct(DBAL $dbal, $class) + /** + * DataMapper constructor. + * @param DBAL $dbal + * @param string $class_name + */ + public function __construct(DBAL $dbal, string $class_name) { - $this->dbal = $dbal; - $this->class = $class; - $path = explode('\\', $class); - $this->table_name = mb_strtolower($this->camelCaseToSnake(array_pop($path))); + $this->dbal = $dbal; + $this->class_name = $class_name; + $path = explode('\\', $class_name); + $this->table_name = mb_strtolower($this->camelCaseToSnake(array_pop($path))); + $this->instantiator = new Instantiator(); } + /** + * @param Document $obj + * @return Document + */ public function insert(Document $obj) { $data = $this->objToArray($obj); if (array_key_exists(self::MONGO_ID, $data) && empty($data[self::MONGO_ID])) { - unset($data[self::MONGO_ID]); + $data[self::MONGO_ID] = $this->generateId(); } $result = $this->dbal->insert($this->table_name, $data); @@ -36,6 +48,10 @@ public function insert(Document $obj) return $obj->setId($result->getInsertedId()); } + /** + * @param Document $obj + * @return Document + */ public function update(Document $obj) { $data = $this->objToArray($obj); @@ -46,16 +62,28 @@ public function update(Document $obj) return $obj; } + /** + * @param Document $obj + * @return \MongoDB\DeleteResult + */ public function delete(Document $obj) { return $this->dbal->delete($this->table_name, [self::MONGO_ID => $obj->getId()]); } + /** + * @return bool + */ public function drop() { - return $this->dbal->drop($this->table_name); + return (bool)$this->dbal->drop($this->table_name); } + /** + * @param array $filter + * @param array $options + * @return Document[]|array + */ public function find(array $filter = [], array $options = []) { if (array_key_exists(self::ID, $filter)) { @@ -65,12 +93,17 @@ public function find(array $filter = [], array $options = []) $result = []; foreach ($this->dbal->find($this->table_name, $filter, $options) as $r) { - $result[] = $this->mapObj(new $this->class, $r); + $result[] = $this->mapObj($this->class_name, (array)$r); } return $result; } + /** + * @param array $filter + * @param array $options + * @return Document|null + */ public function findOne(array $filter = [], array $options = []) { if (array_key_exists(self::ID, $filter)) { @@ -80,46 +113,61 @@ public function findOne(array $filter = [], array $options = []) $data = $this->dbal->findOne($this->table_name, $filter, $options); - return empty($data) ? null : $this->mapObj(new $this->class, $data); + return empty($data) ? null : $this->mapObj($this->class_name, (array)$data); } - private function mapObj($obj, $data) + /** + * @return string + */ + private function generateId() { - $methods = get_class_methods(get_class($obj)); + return bin2hex(random_bytes(15)); + } - foreach ((array)$data as $field => $value) { + /** + * @param string $class_name + * @param array $data + * @return Document + */ + private function mapObj(string $class_name, array $data) + { + $obj = $this->instantiator->instantiate($class_name); + $reflect = new \ReflectionClass($obj); + $properties = array_merge($reflect->getProperties(), $reflect->getParentClass()->getProperties()); - $field_name = self::MONGO_ID === (string)$field ? self::ID : $field; - $value = self::MONGO_ID === (string)$field ? (string)$value : $value; - $value = is_object($value) ? (array)$value : $value; + foreach($properties as $prop) { + + if ($prop->getName() === self::ID) { + $prop_name = self::MONGO_ID; + } else { + $prop_name = $prop->getName(); + } - if (null === $value) { + if (!array_key_exists($prop_name, $data)) { continue; } - $setter = 'set' . $this->snakeToCamelCase($field_name); + if ($prop->isPrivate() || $prop->isProtected()) { + $prop->setAccessible(true); + } + + if ($prop->getName() === self::ID) { + $prop->setValue($obj, (string)$data[$prop_name]); - if (!in_array($setter, $methods)) { continue; } - $obj->$setter($value); + $prop->setValue($obj, $data[$prop_name]); } return $obj; } - private function snakeToCamelCase($input) - { - $new = []; - foreach (explode('_', $input) as $key => $word) { - $new[] = ucfirst($word); - } - - return implode('', $new); - } - - private function camelCaseToSnake($input) + /** + * @param $input + * @return string + */ + private function camelCaseToSnake(string $input) { preg_match_all('!([A-Z][A-Z0-9]*(?=$|[A-Z][a-z0-9])|[A-Za-z][a-z0-9]+)!', $input, $matches); $res = $matches[0]; @@ -130,12 +178,17 @@ private function camelCaseToSnake($input) return implode('_', $res); } - public function objToArray($obj) + /** + * @param Document $obj + * @return array + */ + private function objToArray(Document $obj) { $data = []; $reflect = new \ReflectionClass($obj); - foreach ($reflect->getProperties() as $prop) { - $getter = 'get' . $this->snakeToCamelCase($prop->getName()); + $properties = array_merge($reflect->getProperties(), $reflect->getParentClass()->getProperties()); + + foreach ($properties as $prop) { if ($prop->getName() === self::ID) { $prop_name = self::MONGO_ID; @@ -143,7 +196,11 @@ public function objToArray($obj) $prop_name = $prop->getName(); } - $data[$prop_name] = $obj->$getter(); + if ($prop->isPrivate() || $prop->isProtected()) { + $prop->setAccessible(true); + } + + $data[$prop_name] = $prop->getValue($obj); } return $data; diff --git a/src/DocumentMapper/DataMapperFactory.php b/src/DocumentMapper/DataMapperFactory.php index b30e68a..5113db5 100644 --- a/src/DocumentMapper/DataMapperFactory.php +++ b/src/DocumentMapper/DataMapperFactory.php @@ -8,13 +8,21 @@ class DataMapperFactory { private $dbal; + /** + * DataMapperFactory constructor. + * @param DBAL $dbal + */ public function __construct(DBAL $dbal) { $this->dbal = $dbal; } - public function init($class) + /** + * @param $class_name + * @return DataMapper + */ + public function init($class_name) { - return new DataMapper($this->dbal, $class); + return new DataMapper($this->dbal, $class_name); } } \ No newline at end of file diff --git a/src/Instantiator/Instantiator.php b/src/Instantiator/Instantiator.php new file mode 100644 index 0000000..21ecb9e --- /dev/null +++ b/src/Instantiator/Instantiator.php @@ -0,0 +1,24 @@ + Date: Tue, 4 Jul 2017 00:18:44 +0300 Subject: [PATCH 2/2] Merge branch 'master' of github.com:mrsuh/mongo-odm into dev # Conflicts: # src/DBAL.php # src/Document/Document.php # src/DocumentMapper/DataMapper.php # src/DocumentMapper/DataMapperFactory.php --- README.md | 2 +- composer.json | 3 ++- src/Instantiator/Instantiator.php | 3 --- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 18b5a0b..d6985bb 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ class Note extends ODM\Document\Document } /* Initialize connection */ -$dbal = new ODM\DBAL('127.0.0.1', '27017', 'test2'); +$dbal = new ODM\DBAL('127.0.0.1', '27017', 'test'); $factory = new ODM\DocumentMapper\DataMapperFactory($dbal); /* Initialize DataMapper for your Document */ diff --git a/composer.json b/composer.json index 83f091a..aad52ca 100644 --- a/composer.json +++ b/composer.json @@ -3,7 +3,8 @@ "description": "mongo odm", "type": "library", "require": { - "mongodb/mongodb": "^1.1" + "mongodb/mongodb": "^1.1", + "php": "7.*" }, "autoload": { "psr-4": { "ODM\\": "src/" } diff --git a/src/Instantiator/Instantiator.php b/src/Instantiator/Instantiator.php index 21ecb9e..873aee8 100644 --- a/src/Instantiator/Instantiator.php +++ b/src/Instantiator/Instantiator.php @@ -4,9 +4,6 @@ class Instantiator { - const SERIALIZATION_FORMAT_USE_UNSERIALIZER = 'C'; - const SERIALIZATION_FORMAT_AVOID_UNSERIALIZER = 'O'; - /** * @param string $class_name * @return mixed