Skip to content

Commit

Permalink
TDD - use case calls
Browse files Browse the repository at this point in the history
  • Loading branch information
rigonlucas committed Aug 25, 2024
1 parent e686f23 commit 99a2d90
Show file tree
Hide file tree
Showing 16 changed files with 387 additions and 31 deletions.
28 changes: 28 additions & 0 deletions app/Models/Project.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

namespace App\Models;

use DateTimeInterface;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

/**
* @property int $id
* @property int $status
* @property string $description
* @property string $name
* @property int $created_by_user_id
* @property int $account_id
* @property DateTimeInterface $start_at
* @property DateTimeInterface $finish_at
* @property string $uuid
* @property DateTimeInterface $deleted_at
*/
class Project extends Model
{
use HasFactory;
use SoftDeletes;

protected $table = 'projects';
}
7 changes: 7 additions & 0 deletions app/Providers/AppServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

use Core\Application\Account\Commons\Gateways\AccountCommandInterface;
use Core\Application\Account\Commons\Gateways\AccountMapperInterface;
use Core\Application\Project\Commons\Gateways\ProjectCommandInterface;
use Core\Application\Project\Commons\Gateways\ProjectMapperInterface;
use Core\Application\User\Commons\Gateways\UserCommandInterface;
use Core\Application\User\Commons\Gateways\UserMapperInterface;
use Core\Services\Framework\Contracts\AuthContract;
Expand All @@ -17,6 +19,8 @@
use Illuminate\Support\ServiceProvider;
use Infra\Database\Account\Command\AccountCommand;
use Infra\Database\Account\Mapper\AccountMapper;
use Infra\Database\Project\Command\ProjectCommand;
use Infra\Database\Project\Mapper\ProjectMapper;
use Infra\Database\User\Command\UserCommand;
use Infra\Database\User\Mapper\UserMapper;
use Infra\Services\Framework\Adapters\AuthAdapter;
Expand Down Expand Up @@ -58,6 +62,9 @@ private function registerDataBaseBinds(): void

$this->app->bind(AccountCommandInterface::class, AccountCommand::class);
$this->app->bind(AccountMapperInterface::class, AccountMapper::class);

$this->app->bind(ProjectCommandInterface::class, ProjectCommand::class);
$this->app->bind(ProjectMapperInterface::class, ProjectMapper::class);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace Core\Application\Project\Commons\Exceptions;

use Core\Support\Exceptions\OutputErrorException;

class ProjectAlreadyExistsException extends OutputErrorException
{

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace Core\Application\Project\Commons\Gateways;

use Core\Domain\Entities\Project\ProjectEntity;

interface ProjectCommandInterface
{
public function create(ProjectEntity $entity): ProjectEntity;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

namespace Core\Application\Project\Commons\Gateways;

use Core\Domain\Entities\Account\AccountEntity;
use Core\Domain\Entities\Project\ProjectEntity;

interface ProjectMapperInterface
{
public function findByid(int $id): ?ProjectEntity;

public function findByUuid(string $uuid): ?ProjectEntity;

public function existsByName(string $name, AccountEntity $accountEntity): bool;

public function notExistsByName(string $name, AccountEntity $accountEntity): bool;
}
61 changes: 61 additions & 0 deletions core/Application/Project/Create/CreateProjectUseCase.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

namespace Core\Application\Project\Create;

use Core\Application\Project\Commons\Exceptions\ProjectAlreadyExistsException;
use Core\Application\Project\Commons\Gateways\ProjectCommandInterface;
use Core\Application\Project\Commons\Gateways\ProjectMapperInterface;
use Core\Application\Project\Create\inputs\CreateProjectInput;
use Core\Domain\Entities\Project\ProjectEntity;
use Core\Domain\Entities\User\UserEntity;
use Core\Services\Framework\FrameworkContract;
use Core\Support\Exceptions\Dates\DateMustBeBeforeOtherException;
use Core\Support\Exceptions\Dates\DateMustBeInCurrentDayException;
use Core\Support\Exceptions\Dates\DateRequiredException;
use Core\Support\Exceptions\Dates\DatesMustBeDifferntsException;
use Core\Support\Exceptions\ForbidenException;
use Core\Support\Http\ResponseStatus;

class CreateProjectUseCase
{
public function __construct(
private readonly FrameworkContract $framework,
private readonly ProjectCommandInterface $projectCommand,
private readonly ProjectMapperInterface $projectMapper
) {
}

/**
* @throws DateMustBeBeforeOtherException
* @throws ProjectAlreadyExistsException
* @throws ForbidenException
* @throws DateMustBeInCurrentDayException
* @throws DateRequiredException
* @throws DatesMustBeDifferntsException
*/
public function execute(CreateProjectInput $createProjectInput, UserEntity $authUser): ProjectEntity
{
$hasProjectWithSameName = $this->projectMapper->existsByName(
$createProjectInput->name,
$authUser->getAccount()
);
if ($hasProjectWithSameName) {
throw new ProjectAlreadyExistsException(
'Project already exists with name ([)' . $createProjectInput->name . ')',
ResponseStatus::UNPROCESSABLE_ENTITY->value
);
}
$projectEntity = ProjectEntity::forCreate(
name: $createProjectInput->name,
description: $createProjectInput->description,
user: $authUser,
account: $authUser->getAccount(),
uuid: $this->framework->uuid()->uuid7Generate(),
startAt: $createProjectInput->startAt,
finishAt: $createProjectInput->finishAt

);

return $this->projectCommand->create($projectEntity);
}
}
16 changes: 16 additions & 0 deletions core/Application/Project/Create/inputs/CreateProjectInput.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

namespace Core\Application\Project\Create\inputs;

use Carbon\CarbonInterface;

readonly class CreateProjectInput
{
public function __construct(
public string $name,
public string $description,
public ?CarbonInterface $startAt,
public ?CarbonInterface $finishAt
) {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ trait HasProjectEntityBuilder
* @throws DateRequiredException
* @throws DatesMustBeDifferntsException
*/
public static function create(
public static function forCreate(
string $name,
string $description,
UserEntity $user,
Expand Down
32 changes: 32 additions & 0 deletions database/factories/ProjectFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace Database\Factories;

use App\Models\Account;
use App\Models\Project;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;

/**
* @extends Factory<Project>
*/
class ProjectFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition(): array
{
return [
'name' => $this->faker->name,
'description' => $this->faker->text,
'start_at' => $this->faker->dateTime,
'finish_at' => $this,
'uuid' => $this->faker->uuid,
'created_by_user_id' => User::factory(),
'account_id' => Account::factory(),
];
}
}
8 changes: 2 additions & 6 deletions database/migrations/0001_01_01_000000_create_users_table.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,8 @@ public function up(): void
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->foreignId('account_id')
->nullable()
->default(null)
->constrained()
->onDelete('cascade');
$table->integer('role')->default(0);
$table->foreignId('account_id')->nullable()->default(null);
$table->smallInteger('role')->default(0);
$table->string('name');
$table->string('email')->unique();
$table->date('birthday')->nullable();
Expand Down
35 changes: 35 additions & 0 deletions database/migrations/2024_08_25_214144_create_projects_table.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration {
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('projects', function (Blueprint $table) {
$table->id();
$table->string('name', 255);
$table->string('description', 500);
$table->foreignId('created_by_user_id')->constrained('users');
$table->foreignId('account_id')->constrained('accounts');
$table->dateTime('start_at')->default(null)->nullable();
$table->dateTime('finish_at')->default(null)->nullable();
$table->smallInteger('status')->default(null)->nullable();
$table->timestamps();
$table->softDeletes();
$table->uuid()->unique();
});
}

/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('projects');
}
};
29 changes: 29 additions & 0 deletions infra/Database/Project/Command/ProjectCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

namespace Infra\Database\Project\Command;

use App\Models\Project;
use Core\Application\Project\Commons\Gateways\ProjectCommandInterface;
use Core\Domain\Entities\Project\ProjectEntity;

class ProjectCommand implements ProjectCommandInterface
{

public function create(ProjectEntity $entity): ProjectEntity
{
$project = new Project();
$project->name = $entity->getName();
$project->description = $entity->getDescription();
$project->account_id = $entity->getAccount()->getId();
$project->created_by_user_id = $entity->getUser()->getId();
$project->status = null;
$project->start_at = $entity->getStartAt();
$project->finish_at = $entity->getFinishAt();
$project->uuid = $entity->getUuid()->toString();

$project->save();

$entity->setId($project->id);
return $entity;
}
}
36 changes: 36 additions & 0 deletions infra/Database/Project/Mapper/ProjectMapper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

namespace Infra\Database\Project\Mapper;

use App\Models\Project;
use Core\Application\Project\Commons\Gateways\ProjectMapperInterface;
use Core\Domain\Entities\Account\AccountEntity;
use Core\Domain\Entities\Project\ProjectEntity;
use Exception;

class ProjectMapper implements ProjectMapperInterface
{

public function findByid(int $id): ?ProjectEntity
{
throw new Exception('Method not implemented');
}

public function findByUuid(string $uuid): ?ProjectEntity
{
throw new Exception('Method not implemented');
}

public function notExistsByName(string $name, AccountEntity $accountEntity): bool
{
return !$this->existsByName($name, $accountEntity);
}

public function existsByName(string $name, AccountEntity $accountEntity): bool
{
return Project::query()
->where('name', 'like', $name)
->where('account_id', '=', $accountEntity->getId())
->exists();
}
}
19 changes: 1 addition & 18 deletions tests/ExampleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,9 @@

namespace Tests;

use Illuminate\Foundation\Testing\DatabaseMigrations;

/**
* @group relations
* @group test_
*/
class ExampleTest extends TestCase
{
use DatabaseMigrations;

/**
* A basic feature test example.
*/
/*public function test_example(): void
{
$user = User::factory()->create();
AccountUser::factory()->create([
'user_id' => $user->id,
]);
$user->loadMissing('accounts');
dd($user->accounts->first()->usersWithPivotData->first()->toArray());
dd($user);
}*/
}
Loading

0 comments on commit 99a2d90

Please sign in to comment.