A
A
Analka2022-02-17 15:46:22
PHP
Analka, 2022-02-17 15:46:22

How to build a large project?

Hello. Need advice - how to build a large project?

now I have created something like this project structure:

there is a CategoryController controller

class CategoryController extends Controller
{
    public function __construct(
        private CategoryService $categoryService
    )
    {
    }
    public function store(CategoryRequest $request)
    {
        return $this->categoryService->store($request->validated());
    }
    public function show(int $id)
    {
        return $this->categoryService->showById($id);
    }
    public function update(CategoryRequest $request, int $id)
    {
        return $this->categoryService->updateById($id, $request->validated());
    }
}


in order not to produce a bunch of code in the controller, I created a service layer

class CategoryService
{
    use JsonResponseTrait;

    public function __construct(
        private CategoryQueryInterface  $categoryQuery,
        private CategoryActionInterface $categoryAction,
    )
    {
    }

    public function store(array $data): JsonResponse
    {
        try {
            $this->categoryAction->store($data);

            return $this->successApiResponse([], Lang::get('database.store_success'));

        } catch (Exception $e) {
            return $this->errorStringApiResponse($e->getMessage(), 500);
        }
    }

    public function showById(int $id): JsonResponse
    {
        $category = $this->categoryQuery->findById($id);

        if (!$category) return $this->notFoundApiResponse([], '404');

        $data = [
            'id' => $category->id,
            'name' => $category->name,
            'icon' => $category->icon,
            'description' => $category->description,
            'metaTitle' => $category->meta_title,
            'metaDescription' => $category->meta_description,
            'isPublished' => $category->is_published,
            'slug' => $category->slug,
            'updatedAt' => $category->updated_at
        ];

        return $this->okApiResponse($data);
    }

    public function updateById(int $id, array $data): JsonResponse
    {
        $model = $this->categoryQuery->findById($id);

        if (!$model) return $this->notFoundApiResponse([], Lang::get('database.record_not_fount'));

        try {
            $this->categoryAction->update($id, $data);

            return $this->successApiResponse([], Lang::get('database.update_success'));

        } catch (Exception $e) {
            return $this->errorStringApiResponse($e->getMessage(), 500);
        }
    }
}


also, in order not to produce repetitions of code requests, make the CategoryQuery class

class CategoryQuery implements CategoryQueryInterface
{
    public function findById(int $id): ?Category
    {
        $query = Category::find($id);

        return $query;
    }
}


+ to somehow separate the creation/editing of posts, I made a CategoryAction

class CategoryAction implements CategoryActionInterface
{

    public function store(array $data): void
    {
        $store = new Category();
        $store->name = trim($data['name']);
        $store->icon = trim($data['icon']);
        $store->description = trim($data['description']);
        $store->text = $data['text'];
        $store->meta_title = $data['metaTitle'] ?? $data['name'];
        $store->meta_description = $data['metaDescription'] ?? $data['metaDescription'];
        $store->is_published = $data['isPublished'];
        $store->slug = trim($data['slug']) ?? Str::slug($data['title'], '-');
        $store->save();
    }

    public function update(Category $category, array $data): void
    {
        $category->name = trim($data['name']);
        $category->icon = trim($data['icon']);
        $category->description = trim($data['description']);
        $category->text = $data['text'];
        $category->meta_title = $data['metaTitle'] ?? $data['name'];
        $category->meta_description = $data['metaDescription'] ?? $data['metaDescription'];
        $category->is_published = $data['isPublished'];
        $category->slug = trim($data['slug']) ?? Str::slug($data['title'], '-');
        $category->save();
    }
}


Now I’m sitting and thinking, did I split the logic correctly so that in the future the project would be easy to maintain and expand?

Answer the question

In order to leave comments, you need to log in

3 answer(s)
V
vism, 2022-02-17
@vism

It is called, I heard a ringing, but I don’t know where it is.
1. You turned the service layer into a controller.
Those. you have a controller, and you created another one, because somewhere heard that services are necessary.
But, services do not send responses, this is an internal layer for separating logic.
You can call those methods through the console, other services, etc.
There, return should simply be generated, and the response itself is already in the controller (so that the controller performs its own function). Validation of the request, by the way, also needs to be done not in the server.
2. CategoryQuery is just wild game.
You're making a duplicate again because you heard about the repositories, and even the interface. So I'm dying from people who shove interfaces everywhere. Interfaces are needed where they are needed. Where there will be 2+ interface inheritors.
Where do you get heirs from here, if you are tied to the elocuent?
And the legs are from the Indian repositories. Repository, Query and interfaces are not needed when working in elokuent. He already contains all this in himself and all the repeating things are already wrapped. find, first, firstOrNew etc.
So use elocuent and don't overcomplicate the project unnecessarily. Don't make it hard, make it simple.
3.CategoryAction.
Again, the interface ...
This is Action, in fact, you have a service. Here you transferred the business logic of creation and editing and return the response of this method. Here, delete your CategoryAction and transfer the methods to the service.

S
Sergey delphinpro, 2022-02-17
@delphinpro

the showById method seems superfluous to me.
404 and so will return if you use model binding,
why rebuild attributes? just return the model and that's it. hide unnecessary attributes in the $hidden property, add custom attributes to $appends
will be short

public function show(Category $category)
{
    return response()->json($category->toArray());
}

P
profesor08, 2022-02-17
@profesor08

No no no, first build a flowchart to have a visual representation of what kind of interactions you will have, how the data will walk. Since everything is forgotten over time, you can always turn to her and remember. Moreover, when you want to change something, you will reflect it in the flowchart, and you will know what exactly needs to be changed in the project and, which is very important, you will know how the changed parts affect others.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question