Skip to content

Commit

Permalink
Create PrimaryKey attribute
Browse files Browse the repository at this point in the history
  • Loading branch information
WendellAdriel committed Aug 25, 2023
1 parent fee2434 commit db2adc0
Show file tree
Hide file tree
Showing 10 changed files with 356 additions and 14 deletions.
54 changes: 52 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -257,8 +257,8 @@ final class Product extends Model

### Config

The `Config` attribute allows you to set your model's **public properties** configurations for all the above attributes
with a single attribute.
The `Config` attribute allows you to set your model's **public properties** configurations for the attributes:
`Cast`, `Fillable`, `Hidden` and `Rules`.

```php
use Carbon\CarbonImmutable;
Expand All @@ -284,6 +284,56 @@ class Product extends Model
}
```

### Primary Key

By default, the Eloquent Model uses the `id` column as the primary key as an auto-incrementing integer value.
With the `PrimaryKey` attribute you can configure in a simple and easy way the primary key of your model.

If your model uses a different column as the primary key, you can set it using the `PrimaryKey` attribute:

```php
use Illuminate\Database\Eloquent\Model;
use WendellAdriel\Lift\Attributes\Fillable;
use WendellAdriel\Lift\Attributes\PrimaryKey;
use WendellAdriel\Lift\Attributes\Rules;
use WendellAdriel\Lift\Lift;

final class Product extends Model
{
use Lift;

#[PrimaryKey]
public int $custom_id;

#[Rules(['required', 'string'], ['required' => 'The Product name can not be empty'])]
#[Fillable]
public string $name;
}
```

If your model uses a column with a different type and not incrementing like a UUID, you can set it using the
`PrimaryKey` attribute like this:

```php
use Illuminate\Database\Eloquent\Model;
use WendellAdriel\Lift\Attributes\Fillable;
use WendellAdriel\Lift\Attributes\PrimaryKey;
use WendellAdriel\Lift\Attributes\Rules;
use WendellAdriel\Lift\Lift;

final class Product extends Model
{
use Lift;

#[PrimaryKey(type: 'string', incrementing: false)]
public string $uuid;

#[Rules(['required', 'string'], ['required' => 'The Product name can not be empty'])]
#[Fillable]
public string $name;
}
```

## Methods

When using the `Lift` trait, your model will have some new methods available.
Expand Down
17 changes: 17 additions & 0 deletions src/Attributes/PrimaryKey.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

declare(strict_types=1);

namespace WendellAdriel\Lift\Attributes;

use Attribute;

#[Attribute(Attribute::TARGET_PROPERTY)]
final class PrimaryKey
{
public function __construct(
public string $type = 'int',
public bool $incrementing = true,
) {
}
}
19 changes: 9 additions & 10 deletions src/Concerns/AttributesGuard.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

namespace WendellAdriel\Lift\Concerns;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use WendellAdriel\Lift\Attributes\Config;
use WendellAdriel\Lift\Attributes\Fillable;
Expand All @@ -16,28 +15,28 @@ trait AttributesGuard
/**
* @param Collection<PropertyInfo> $properties
*/
private static function applyAttributesGuard(Model $model, Collection $properties): void
private function applyAttributesGuard(Collection $properties): void
{
$model->mergeGuarded(['*']);
$this->mergeGuarded(['*']);

$fillableProperties = self::getPropertiesForAttributes($properties, [Fillable::class]);
$model->mergeFillable($fillableProperties->map(fn ($property) => $property->name)->values()->toArray());
$this->mergeFillable($fillableProperties->map(fn ($property) => $property->name)->values()->toArray());

$hiddenProperties = self::getPropertiesForAttributes($properties, [Hidden::class]);
$model->setHidden($hiddenProperties->map(fn ($property) => $property->name)->values()->toArray());
$this->setHidden($hiddenProperties->map(fn ($property) => $property->name)->values()->toArray());

$configProperties = self::getPropertiesForAttributes($properties, [Config::class]);
$model->mergeFillable(self::buildLiftList($configProperties, 'fillable'));
$model->setHidden([
...$model->getHidden(),
...self::buildLiftList($configProperties, 'hidden'),
$this->mergeFillable($this->buildLiftList($configProperties, 'fillable'));
$this->setHidden([
...$this->getHidden(),
...$this->buildLiftList($configProperties, 'hidden'),
]);
}

/**
* @param Collection<PropertyInfo> $properties
*/
private static function buildLiftList(Collection $properties, string $attributeProperty): array
private function buildLiftList(Collection $properties, string $attributeProperty): array
{
$result = [];
$properties->each(function ($property) use (&$result, $attributeProperty) {
Expand Down
33 changes: 33 additions & 0 deletions src/Concerns/CustomPrimary.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace WendellAdriel\Lift\Concerns;

use Illuminate\Support\Collection;
use WendellAdriel\Lift\Attributes\PrimaryKey;
use WendellAdriel\Lift\Support\PropertyInfo;

trait CustomPrimary
{
/**
* @param Collection<PropertyInfo> $properties
*/
private function applyPrimaryKey(Collection $properties): void
{
$primaryKeyProperty = self::getPropertyForAttribute($properties, PrimaryKey::class);
if (! blank($primaryKeyProperty)) {
$primaryKeyAttribute = $primaryKeyProperty->attributes->first(fn ($attribute) => $attribute->getName() === PrimaryKey::class);
if (! blank($primaryKeyAttribute)) {
$primaryKeyAttribute = $primaryKeyAttribute->newInstance();
$this->setKeyName($primaryKeyProperty->name);
$this->setKeyType($primaryKeyAttribute->type);
$this->setIncrementing($primaryKeyAttribute->incrementing);

if (! $this->incrementing) {
$this->mergeFillable([$primaryKeyProperty->name]);
}
}
}
}
}
20 changes: 18 additions & 2 deletions src/Lift.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@
use ReflectionProperty;
use WendellAdriel\Lift\Concerns\AttributesGuard;
use WendellAdriel\Lift\Concerns\CastValues;
use WendellAdriel\Lift\Concerns\CustomPrimary;
use WendellAdriel\Lift\Concerns\RulesValidation;
use WendellAdriel\Lift\Support\PropertyInfo;

trait Lift
{
use RulesValidation, CastValues, AttributesGuard;
use RulesValidation, CastValues, AttributesGuard, CustomPrimary;

public static function bootLift(): void
{
Expand All @@ -35,7 +36,9 @@ public function syncOriginal(): void
{
parent::syncOriginal();

self::applyAttributesGuard($this, self::getPropertiesWithAtributes($this));
$properties = self::getPropertiesWithAtributes($this);
$this->applyPrimaryKey($properties);
$this->applyAttributesGuard($properties);
}

protected static function ignoredProperties(): array
Expand Down Expand Up @@ -112,6 +115,19 @@ private static function getPropertiesForAttributes(Collection $properties, array
);
}

/**
* @param Collection<PropertyInfo> $properties
* @param class-string $attributeClass
*/
private static function getPropertyForAttribute(Collection $properties, string $attributeClass): ?PropertyInfo
{
return $properties->first(
fn ($property) => $property->attributes->contains(
fn ($attribute) => $attribute->getName() === $attributeClass
)
);
}

private static function fillProperties(Model $model): void
{
self::castValues($model, self::getPropertiesWithAtributes($model));
Expand Down
4 changes: 4 additions & 0 deletions tests/Datasets/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,17 @@
namespace WendellAdriel\Lift\Tests\Datasets;

use Illuminate\Database\Eloquent\Model;
use WendellAdriel\Lift\Attributes\PrimaryKey;
use WendellAdriel\Lift\Attributes\Rules;
use WendellAdriel\Lift\Lift;

class User extends Model
{
use Lift;

#[PrimaryKey]
public int $id;

#[Rules(['required', 'string'], ['required' => 'The user name cannot be empty'])]
public string $name;

Expand Down
35 changes: 35 additions & 0 deletions tests/Datasets/UserCustom.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

declare(strict_types=1);

namespace WendellAdriel\Lift\Tests\Datasets;

use Illuminate\Database\Eloquent\Model;
use WendellAdriel\Lift\Attributes\PrimaryKey;
use WendellAdriel\Lift\Attributes\Rules;
use WendellAdriel\Lift\Lift;

class UserCustom extends Model
{
use Lift;

#[PrimaryKey(incrementing: false)]
public int $id;

#[Rules(['required', 'string'], ['required' => 'The user name cannot be empty'])]
public string $name;

#[Rules(['required', 'email'])]
public string $email;

#[Rules(['required', 'string', 'min:8'])]
public string $password;

protected $table = 'users';

protected $fillable = [
'name',
'email',
'password',
];
}
35 changes: 35 additions & 0 deletions tests/Datasets/UserUuid.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

declare(strict_types=1);

namespace WendellAdriel\Lift\Tests\Datasets;

use Illuminate\Database\Eloquent\Model;
use WendellAdriel\Lift\Attributes\PrimaryKey;
use WendellAdriel\Lift\Attributes\Rules;
use WendellAdriel\Lift\Lift;

class UserUuid extends Model
{
use Lift;

#[PrimaryKey(type: 'string', incrementing: false)]
public string $uuid;

#[Rules(['required', 'string'], ['required' => 'The user name cannot be empty'])]
public string $name;

#[Rules(['required', 'email'])]
public string $email;

#[Rules(['required', 'string', 'min:8'])]
public string $password;

protected $table = 'users_uuid';

protected $fillable = [
'name',
'email',
'password',
];
}
Loading

0 comments on commit db2adc0

Please sign in to comment.