wip: refactor service connection components and add ConnectionProtocol and ConnectionProvider services
- Renamed `ConnectedServicesService` to `ConnectedAppService` and adjusted related factories, DTOs, and forms. - Introduced `ConnectionProtocolService` and `ConnectionProviderService` for managing protocols and providers. - Updated Livewire forms to improve validation and allow real-time provider searches. - Added a `ConnectionStatus` field and related dropdown to service connection forms. - Enhanced form handling with new services, search functionality, and validation rules. - Refactored factory and DTO structure for better consistency and modularity. - Added service layer documentation and streamlined component data mappings.
This commit is contained in:
parent
6f07068b1d
commit
df3a37d6cb
@ -1,19 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\Data\ConnectService;
|
|
||||||
|
|
||||||
use Spatie\LaravelData\Data;
|
|
||||||
|
|
||||||
class ConnectServiceData extends Data
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
public string $name,
|
|
||||||
public int $serviceProviderId,
|
|
||||||
public int $serviceProtocolId,
|
|
||||||
public ?string $connectionService = null,
|
|
||||||
public ?string $logoUrl = null,
|
|
||||||
public ?string $slug = null,
|
|
||||||
) {}
|
|
||||||
}
|
|
||||||
23
app/Data/ConnectedApp/ConnectAppRequest.php
Normal file
23
app/Data/ConnectedApp/ConnectAppRequest.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Data\ConnectedApp;
|
||||||
|
|
||||||
|
use Spatie\LaravelData\Attributes\MapInputName;
|
||||||
|
use Spatie\LaravelData\Data;
|
||||||
|
use Spatie\LaravelData\Mappers\SnakeCaseMapper;
|
||||||
|
|
||||||
|
#[MapInputName(SnakeCaseMapper::class)]
|
||||||
|
class ConnectAppRequest extends Data
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public string $name,
|
||||||
|
public int $connectionProviderId,
|
||||||
|
public int $connectionProtocolId,
|
||||||
|
public ?string $connectionService = null,
|
||||||
|
public ?string $logoUrl = null,
|
||||||
|
public ?string $slug = null,
|
||||||
|
public ?int $statusId = null,
|
||||||
|
) {}
|
||||||
|
}
|
||||||
@ -4,25 +4,26 @@
|
|||||||
|
|
||||||
namespace App\Factories;
|
namespace App\Factories;
|
||||||
|
|
||||||
use App\Data\ConnectService\ConnectServiceData;
|
use App\Data\ConnectedApp\ConnectAppRequest;
|
||||||
use App\Enums\ConnectionStatusEnum;
|
use App\Enums\ConnectionStatusEnum;
|
||||||
|
use App\Models\ConnectionStatus;
|
||||||
|
|
||||||
final class ConnectedAppFactory
|
final class ConnectedAppFactory
|
||||||
{
|
{
|
||||||
public function createDataFromDto(ConnectServiceData $data): array
|
public function createDataFromDto(ConnectAppRequest $data): array
|
||||||
{
|
{
|
||||||
$result = [
|
$result = [
|
||||||
'name' => $data->name,
|
'name' => $data->name,
|
||||||
'service_provider_id' => $data->serviceProviderId,
|
'connection_provider_id' => $data->connectionProviderId,
|
||||||
'service_protocol_id' => $data->serviceProtocolId,
|
'connection_protocol_id' => $data->connectionProtocolId,
|
||||||
'logo_url' => $data->logoUrl,
|
'logo_url' => $data->logoUrl,
|
||||||
'slug' => $data->slug,
|
'slug' => $data->slug,
|
||||||
'service_status_id' => $data->statusId,
|
'connection_status_id' => $data->statusId,
|
||||||
];
|
];
|
||||||
|
|
||||||
// Check if the staus is filled, if not select disconnected by default
|
// Check if the staus is filled, if not select disconnected by default
|
||||||
if (null === $data->statusId) {
|
if (null === $data->statusId) {
|
||||||
$status = ConnectionStatusEnum::query()
|
$status = ConnectionStatus::query()
|
||||||
->where('name', '=', ConnectionStatusEnum::Disconnected->value)
|
->where('name', '=', ConnectionStatusEnum::Disconnected->value)
|
||||||
->pluck('id');
|
->pluck('id');
|
||||||
$result['service_status_id'] = $status[0];
|
$result['service_status_id'] = $status[0];
|
||||||
|
|||||||
16
app/Livewire/Forms/README.md
Normal file
16
app/Livewire/Forms/README.md
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
All the forms used in the application are stored here.
|
||||||
|
|
||||||
|
Each form should validate the data before sending it to the server.
|
||||||
|
This is done by using the `validate` method.
|
||||||
|
|
||||||
|
Validations that require the db, should not be live (realtime),
|
||||||
|
they should be done on the only once, preferably after the form is submitted.
|
||||||
|
|
||||||
|
Form can be used to both create and update data. Name should start with:
|
||||||
|
|
||||||
|
- `Store` for both cases - preferred
|
||||||
|
- `Create` for creating a new record
|
||||||
|
- `Update` for updating an existing record
|
||||||
|
|
||||||
|
When handle both cases, use separate `save` and `update` methods.
|
||||||
|
Livewire form docs: https://livewire.laravel.com/docs/4.x/forms
|
||||||
@ -4,8 +4,8 @@
|
|||||||
|
|
||||||
namespace App\Livewire\Forms;
|
namespace App\Livewire\Forms;
|
||||||
|
|
||||||
use App\Data\ConnectService\ConnectServiceData;
|
use App\Data\ConnectedApp\ConnectAppRequest;
|
||||||
use App\Services\ConnectedServicesService;
|
use App\Services\ConnectedAppService;
|
||||||
use Livewire\Attributes\Validate;
|
use Livewire\Attributes\Validate;
|
||||||
use Livewire\Form;
|
use Livewire\Form;
|
||||||
|
|
||||||
@ -14,12 +14,15 @@ class StoreConnectedAppFrom extends Form
|
|||||||
#[Validate('required|string|max:255|min:3')]
|
#[Validate('required|string|max:255|min:3')]
|
||||||
public string $name = '';
|
public string $name = '';
|
||||||
|
|
||||||
#[Validate('required|numeric|min:1')]
|
#[Validate('required|numeric|min:1|exists:connection_providers,id')]
|
||||||
public int $providerId = 0;
|
public int $providerId = 0;
|
||||||
|
|
||||||
#[Validate('required|numeric|min:1')]
|
#[Validate('required|numeric|min:1|exists:connection_protocols,id')]
|
||||||
public int $protocolId = 0;
|
public int $protocolId = 0;
|
||||||
|
|
||||||
|
#[Validate('required|numeric|min:1|exists:connection_statuses,id')]
|
||||||
|
public int $statusId = 0;
|
||||||
|
|
||||||
#[Validate('nullable|string|max:255|min:3')]
|
#[Validate('nullable|string|max:255|min:3')]
|
||||||
public ?string $logoUrl = null;
|
public ?string $logoUrl = null;
|
||||||
|
|
||||||
@ -27,15 +30,16 @@ public function save(): void
|
|||||||
{
|
{
|
||||||
$this->validate();
|
$this->validate();
|
||||||
|
|
||||||
$serviceData = new ConnectServiceData(
|
$serviceData = new ConnectAppRequest(
|
||||||
name: $this->name,
|
name: $this->name,
|
||||||
serviceProviderId: $this->providerId,
|
connectionProviderId: $this->providerId,
|
||||||
serviceProtocolId: $this->protocolId,
|
connectionProtocolId: $this->protocolId,
|
||||||
logoUrl: $this->logoUrl,
|
logoUrl: $this->logoUrl,
|
||||||
slug: str($this->name)->slug()->toString(),
|
slug: str($this->name)->slug()->toString(),
|
||||||
|
statusId: $this->statusId,
|
||||||
);
|
);
|
||||||
|
|
||||||
app(ConnectedServicesService::class)->create($serviceData);
|
app(ConnectedAppService::class)->create($serviceData);
|
||||||
$this->reset();
|
$this->reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,14 +4,14 @@
|
|||||||
|
|
||||||
namespace App\Services;
|
namespace App\Services;
|
||||||
|
|
||||||
use App\Data\ConnectService\ConnectServiceData;
|
use App\Data\ConnectedApp\ConnectAppRequest;
|
||||||
use App\Factories\ConnectedAppFactory;
|
use App\Factories\ConnectedAppFactory;
|
||||||
use App\Models\ConnectedApp;
|
use App\Models\ConnectedApp;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
final class ConnectedServicesService
|
final class ConnectedAppService
|
||||||
{
|
{
|
||||||
public function create(ConnectServiceData $data): void
|
public function create(ConnectAppRequest $data): void
|
||||||
{
|
{
|
||||||
$data = app(ConnectedAppFactory::class)->createDataFromDto($data);
|
$data = app(ConnectedAppFactory::class)->createDataFromDto($data);
|
||||||
DB::transaction(
|
DB::transaction(
|
||||||
30
app/Services/ConnectionProtocolService.php
Normal file
30
app/Services/ConnectionProtocolService.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
use App\Models\ConnectionProtocol;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
readonly class ConnectionProtocolService
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var Builder<ConnectionProtocol>
|
||||||
|
*/
|
||||||
|
private Builder $builder;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
) {
|
||||||
|
$this->builder = ConnectionProtocol::query();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Collection<int, ConnectionProtocol>
|
||||||
|
*/
|
||||||
|
public function getAll(): Collection
|
||||||
|
{
|
||||||
|
return $this->builder->get();
|
||||||
|
}
|
||||||
|
}
|
||||||
22
app/Services/ConnectionProviderService.php
Normal file
22
app/Services/ConnectionProviderService.php
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
use App\Models\ConnectionProvider;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
class ConnectionProviderService
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return Collection<int, ConnectionProvider>
|
||||||
|
*/
|
||||||
|
public function search(string $value): Collection
|
||||||
|
{
|
||||||
|
return ConnectionProvider::query()
|
||||||
|
->whereLike('slug', "%{$value}%")
|
||||||
|
->orWhereLike('name', "%{$value}%")
|
||||||
|
->get();
|
||||||
|
}
|
||||||
|
}
|
||||||
6
art/STRUCTURE.md
Normal file
6
art/STRUCTURE.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
## Service Layer
|
||||||
|
|
||||||
|
Service layer should return DTO objects to application layer (Livewire Components, Forms, Views).
|
||||||
|
As Livewire sends whole properties to the component, any data returned from Repository should not be returned to the
|
||||||
|
components.
|
||||||
|
It's a critical security concern not to expose any sensitive data to the components.
|
||||||
@ -3,6 +3,10 @@
|
|||||||
use App\Livewire\Forms\StoreConnectedAppFrom;
|
use App\Livewire\Forms\StoreConnectedAppFrom;
|
||||||
use App\Models\ConnectionProtocol;
|
use App\Models\ConnectionProtocol;
|
||||||
use App\Models\ConnectionProvider;
|
use App\Models\ConnectionProvider;
|
||||||
|
use App\Models\ConnectionStatus;
|
||||||
|
use App\Services\ConnectionProtocolService;
|
||||||
|
use App\Services\ConnectionProviderService;
|
||||||
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
use Livewire\Attributes\Computed;
|
use Livewire\Attributes\Computed;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
use Livewire\Attributes\Title;
|
use Livewire\Attributes\Title;
|
||||||
@ -18,15 +22,36 @@ public function providers()
|
|||||||
return ConnectionProvider::query()->get();
|
return ConnectionProvider::query()->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[Computed]
|
#[Computed]
|
||||||
public function protocols()
|
public function protocols(): Collection
|
||||||
{
|
{
|
||||||
return ConnectionProtocol::query()->get()->map(function (ConnectionProtocol $protocol) {
|
$protocolService = app(ConnectionProtocolService::class);
|
||||||
$protocol->name = ucfirst($protocol->name);
|
|
||||||
|
return $protocolService->getAll()->map(function (ConnectionProtocol $protocol) {
|
||||||
|
$protocol->name = strtoupper($protocol->name);
|
||||||
return $protocol;
|
return $protocol;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns Collection<int, ConnectionStatus>
|
||||||
|
*/
|
||||||
|
#[Computed]
|
||||||
|
public function connectionStatuses(): Collection
|
||||||
|
{
|
||||||
|
return ConnectionStatus::query()->get()->map(function (ConnectionStatus $status) {
|
||||||
|
$status->name = ucfirst($status->name);
|
||||||
|
return $status;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function searchProvider(string $name)
|
||||||
|
{
|
||||||
|
$providerService = app(ConnectionProviderService::class);
|
||||||
|
$this->providers = $providerService->search($name);
|
||||||
|
}
|
||||||
|
|
||||||
public function save()
|
public function save()
|
||||||
{
|
{
|
||||||
$this->form->save();
|
$this->form->save();
|
||||||
@ -54,6 +79,16 @@ public function save()
|
|||||||
:single="true"
|
:single="true"
|
||||||
:options="$this->providers"
|
:options="$this->providers"
|
||||||
searchable
|
searchable
|
||||||
|
search-function="searchProvider"
|
||||||
|
debounce="300"
|
||||||
|
/>
|
||||||
|
<x-choices
|
||||||
|
required
|
||||||
|
wire:model.live="form.statusId"
|
||||||
|
:label="__('Status')"
|
||||||
|
:single="true"
|
||||||
|
:options="$this->connectionStatuses"
|
||||||
|
placeholder="Select"
|
||||||
/>
|
/>
|
||||||
<div class="md:col-span-2 flex gap-x-4 font-medium justify-end">
|
<div class="md:col-span-2 flex gap-x-4 font-medium justify-end">
|
||||||
<x-shared.button>Cancel</x-shared.button>
|
<x-shared.button>Cancel</x-shared.button>
|
||||||
|
|||||||
2
storage/debugbar/.gitignore
vendored
Normal file
2
storage/debugbar/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
*
|
||||||
|
!.gitignore
|
||||||
Loading…
x
Reference in New Issue
Block a user