DI, akcie a DTO
Fasáda je odporúčaná predvoľba, nie jediná cesta. Ten istý kód spúšťajú tri vstupné body:
- Fasáda Reports — najkratší zápis.
- Manažér vložený cez konštruktor — rovnaké API s explicitnou závislosťou a bez statických volaní. RoundlyConsulting\Reports\ReportsManager je koreň fasády, zámerne nie final, aby ho fake mohol rozšíriť.
- Akcie — jednoúčelové triedy s metódou execute(), dostupné z kontajnera, ktoré zapojíte do vlastných jobov, služieb a príkazov.
Vloženie manažéra
Reports::fake() nahradí manažér aj v kontajneri, takže vložené manažéry skončia na fake:
use RoundlyConsulting\Reports\ReportsManager;
final class ReportPost
{
public function __construct(private ReportsManager $reports) {}
public function __invoke(User $user, Post $post): Report
{
return $this->reports->report($post)->by($user)->for('spam')->create();
}
}
// The whole facade API is on the manager:
$this->reports->review($report);Spustenie akcie
use RoundlyConsulting\Approvals\Enums\ApprovalRule;
use RoundlyConsulting\Reports\Actions\ChangeReportStatusAction;
use RoundlyConsulting\Reports\Actions\CreateReportAction;
use RoundlyConsulting\Reports\Actions\OpenModerationAction;
use RoundlyConsulting\Reports\Actions\PruneReportsAction;
use RoundlyConsulting\Reports\Actions\RejectReportAction;
use RoundlyConsulting\Reports\Actions\ResolveReportAction;
use RoundlyConsulting\Reports\DataTransferObjects\CreateReportData;
use RoundlyConsulting\Reports\DataTransferObjects\ResolveReportData;
use RoundlyConsulting\Reports\Enums\Reason;
use RoundlyConsulting\Reports\Enums\Status;
$report = app(CreateReportAction::class)->execute(new CreateReportData(
subject: $post,
reason: Reason::Spam, // Reason|string, normalised to a slug
reporter: $user, // optional
description: 'Looks like spam.',
guestIdentifier: null, // optional dedupe key for anonymous reports
));
app(ChangeReportStatusAction::class)->execute($report, Status::InReview);
app(ResolveReportAction::class)
->execute($report, new ResolveReportData(resolver: $moderator, note: 'Handled.'));
// or
app(RejectReportAction::class)
->execute($report, new ResolveReportData(resolver: $moderator, note: 'No violation.'));
app(OpenModerationAction::class)->execute($report, [$alice, $bob], ApprovalRule::Quorum, 1); // ApprovalRequest
app(PruneReportsAction::class)->execute(days: 90, force: false); // intMetóda fasády → akcia
| Metóda fasády / manažéra | Akcia |
|---|---|
report($subject) / from($reporter) | CreateReportAction (via ->create()) |
create(CreateReportData $data) | CreateReportAction |
moderate($report) | OpenModerationAction (via ->open()) |
resolve($report, ?$by, ?$note) | ResolveReportAction |
reject($report, ?$by, ?$note) | RejectReportAction |
changeStatus($report, Status $status) | ChangeReportStatusAction |
review($report) / close($report) | ChangeReportStatusAction |
prune(?int $days = null, bool $force = false) | PruneReportsAction |
- CreateReportAction — overí dôvod, uplatní ochranu pred duplicitami (hlásenia na jeden subjekt sa spracúvajú postupne), uloží hlásenie v stave Pending a skontroluje prah.
- ResolveReportAction / RejectReportAction — vybavia hlásenie v jednom uzamknutom kroku overenom voči uloženému stavu; kým je otvorená žiadosť o moderáciu, zaznamenajú namiesto toho rozhodnutie určeného moderátora a ostatných odmietnu výnimkou ModeratorRequiredException.
- ChangeReportStatusAction — zodpovedá za každý presun stavu: pri rovnakom stave nič, pri strict_transitions InvalidStatusTransitionException, pri presune z otvorených stavov počas otvorenej moderácie ModeratorRequiredException, inak zmena a ReportStatusChanged.
- OpenModerationAction — bez moderátorov vyhodí MissingModeratorsException, inak otvorí žiadosť v approvals.
- PruneReportsAction — mäkko, alebo s force natrvalo, zmaže hlásenia v stave Resolved, Rejected a Closed vytvorené pred hranicou.
Čítanie dôvodov za sebou žiadnu akciu nemá. ReportsManager::openModeration() — koncový krok moderate()->open() — je @internal. Priame volanie akcie manažér obíde, preto ho Reports::fake() nezaznamená.
DTO
final readonly class CreateReportData
{
public string $reason; // normalised from Reason|string
public function __construct(
public Model $subject,
Reason|string $reason,
public ?Model $reporter = null,
public ?string $description = null,
public ?string $guestIdentifier = null,
) {}
}
final readonly class ResolveReportData
{
public function __construct(
public ?Model $resolver = null,
public ?string $note = null,
) {}
}CreateReportData prevedie prípad Reason na jeho slug, takže $data->reason je vždy reťazec.
Prejavte lásku k open source
Tento balík je zadarmo pod licenciou MIT. Ak vám šetrí čas, jednorazový príspevok alebo členstvo na Patreone nám pomôže ho ďalej udržiavať, testovať a dokumentovať.
Ďalšie spôsoby podpory vrátane kryptomienOdoslaním daru súhlasíte s našimi podmienkami prijímania darov.
Chcete to zabudovať do svojho produktu?
Naše balíky integrujeme do zákazkových Laravel a AI riešení. Napíšte nám, na čom pracujete, a ozveme sa do 48 hodín.