diff --git a/src/ORM/Manager.php b/src/ORM/Manager.php index 075c05f..c79d5b0 100644 --- a/src/ORM/Manager.php +++ b/src/ORM/Manager.php @@ -146,7 +146,7 @@ public function fetchObjectsByLabelAndProps(string $model_class, array $props, a return $objects; } - public function createObject(ModelAbstract $object) + public function createNode(ModelAbstract $object) { $entity = $object->getEntityType(); @@ -177,7 +177,7 @@ public function createObject(ModelAbstract $object) try { $result = $this->_neo4j_client->executeQuery($query, $params); $info = $result->getSingleResult()[0]['info']; - return $object->withProperties($info); + return $object->withProperties($info, $this); //print_r($result->getSingleResult());exit; } catch (HttpClient\Exception\CypherQueryException $e) { if ($e->isConstraintViolation()) { @@ -292,6 +292,134 @@ public function loadRelationsForNode(NodeModelAbstract $node, array $relation_ty } + public function saveNode(NodeModelAbstract $node) : NodeModelAbstract + { + $modified_properties = $node->getModifiedProperties(); + + if (!$modified_properties) { + return $node; + } + + + $primary_id_info = $node->getPrimaryIdInfo(); + $model_class = get_class($node); + + $entity = $node::ENTITY; + + $key = $primary_id_info['name']; + + $query = "MATCH (n:$entity{{$key}:{id}}) + WITH n + SET n += {props} + WITH n, ID(n) as neo4j_id + RETURN n{.*, neo4j_id} as info"; + + $params = ['id' => $primary_id_info['value'], 'props' => $modified_properties]; + + $result = $this->_neo4j_client->executeQuery($query, $params); + + $result = $result->getSingleResult(); + + if (!isset($result[0]['info'])) { + return null; + } + + return new $model_class($result[0]['info'], $this); + + } + + public function deleteNode(NodeModelAbstract $node) + { + $primary_id_info = $node->getPrimaryIdInfo(); + + $entity = $node::ENTITY; + + $key = $primary_id_info['name']; + + $query = "MATCH (n:$entity{{$key}:{id}}) + WITH n + DETACH DELETE n"; + + $params = ['id' => $primary_id_info['value']]; + + $result = $this->_neo4j_client->executeQuery($query, $params); + } + + public function saveRelationship(RelationshipModelAbstract $relationship) + { + $modified_properties = $relationship->getModifiedProperties(); + + if (!$modified_properties) { + return $relationship; + } + + $from_node_info = $relationship->getStartNode()->getPropertyInfo(); + $to_node_info = $relationship->getEndNode()->getPropertyInfo(); + + $n1_primary_field = $from_node_info['extra'][ModelAbstract::PROP_INFO_PRIMARY]; + $n2_primary_field = $to_node_info['extra'][ModelAbstract::PROP_INFO_PRIMARY]; + + $n1_id = $from_node_info['props'][$n1_primary_field]; + $n2_id = $to_node_info['props'][$n2_primary_field]; + + $relationship_type = $relationship->getEntityType(); + + $from_type = $relationship->getStartNode()->getEntityType(); + $to_type = $relationship->getEndNode()->getEntityType(); + + $query = " + MATCH (n1:{$from_type}{{$n1_primary_field}:{n1_id}}), (n2:{$to_type}{{$n2_primary_field}:{n2_id}}) + WITH n1, n2 + MATCH (n1)-[r:{$relationship_type}]->(n2) + WHERE ID(r)={relationship_neo4j_id} + WITH r + SET r += {props} + WITH r, ID(r) as neo4j_id + RETURN r{.*, neo4j_id} as info + "; + + $result = $this->_neo4j_client->executeQuery($query, [ + 'n1_id' => $n1_id, + 'n2_id' => $n2_id, + 'relationship_neo4j_id' => $relationship->getNeo4jId(), + 'props' => $modified_properties, + ]); + + return $relationship->withProperties($result->getSingleResult()[0]['info']); + } + + public function deleteRelationship(RelationshipModelAbstract $relationship) + { + $from_node_info = $relationship->getStartNode()->getPropertyInfo(); + $to_node_info = $relationship->getEndNode()->getPropertyInfo(); + + $n1_primary_field = $from_node_info['extra'][ModelAbstract::PROP_INFO_PRIMARY]; + $n2_primary_field = $to_node_info['extra'][ModelAbstract::PROP_INFO_PRIMARY]; + + $n1_id = $from_node_info['props'][$n1_primary_field]; + $n2_id = $to_node_info['props'][$n2_primary_field]; + + $relationship_type = $relationship->getEntityType(); + + $from_type = $relationship->getStartNode()->getEntityType(); + $to_type = $relationship->getEndNode()->getEntityType(); + + $query = " + MATCH (n1:{$from_type}{{$n1_primary_field}:{n1_id}}), (n2:{$to_type}{{$n2_primary_field}:{n2_id}}) + WITH n1, n2 + MATCH (n1)-[r:{$relationship_type}]->(n2) + WHERE ID(r)={relationship_neo4j_id} + WITH r + DELETE r + "; + + $result = $this->_neo4j_client->executeQuery($query, [ + 'n1_id' => $n1_id, + 'n2_id' => $n2_id, + 'relationship_neo4j_id' => $relationship->getNeo4jId(), + ]); + } + private function _getPropsInfo(array $props) : array { } diff --git a/src/ORM/ModelAbstract.php b/src/ORM/ModelAbstract.php index d45ce09..48431ef 100644 --- a/src/ORM/ModelAbstract.php +++ b/src/ORM/ModelAbstract.php @@ -38,7 +38,6 @@ abstract class ModelAbstract { protected $_manager; private $_neo4j_id; - private $_has_unsaved_changes; public function __construct(array $data = [], Manager $manager = null) { @@ -89,6 +88,7 @@ public function __construct(array $data = [], Manager $manager = null) $use_value = $data[$clean_prop_name]; } + $prop_value['value'] = $use_value; $this->_field_info[$clean_prop_name] = $prop_value; if (($prop_value[self::PROP_INFO_TYPE] != self::TYPE_AUTO_INCREMENT && $prop_value[self::PROP_INFO_TYPE] != self::TYPE_RELATION) || is_numeric($use_value)) { @@ -99,8 +99,6 @@ public function __construct(array $data = [], Manager $manager = null) } $this->_neo4j_id = $data['neo4j_id'] ?? null; - $this->_has_unsaved_changes = $this->_neo4j_id === null; - } public function getPropertyInfo() : array @@ -159,7 +157,30 @@ public static function fromDataList(array $infos) : array return $objects; } - public function set(string $property, $value) { + public function getModifiedProperties() : array + { + $property_info = $this->getPropertyInfo(); + + $modified_fields = []; + $modified_field = null; + + foreach ($this->_field_info as $field_name => $field_info) { + if ($field_info['type'] != ModelAbstract::TYPE_RELATION && $field_info['value'] !== $property_info['props'][$field_name]) { + $modified_fields[$field_name] = $property_info['props'][$field_name]; + } elseif ($field_info['type'] === ModelAbstract::TYPE_MODIFIED_ON) { + $modified_field = $field_name; + } + } + if ($modified_fields && $modified_field) { + $modified_fields[$modified_field] = time(); + } + + return $modified_fields; + } + + public function getNeo4jId() : int + { + return $this->_neo4j_id; } } diff --git a/src/ORM/NodeModelAbstract.php b/src/ORM/NodeModelAbstract.php index 174fe5c..1a64716 100644 --- a/src/ORM/NodeModelAbstract.php +++ b/src/ORM/NodeModelAbstract.php @@ -4,9 +4,9 @@ abstract class NodeModelAbstract extends ModelAbstract { - public function withProperties(array $properties) : ModelAbstract + public function withProperties(array $properties, Manager $manager = null) : ModelAbstract { - return new $this($properties, $this->_manager); + return new $this($properties, $manager ?? $this->_manager); } public function __get($name) @@ -39,4 +39,18 @@ public function getRelationsInfo(array $relation_names) : array return $relations_info; } + public function getPrimaryIdInfo() : array + { + foreach ($this->_field_info as $field_name => $field_info) { + if (isset($field_info['primary']) && $field_info['primary'] === true) { + return [ + 'name' => $field_name, + 'value' => $field_info['value'], + ]; + } + } + + // throw error! + } + }