-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: add exceptions * ForbiddenException * NotFoundException * ProjectManagerException * feat(helper): add Randomizer * feat(project): add slug * add SluggableTrait * update entity * add migration * chore(Makefile): add db drop-create-migrate-fixtures targets * feat: add Project DTO,Mapper * feat(helper): add ApiMessages,ApiResponse * feat: add ProjectController * feat: add project validator * fix(ProjectDTO): set nullable slug A nullable slug is required when creating a new project * feat(ApiMessages): add project related translations * feat: add Project helper * feat(validator): add "not empty" methods * feat: add Finder * fix(SluggableTrait): getSlug return type * feat(BadDataException): add default message, status code * refac(DTO): set default values * refac(Helper): set validateRequestResource Project argument not null * fix(Validator): translate validateKnownEntity exception message * refac(Controller): use MapRequestPayload for create/update function * feat: add ExceptionLogger * feat: add poc template * feat: add Archiver * feat: add persister * feat: add Handler * refac: improve Finder::get,Handler::HandleGetProject * refac(ApiMessages): add missing messages and sort * fix(Helper): generateEditSucccessMessage typo * fix(Helper): edit/create check * feat: do not edit/show archived data close: #12
- Loading branch information
Showing
22 changed files
with
781 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace DoctrineMigrations; | ||
|
||
use Doctrine\DBAL\Schema\Schema; | ||
use Doctrine\Migrations\AbstractMigration; | ||
|
||
final class Version20230906163121 extends AbstractMigration | ||
{ | ||
public function getDescription(): string | ||
{ | ||
return 'add Project slug column'; | ||
} | ||
|
||
public function up(Schema $schema): void | ||
{ | ||
$this->addSql('ALTER TABLE project ADD slug VARCHAR(255) NOT NULL'); | ||
} | ||
|
||
public function down(Schema $schema): void | ||
{ | ||
$this->addSql('CREATE SCHEMA public'); | ||
$this->addSql('ALTER TABLE project DROP slug'); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
<?php | ||
|
||
namespace App\Controller; | ||
|
||
use App\Entity\Project; | ||
use App\Service\Project\DTO; | ||
use App\Service\Project\Handler; | ||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; | ||
use Symfony\Component\HttpFoundation\JsonResponse; | ||
use Symfony\Component\HttpFoundation\Request; | ||
use Symfony\Component\HttpKernel\Attribute\MapRequestPayload; | ||
use Symfony\Component\Routing\Annotation\Route; | ||
|
||
final class ProjectController extends AbstractController | ||
{ | ||
public function __construct( | ||
private Handler $handler, | ||
) { | ||
} | ||
|
||
public const ROUTE_ADD = 'project_add'; | ||
public const ROUTE_ARCHIVE = 'project_archive'; | ||
public const ROUTE_EDIT = 'project_edit'; | ||
public const ROUTE_FETCH = 'project_fetch'; | ||
public const ROUTE_FIND_ALL = 'project_find_all'; | ||
|
||
#[Route('/project/{slug}', name: self::ROUTE_FETCH, methods: Request::METHOD_GET)] | ||
public function getProject(?Project $project): JsonResponse | ||
{ | ||
return $this->handler->handleGetProject($project); | ||
} | ||
|
||
#[Route('/project', name: self::ROUTE_ADD, methods: Request::METHOD_POST)] | ||
#[Route('/project/{slug}', name: self::ROUTE_EDIT, methods: Request::METHOD_POST)] | ||
public function persistProject( | ||
?Project $project, | ||
#[MapRequestPayload()] ?DTO $dto, | ||
Request $request, | ||
): JsonResponse { | ||
return $this->handler->handlePersistProject($project, $request, $dto); | ||
} | ||
|
||
#[Route('/projects', name: self::ROUTE_FIND_ALL, methods: Request::METHOD_GET)] | ||
public function getAllProjects(): JsonResponse | ||
{ | ||
return $this->handler->handleGetAllProjects(); | ||
} | ||
|
||
#[Route('/project/{slug}', name: self::ROUTE_ARCHIVE, methods: 'DELETE')] | ||
public function classeArchive(?Project $project): JsonResponse | ||
{ | ||
return $this->handler->handleArchiveProject($project); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
<?php | ||
|
||
namespace App\Entity; | ||
|
||
use App\Helper\Randomizer; | ||
use Doctrine\ORM\Mapping as ORM; | ||
|
||
trait SluggableTrait | ||
{ | ||
#[ORM\Column(type: 'string', length: 255)] | ||
private ?string $slug = null; | ||
|
||
final public function getSlug(): ?string | ||
{ | ||
return $this->slug; | ||
} | ||
|
||
final public function setSlug(string $slug): self | ||
{ | ||
$this->slug = $slug; | ||
|
||
return $this; | ||
} | ||
|
||
#[ORM\PrePersist] | ||
final public function generateSlug(): void | ||
{ | ||
null === $this->slug | ||
&& $this->setSlug(Randomizer::generateSlug()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<?php | ||
|
||
namespace App\Exception; | ||
|
||
use Symfony\Component\HttpFoundation\Response; | ||
|
||
class BadDataException extends ProjectManagerException | ||
{ | ||
public function __construct(string $message = '') | ||
{ | ||
parent::__construct($message, Response::HTTP_BAD_REQUEST); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
<?php | ||
|
||
namespace App\Exception; | ||
|
||
class ForbiddenException extends ProjectManagerException | ||
{ | ||
public const ACCESS_DENIED_EXCEPTION_MESSAGE = "Vous n'êtes pas autorisé à accéder à cette page"; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
<?php | ||
|
||
namespace App\Exception; | ||
|
||
class NotFoundException extends ProjectManagerException | ||
{ | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
<?php | ||
|
||
namespace App\Exception; | ||
|
||
class ProjectManagerException extends \Exception | ||
{ | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
<?php | ||
|
||
namespace App\Helper; | ||
|
||
final class ApiMessages | ||
{ | ||
public const ACCESS_DENIED_EXCEPTION_MESSAGE = "Vous n'êtes pas autorisé à accéder à cette page"; | ||
public const DEFAULT_ERROR_MESSAGE = 'Oops, an error occured...'; | ||
public const DEFAULT_NOT_FOUND_MESSAGE = "La ressource demandée n'a pas été trouvée"; | ||
public const DEFAULT_UNSUPPORTED_FORMAT_MESSAGE = 'La sérialisation a échouée'; | ||
public const DUPLICATED_RESOURCE_MESSAGE = 'Les données de la ressource ne peuvent être enregistrées (génererait un doublon)'; | ||
public const EMAIL_ADDRESS_UNKNOWN = "Aucun utilisateur avec cette adresse mail n'a été trouvé"; | ||
public const ERROR_EMPTY_PASSWORD_TERMS = 'The presented password cannot be empty.'; | ||
public const ERROR_MAIL_TERMS = 'Bad credentials.'; | ||
public const ERROR_PASSWORD_TERMS = 'The presented password is invalid.'; | ||
public const FETCHING_USER_PROFILE_ERROR_MESSAGE = 'An error occurred while fetching user profile'; | ||
public const INDEX_ERROR = 'error'; | ||
public const INDEX_MESSAGE = 'message'; | ||
public const INDEX_STATUS = 'status'; | ||
public const INDEX_SUCCESS = 'success'; | ||
public const INDEX_WARNING = 'warning'; | ||
public const MESSAGE_OK = 'OK'; | ||
public const PROJECT_CREATE_ERROR_MESSAGE = 'An error occurred while persisting project'; | ||
public const PROJECT_CREATE_SUCCESS_MESSAGE = 'Le project a bien été créé'; | ||
public const PROJECT_DELETE_ERROR_MESSAGE = 'An error occurred during project removal'; | ||
public const PROJECT_DELETE_SUCCESS_MESSAGE = 'Le projet a bien été supprimé'; | ||
public const PROJECT_NAME_UNAVAILABLE = 'Project name already exists'; | ||
public const PROJECT_NOT_FOUND = 'Project not found'; | ||
public const PROJECT_UNKNOWN = 'Project not found'; | ||
public const PROJECT_UPDATE_ERROR_MESSAGE = 'An error occurred during project update'; | ||
public const PROJECT_UPDATE_SUCCESS_MESSAGE = 'Le projet a bien été mis à jour'; | ||
|
||
public static function translate(string $key): string | ||
{ | ||
return self::TRANSLATIONS[$key] ?? $key; | ||
} | ||
|
||
public const TRANSLATIONS = [ | ||
self::ERROR_EMPTY_PASSWORD_TERMS => 'Le mot de passe est nécessaire', | ||
self::ERROR_MAIL_TERMS => 'Votre mot de passe ou votre adresse mail est incorrect', | ||
self::ERROR_PASSWORD_TERMS => 'Votre mot de passe ou votre adresse mail est incorrect', | ||
self::FETCHING_USER_PROFILE_ERROR_MESSAGE => 'Oops, une erreur est survenue durant la récupération de vos données', | ||
self::PROJECT_NOT_FOUND => "Le projet n'a pas été trouvé", | ||
self::PROJECT_UNKNOWN => "Le projet n'a pas été trouvé", | ||
self::PROJECT_UPDATE_ERROR_MESSAGE => 'Oops, une erreur est survenue lors de la modification du projet', | ||
]; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
<?php | ||
|
||
namespace App\Helper; | ||
|
||
use Symfony\Component\HttpFoundation\JsonResponse; | ||
use Symfony\Component\HttpFoundation\Response; | ||
|
||
class ApiResponse extends JsonResponse | ||
{ | ||
public static function createAndFormat( | ||
mixed $data, | ||
?string $message = ApiMessages::MESSAGE_OK, | ||
?string $key = ApiMessages::INDEX_SUCCESS, | ||
?int $statusCode = Response::HTTP_OK | ||
): self { | ||
return self::create([ | ||
'data' => $data, | ||
'status' => $key, | ||
'message' => $message, | ||
], $statusCode); | ||
} | ||
|
||
public static function create($data, $statusCode = self::HTTP_OK): self | ||
{ | ||
return new self($data, $statusCode); | ||
} | ||
|
||
public static function createMessage($message, $statusCode = self::HTTP_OK): self | ||
{ | ||
return new self( | ||
[ | ||
ApiMessages::INDEX_STATUS => ApiMessages::INDEX_SUCCESS, | ||
ApiMessages::INDEX_MESSAGE => $message, | ||
], | ||
$statusCode); | ||
} | ||
|
||
public static function createWarningMessage($message, $statusCode = self::HTTP_BAD_REQUEST): self | ||
{ | ||
return new self( | ||
[ | ||
ApiMessages::INDEX_STATUS => ApiMessages::INDEX_WARNING, | ||
ApiMessages::INDEX_MESSAGE => $message, | ||
], | ||
$statusCode | ||
); | ||
} | ||
|
||
public static function createErrorMessage( | ||
string $message, | ||
int $statusCode = self::HTTP_INTERNAL_SERVER_ERROR, | ||
\Throwable $exception = null | ||
): self { | ||
$data = [ | ||
ApiMessages::INDEX_STATUS => ApiMessages::INDEX_ERROR, | ||
ApiMessages::INDEX_MESSAGE => $message, | ||
]; | ||
|
||
if ('dev' === $_ENV['APP_ENV']) { | ||
$data['debug'] = $exception?->getMessage(); | ||
} | ||
|
||
return new self( | ||
$data, | ||
$statusCode | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
<?php | ||
|
||
namespace App\Helper; | ||
|
||
use Psr\Log\LoggerInterface; | ||
|
||
final class ExceptionLogger | ||
{ | ||
public function __construct( | ||
private LoggerInterface $logger, | ||
) { | ||
} | ||
|
||
public function logAndTrace(\Throwable $exception, string $message = null): void | ||
{ | ||
$message && $this->logger->error($message); | ||
$this->logger->error($exception->getMessage()); | ||
$this->logger->debug($exception->getTraceAsString()); | ||
} | ||
|
||
public function logCriticalAndTrace(\Throwable $exception, string $message = null): void | ||
{ | ||
$message && $this->logger->critical($message); | ||
$this->logger->critical($exception->getMessage()); | ||
$this->logger->critical($exception->getTraceAsString()); | ||
} | ||
|
||
public function log(\Throwable $exception, string $message = null): void | ||
{ | ||
$message && $this->logger->error($message); | ||
$this->logger->error($exception->getMessage()); | ||
} | ||
|
||
public function logNotice(\Throwable $exception, string $message = null): void | ||
{ | ||
$message && $this->logger->notice($message); | ||
$this->logger->notice($exception->getMessage()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
<?php | ||
|
||
namespace App\Helper; | ||
|
||
use Psr\Log\LoggerInterface; | ||
|
||
final class Randomizer | ||
{ | ||
public function __construct( | ||
private LoggerInterface $logger, | ||
) { | ||
} | ||
|
||
public static function generateSlug(): string | ||
{ | ||
return self::generateRandomBytes(); | ||
} | ||
|
||
public static function generateRandomBytes(int $nbytes = 16): string | ||
{ | ||
try { | ||
$result = bin2hex(random_bytes($nbytes)); | ||
|
||
version_compare(phpversion(), '8.2.0', '>=') | ||
&& $result = bin2hex((new \Random\Randomizer())->getBytes($nbytes)); | ||
} catch (\Throwable $throwable) { | ||
$this->logger->error($throwable->getMessage()); | ||
$result = uniqid(uniqid('', true), true); | ||
} | ||
|
||
return $result; | ||
} | ||
} |
Oops, something went wrong.