Skip to content

Worked extension examples

These developer-facing recipes are kept beside the package contract. Replace the example values with the site-specific records and data objects used by the calling workflow.

<?php
declare(strict_types=1);
final class ExampleImportSessionExecutorImplementation implements \Capell\MigrationAssistant\Contracts\ImportSessionExecutor
{
public function supports(\Capell\MigrationAssistant\Models\ImportSession $session): bool
{
throw new LogicException('Implement this package contract for the calling site.');
}
public function canRetry(\Capell\MigrationAssistant\Models\ImportSession $session): bool
{
throw new LogicException('Implement this package contract for the calling site.');
}
public function execute(\Capell\MigrationAssistant\Models\ImportSession $session): void
{
throw new LogicException('Implement this package contract for the calling site.');
}
}
app()->bind(\Capell\MigrationAssistant\Contracts\ImportSessionExecutor::class, ExampleImportSessionExecutorImplementation::class);
<?php
declare(strict_types=1);
final class ExampleImportSessionSubNavigationExtenderImplementation implements \Capell\MigrationAssistant\Contracts\ImportSessionSubNavigationExtender
{
/** @return array<int, NavigationItem> */
public function getItems(): array
{
throw new LogicException('Implement this package contract for the calling site.');
}
}
app()->bind(\Capell\MigrationAssistant\Contracts\ImportSessionSubNavigationExtender::class, ExampleImportSessionSubNavigationExtenderImplementation::class);
<?php
declare(strict_types=1);
final class ExampleImportSourceReaderImplementation implements \Capell\MigrationAssistant\Contracts\ImportSourceReader
{
public function supports(string $extension): bool
{
throw new LogicException('Implement this package contract for the calling site.');
}
public function read(string $path): \Capell\MigrationAssistant\Data\ExternalImportReadResult
{
throw new LogicException('Implement this package contract for the calling site.');
}
}
app()->bind(\Capell\MigrationAssistant\Contracts\ImportSourceReader::class, ExampleImportSourceReaderImplementation::class);
<?php
declare(strict_types=1);
final class ExampleMigrationAssistantContextResolverImplementation implements \Capell\MigrationAssistant\Contracts\MigrationAssistantContextResolver
{
/**
* Execute $callback inside any ambient scope the resolver manages.
* The resolver decides what state to set up before the callback and
* tears it down after.
*
* @template TReturn
*
* @param Closure(): TReturn $callback
* @return TReturn
*/
public function wrap(\Closure $callback, ?int $sourceWorkspaceId = null): mixed
{
throw new LogicException('Implement this package contract for the calling site.');
}
/**
* @param array<int, int|string> $pageIds
* @return array<int, int|string>
*/
public function resolvePageIds(array $pageIds, ?int $sourceWorkspaceId = null): array
{
throw new LogicException('Implement this package contract for the calling site.');
}
}
app()->bind(\Capell\MigrationAssistant\Contracts\MigrationAssistantContextResolver::class, ExampleMigrationAssistantContextResolverImplementation::class);
<?php
declare(strict_types=1);
final class ExampleMigrationAssistantRowContributorImplementation implements \Capell\MigrationAssistant\Contracts\MigrationAssistantRowContributor
{
/**
* Extra attributes to include in an exported row. Return [] when no
* extra columns exist on the model's table.
*
* @return array<string, mixed>
*/
public function extraAttributes(\Illuminate\Database\Eloquent\Model $model): array
{
throw new LogicException('Implement this package contract for the calling site.');
}
/**
* Strip attributes from an incoming imported row that core cannot persist.
*
* @param array<string, mixed> $attributes
* @return array<string, mixed>
*/
public function normalizeIncomingRow(array $attributes): array
{
throw new LogicException('Implement this package contract for the calling site.');
}
/**
* Apply any filtering the contributor requires to restrict the query
* to rows that should be exportable. Core calls this and does not
* describe what the contributor should filter by.
*
* @template TModel of Model
*
* @param Builder<TModel> $query
* @return Builder<TModel>
*/
public function scopeExportable(\Illuminate\Database\Eloquent\Builder $query): \Illuminate\Database\Eloquent\Builder
{
throw new LogicException('Implement this package contract for the calling site.');
}
}
app()->bind(\Capell\MigrationAssistant\Contracts\MigrationAssistantRowContributor::class, ExampleMigrationAssistantRowContributorImplementation::class);
<?php
declare(strict_types=1);
final class ExamplePageCollisionDetectorImplementation implements \Capell\MigrationAssistant\Contracts\PageCollisionDetector
{
/**
* @param list<array{site_id: int|null, language_id: int|null, url: string}> $urls
* @return array{0: string, 1: list<string>, 2: string} [collisionState, conflictMessages, suggestedAction]
*/
public function detect(array $urls, ?int $resolvedSiteId): array
{
throw new LogicException('Implement this package contract for the calling site.');
}
}
app()->bind(\Capell\MigrationAssistant\Contracts\PageCollisionDetector::class, ExamplePageCollisionDetectorImplementation::class);
<?php
declare(strict_types=1);
final class ExamplePageImportTargetResolverImplementation implements \Capell\MigrationAssistant\Contracts\PageImportTargetResolver
{
public function create(string $name): \Capell\MigrationAssistant\Data\PageImportTargetData
{
throw new LogicException('Implement this package contract for the calling site.');
}
public function resolve(\Capell\MigrationAssistant\Models\ImportSession $session): \Capell\MigrationAssistant\Data\PageImportTargetData
{
throw new LogicException('Implement this package contract for the calling site.');
}
}
app()->bind(\Capell\MigrationAssistant\Contracts\PageImportTargetResolver::class, ExamplePageImportTargetResolverImplementation::class);
<?php
declare(strict_types=1);
final class ExamplePathAwareImportSourceReaderImplementation implements \Capell\MigrationAssistant\Contracts\PathAwareImportSourceReader
{
public function supportsPath(string $path): bool
{
throw new LogicException('Implement this package contract for the calling site.');
}
}
app()->bind(\Capell\MigrationAssistant\Contracts\PathAwareImportSourceReader::class, ExamplePathAwareImportSourceReaderImplementation::class);