From bf52e203da0e247eb66013f1c014641ff6d77b76 Mon Sep 17 00:00:00 2001 From: JohGuentner <3506359+johguentner@users.noreply.github.com> Date: Sun, 19 Sep 2021 14:59:55 +0200 Subject: [PATCH 1/4] mark databases->all() as deprecated --- src/Endpoints/Databases.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Endpoints/Databases.php b/src/Endpoints/Databases.php index b18445e..b94517d 100644 --- a/src/Endpoints/Databases.php +++ b/src/Endpoints/Databases.php @@ -26,6 +26,7 @@ class Databases extends Endpoint implements EndpointInterface * @return DatabaseCollection * @throws HandlingException * @throws NotionException + * @deprecated */ public function all(): DatabaseCollection { From 31aa939a80d6e56e5d8bf70b4b98e198c2a05634 Mon Sep 17 00:00:00 2001 From: JohGuentner <3506359+johguentner@users.noreply.github.com> Date: Sun, 19 Sep 2021 20:49:55 +0200 Subject: [PATCH 2/4] improve database retreival and add icon/cover - replace notion-api-docs link with updated page (Databases) - add icon, iconType, cover, coverType to Database and Page with according extraction of different cover- and icon-types - add database-notion-url retrieval to database - add raw-information-retrieval to database-retrieval (add as empty properties with according information to property-key and options) - add retrieval of available options to MultiSelect and Select during database retrieval - don't retrieve rollup and formula if type-value is not given - don't retrieve created_time and last_edited_time if retrieved content is null - fix missing id's and wrong options-field (array in array) within response-json-files --- src/Endpoints/Databases.php | 2 +- src/Entities/Database.php | 200 +++++++++++++++++- src/Entities/Page.php | 90 ++++++++ src/Entities/Properties/CreatedTime.php | 7 +- src/Entities/Properties/Formula.php | 18 +- src/Entities/Properties/LastEditedTime.php | 7 +- src/Entities/Properties/MultiSelect.php | 25 ++- src/Entities/Properties/Rollup.php | 31 +-- src/Entities/Properties/Select.php | 24 ++- .../endpoints/databases/response_all_200.json | 4 + .../databases/response_specific_200.json | 5 +- 11 files changed, 372 insertions(+), 41 deletions(-) diff --git a/src/Endpoints/Databases.php b/src/Endpoints/Databases.php index b94517d..8016150 100644 --- a/src/Endpoints/Databases.php +++ b/src/Endpoints/Databases.php @@ -37,7 +37,7 @@ public function all(): DatabaseCollection /** * Retrieve a database * url: https://api.notion.com/{version}/databases/{database_id} - * notion-api-docs: https://developers.notion.com/reference/get-database + * notion-api-docs: https://developers.notion.com/reference/retrieve-a-database * * @param string $databaseId * @return Database diff --git a/src/Entities/Database.php b/src/Entities/Database.php index 443f2a8..9705a6f 100644 --- a/src/Entities/Database.php +++ b/src/Entities/Database.php @@ -3,8 +3,10 @@ namespace FiveamCode\LaravelNotionApi\Entities; use DateTime; +use FiveamCode\LaravelNotionApi\Entities\Properties\Property; use FiveamCode\LaravelNotionApi\Exceptions\HandlingException; use Illuminate\Support\Arr; +use Illuminate\Support\Collection; /** @@ -13,15 +15,81 @@ */ class Database extends Entity { + /** + * @var string + */ protected string $title = ''; + + /** + * @var string + */ + private string $icon = ''; + + /** + * @var string + */ + private string $iconType = ''; + + /** + * @var string + */ + private string $cover = ''; + + /** + * @var string + */ + private string $coverType = ''; + + /** + * @var string + */ + private string $url; + + /** + * @var string + */ protected string $objectType = ''; + + /** + * @var array + */ protected array $rawTitle = []; + + /** + * @var array + */ protected array $rawProperties = []; + + /** + * @var array + */ protected array $propertyKeys = []; + + /** + * @var array + */ + protected array $propertyMap = []; + + /** + * @var Collection + */ + protected Collection $properties; + + /** + * @var DateTime + */ protected DateTime $createdTime; + + /** + * @var DateTime + */ protected DateTime $lastEditedTime; + + /** + * + */ protected function setResponseData(array $responseData): void { parent::setResponseData($responseData); @@ -30,17 +98,25 @@ protected function setResponseData(array $responseData): void $this->fillFromRaw(); } - + /** + * + */ private function fillFromRaw() { $this->fillId(); + $this->fillIcon(); + $this->fillCover(); $this->fillTitle(); $this->fillObjectType(); $this->fillProperties(); + $this->fillDatabaseUrl(); $this->fillCreatedTime(); $this->fillLastEditedTime(); } + /** + * + */ private function fillTitle(): void { if (Arr::exists($this->responseData, 'title') && is_array($this->responseData['title'])) { @@ -49,6 +125,54 @@ private function fillTitle(): void } } + /** + * + */ + private function fillDatabaseUrl(): void + { + if (Arr::exists($this->responseData, 'url')) { + $this->url = $this->responseData['url']; + } + } + + /** + * + */ + private function fillIcon(): void + { + if (Arr::exists($this->responseData, 'icon') && $this->responseData['icon'] != null) { + $this->iconType = $this->responseData['icon']['type']; + if(Arr::exists($this->responseData['icon'], 'emoji')){ + $this->icon = $this->responseData['icon']['emoji']; + } + else if(Arr::exists($this->responseData['icon'], 'file')){ + $this->icon = $this->responseData['icon']['file']['url']; + } + else if(Arr::exists($this->responseData['icon'], 'external')){ + $this->icon = $this->responseData['icon']['external']['url']; + } + } + } + + /** + * + */ + private function fillCover(): void + { + if (Arr::exists($this->responseData, 'cover') && $this->responseData['cover'] != null) { + $this->coverType = $this->responseData['cover']['type']; + if(Arr::exists($this->responseData['cover'], 'file')){ + $this->cover = $this->responseData['cover']['file']['url']; + } + else if(Arr::exists($this->responseData['cover'], 'external')){ + $this->cover = $this->responseData['cover']['external']['url']; + } + } + } + + /** + * + */ private function fillObjectType(): void { if (Arr::exists($this->responseData, 'object')) { @@ -56,29 +180,95 @@ private function fillObjectType(): void } } + /** + * + */ private function fillProperties(): void { if (Arr::exists($this->responseData, 'properties')) { $this->rawProperties = $this->responseData['properties']; $this->propertyKeys = array_keys($this->rawProperties); + $this->properties = new Collection(); + + foreach ($this->rawProperties as $propertyKey => $propertyContent) { + $propertyObj = Property::fromResponse($propertyKey, $propertyContent); + $this->properties->add($propertyObj); + $this->propertyMap[$propertyKey] = $propertyObj; + } + } + } + + /** + * @param string $propertyKey + * @return Property|null + */ + public function getProperty(string $propertyKey): ?Property + { + if (!isset($this->propertyMap[$propertyKey])) { + return null; } + return $this->propertyMap[$propertyKey]; } + /** + * @return string + */ public function getObjectType(): string { return $this->objectType; } - + /** + * @return string + */ public function getTitle(): string { return $this->title; } - public function getProperties() + /** + * @return string + */ + public function getUrl(): string + { + return $this->url; + } + + /** + * @return string + */ + public function getIcon(): string + { + return $this->icon; + } + + /** + * @return string + */ + public function getIconType(): string + { + return $this->iconType; + } + + /** + * @return string + */ + public function getCover(): string + { + return $this->cover; + } + + /** + * @return string + */ + public function getCoverType(): string + { + return $this->coverType; + } + + public function getProperties(): Collection { - //TODO: return collection of property-entities (id, type, title) - throw new HandlingException('Not implemented'); + return $this->properties; } public function getRawTitle(): array diff --git a/src/Entities/Page.php b/src/Entities/Page.php index 1a9f2d9..267cf15 100644 --- a/src/Entities/Page.php +++ b/src/Entities/Page.php @@ -36,6 +36,27 @@ class Page extends Entity */ protected string $url = ''; + + /** + * @var string + */ + private string $icon = ''; + + /** + * @var string + */ + private string $iconType = ''; + + /** + * @var string + */ + private string $cover = ''; + + /** + * @var string + */ + private string $coverType = ''; + /** * @var string */ @@ -107,6 +128,8 @@ private function fillFromRaw(): void $this->fillProperties(); $this->fillTitle(); // This has to be called after fillProperties(), since title is provided by properties $this->fillPageUrl(); + $this->fillIcon(); + $this->fillCover(); $this->fillCreatedTime(); $this->fillLastEditedTime(); } @@ -157,6 +180,41 @@ private function fillTitle(): void } } + /** + * + */ + private function fillIcon(): void + { + if (Arr::exists($this->responseData, 'icon') && $this->responseData['icon'] != null) { + $this->iconType = $this->responseData['icon']['type']; + if(Arr::exists($this->responseData['icon'], 'emoji')){ + $this->icon = $this->responseData['icon']['emoji']; + } + else if(Arr::exists($this->responseData['icon'], 'file')){ + $this->icon = $this->responseData['icon']['file']['url']; + } + else if(Arr::exists($this->responseData['icon'], 'external')){ + $this->icon = $this->responseData['icon']['external']['url']; + } + } + } + + /** + * + */ + private function fillCover(): void + { + if (Arr::exists($this->responseData, 'cover') && $this->responseData['cover'] != null) { + $this->coverType = $this->responseData['cover']['type']; + if(Arr::exists($this->responseData['cover'], 'file')){ + $this->cover = $this->responseData['cover']['file']['url']; + } + else if(Arr::exists($this->responseData['cover'], 'external')){ + $this->cover = $this->responseData['cover']['external']['url']; + } + } + } + /** * */ @@ -340,6 +398,38 @@ public function getTitle(): string return $this->title; } + /** + * @return string + */ + public function getIcon(): string + { + return $this->icon; + } + + /** + * @return string + */ + public function getIconType(): string + { + return $this->iconType; + } + + /** + * @return string + */ + public function getCover(): string + { + return $this->cover; + } + + /** + * @return string + */ + public function getCoverType(): string + { + return $this->coverType; + } + /** * @return string */ diff --git a/src/Entities/Properties/CreatedTime.php b/src/Entities/Properties/CreatedTime.php index e08105f..12e36cf 100644 --- a/src/Entities/Properties/CreatedTime.php +++ b/src/Entities/Properties/CreatedTime.php @@ -18,12 +18,11 @@ class CreatedTime extends Property protected function fillFromRaw(): void { parent::fillFromRaw(); - if ($this->rawContent == null) { - throw HandlingException::instance('The property-type is created_time, however the raw data-structure is null. Please check the raw response-data.'); - } try { - $this->content = new DateTime($this->rawContent); + if ($this->rawContent != null) { + $this->content = new DateTime($this->rawContent); + } } catch (Exception $e) { throw HandlingException::instance('The content of created_time is not a valid ISO 8601 date time string.'); } diff --git a/src/Entities/Properties/Formula.php b/src/Entities/Properties/Formula.php index e8ab41d..a6e9b08 100644 --- a/src/Entities/Properties/Formula.php +++ b/src/Entities/Properties/Formula.php @@ -20,14 +20,16 @@ protected function fillFromRaw(): void { parent::fillFromRaw(); - $this->formulaType = $this->rawContent['type']; - - if ($this->formulaType == 'string' || $this->formulaType == 'number' || $this->formulaType == 'boolean') { - $this->content = $this->rawContent[$this->formulaType]; - } else if ($this->formulaType == 'date') { - $this->content = new RichDate(); - if (isset($this->rawContent[$this->formulaType]['start'])) $this->content->setStart(new DateTime($this->rawContent[$this->formulaType]['start'])); - if (isset($this->rawContent[$this->formulaType]['end'])) $this->content->setEnd(new DateTime($this->rawContent[$this->formulaType]['end'])); + if (array_key_exists('type', $this->rawContent)) { + $this->formulaType = $this->rawContent['type']; + + if ($this->formulaType == 'string' || $this->formulaType == 'number' || $this->formulaType == 'boolean') { + $this->content = $this->rawContent[$this->formulaType]; + } else if ($this->formulaType == 'date') { + $this->content = new RichDate(); + if (isset($this->rawContent[$this->formulaType]['start'])) $this->content->setStart(new DateTime($this->rawContent[$this->formulaType]['start'])); + if (isset($this->rawContent[$this->formulaType]['end'])) $this->content->setEnd(new DateTime($this->rawContent[$this->formulaType]['end'])); + } } } diff --git a/src/Entities/Properties/LastEditedTime.php b/src/Entities/Properties/LastEditedTime.php index ddbb444..206b42e 100644 --- a/src/Entities/Properties/LastEditedTime.php +++ b/src/Entities/Properties/LastEditedTime.php @@ -18,12 +18,11 @@ class LastEditedTime extends Property protected function fillFromRaw(): void { parent::fillFromRaw(); - if ($this->rawContent == null) { - throw HandlingException::instance('The property-type is last_edited_time, however the raw data-structure is null. Please check the raw response-data.'); - } try { - $this->content = new DateTime($this->rawContent); + if ($this->rawContent != null) { + $this->content = new DateTime($this->rawContent); + } } catch (Exception $e) { throw HandlingException::instance('The content of last_edited_time is not a valid ISO 8601 date time string.'); } diff --git a/src/Entities/Properties/MultiSelect.php b/src/Entities/Properties/MultiSelect.php index ff983e9..df1a71f 100644 --- a/src/Entities/Properties/MultiSelect.php +++ b/src/Entities/Properties/MultiSelect.php @@ -13,6 +13,11 @@ */ class MultiSelect extends Property implements Modifiable { + /** + * @var Collection + */ + private Collection $options; + /** * @param $names * @return MultiSelect @@ -51,8 +56,16 @@ protected function fillFromRaw(): void $itemCollection = new Collection(); - foreach ($this->rawContent as $item) { - $itemCollection->add(new SelectItem($item)); + if(array_key_exists('options', $this->rawContent)){ + $this->options = new Collection(); + foreach ($this->rawContent['options'] as $key => $item) { + $this->options->add(new SelectItem($item)); + } + } + else{ + foreach ($this->rawContent as $key => $item) { + $itemCollection->add(new SelectItem($item)); + } } $this->content = $itemCollection; @@ -74,6 +87,14 @@ public function getItems(): Collection return $this->content; } + /** + * @return Collection + */ + public function getOptions(): Collection + { + return $this->options; + } + /** * @return array */ diff --git a/src/Entities/Properties/Rollup.php b/src/Entities/Properties/Rollup.php index 52931ca..2ce9c9f 100644 --- a/src/Entities/Properties/Rollup.php +++ b/src/Entities/Properties/Rollup.php @@ -22,22 +22,25 @@ protected function fillFromRaw(): void { parent::fillFromRaw(); - $this->rollupType = $this->rawContent['type']; - - switch ($this->rollupType) { - case 'number': - $this->setRollupContentNumber(); - break; - case 'array': - $this->setRollupContentArray(); - break; - case 'date': - $this->setRollupContentDate(); - break; - default: - throw new HandlingException("Unexpected rollupType {$this->rollupType}"); + if(array_key_exists('type', $this->rawContent)) + { + $this->rollupType = $this->rawContent['type']; + + switch ($this->rollupType) { + case 'number': + $this->setRollupContentNumber(); + break; + case 'array': + $this->setRollupContentArray(); + break; + case 'date': + $this->setRollupContentDate(); + break; + default: + throw new HandlingException("Unexpected rollupType {$this->rollupType}"); } } + } /** * @return mixed diff --git a/src/Entities/Properties/Select.php b/src/Entities/Properties/Select.php index 012c764..cef3b81 100644 --- a/src/Entities/Properties/Select.php +++ b/src/Entities/Properties/Select.php @@ -5,6 +5,7 @@ use FiveamCode\LaravelNotionApi\Entities\Contracts\Modifiable; use FiveamCode\LaravelNotionApi\Entities\PropertyItems\SelectItem; use FiveamCode\LaravelNotionApi\Exceptions\HandlingException; +use Illuminate\Database\Eloquent\Collection; /** * Class Select @@ -12,6 +13,10 @@ */ class Select extends Property implements Modifiable { + /** + * @var Collection + */ + private Collection $options; /** * @param $name @@ -43,7 +48,16 @@ protected function fillFromRaw(): void if (!is_array($this->rawContent)) throw HandlingException::instance('The property-type is select, however the raw data-structure does not reprecent this type. Please check the raw response-data.'); - $this->content = new SelectItem($this->rawContent); + if (array_key_exists('options', $this->rawContent)) { + $this->options = new Collection(); + foreach ($this->rawContent['options'] as $key => $item) { + $this->options->add(new SelectItem($item)); + } + } else { + foreach ($this->rawContent as $key => $item) { + $this->content = new SelectItem($this->rawContent); + } + } } /** @@ -62,6 +76,14 @@ public function getItem(): SelectItem return $this->content; } + /** + * @return Collection + */ + public function getOptions(): Collection + { + return $this->options; + } + /** * @return mixed */ diff --git a/tests/stubs/endpoints/databases/response_all_200.json b/tests/stubs/endpoints/databases/response_all_200.json index 674e078..d4a7e37 100644 --- a/tests/stubs/endpoints/databases/response_all_200.json +++ b/tests/stubs/endpoints/databases/response_all_200.json @@ -7,10 +7,12 @@ "title": "Grocery list", "properties": { "Name": { + "id": "testid", "type": "title", "title": {} }, "Description": { + "id": "testid", "type": "text", "text": {} } @@ -22,10 +24,12 @@ "title": "Pantry", "properties": { "Name": { + "id": "testid", "type": "title", "title": {} }, "Description": { + "id": "testid", "type": "rich_text", "rich_text": {} } diff --git a/tests/stubs/endpoints/databases/response_specific_200.json b/tests/stubs/endpoints/databases/response_specific_200.json index fac7137..a900324 100644 --- a/tests/stubs/endpoints/databases/response_specific_200.json +++ b/tests/stubs/endpoints/databases/response_specific_200.json @@ -81,6 +81,7 @@ "date": {} }, "Meals": { + "id": "Z\\Eh", "type": "relation", "relation": { "database": "668d797c-76fa-4934-9b05-ad288df2d136", @@ -99,9 +100,10 @@ } }, "Store availability": { + "id": "Z\\Eh", "type": "multi_select", "multi_select": { - "options": [ + "options": [ { "id": "d209b920-212c-4040-9d4a-bdf349dd8b2a", @@ -124,7 +126,6 @@ "color": "yellow" } ] - ] } }, "+1": { From e5f3363219e4701750ce9c776b8353181cc68c23 Mon Sep 17 00:00:00 2001 From: JohGuentner <3506359+johguentner@users.noreply.github.com> Date: Fri, 24 Sep 2021 11:25:29 +0200 Subject: [PATCH 3/4] add phpdocs to Database getters --- src/Entities/Database.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/Entities/Database.php b/src/Entities/Database.php index 9705a6f..cbd5e01 100644 --- a/src/Entities/Database.php +++ b/src/Entities/Database.php @@ -266,31 +266,49 @@ public function getCoverType(): string return $this->coverType; } + /** + * @return Collection + */ public function getProperties(): Collection { return $this->properties; } + /** + * @return array + */ public function getRawTitle(): array { return $this->rawTitle; } + /** + * @return array + */ public function getRawProperties(): array { return $this->rawProperties; } + /** + * @return array + */ public function getPropertyKeys(): array { return $this->propertyKeys; } + /** + * @return DateTime + */ public function getCreatedTime(): DateTime { return $this->createdTime; } + /** + * @return array + */ public function getLastEditedTime(): DateTime { return $this->lastEditedTime; From cf61e9770424b59222545aa576c84d71c300fd8a Mon Sep 17 00:00:00 2001 From: JohGuentner <3506359+johguentner@users.noreply.github.com> Date: Fri, 24 Sep 2021 11:29:09 +0200 Subject: [PATCH 4/4] replace 'array_key_exists' with 'Arr::exists' - and replace == to ===, != to !== in according places --- src/Entities/Properties/Formula.php | 7 ++++--- src/Entities/Properties/LastEditedTime.php | 2 +- src/Entities/Properties/MultiSelect.php | 3 ++- src/Entities/Properties/Rollup.php | 3 ++- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/Entities/Properties/Formula.php b/src/Entities/Properties/Formula.php index a6e9b08..4cae0f0 100644 --- a/src/Entities/Properties/Formula.php +++ b/src/Entities/Properties/Formula.php @@ -4,6 +4,7 @@ use DateTime; use FiveamCode\LaravelNotionApi\Entities\PropertyItems\RichDate; +use Illuminate\Support\Arr; /** * Class Formula @@ -20,12 +21,12 @@ protected function fillFromRaw(): void { parent::fillFromRaw(); - if (array_key_exists('type', $this->rawContent)) { + if (Arr::exists($this->rawContent, 'type')) { $this->formulaType = $this->rawContent['type']; - if ($this->formulaType == 'string' || $this->formulaType == 'number' || $this->formulaType == 'boolean') { + if ($this->formulaType === 'string' || $this->formulaType === 'number' || $this->formulaType === 'boolean') { $this->content = $this->rawContent[$this->formulaType]; - } else if ($this->formulaType == 'date') { + } else if ($this->formulaType === 'date') { $this->content = new RichDate(); if (isset($this->rawContent[$this->formulaType]['start'])) $this->content->setStart(new DateTime($this->rawContent[$this->formulaType]['start'])); if (isset($this->rawContent[$this->formulaType]['end'])) $this->content->setEnd(new DateTime($this->rawContent[$this->formulaType]['end'])); diff --git a/src/Entities/Properties/LastEditedTime.php b/src/Entities/Properties/LastEditedTime.php index 206b42e..4010ee9 100644 --- a/src/Entities/Properties/LastEditedTime.php +++ b/src/Entities/Properties/LastEditedTime.php @@ -20,7 +20,7 @@ protected function fillFromRaw(): void parent::fillFromRaw(); try { - if ($this->rawContent != null) { + if ($this->rawContent !== null) { $this->content = new DateTime($this->rawContent); } } catch (Exception $e) { diff --git a/src/Entities/Properties/MultiSelect.php b/src/Entities/Properties/MultiSelect.php index df1a71f..0851266 100644 --- a/src/Entities/Properties/MultiSelect.php +++ b/src/Entities/Properties/MultiSelect.php @@ -5,6 +5,7 @@ use FiveamCode\LaravelNotionApi\Entities\Contracts\Modifiable; use FiveamCode\LaravelNotionApi\Entities\PropertyItems\SelectItem; use FiveamCode\LaravelNotionApi\Exceptions\HandlingException; +use Illuminate\Support\Arr; use Illuminate\Support\Collection; /** @@ -56,7 +57,7 @@ protected function fillFromRaw(): void $itemCollection = new Collection(); - if(array_key_exists('options', $this->rawContent)){ + if(Arr::exists($this->rawContent, 'options')){ $this->options = new Collection(); foreach ($this->rawContent['options'] as $key => $item) { $this->options->add(new SelectItem($item)); diff --git a/src/Entities/Properties/Rollup.php b/src/Entities/Properties/Rollup.php index 2ce9c9f..8ac2dcd 100644 --- a/src/Entities/Properties/Rollup.php +++ b/src/Entities/Properties/Rollup.php @@ -5,6 +5,7 @@ use DateTime; use FiveamCode\LaravelNotionApi\Entities\PropertyItems\RichDate; use FiveamCode\LaravelNotionApi\Exceptions\HandlingException; +use Illuminate\Support\Arr; use Illuminate\Support\Collection; /** @@ -22,7 +23,7 @@ protected function fillFromRaw(): void { parent::fillFromRaw(); - if(array_key_exists('type', $this->rawContent)) + if(Arr::exists($this->rawContent, 'type')) { $this->rollupType = $this->rawContent['type'];