Skip to content

Commit

Permalink
Refactor Eloquent Model Attributes casting (#251)
Browse files Browse the repository at this point in the history
Use Eloquent Attributes instead of magic methods
  • Loading branch information
antonkomarev authored Mar 9, 2024
1 parent d9fae25 commit 55d5640
Show file tree
Hide file tree
Showing 9 changed files with 103 additions and 75 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ All notable changes to `laravel-love` will be documented in this file.

### Changed

- ([#251]) Changed Models attributes casting style
- ([#252]) All Models are unguarded now

### Removed
Expand Down Expand Up @@ -596,6 +597,7 @@ Follow [upgrade instructions](UPGRADING.md#from-v5-to-v6) to migrate database to

[#258]: https://github.com/cybercog/laravel-love/pull/258
[#252]: https://github.com/cybercog/laravel-love/pull/252
[#251]: https://github.com/cybercog/laravel-love/pull/251
[#248]: https://github.com/cybercog/laravel-love/pull/248
[#247]: https://github.com/cybercog/laravel-love/pull/247
[#240]: https://github.com/cybercog/laravel-love/pull/240
Expand Down
10 changes: 10 additions & 0 deletions UPGRADING.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
# Upgrade Guide

- [From v9 to v10](#from-v9-to-v10)
- [From v8 to v9](#from-v8-to-v9)
- [From v7 to v8](#from-v7-to-v8)
- [From v6 to v7](#from-v6-to-v7)
- [From v5 to v6](#from-v5-to-v6)
- [From v4 to v5](#from-v4-to-v5)
- [From v3 to v4](#from-v3-to-v4)

## From v9 to v10

`ReactionCounterObserver`, `ReactionTotalObserver` & `ReactionObserver::creating` were removed.
Default values of `ReactionCounter`, `ReactionTotal` & `Reaction` models are defined inside models now.
If you are using default models from the package, it is not a breaking change.

All package models are unguarded now. If you are passing all values without validation,
you should refactor code which passing to them.

## From v8 to v9

Release v9 has new Eloquent model local scopes approach described in ([#226](https://github.com/cybercog/laravel-love/discussions/226#discussioncomment-4612667)).
Expand Down
14 changes: 8 additions & 6 deletions src/Reactant/Models/Reactant.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
use Cog\Laravel\Love\Reactant\ReactionTotal\Models\ReactionTotal;
use Cog\Laravel\Love\Reaction\Models\Reaction;
use Cog\Laravel\Love\Support\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
Expand All @@ -45,12 +46,13 @@ final class Reactant extends Model implements

protected static $unguarded = true;

/**
* @var string[]
*/
protected $casts = [
'id' => 'string',
];
public function id(): Attribute
{
return new Attribute(
get: fn (string | null $value) => $value,
set: fn (string | null $value) => $value,
);
}

public function reactable(): MorphTo
{
Expand Down
35 changes: 16 additions & 19 deletions src/Reactant/ReactionCounter/Models/ReactionCounter.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use Cog\Laravel\Love\Reactant\Models\Reactant;
use Cog\Laravel\Love\ReactionType\Models\ReactionType;
use Cog\Laravel\Love\Support\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

Expand All @@ -43,13 +44,21 @@ final class ReactionCounter extends Model implements
'weight' => self::WEIGHT_DEFAULT,
];

/**
* @var string[]
*/
protected $casts = [
'count' => 'integer',
'weight' => 'float',
];
public function count(): Attribute
{
return new Attribute(
get: fn (int | null $value) => $value ?? self::COUNT_DEFAULT,
set: fn (int | null $value) => $value ?? self::COUNT_DEFAULT,
);
}

public function weight(): Attribute
{
return new Attribute(
get: fn (float | null $value) => $value ?? self::WEIGHT_DEFAULT,
set: fn (float | null $value) => $value ?? self::WEIGHT_DEFAULT,
);
}

public function reactant(): BelongsTo
{
Expand Down Expand Up @@ -116,16 +125,4 @@ public function decrementWeight(
): void {
$this->decrement('weight', $amount);
}

public function setCountAttribute(
int | null $count,
): void {
$this->attributes['count'] = $count ?? self::COUNT_DEFAULT;
}

public function setWeightAttribute(
float | null $weight,
): void {
$this->attributes['weight'] = $weight ?? self::WEIGHT_DEFAULT;
}
}
35 changes: 16 additions & 19 deletions src/Reactant/ReactionTotal/Models/ReactionTotal.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use Cog\Contracts\Love\Reactant\ReactionTotal\Models\ReactionTotal as ReactionTotalInterface;
use Cog\Laravel\Love\Reactant\Models\Reactant;
use Cog\Laravel\Love\Support\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

Expand All @@ -41,13 +42,21 @@ final class ReactionTotal extends Model implements
'weight' => self::WEIGHT_DEFAULT,
];

/**
* @var string[]
*/
protected $casts = [
'count' => 'integer',
'weight' => 'float',
];
public function count(): Attribute
{
return new Attribute(
get: fn (int | null $value) => $value ?? self::COUNT_DEFAULT,
set: fn (int | null $value) => $value ?? self::COUNT_DEFAULT,
);
}

public function weight(): Attribute
{
return new Attribute(
get: fn (float | null $value) => $value ?? self::WEIGHT_DEFAULT,
set: fn (float | null $value) => $value ?? self::WEIGHT_DEFAULT,
);
}

public function reactant(): BelongsTo
{
Expand Down Expand Up @@ -92,16 +101,4 @@ public function decrementWeight(
): void {
$this->decrement('weight', $amount);
}

public function setCountAttribute(
int | null $count,
): void {
$this->attributes['count'] = $count ?? self::COUNT_DEFAULT;
}

public function setWeightAttribute(
float | null $weight,
): void {
$this->attributes['weight'] = $weight ?? self::WEIGHT_DEFAULT;
}
}
14 changes: 8 additions & 6 deletions src/Reacter/Models/Reacter.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
use Cog\Contracts\Love\ReactionType\Models\ReactionType as ReactionTypeInterface;
use Cog\Laravel\Love\Reaction\Models\Reaction;
use Cog\Laravel\Love\Support\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\MorphTo;
Expand All @@ -37,12 +38,13 @@ final class Reacter extends Model implements

protected static $unguarded = true;

/**
* @var string[]
*/
protected $casts = [
'id' => 'string',
];
public function id(): Attribute
{
return new Attribute(
get: fn (string | null $value) => $value,
set: fn (string | null $value) => $value,
);
}

public function reacterable(): MorphTo
{
Expand Down
43 changes: 26 additions & 17 deletions src/Reaction/Models/Reaction.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
use Cog\Laravel\Love\Reacter\Models\Reacter;
use Cog\Laravel\Love\ReactionType\Models\ReactionType;
use Cog\Laravel\Love\Support\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

Expand All @@ -46,13 +47,31 @@ final class Reaction extends Model implements
'rate' => self::RATE_DEFAULT,
];

/**
* @var string[]
*/
protected $casts = [
'id' => 'string',
'rate' => 'float',
];
public function id(): Attribute
{
return new Attribute(
get: fn (string | null $value) => $value,
set: fn (string | null $value) => $value,
);
}

public function rate(): Attribute
{
return new Attribute(
get: fn (float | null $value) => $value ?? self::RATE_DEFAULT,
set: function (float | null $value) {
if ($value !== null && ($value < self::RATE_MIN || $value > self::RATE_MAX)) {
throw RateOutOfRange::withValueBetween(
$value,
self::RATE_MIN,
self::RATE_MAX,
);
}

return $value ?? self::RATE_DEFAULT;
},
);
}

public function reactant(): BelongsTo
{
Expand Down Expand Up @@ -99,16 +118,6 @@ public function getWeight(): float
return $this->getType()->getMass() * $this->getRate();
}

public function setRateAttribute(
float | null $rate,
): void {
if ($rate !== null && ($rate < self::RATE_MIN || $rate > self::RATE_MAX)) {
throw RateOutOfRange::withValueBetween($rate, self::RATE_MIN, self::RATE_MAX);
}

$this->attributes['rate'] = $rate ?? self::RATE_DEFAULT;
}

public function isOfType(
ReactionTypeInterface $reactionType,
): bool {
Expand Down
23 changes: 16 additions & 7 deletions src/ReactionType/Models/ReactionType.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use Cog\Contracts\Love\ReactionType\Models\ReactionType as ReactionTypeInterface;
use Cog\Laravel\Love\Reaction\Models\Reaction;
use Cog\Laravel\Love\Support\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\HasMany;

Expand All @@ -38,13 +39,21 @@ final class ReactionType extends Model implements
'mass' => self::MASS_DEFAULT,
];

/**
* @var string[]
*/
protected $casts = [
'id' => 'string',
'mass' => 'integer',
];
public function id(): Attribute
{
return new Attribute(
get: fn (string | null $value) => $value,
set: fn (string | null $value) => $value,
);
}

public function mass(): Attribute
{
return new Attribute(
get: fn (int | null $value) => $value ?? self::MASS_DEFAULT,
set: fn (int | null $value) => $value ?? self::MASS_DEFAULT,
);
}

/**
* @var array<self>
Expand Down
2 changes: 1 addition & 1 deletion tests/Unit/Reaction/Models/ReactionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public function it_throws_rate_out_of_range_on_fill_rate_with_overflow_value():
/** @test */
public function it_casts_id_to_string(): void
{
$reaction = Reaction::factory()->make([
$reaction = new Reaction([
'id' => 4,
]);

Expand Down

0 comments on commit 55d5640

Please sign in to comment.