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/DBAL.php b/src/DBAL.php index b5d547f..aef52d8 100644 --- a/src/DBAL.php +++ b/src/DBAL.php @@ -8,79 +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; } /** - * @param $table_name - * @param array $data - * @return mixed + * @param string $table_name + * @param array $data + * @return \MongoDB\InsertOneResult */ - public function insert($table_name, array $data) + public function insert(string $table_name, array $data) { return $this->db->$table_name->insertOne($data); } /** - * @param $table_name - * @param array $data - * @return mixed + * @param string $table_name + * @param array $data + * @return \MongoDB\InsertManyResult */ - public function insertMany($table_name, array $data) + public function insertMany(string $table_name, array $data) { return $this->db->$table_name->insertMany($data); } /** - * @param $table_name - * @param array $filter - * @param array $data - * @return mixed + * @param string $table_name + * @param array $filter + * @param array $data + * @return \MongoDB\UpdateResult */ - public function update($table_name, array $filter, array $data) + public function update(string $table_name, array $filter, array $data) { return $this->db->$table_name->updateOne($filter, ['$set' => $data]); } /** - * @param $table_name - * @param array $filter - * @return mixed + * @param string $table_name + * @param array $filter + * @return \MongoDB\DeleteResult */ - public function delete($table_name, array $filter) + public function delete(string $table_name, array $filter) { return $this->db->$table_name->deleteOne($filter); } /** - * @param $table_name - * @param array $filter - * @param array $options - * @return mixed + * @param string $table_name + * @param array $filter + * @param array $options + * @return \MongoDB\Driver\Cursor */ - public function find($table_name, array $filter, array $options = []) + public function find(string $table_name, array $filter, array $options = []) { return $this->db->$table_name->find($filter, $options); } /** - * @param $table_name - * @param array $filter - * @param array $options - * @return mixed + * @param string $table_name + * @param array $filter + * @param array $options + * @return array|null|object */ - public function findOne($table_name, array $filter, array $options = []) + public function findOne(string $table_name, array $filter, array $options = []) { return $this->db->$table_name->findOne($filter, $options); } /** - * @param $table_name - * @return mixed + * @param string $table_name + * @return array|object */ - public function drop($table_name) + 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 6082ae2..418a681 100644 --- a/src/Document/Document.php +++ b/src/Document/Document.php @@ -4,25 +4,24 @@ class Document { - private $id; + private $id; /** * @return mixed */ public function getId() { - return $this->id; + return (string)$this->id; } /** * @param $id * @return $this */ - public function setId($id) + 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 a5fc4b5..6a2605f 100644 --- a/src/DocumentMapper/DataMapper.php +++ b/src/DocumentMapper/DataMapper.php @@ -4,40 +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'; /** * DataMapper constructor. - * @param DBAL $dbal - * @param $class + * @param DBAL $dbal + * @param string $class_name */ - public function __construct(DBAL $dbal, $class) + 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 mixed + * @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); @@ -61,7 +64,7 @@ public function update(Document $obj) /** * @param Document $obj - * @return mixed + * @return \MongoDB\DeleteResult */ public function delete(Document $obj) { @@ -69,11 +72,11 @@ public function delete(Document $obj) } /** - * @return mixed + * @return bool */ public function drop() { - return $this->dbal->drop($this->table_name); + return (bool)$this->dbal->drop($this->table_name); } /** @@ -90,7 +93,7 @@ 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; @@ -110,35 +113,51 @@ 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); } /** - * @param $obj - * @param $data - * @return mixed + * @return string */ - private function mapObj($obj, $data) + 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 (null === $value) { + if ($prop->getName() === self::ID) { + $prop_name = self::MONGO_ID; + } else { + $prop_name = $prop->getName(); + } + + 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, true)) { continue; } - $obj->$setter($value); + $prop->setValue($obj, $data[$prop_name]); } return $obj; @@ -148,21 +167,7 @@ private function mapObj($obj, $data) * @param $input * @return string */ - private function snakeToCamelCase($input) - { - $new = []; - foreach (explode('_', $input) as $key => $word) { - $new[] = ucfirst($word); - } - - return implode('', $new); - } - - /** - * @param $input - * @return string - */ - private function camelCaseToSnake($input) + 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]; @@ -174,15 +179,16 @@ private function camelCaseToSnake($input) } /** - * @param $obj + * @param Document $obj * @return array */ - public function objToArray($obj) + 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; @@ -190,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 db8ebdf..5113db5 100644 --- a/src/DocumentMapper/DataMapperFactory.php +++ b/src/DocumentMapper/DataMapperFactory.php @@ -18,11 +18,11 @@ public function __construct(DBAL $dbal) } /** - * @param $class + * @param $class_name * @return DataMapper */ - public function init($class) + 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..873aee8 --- /dev/null +++ b/src/Instantiator/Instantiator.php @@ -0,0 +1,21 @@ +