-
-
Notifications
You must be signed in to change notification settings - Fork 50
Feature/notion models and commands #121
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
base: dev
Are you sure you want to change the base?
Conversation
- command for creating NotionModels - add Notion Models for simple interation with Notion databases - add NotionQueryBuilder for simple query-behaviour for Notion databases (similar to eloquent)
…om/5am-code/laravel-notion-api into feature/notion-models-and-commands
- add filterbags instead of collections
- some entities have parents or expose user-ids, without additional information - by resolving these within the "endpoint" (not a real notion enpoint) ``Resolve::class``, the additional information can be easily obtained
|
…om/5am-code/laravel-notion-api into feature/notion-models-and-commands
- for json_encode
…om/5am-code/laravel-notion-api into feature/notion-models-and-commands
- why `HasTitle` trait is not used within `Page::class`
- remove adding query to file-name - instead add short hash of query to file-name - or (if given) allow user to set a specific name for upcoming query - additionally save header, method and payload within the snapshot
- polish `PestHttpRecorder::class`
- ... rebuild snapshots for comments (due to changed file-naming structure)
- specifically regarding type checking
- prototypical
Hey, I have tried to find the spot where you cast the page properties to model attributes but can't find it!? 🤔 That's the trait with all the abstracted logic to link an eloquent model to a notion database. <?php
namespace App\Models\Concerns;
use BackedEnum;
use FiveamCode\LaravelNotionApi\Endpoints\Database;
use FiveamCode\LaravelNotionApi\Entities\Collections\PageCollection;
use FiveamCode\LaravelNotionApi\Entities\Page;
use FiveamCode\LaravelNotionApi\Entities\Properties\Checkbox;
use FiveamCode\LaravelNotionApi\Entities\Properties\MultiSelect;
use FiveamCode\LaravelNotionApi\Entities\Properties\Number;
use FiveamCode\LaravelNotionApi\Entities\Properties\Property;
use FiveamCode\LaravelNotionApi\Entities\Properties\Relation;
use FiveamCode\LaravelNotionApi\Entities\Properties\Select;
use FiveamCode\LaravelNotionApi\Entities\Properties\Text;
use FiveamCode\LaravelNotionApi\Entities\Properties\Title;
use FiveamCode\LaravelNotionApi\Entities\Properties\Url;
use FiveamCode\LaravelNotionApi\Entities\PropertyItems\SelectItem;
use FiveamCode\LaravelNotionApi\Notion;
use FiveamCode\LaravelNotionApi\Query\StartCursor;
use Generator;
use GuzzleHttp\Psr7\Uri;
use Illuminate\Support\LazyCollection;
use OutOfRangeException;
use Ramsey\Uuid\Uuid;
use Sushi\Sushi;
trait HasNotionDatabase
{
use Sushi;
abstract protected function getNotionDatabaseId(): string;
abstract protected function getNotionPageData(Page $page): array;
protected function getNotionDatabase(): Database
{
return app(Notion::class)->database($this->getNotionDatabaseId());
}
protected function queryNotionDatabase(?StartCursor $cursor = null): PageCollection
{
return $cursor !== null
? $this->getNotionDatabase()->offset($cursor)->query()
: $this->getNotionDatabase()->query();
}
protected function getNotionPages(): LazyCollection
{
return LazyCollection::make(function (): Generator {
$cursor = null;
do {
$response = $this->queryNotionDatabase($cursor);
$cursor = $response->nextCursor();
$pages = $response->asCollection();
foreach ($pages as $page) {
yield $page;
}
} while ($response->hasMoreEntries());
});
}
protected function getNotionPropertyValue(Page $page, string $key): mixed
{
$property = $page->getProperty($key);
return $property === null
? null
: $this->castNotionProperty($property);
}
protected function castNotionProperty(Property $property): mixed
{
return match ($property::class) {
Checkbox::class => $property->getContent(),
Select::class => $property->getContent()->getName(),
MultiSelect::class => $property->getContent()
->map(fn (SelectItem $item) => $item->getName())
->all(),
Title::class, Text::class => $property->getContent()->getPlainText() ?: null,
Url::class => new Uri($property->getContent()),
Number::class => $property->getContent(),
Relation::class => $property->getContent()
->pluck('id')
->map(fn (string $id) => Uuid::fromString($id))
->all(),
default => throw new OutOfRangeException('Missing notion property cast for: '.$property::class),
};
}
public function getRows(): array
{
return $this->getNotionPages()
->map($this->getNotionPageData(...))
->map(static function (array $attributes): array {
return collect($attributes)
->map(static function (mixed $value) {
if ($value === null) {
return null;
}
if (is_array($value)) {
return json_encode($value);
}
if ($value instanceof Uri) {
return (string) $value;
}
if ($value instanceof BackedEnum) {
return $value->value;
}
return $value;
})
->all();
})
->collect()
->all();
}
} And here's an example model - with working relation, casting and all we love about Eloquent: <?php
namespace App\Models;
use App\Enums\Alignment;
use App\Enums\Race;
use App\Enums\Sex;
use App\Models\Concerns\HasNotionDatabase;
use App\Renderers\PageRenderer;
use Carbon\CarbonInterval;
use FiveamCode\LaravelNotionApi\Entities\Page;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Str;
class Character extends Model
{
use HasNotionDatabase;
protected $casts = [
'aliases' => 'array',
'race' => Race::class,
'sex' => Sex::class,
'alignment' => Alignment::class,
'is_deceased' => 'bool',
'born_at' => 'int',
'died_at' => 'int',
];
public function partner(): BelongsTo
{
return $this->belongsTo(Character::class, 'partner_id', 'id');
}
public function getNotionDatabaseId(): string
{
return 'c10fea27034e4de993201eb9323cd885';
}
public function getNotionPageData(Page $page): array
{
return [
'id' => $page->getId(),
'name' => $page->getTitle(),
'aliases' => Str::of($this->getNotionPropertyValue($page, 'Alias'))
->explode(',')
->map(fn (string $alias): string => trim($alias))
->filter()
->all(),
'race' => $this->getNotionPropertyValue($page, 'Race'),
'sex' => $this->getNotionPropertyValue($page, 'Sex'),
'alignment' => $this->getNotionPropertyValue($page, 'Alignment'),
'is_deceased' => $this->getNotionPropertyValue($page, 'Deceased'),
'born_at' => (int) $this->getNotionPropertyValue($page, 'Born at'),
'died_at' => (int) $this->getNotionPropertyValue($page, 'Died at'),
// relations
'partner_id' => Arr::first($this->getNotionPropertyValue($page, 'Partner')),
// links
'5etools_url' => $this->getNotionPropertyValue($page, '5e.tools'),
'fandom_url' => $this->getNotionPropertyValue($page, 'Fandom'),
// content
'content' => Cache::remember(
key: "{$this->getTable()}.{$page->getId()}.content",
ttl: CarbonInterval::day(),
callback: fn () => PageRenderer::make($page)->render()
),
];
}
} |
No description provided.