diff --git a/LICENSE b/LICENSE index f98b67c..82576b9 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ icanboogie/bind-activerecord is free software. It is released under the terms of the following BSD License. -Copyright (c) 2015-2023 by Olivier Laviale +Copyright (c) 2015-present by Olivier Laviale All rights reserved. Redistribution and use in source and binary forms, with or without modification, diff --git a/Makefile b/Makefile index b3a923b..40819b8 100644 --- a/Makefile +++ b/Makefile @@ -33,7 +33,7 @@ test-coveralls: test-dependencies .PHONY: test-cleanup test-cleanup: - @rm -rf tests/lib/sandbox/* + @# nothing .PHONY: test-container test-container: test-container-81 diff --git a/lib/ConfigBuilder.php b/lib/ConfigBuilder.php index 6f9dbfa..a74dd78 100644 --- a/lib/ConfigBuilder.php +++ b/lib/ConfigBuilder.php @@ -14,6 +14,7 @@ use Closure; use ICanBoogie\ActiveRecord; use ICanBoogie\ActiveRecord\Config; +use ICanBoogie\ActiveRecord\Config\AssociationBuilder; use ICanBoogie\ActiveRecord\Config\ConnectionDefinition; use ICanBoogie\ActiveRecord\Model; use ICanBoogie\ActiveRecord\Query; @@ -43,6 +44,14 @@ public function build(): Config } /** + * @param non-empty-string $id + * @param non-empty-string $dsn + * @param non-empty-string|null $username + * @param non-empty-string|null $password + * @param non-empty-string|null $table_name_prefix + * @param non-empty-string $charset_and_collate + * @param non-empty-string $time_zone + * * @return $this */ public function add_connection( @@ -71,9 +80,15 @@ public function add_connection( * @param class-string $activerecord_class * @param class-string $model_class * @param class-string $query_class - * @param (Closure(SchemaBuilder $schema): SchemaBuilder)|null $schema_builder + * @param non-empty-string|null $table_name + * @param non-empty-string|null $alias + * @param (Closure(SchemaBuilder): SchemaBuilder)|null $schema_builder + * @param (Closure(AssociationBuilder): AssociationBuilder)|null $association_builder + * @param non-empty-string $connection + * + * @return $this */ - public function add_model( + public function add_model( // @phpstan-ignore-line string $activerecord_class, string $model_class = Model::class, string $query_class = Query::class, diff --git a/lib/Console/InstallCommand.php b/lib/Console/InstallCommand.php index 3f66ec1..e37c801 100644 --- a/lib/Console/InstallCommand.php +++ b/lib/Console/InstallCommand.php @@ -2,6 +2,7 @@ namespace ICanBoogie\Binding\ActiveRecord\Console; +use ICanBoogie\ActiveRecord; use ICanBoogie\ActiveRecord\ModelIterator; use ICanBoogie\ActiveRecord\ModelProvider; use Symfony\Component\Console\Attribute\AsCommand; @@ -11,6 +12,7 @@ use Throwable; use function array_filter; +use function sprintf; #[AsCommand('activerecord:install', "Install models")] final class InstallCommand extends Command @@ -24,50 +26,61 @@ public function __construct( protected function execute(InputInterface $input, OutputInterface $output): int { + /** + * @var array, true|null> $tried + */ $tried = []; - $recursive_install = function (string $id) use (&$recursive_install, &$tried, $output): bool { - if (isset($tried[$id])) { - return $tried[$id]; + $recursive_install = function (string $activerecord_class) use (&$recursive_install, &$tried, $output): bool { + /** @var class-string $activerecord_class */ + + if (isset($tried[$activerecord_class])) { + return $tried[$activerecord_class]; } - $model = $this->models->model_for_id($id); + $model = $this->models->model_for_record($activerecord_class); if ($model->is_installed()) { - $output->writeln("Model already installed: $id"); + $output->writeln("Model already installed: $activerecord_class"); - return $tried[$id] = true; + return $tried[$activerecord_class] = true; } - $parent_id = $model->parent?->id; + $parent_activerecord_class = $model->parent?->activerecord_class; - if ($parent_id) { - $rc = $recursive_install($parent_id); + if ($parent_activerecord_class) { + $rc = $recursive_install($parent_activerecord_class); if (!$rc) { - $output->writeln("Unable to install model '$id', parent install failed: '{$parent_id}'"); - - return $tried[$id] = false; + $output->writeln( + sprintf( + "Unable to install model '%s', parent install failed: '%s'", + $activerecord_class, + $parent_activerecord_class + ) + ); + + return $tried[$activerecord_class] = false; } } try { $model->install(); - $output->writeln("Model installed: $id"); + $output->writeln("Model installed: $activerecord_class"); - return $tried[$id] = true; + return $tried[$activerecord_class] = true; } catch (Throwable $e) { - $output->writeln("Unable to install model '$id': {$e->getMessage()}"); + $output->writeln("Unable to install model '$activerecord_class': {$e->getMessage()}"); } - return $tried[$id] = false; + return $tried[$activerecord_class] = false; }; - foreach ($this->iterator->model_iterator() as $id => $_) { - $recursive_install($id); + foreach ($this->iterator->model_iterator() as $activerecord_class => $_) { + $recursive_install($activerecord_class); } - return count(array_filter($tried, fn ($v) => $v === false)) + return count(array_filter($tried, fn($v) => $v === false)) ? Command::FAILURE : Command::SUCCESS; } diff --git a/lib/Hooks.php b/lib/Hooks.php index 7c3692d..341dc9f 100644 --- a/lib/Hooks.php +++ b/lib/Hooks.php @@ -26,20 +26,12 @@ final class Hooks */ /** - * Define model provider. - * - * Models are provided using the model collection bound to the application. + * Sets the factory for the {@link StaticModelProvider}. */ public static function on_app_boot(Application\BootEvent $event): void { - $app = $event->app; - StaticModelProvider::define( - static function () use ($app): ModelProvider { - static $resolver; - - return $resolver ??= $app->service_for_class(ModelProvider::class); - } + static fn() => $event->app->service_for_class(ModelProvider::class) ); } @@ -61,8 +53,6 @@ public static function active_record_validate(ActiveRecord $record): array|Valid /** * Returns the records cache associated with the model. - * - * @param Model $model */ public static function model_lazy_get_activerecord_cache(Model $model): RuntimeActiveRecordCache { diff --git a/phpcs.xml b/phpcs.xml index 8c33a9f..503ddb6 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -3,8 +3,8 @@ xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/squizlabs/PHP_CodeSniffer/master/phpcs.xsd"> lib tests - tests/lib/sandbox/* - tests/repository/* + tests/sandbox/* + tests/var/* diff --git a/phpstan.neon b/phpstan.neon index f638b07..03a60f9 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -2,3 +2,6 @@ parameters: level: max paths: - lib + ignoreErrors: + - '#ICanBoogie.+ActiveRecord but does not specify its types#' + - '#ICanBoogie.+ActiveRecord.+Model but does not specify its types:#' diff --git a/tests/lib/Acme/Article.php b/tests/lib/Acme/Article.php index 7714b8f..5a09304 100644 --- a/tests/lib/Acme/Article.php +++ b/tests/lib/Acme/Article.php @@ -2,8 +2,14 @@ namespace Test\ICanBoogie\Binding\ActiveRecord\Acme; +use ICanBoogie\ActiveRecord\Schema\Date; +use ICanBoogie\ActiveRecord\Schema\Text; + class Article extends Node { + #[Text] public string $body; + + #[Date] public string $date; } diff --git a/tests/lib/Acme/Node.php b/tests/lib/Acme/Node.php index 593c7bc..cd842b6 100644 --- a/tests/lib/Acme/Node.php +++ b/tests/lib/Acme/Node.php @@ -3,9 +3,15 @@ namespace Test\ICanBoogie\Binding\ActiveRecord\Acme; use ICanBoogie\ActiveRecord; +use ICanBoogie\ActiveRecord\Schema\Character; +use ICanBoogie\ActiveRecord\Schema\Id; +use ICanBoogie\ActiveRecord\Schema\Serial; class Node extends ActiveRecord { + #[Serial, Id] public int $id; + + #[Character] public string $title; } diff --git a/tests/lib/ConfigBuilderTest.php b/tests/lib/ConfigBuilderTest.php index 82e1277..2f9a92c 100644 --- a/tests/lib/ConfigBuilderTest.php +++ b/tests/lib/ConfigBuilderTest.php @@ -52,6 +52,34 @@ public function test_build(): void ); } + public function test_use_attributes(): void + { + $expected = (new ConfigBuilder()) + ->add_connection(Config::DEFAULT_CONNECTION_ID, 'sqlite::memory:') + ->add_model( + activerecord_class: Node::class, + schema_builder: fn(SchemaBuilder $b) => $b + ->add_serial('id', primary: true) + ->add_character('title'), + ) + ->add_model( + activerecord_class: Article::class, + schema_builder: fn(SchemaBuilder $b) => $b + ->add_text('body') + ->add_date('date'), + ) + ->build(); + + $actual = (new ConfigBuilder()) + ->add_connection(Config::DEFAULT_CONNECTION_ID, 'sqlite::memory:') + ->use_attributes() + ->add_model(Node::class) + ->add_model(Article::class) + ->build(); + + $this->assertEquals($expected, $actual); + } + public function test_integration(): void { $expected = (new ConfigBuilder()) diff --git a/tests/lib/IntegrationTest.php b/tests/lib/IntegrationTest.php index 86db155..4c857c5 100644 --- a/tests/lib/IntegrationTest.php +++ b/tests/lib/IntegrationTest.php @@ -7,7 +7,6 @@ use Test\ICanBoogie\Binding\ActiveRecord\Acme\Article; use Test\ICanBoogie\Binding\ActiveRecord\Acme\Node; use Test\ICanBoogie\Binding\ActiveRecord\Acme\NodeModel; - use Test\ICanBoogie\Binding\ActiveRecord\Acme\SampleService; use function ICanBoogie\app; diff --git a/tests/repository/cache/.gitignore b/tests/repository/cache/.gitignore deleted file mode 100644 index d6b7ef3..0000000 --- a/tests/repository/cache/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore diff --git a/tests/lib/sandbox/.gitignore b/tests/var/cache/.gitignore similarity index 100% rename from tests/lib/sandbox/.gitignore rename to tests/var/cache/.gitignore