A
A
Alexey Voropaev2018-12-02 10:05:16
symfony
Alexey Voropaev, 2018-12-02 10:05:16

How to properly build Symfony 4 architecture?

1 time I'm doing a Symfony project and I'm not sure how to build the architecture correctly. First I will show the code that I have, and then the questions.
The project will be RestApi. We accept json, we return json in JSend format .
The architecture is something like this:
Controller -> Service -> Repository -> Entity
Example: Creating a product. The product has a ManyToOne relationship with the Workspace.

ProductController:
public function store(
        Request $request,
        ProductStoreValidation $productStoreValidation,
        ValidationTransformer $validationTransformer
    ): Response {
        $body = $request->request->all();
        $violations = $productStoreValidation->validate($body);

        if ($violations->count()) {
            $errorsData = $validationTransformer->transform($violations);
            throw new ValidationRawException($errorsData);
        }

        $product = $this->productService->addProduct($body);

        $data = [
            'product' => $product
        ];

        $response = new JSendResponse(JSendResponse::SUCCESS, $data);

        return new JsonResponse($response, Response::HTTP_CREATED);
    }

product service:
public function addProduct(array $body): Product
    {
        $product = new Product();
        $product->setName($body['name']);
        $product->setSku($body['sku']);
        $product->setImage($body['image']);

        $workspace = $this->workspaceService->getWorkspaceById($body['workspace_id']);
        $product->setWorkspace($workspace);

        $product = $this->productRepository->save($product);

        return $product;
    }

DoctrineProductRepository:
public function save(Product $product): Product
    {
        $this->entityManager->beginTransaction();
        try {
            $this->entityManager->persist($product);
            $this->entityManager->flush();
            $this->entityManager->commit();
        } catch (\Exception $e) {
            $this->entityManager->rollback();
            throw new ProductRepositoryException('Error while saving product', $e->getCode(), $e);
        }

        return $product;
    }


Questions:
1) Where would it be correct to check "Does Workspace exist?"? Is it business logic?
right now I'm checking in the validation class, but maybe it needs to be done in the Service or somewhere else?
2) Where should the Product object be populated?
now I just call the service method and pass the whole body to it (after validation) and each property is filled there. I looked at many examples with forms and there the form performs validation and returns a Product object, maybe you need to do the same, but without forms? I don't use forms.
3) If I move the validation from question 1 to the service. That the service should form an error and throw out an eksepshen?
4) I understand why a repository is needed, entety, but I don’t really understand what should be in the service? in the controller?
In general, do you have any advice? Maybe I'm not doing it right? I'm trying to make thin controllers.
Another example:
Updating a Product
The code is about the same, but in the creation example, I create a Product in the service, and when I update, I get the Product in the controller and pass it to the service. Is this correct or is this the solution?
POST - /product/{id}
ProductController
public function update(
        Request $request,
        int $id,
        ProductUpdateValidation $productUpdateValidation,
        ValidationTransformer $validationTransformer
    ): Response {
        if (null === $product = $this->productService->getProductById($id)) {
            throw new NotFoundHttpException('Product not found');
        }

        $body = $request->request->all();
        if (empty($body)) {
            throw new BadRequestHttpException('Bad request');
        }

        $violations = $productUpdateValidation->validate($body);
        if ($violations->count()) {
            $errorsData = $validationTransformer->transform($violations);
            throw new ValidationRawException($errorsData);
        }

        $this->productService->updateProduct($product, $body);

        $data = [
            'product' => $product
        ];

        $response = new JSendResponse(JSendResponse::SUCCESS, $data);

        return new JsonResponse($response, Response::HTTP_OK);
    }

product service
public function updateProduct(Product $product, array $body): Product
    {
        if (isset($body['name'])) {
            $product->setName($body['name']);
        }

        if (isset($body['sku'])) {
            $product->setSku($body['sku']);
        }

        if (isset($body['image'])) {
            $product->setImage($body['image']);
        }

        if (isset($body['workspace_id'])) {
            $workspace = $this->workspaceService->getWorkspaceById($body['workspace_id']);
            $product->setWorkspace($workspace);
        }

        return $this->productRepository->save($product);
    }

Answer the question

In order to leave comments, you need to log in

2 answer(s)
D
dreamerz, 2018-12-03
@dreamerz

How do I compile the Symphony project
composer self-update
composer require symfony/symfony-skeletone (requires php memory limit over 1800M)
Never do anything when starting manually - First rule =)
If you suddenly need authorization from the box -
php bin/console make :auth
Your first controller
php bin/console make:controller
> MyShopController
We need a class to communicate with the database
php bin/console make:entity
> Shop
in the process You will be told that the Repository was created automatically
We forgot about the database! Do not be afraid to do a couple more commands)
php bin/console doctrine:database:create
Now you can upload tables:
php bin/console make:migration
Now, to see the tables in the database itself, let's say the command
php bin/console doctrine:migrations:migrate
Voila - this is the Magic of the Symphony)
If anything - contact
If specifically in question -
My router looks like this:
app_product
path: /product/{slug}/{action}
controller: App\Controller\ProductController:indexAction
By reference /product/update/#id
POST ajax request
ProductController:
$post = $request->request->all(); // all POST requests
$product = new Product;
$product->setPrice($post['price']);
...
/product/show/#id
The product page is loaded.
This is a concrete example of logic

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question