-
-
Notifications
You must be signed in to change notification settings - Fork 50
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature/notion models and commands #121
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.