Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion config/ozu-client.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
<?php

return [
// List here your collections, ie the Models that will be handled by the Ozu CMS.
// List here your (parent) collections, ie the Models that will be handled by the Ozu CMS.
// You must not declare the subcollections here, they will be automatically handled by their parents.
// You must also properly configure them (see documentation).
'collections' => [
// \App\Models\Project::class,
Expand Down
198 changes: 121 additions & 77 deletions src/Console/ConfigureCmsCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

namespace Code16\OzuClient\Console;

use Closure;
use Code16\OzuClient\Client;
use Code16\OzuClient\OzuCms\Form\OzuField;
use Code16\OzuClient\OzuCms\List\OzuColumn;
Expand All @@ -16,8 +15,11 @@
class ConfigureCmsCommand extends Command
{
protected $signature = 'ozu:configure-cms';
protected $aliases = ['ozu:configure', 'configure:ozu'];
protected $description = 'Sends CMS configuration to Ozu.';
private Client $ozuClient;

protected $description = 'Send CMS configuration to Ozu.';
private array $processedCollections = [];

public function handle(Client $ozuClient): int
{
Expand All @@ -27,85 +29,127 @@ public function handle(Client $ozuClient): int
return self::SUCCESS;
}

$this->ozuClient = $ozuClient;

$this->newLine();
$this->line('<fg=white>Sending configuration to <options=bold>'.config('ozu-client.api_host').'</></>');
$this->newLine();

collect(config('ozu-client.collections'))
->map(function ($collection, $k) {
$model = match (true) {
is_string($collection) => app($collection),
$collection instanceof Closure => $collection(),
default => $collection,
};

$collection = $model::configureOzuCollection(new OzuCollectionConfig());
$list = $model::configureOzuCollectionList(new OzuCollectionListConfig());
$form = $model::configureOzuCollectionForm(new OzuCollectionFormConfig());

return [
'key' => $model->ozuCollectionKey(),
'label' => $collection->label(),
'icon' => $collection->icon(),
'hasPublicationState' => $collection->hasPublicationState(),
'autoDeployDateField' => $collection->autoDeployDateField(),
'isCreatable' => $collection->isCreatable(),
'isDeletable' => $collection->isDeletable(),
'order' => $k + 1,
'list' => [
'isReorderable' => $list->isReorderable(),
'isSearchable' => $list->isSearchable(),
'isPaginated' => $list->isPaginated(),
'defaultSort' => $list->defaultSort(),
'belongsToFilter' => $list->belongsToFilter()?->toArray(),
'columns' => $list
->columns()
->map(fn (OzuColumn $column) => [
'type' => $column->type(),
'key' => $column->key(),
'label' => $column->label(),
'size' => $column->size(),
]),
],
'form' => [
'title' => $form->titleField()?->toArray(),
'cover' => $form->coverField()?->toArray(),
'content' => $form->contentField()?->toArray(),
'fields' => $form
->customFields()
->map(fn (OzuField $field) => $field->toArray()),
],
'customFields' => collect(Schema::getColumnListing($model->getTable()))
->filter(fn (string $column) => !in_array($column, $model::$ozuColumns))
->mapWithKeys(fn (string $column) => [
$column => match (Schema::getColumnType($model->getTable(), $column)) {
'datetime', 'timestamps' => 'dateTime',
'date' => 'date',
'int', 'bigint', 'smallint', 'mediumint', 'tinyint' => 'integer',
'float', 'double' => 'float',
'text', 'json' => 'text',
default => 'string',
},
]),
];
})
->each(function (array $collection) use ($ozuClient) {
$this->info('Update CMS configuration for ['.$collection['key'].'].');
try {
$ozuClient->updateCollectionSharpConfiguration(
$collection['key'],
$collection
);
} catch (RequestException $e) {
if ($message = $e->response->json()) {
if (!isset($message['message'])) {
throw $e;
}
$this->error('['.$collection['key'].'] '.$message['message']);
} else {
throw $e;
}
}
});
->each(fn ($collection, $k) => $this->updateCmsConfigurationFor($collection, $k+1));

$this->newLine();
$this->info('CMS configuration sent to Ozu.');

return self::SUCCESS;
}

private function updateCmsConfigurationFor($collectionClass, int $order = 1, bool $isSubCollection = false): void
{
$model = match (true) {
is_string($collectionClass) => app($collectionClass),
is_callable($collectionClass) => $collectionClass(),
default => $collectionClass,
};

// avoid processing the same collection twice
if (in_array($model::class, $this->processedCollections)) {
/*
* We avoid processing multiple times the same subcollection, but we'll warn the
* user only if it's not a subcollection, because subcollection models can be
* declared in multiple parent collections.
*/

if(!$isSubCollection) {
$this->line('<fg=yellow>Skipping <options=bold>'.($model->ozuCollectionKey() ?? $model::class).'</> because it has already been processed.</>');
$this->line('<fg=yellow>You may have wrongly configured your subcollections, or included a subcollection to the collections array in the ozu-client config file...</>');
}

return;
} else { $this->processedCollections[] = $model::class; }

$collection = $model::configureOzuCollection(new OzuCollectionConfig());
$list = $model::configureOzuCollectionList(new OzuCollectionListConfig());
$form = $model::configureOzuCollectionForm(new OzuCollectionFormConfig());

$payload = [
'key' => $model->ozuCollectionKey(),
'label' => $collection->label(),
'icon' => $collection->icon(),
'isSubCollection' => !$isSubCollection,
'hasPublicationState' => $collection->hasPublicationState(),
'autoDeployDateField' => $collection->autoDeployDateField(),
'isCreatable' => $collection->isCreatable(),
'isDeletable' => $collection->isDeletable(),
'subCollections' => $collection->subCollections()
->map(fn ($subCollectionClass) => app($subCollectionClass)->ozuCollectionKey()),
'order' => $order,
'list' => [
'isReorderable' => $list->isReorderable(),
'isSearchable' => $list->isSearchable(),
'isPaginated' => $list->isPaginated(),
'defaultSort' => $list->defaultSort(),
'belongsToFilter' => $list->belongsToFilter()?->toArray(),
'columns' => $list
->columns()
->map(fn (OzuColumn $column) => [
'type' => $column->type(),
'key' => $column->key(),
'label' => $column->label(),
'size' => $column->size(),
]),
],
'form' => [
'title' => $form->titleField()?->toArray(),
'cover' => $form->coverField()?->toArray(),
'content' => $form->contentField()?->toArray(),
'fields' => $form
->customFields()
->map(fn (OzuField $field) => $field->toArray()),
],
'customFields' => collect(Schema::getColumnListing($model->getTable()))
->filter(fn (string $column) => !in_array($column, $model::$ozuColumns))
->mapWithKeys(fn (string $column) => [
$column => match (Schema::getColumnType($model->getTable(), $column)) {
'datetime', 'timestamps' => 'dateTime',
'date' => 'date',
'int', 'bigint', 'smallint', 'mediumint', 'tinyint' => 'integer',
'float', 'double' => 'float',
'text', 'json' => 'text',
default => 'string',
},
]),
];

$this->line('<fg=green>Updating CMS configuration for <options=bold>'.$payload['key'].'</>...</>');

try {
$this->ozuClient->updateCollectionSharpConfiguration($payload['key'], $payload);

$collection->subCollections()
->each(fn ($subCollectionClass) => $this
->updateCmsConfigurationFor($subCollectionClass, isSubCollection: true)
);

} catch (RequestException $e) {
if ($message = $e->response->json()) {
if (!isset($message['message'])) {
throw $e;
}

// Display by priority: validations errors, generic error, json dump of the response
$this->error(sprintf(
'[%s] %s',
$collection['key'],
isset($message['errors']) ?
collect(is_array($message['errors']) ? $message['errors'] : [])
->map(fn ($error, $key) => sprintf('%s: %s', $key, $error[0]))
->implode(', ') ?? ($message['message'] ?? json_encode($message))
: ($message['message'] ?? json_encode($message))
));
} else {
throw $e;
}
}
}
}
Empty file removed src/Deploy/Crawler/Observer.php
Empty file.
Empty file.
Empty file removed src/Deploy/Jobs/CrawlSite.php
Empty file.
Empty file.
Empty file.
Empty file.
23 changes: 15 additions & 8 deletions src/OzuCms/OzuCollectionConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,17 @@

namespace Code16\OzuClient\OzuCms;

use Illuminate\Support\Collection;

class OzuCollectionConfig
{
protected string $label;

protected string $icon;

protected bool $hasPublicationState = false;

protected ?string $autoDeployDateField = null;

private bool $isCreatable = true;

private bool $isDeletable = true;
private array $subCollections = [];

public function setLabel(string $label): self
{
Expand All @@ -39,9 +37,6 @@ public function setHasPublicationState(bool $hasState = true): self

/**
* Declare which date field will trigger auto-deploy when reached
*
* @param string|null $field
* @return $this
*/
public function setAutoDeployDateField(string $fieldKey): self
{
Expand All @@ -64,6 +59,13 @@ public function setIsDeletable(bool $isDeletable = true): self
return $this;
}

public function addSubCollection(string $collectionClass): self
{
$this->subCollections[] = $collectionClass;

return $this;
}

public function label(): string
{
return $this->label ?? 'no label';
Expand Down Expand Up @@ -98,4 +100,9 @@ public function isDeletable(): bool
{
return $this->isDeletable;
}

public function subCollections(): Collection
{
return collect($this->subCollections);
}
}
50 changes: 50 additions & 0 deletions tests/Console/ConfigureCmsCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Code16\OzuClient\OzuCms\OzuCollectionConfig;
use Code16\OzuClient\OzuCms\OzuCollectionFormConfig;
use Code16\OzuClient\OzuCms\OzuCollectionListConfig;
use Code16\OzuClient\Tests\Fixtures\DummySubcollectionTestModel;
use Code16\OzuClient\Tests\Fixtures\DummyTestModel;
use Illuminate\Console\Command;
use Illuminate\Http\Client\Request;
Expand Down Expand Up @@ -261,3 +262,52 @@ public function ozuCollectionKey(): string
]);
});
});

it('sends subcollections configuration to Ozu', function () {
Http::fake();

// Create a parent collection with subcollections
$parentCollectionClass = new class extends DummyTestModel
{
public function ozuCollectionKey(): string
{
return 'dummy-parent';
}

public static function configureOzuCollection(OzuCollectionConfig $config): OzuCollectionConfig
{
return $config
->setLabel('Parent collection')
->addSubCollection(DummySubcollectionTestModel::class);
}
};

config(['ozu-client.collections' => [$parentCollectionClass]]);

$this->artisan('ozu:configure-cms')
->expectsOutput('CMS configuration sent to Ozu.')
->assertExitCode(Command::SUCCESS);

// Assert parent is sent with subcollections in payload
Http::assertSent(function (Request $request) {
return $request->url() == sprintf(
'%s/api/%s/%s/collections/%s/configure',
rtrim(config('ozu-client.api_host'), '/'),
config('ozu-client.api_version'),
'test',
'dummy-parent'
) && $request['subCollections']->count() === 1
&& $request['subCollections']->first() === 'dummy-subcollection';
});

// Assert subcollection is also processed and sent
Http::assertSent(function (Request $request) {
return $request->url() == sprintf(
'%s/api/%s/%s/collections/%s/configure',
rtrim(config('ozu-client.api_host'), '/'),
config('ozu-client.api_version'),
'test',
'dummy-subcollection'
);
});
});
38 changes: 38 additions & 0 deletions tests/Fixtures/DummySubcollectionTestModel.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

namespace Code16\OzuClient\Tests\Fixtures;

use Code16\OzuClient\Eloquent\IsOzuModel;
use Code16\OzuClient\OzuCms\OzuCollectionConfig;
use Code16\OzuClient\OzuCms\OzuCollectionFormConfig;
use Code16\OzuClient\OzuCms\OzuCollectionListConfig;
use Illuminate\Database\Eloquent\Model;

class DummySubcollectionTestModel extends Model
{
protected $table = 'dummy_test_models';

use IsOzuModel;

protected $guarded = [];

public function ozuCollectionKey(): string
{
return 'dummy-subcollection';
}

public static function configureOzuCollection(OzuCollectionConfig $config): OzuCollectionConfig
{
return $config;
}

public static function configureOzuCollectionList(OzuCollectionListConfig $config): OzuCollectionListConfig
{
return $config;
}

public static function configureOzuCollectionForm(OzuCollectionFormConfig $config): OzuCollectionFormConfig
{
return $config;
}
}