From 9ec0d7b56decfb750d1ad67823f9e9465547df3b Mon Sep 17 00:00:00 2001
From: EK <ek@neomerx.com>
Date: Wed, 21 Feb 2018 15:44:57 +0300
Subject: [PATCH] Close #199

---
 src/Schema/RelationshipObject.php | 72 ++++++++++++++++++++++++++++---
 1 file changed, 65 insertions(+), 7 deletions(-)

diff --git a/src/Schema/RelationshipObject.php b/src/Schema/RelationshipObject.php
index 7321652b..586516ed 100644
--- a/src/Schema/RelationshipObject.php
+++ b/src/Schema/RelationshipObject.php
@@ -55,6 +55,11 @@ class RelationshipObject implements RelationshipObjectInterface
      */
     private $isRoot;
 
+    /**
+     * @var bool
+     */
+    private $isMetaEvaluated = false;
+
     /**
      * @var bool
      */
@@ -81,10 +86,7 @@ public function __construct(
         $isOk = (($isRoot === false && $name !== null) || ($isRoot === true && $name === null));
         $isOk ?: Exceptions::throwInvalidArgument('name', $name);
 
-        $this->name       = $name;
-        $this->data       = $data;
-        $this->links      = $links;
-        $this->meta       = $meta;
+        $this->setName($name)->setData($data)->setLinks($links)->setMeta($meta);
         $this->isShowData = $isShowData;
         $this->isRoot     = $isRoot;
     }
@@ -97,6 +99,18 @@ public function getName(): ?string
         return $this->name;
     }
 
+    /**
+     * @param null|string $name
+     *
+     * @return self
+     */
+    public function setName(?string $name): self
+    {
+        $this->name = $name;
+
+        return $this;
+    }
+
     /**
      * @inheritdoc
      */
@@ -107,14 +121,31 @@ public function getData()
 
             if ($this->data instanceof Closure) {
                 /** @var Closure $data */
-                $data       = $this->data;
-                $this->data = $data();
+                $data = $this->data;
+                $this->setData($data());
             }
         }
 
+        assert(is_array($this->data) === true || is_object($this->data) === true || $this->data === null);
+
         return $this->data;
     }
 
+    /**
+     * @param object|array|null|Closure $data
+     *
+     * @return RelationshipObject
+     */
+    public function setData($data): self
+    {
+        assert(is_array($data) === true || $data instanceof Closure || is_object($data) === true || $data === null);
+
+        $this->data            = $data;
+        $this->isDataEvaluated = false;
+
+        return $this;
+    }
+
     /**
      * @inheritdoc
      */
@@ -123,19 +154,46 @@ public function getLinks(): array
         return $this->links;
     }
 
+    /**
+     * @param array $links
+     *
+     * @return self
+     */
+    public function setLinks(array $links): self
+    {
+        $this->links = $links;
+
+        return $this;
+    }
+
     /**
      * @inheritdoc
      */
     public function getMeta()
     {
-        if ($this->meta instanceof Closure) {
+        if ($this->isMetaEvaluated === false && $this->meta instanceof Closure) {
             $meta       = $this->meta;
             $this->meta = $meta();
         }
 
+        $this->isMetaEvaluated = true;
+
         return $this->meta;
     }
 
+    /**
+     * @param mixed $meta
+     *
+     * @return self
+     */
+    public function setMeta($meta): self
+    {
+        $this->meta            = $meta;
+        $this->isMetaEvaluated = false;
+
+        return $this;
+    }
+
     /**
      * @inheritdoc
      */