alex4answ
@alex4answ

Как правильно организовать код, файлы в проекте?

Добрый день, принялся за большой проект, и понял, что очень костыльно его проектирую и организовываю.

Например, для MVC,
Есть модели:
User - id | name | login ...
Page - id | owner_id | title ...
Setting - id | page_id ...

Для реализации тонкого контроллера, создаю "Сервис" для каждой сущности, куда выношу частые операции делаю , например:
UserService

class UserService 
{
    public static function createUser(array $data) : bool
    {
		$model = new User();
		...
		$transaction->begin();
		
		try{
			if($model->save() && PageService::create(...)){
				$transaction->commit();
			}
			else{
				$transaction->rollBack();
			}
		}
		catch{
			$transaction->rollBack();
		}
		
		return true;
    }
}


PageService

class PageService 
{
    public static function createPage(array $data) : bool
    {
		// Почти тоже самое что в UserService::createUser, только создаются Настройки SettingService::create()...
		return true;
    }
	
	public static function getUserPages(int $user_id): ?ActiveRecord
	{
		return Page::findAll(['owner_id' => $user_id]);
	}
	
	public static function updatePage(int $page_id, array $data): bool
	{
		// обновление
	}
	
	// и тп, все возможные операции
}



Соответственно, на выходе у нас классы почти полностью забитые статическими методами, все в кучу..

Подскажите, как правильно организовать структуру проекта, как понять, что пора например создать отдельный класс для каких-то типов запросов, операций..

Буду очень благодарен за наставление на путь истенный, пока мне кажется мне за такую организацию плюнут в лицо.
  • Вопрос задан
  • 140 просмотров
Решения вопроса 1
myks92
@myks92 Куратор тега Yii
Нашёл решение — пометь вопрос ответом!
1. Сервисы - это вспомогательный код, перед моделью, который вы выносите из контроллера. Пример. Сами сервисы не должны посылать запросы напрямую в базу. Для это го делается отдельный репозиторий, который передается через конструктор в сервис.

2. Сервисы подключаются в контроллер через конструктор и обращаются к ним как
$this->userService->create($userFrom или $userDto);

3. Делить сервисы можно хоть на каждое действие (UseCase)
..../Service/User/Create/Service.php всё зависит от вашей архитектуры. Выносите тогда, когда кода в сервисе становится много. Либо сразу.

Можете ещё почитать это Архитектура приложения. Как сделать независимые модули (сервисы)? и посмотреть тот репозиторий из github, который вставлял в качестве примера.

Ваш код можно переписать так: Исключил контроллер и PageRepository
class UserService
{
    public $users; 
    public $pages; 

    public function __construct(UserRepository $users, PageRepository $pages) 
    {
        $this->users = $users;
        $this->pages = $pages;
    }
        
    public function createUser(CreateForm $form) : void
    {
        if($this->users->existsByEmail($form->email)) {
            thow new DomainExeption('Пользователь уже существует!')
        }

        $user = new User([
            'username' => $form->username,
            'name' => $form->name,
            'email' => $form->email
        ]);

        $page = new Page([
            'name' => $form->page->name
        ]);

        ...

        $transaction->begin();
        try{
            $this->users->save($user);
            $this->pages->save($page);
            $transaction->commit();
        }
        catch{
          $transaction->rollBack();
        }

        //PS Транзакцию тоже можно вынести в отдельный сервис.
    }
}

class UserRepository
{        
    public function save(User $user): bool
    {
        if (!$user->save(false)) {
            throw new \RuntimeException('Saving error.');
        }
    }
        
    public function existsByEmail(string $email): bool
    {
        return User::find()->andWhere(['email' => $email])->exists();
    }
}
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы