Skip to content

Commit

Permalink
Remove AssociationBuilder::belongs_to
Browse files Browse the repository at this point in the history
The belongs_to relationship is defined by the Schema
  • Loading branch information
olvlvl committed Sep 13, 2023
1 parent f26ec3f commit 9fd2be9
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 121 deletions.
79 changes: 3 additions & 76 deletions lib/ActiveRecord/Config/AssociationBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,11 @@
namespace ICanBoogie\ActiveRecord\Config;

use ICanBoogie\ActiveRecord;
use ICanBoogie\ActiveRecord\Schema\BelongsTo;
use ICanBoogie\ActiveRecord\Schema\HasMany;
use ICanBoogie\ActiveRecord\Schema\SchemaAttribute;
use ICanBoogie\ActiveRecord\Schema;
use ReflectionClass;

use function assert;
use function ICanBoogie\trim_suffix;
use function printf;
use function strlen;

final class AssociationBuilder
{
/**
* @var array<TransientBelongsToAssociation>
*/
private array $belongs_to = [];

/**
* @var array<TransientHasManyAssociation>
*/
Expand All @@ -29,30 +17,7 @@ public function build(): TransientAssociation
{
return new TransientAssociation(
has_many: $this->has_many,
belongs_to: $this->belongs_to,
);
}

/**
* When "A" has a reference to "B", we say "A" belongs to "B".
*
* @param class-string<ActiveRecord> $associate
* The associate ActiveRecord class.
* @param non-empty-string|null $as
* The name of the accessor.
*/
public function belongs_to(
string $associate,
string $local_key = null,
string $as = null,
): self {
$this->belongs_to[] = new TransientBelongsToAssociation(
associate: $associate,
local_key: $local_key,
as: $as,
);

return $this;
}

/**
Expand Down Expand Up @@ -94,10 +59,10 @@ public function use_record(string $activerecord_class): self
{
$class = new ReflectionClass($activerecord_class);

foreach ($class->getAttributes(HasMany::class) as $attribute) {
foreach ($class->getAttributes(Schema\HasMany::class) as $attribute) {
$attribute = $attribute->newInstance();
/** @var Schema\HasMany $attribute */

/** @var HasMany $attribute */
$this->has_many(
associate: $attribute->associate,
foreign_key: $attribute->foreign_key,
Expand All @@ -106,44 +71,6 @@ public function use_record(string $activerecord_class): self
);
}

// note: belongs_to is configured with a schema.

return $this;
}

/**
* @internal
*
* @return $this
*/
public function use_schema(ActiveRecord\Schema $schema): self
{
foreach ($schema->columns as $local_key => $column) {
if (!$column instanceof BelongsTo) {
continue;
}

$this->belongs_to(
associate: $column->associate,
local_key: $local_key,
as: $column->as ?? $this->resolve_belong_to_accessor($local_key),
);
}

return $this;
}

/**
* @param non-empty-string $local_key
*
* @return non-empty-string
*/
private function resolve_belong_to_accessor(string $local_key): string
{
$local_key = trim_suffix($local_key, '_id');

assert($local_key !== '');

return $local_key;
}
}
2 changes: 0 additions & 2 deletions lib/ActiveRecord/Config/TransientAssociation.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,9 @@ final class TransientAssociation
{
/**
* @param array<TransientHasManyAssociation> $has_many
* @param array<TransientBelongsToAssociation> $belongs_to
*/
public function __construct(
public readonly array $has_many,
public readonly array $belongs_to,
) {
}
}
19 changes: 0 additions & 19 deletions lib/ActiveRecord/Config/TransientBelongsToAssociation.php

This file was deleted.

47 changes: 23 additions & 24 deletions lib/ActiveRecord/ConfigBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@
use ICanBoogie\ActiveRecord\Config\ModelDefinition;
use ICanBoogie\ActiveRecord\Config\TableDefinition;
use ICanBoogie\ActiveRecord\Config\TransientAssociation;
use ICanBoogie\ActiveRecord\Config\TransientBelongsToAssociation;
use ICanBoogie\ActiveRecord\Config\TransientHasManyAssociation;
use ICanBoogie\ActiveRecord\Config\TransientModelDefinition;
use ICanBoogie\ActiveRecord\Schema\BelongsTo;
use ICanBoogie\ActiveRecord\Schema\Integer;
use InvalidArgumentException;
use LogicException;
Expand Down Expand Up @@ -122,10 +122,12 @@ private function build_associations(): array
foreach ($this->association as $activerecord_class => $association) {
$owner = $this->model_definitions[$activerecord_class];

$belongs_to = array_map(
fn(TransientBelongsToAssociation $a): BelongsToAssociation => $this->resolve_belongs_to($owner, $a),
$association->belongs_to
);
$belongs_to = [];

foreach ($owner->schema->belongs_to_iterator() as $name => $column) {
/** @var BelongsTo $column */
$belongs_to[] = $this->resolve_belongs_to($name, $column);
}

$has_many = array_map(
fn(TransientHasManyAssociation $a): HasManyAssociation => $this->resolve_has_many($owner, $a),
Expand Down Expand Up @@ -193,30 +195,28 @@ private function try_key(mixed $key, TransientModelDefinition $on): ?string
return null;
}

assert(strlen($key) > 1);

return $on->schema->has_column($key) ? $key : null;
}

private function resolve_belongs_to(
TransientModelDefinition $owner,
TransientBelongsToAssociation $association
): BelongsToAssociation {
$associate = $this->model_definitions[$association->associate];
/**
* @param non-empty-string $local_key
*/
private function resolve_belongs_to(string $local_key, Schema\BelongsTo $column): BelongsToAssociation
{
$associate = $this->model_definitions[$column->associate];
$foreign_key = $associate->schema->primary;

if (!is_string($foreign_key)) {
throw new InvalidConfig(
"Unable to create 'belongs to' association, primary key of model '$associate->model_class' is not a string."
"Unable to create 'belongs to' association, primary key of `$associate->activerecord_class` is not a string."

Check warning on line 213 in lib/ActiveRecord/ConfigBuilder.php

View workflow job for this annotation

GitHub Actions / phpcs

Line exceeds 120 characters; contains 125 characters
);
}

$local_key = $association->local_key
?? $this->try_key($foreign_key, $owner)
?? throw new LogicException(
"Don't know how to resolve local key on '$owner->model_class' for association belongs_to($associate->model_class)"
);
$as = $column->as ?? singularize($associate->alias);

$as = $association->as
?? singularize($associate->alias);
assert(strlen($as) > 0);

return new BelongsToAssociation(
$associate->activerecord_class,
Expand All @@ -242,18 +242,18 @@ private function resolve_has_many(
}

$foreign_key or throw new InvalidConfig(
"Don't know how to resolve foreign key on '$owner->model_class' for association has_many($related->model_class)"
"Don't know how to resolve foreign key on `$owner->activerecord_class` for association has_many($related->model_class)"

Check warning on line 245 in lib/ActiveRecord/ConfigBuilder.php

View workflow job for this annotation

GitHub Actions / phpcs

Line exceeds 120 characters; contains 131 characters
);

if (!is_string($local_key)) {
throw new InvalidConfig(
"Unable to create 'has many' association, primary key of model '$owner->model_class' is not a string."
"Unable to create 'has many' association, primary key of model '$owner->activerecord_class' is not a string."

Check warning on line 250 in lib/ActiveRecord/ConfigBuilder.php

View workflow job for this annotation

GitHub Actions / phpcs

Line exceeds 120 characters; contains 125 characters
);
}

if (!is_string($foreign_key)) {
throw new InvalidConfig(
"Unable to create 'has many' association, primary key of model '$related->model_class' is not a string."
"Unable to create 'has many' association, primary key of model '$related->activerecord_class' is not a string."

Check warning on line 256 in lib/ActiveRecord/ConfigBuilder.php

View workflow job for this annotation

GitHub Actions / phpcs

Line exceeds 120 characters; contains 127 characters
);
}

Expand Down Expand Up @@ -351,7 +351,6 @@ public function add_model( // @phpstan-ignore-line
// association

$schema = $inner_schema_builder->build();
$inner_association_builder->use_schema($schema);

if ($association_builder) {
$association_builder($inner_association_builder);
Expand All @@ -369,7 +368,7 @@ public function add_model( // @phpstan-ignore-line
activerecord_class: $activerecord_class,
query_class: $query_class,
table_name: $table_name,
alias: $alias ?? singularize($table_name),
alias: $alias ?? singularize($table_name), // @phpstan-ignore-line
connection: $connection,
);

Expand All @@ -386,7 +385,7 @@ private static function resolve_table_name(string $activerecord_class): string
$pos = strrpos($activerecord_class, '\\');
$base = substr($activerecord_class, $pos + 1);

return pluralize(underscore($base));
return pluralize(underscore($base)); // @phpstan-ignore-line
}

private bool $use_attributes = false;
Expand Down
14 changes: 14 additions & 0 deletions lib/ActiveRecord/Schema.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
namespace ICanBoogie\ActiveRecord;

use ICanBoogie\ActiveRecord;
use ICanBoogie\ActiveRecord\Schema\BelongsTo;
use ICanBoogie\ActiveRecord\Schema\Column;
use ICanBoogie\ActiveRecord\Schema\Index;
use InvalidArgumentException;
Expand Down Expand Up @@ -102,4 +103,17 @@ public function filter_values(array $values): array
{
return array_intersect_key($values, $this->columns);
}

/**
* @return iterable<non-empty-string, BelongsTo>
* Where _key_ is the name of a column.
*/
public function belongs_to_iterator(): iterable
{
foreach ($this->columns as $name => $column) {
if ($column instanceof BelongsTo) {
yield $name => $column;
}
}
}
}

0 comments on commit 9fd2be9

Please sign in to comment.