4471 | src/AppBundle/Controller/Platform/ContentController.php
2858 | src/Musement/ApiClient/MusementApiClient.php
2231 | src/AppBundle/Controller/Api/ApiController.php
1992 | src/AppBundle/Controller/Platform/UpdateEventController.php
1591 | src/AppBundle/Controller/Api/v2/EventDateController.php
1512 | src/AppBundle/Controller/Api/v2/SupplierController.php
1346 | src/AppBundle/Controller/Api/v2/EventController.php
1288 | src/AppBundle/Controller/Platform/CreateEventController.php
574 | src/AppBundle/Command/EventUpdateRequestsCommand.php
525 | src/AppBundle/Command/OrdersExcelCreationCommand.php
Just few examples
if (!isset($headers['tk'])) {
$httpResponse->setContent(
\json_encode((object) [
'data' => [
'error' => (object) [
'code' => 'TEXT_OK',
'message' => 'Wrong arguments.'
]
]
])
);
return $httpResponse;
}
$client = $this->getApiClient();
$httpResponse = new JsonResponse();
// Allow all websites
$httpResponse->headers->set('Access-Control-Allow-Headers', 'Access-Control-Allow-Origin,Content-Type,tk,role');
$httpResponse->headers->set('Access-Control-Allow-Methods', 'GET,OPTIONS');
$httpResponse->headers->set('Access-Control-Allow-Origin', '*');
$headers = $request->headers->all();
if (!isset($headers['tk'])) {
$httpResponse->setContent(\json_encode((object) ['data' => ['error' => (object) ['code' => 'WRONG_ARGS', 'message' => 'Wrong arguments.']]]));
return $httpResponse;
}
$response = $client->getCities();
$result = (object) ['data' => (array) $response];
$httpResponse->setContent(\json_encode($result));
return $httpResponse;
$client = $this->getApiClient();
$httpResponse = new JsonResponse();
// Allow all websites
$httpResponse->headers->set('Access-Control-Allow-Headers', 'Access-Control-Allow-Origin,Content-Type,tk,role');
$httpResponse->headers->set('Access-Control-Allow-Methods', 'PATCH,OPTIONS');
$httpResponse->headers->set('Access-Control-Allow-Origin', '*');
$headers = $request->headers->all();
if (!isset($headers['tk'])) {
$httpResponse->setContent(\json_encode((object) ['data' => ['error' => (object) ['code' => 'WRONG_ARGS', 'message' => 'Wrong arguments.']]]));
return $httpResponse;
}
$response = $client->getCountries();
$result = (object) ['data' => (array) $response];
$httpResponse->setContent(\json_encode($result));
return $httpResponse;
list($response, $statusCode) = $client->getLoggedSupplierTicketHolders($accessToken[0]);
if (200 !== $statusCode) {
$result = (object) [
'error' => (object) [
'message' => $response,
'http_code' => $statusCode
]
];
} else {
$result = (object) ['data' => $response];
}
return new JsonResponse($result);
public function getActivityDatesV2($eventId, $params, $currency = 'USD')
{
$endpoint = \sprintf('activities/%s/dates', $eventId);
try {
$response = $this->request('GET', $endpoint.'?'.\http_build_query($params), [
'headers' => [
'Accept' => 'application/json',
'X-Musement-Version' => '3.2.0',
'X-Musement-Currency' => $currency,
],
]);
} catch (Exception $e) {
return [$e->getCode().' | '.$e->getResponse()->getBody()->getContents(), 401];
}
return [GetEventDatesMapper::map($response), $response->getStatusCode()];
}
public function activityDatesTimeslotsPatchV2($accessToken, $eventId, $day, $time, $payload)
{
$endpoint = \sprintf('activities/%s/dates/%s/timeslots/%s', $eventId, $day, $time);
try {
$response = $this->request('PATCH', $endpoint, [
'headers' => [
'Accept' => 'application/json',
'X-Musement-Version' => '3.2.2',
'Authorization' => 'Bearer '.$accessToken,
],
'json' => $payload,
]);
} catch (Exception $e) {
return [$e->getCode().' | '.$e->getResponse()->getBody()->getContents(), $e->getCode()];
}
return [ActivityDatesPatchMapper::map($response), $response->getStatusCode()];
}
class EventSentToOnline extends Event
{
public function eventSentToOnline(EntityManager $entityManager, Container $container)
{
$this->notificationRepository = $entityManager->getRepository('AppBundle:Notification');
$this->eventRepository = $entityManager->getRepository('AppBundle:Event');
$this->setpRepository = $entityManager->getRepository('AppBundle:Step');
$this->mailer = $container->get('mailer');
$this->templating = $container->get('templating');
$event = $this->eventRepository->find($this->eventId);
$notification = new Notification();
$notification->setMessage($event->getTitle().' is now Online');
$notification->setActivityId($this->eventId);
$notification->setStatus('UNSEEN');
$notification->setType('EVENT_ONLINE');
$notification->setUserId($event->getSupplierId());
$notification->setUserType('supplier');
$notification->setCreatedAt(new \DateTime('now'));
$entityManager->persist($notification);
$entityManager->flush();
}
Dependencies injected to a method
Dependency getted from the container and never used
Hardcoded strings
Persistence inside an event???
In the last 2 years we tried to build the platform but we fail cause several issues and poor software quality.
Improve and stabilize it cause it will be very important in the near future.
(Strangler pattern)
class JwtAuthMiddleware
{
public function onKernelRequest(GetResponseEvent $event) { /* ... */ }
}
private function renderValidationError(ValidationError $exception): JsonResponse
{
$response = JsonResponse::create(
[
'message' => $exception->getMessage(),
'type' => $exception->getType(),
],
Response::HTTP_BAD_REQUEST
);
return $response;
}
private function renderResourceNotFound(ResourceNotFound $exception): JsonResponse
{
return JsonResponse::create(
[ 'message' => $exception->getMessage() ],
Response::HTTP_NOT_FOUND
);
}
private function renderUnauthorized(Unauthorized $exception): JsonResponse
{
return JsonResponse::create(
[ 'message' => $exception->getMessage() ],
Response::HTTP_UNAUTHORIZED
);
}
catch-all:
path: /api/v3/{req}
defaults: { _controller: business_platform.proxy.core.controller }
requirements:
req: ".+"
public function __construct(
CredentialChecker $credentialChecker,
TokenFactory $tokenFactory,
EventDispatcher $eventDispatcher
)
final class Email
{
/* ... */
public function __construct(string $email)
{
$this->assertNotEmpty($email);
$this->assertIsEmail($email);
$this->email = $email;
}
final class DateRange implements \IteratorAggregate
{
/* ... */
public function __construct(Date $from, Date $to)
{
if ($from->greaterThan($to)) {
throw new ValidationError(self::class, 'Invalid date range');
}
$this->from = $from;
$this->to = $to;
}
"require": {
"nelmio/cors-bundle": "^1.5"
}
Controllers
Get the input and call the use case. Format the response
Use cases
Responsible for the domain business logic. Feature-based.
Mappers
Transform raw data into domain value objects
(and vice-versa)
Repositories
Responsible for the domain entities persistence
Entities and Value Objects
Autovalidating and almost immutables.
Describes the domain data
(except for specific cases)
Services
Contains logic shared between several use cases.
Adapters
Connect the application to an external domain (ex: Core)
Handlers
Executes code after an event occured
Example 1
/* CreateUserSessionController */
public function __invoke(Request $request)
{
$json = $this->parseJson($request);
$credentials = $this->getCredentials($json);
$token = $this->userSession->create($credentials);
return JsonResponse::create([
'token' => (string) $token,
'role' => (string) $token->role(),
'uuid' => $token->userId()->value(),
], JsonResponse::HTTP_CREATED);
}
private function getCredentials($json): EmailAndPasswordCredentials
{
$credentials = new EmailAndPasswordCredentials(
new Email($json[self::FIELD_EMAIL] ?? ''),
new Password($json[self::FIELD_PASSWORD] ?? '')
);
return $credentials;
}
Get and validate the input
Call the use case
Create the response
/* CreateUserSession */
public function create(Credentials $credentials): Token
{
// Throws UserNotFound and InvalidPassword
$user = $this->credentialChecker->check($credentials);
$this->eventDispatcher->dispatch(new UserSessionCreated($user));
return $this->tokenFactory->createToken($user);
}
No primitives as arguments. Clear contract
Check the credentials
Trigger the event
Create and returns the Access Token
Example 2
/* GetSeasonsController */
public function __invoke(Request $request, string $id): JsonResponse
{
// Throws ValidationError
$activityId = ActivityId::fromString($id);
// Throws ResourceNotFound
$seasons = $this->getSeasons($activityId);
$response = JsonResponse::create(
$this->serializeSeasons($seasons)
);
return $response;
}
Invokable force Single Responsible controllers
Get and validate the input
Get the seasons
Create the response
Distro
Bundle
Domain
Distro (infrastructure)
Contains the framework and the legacy code.
It provides the configuration to all the external resources (like DB, cache, remote services, etc...)
Distro
Bundle
Domain
Bundle (Application)
Contains all the business platform related code.
It knows about Symfony and exposes several services and routes.
Distro
Bundle
Domain
Domain
Contains all the Musement domain concept used in the Business Platform.
It's a stable library that could be shared between several application.