Как протолкнуть логику в модель вместо того, чтобы держать ее в контроллере?
Согласно моему пониманию в MVC, логика находится в модели, контроллер обрабатывает координационную часть и представление существует для представления данных.
Ниже приведен извлеченный из контроллера код. Он написан в codeigniter, который является фреймворком PHP. То, что происходит ниже, если изображение доступно, оно будет удалено, иначе пользователь будет перенаправлен на удаление формы изображения.if($this->records_model->check_img_availability($img_data))
{
//delete if the image is available
$this->records_model->delete_img($img_data);
}
else
{
//redirected to delete image form
$this->session->set_flashdata('errormsg', 'Img is not available');
redirect(base_url() . 'records/deleteimg/');
}
Согласно MVC выше неверно, так как логика находится в контроллер. Он проверяет, доступно ли изображение, в зависимости от того, что изображение будет удалено или перенаправлено пользователем.
Как протолкнуть логику в модель вместо того, чтобы держать ее в контроллере?
1 ответ:
Используйте слой сервиса. Логика, которую вы теперь имеете в своих контроллерах, входит в одну из ваших служб.
Служба обычно имеет дело с большими кусками связанной прикладной логики.
Например, если ваше приложение продает продукты, функциональность / логика корзины покупок и клиентской проверки должны были бы куда-то пойти. Поскольку функциональные возможности схожи, вы бы поместили всю связанную логику в класс
Services\Shopping
, и он мог бы иметь API, подобный следующее:interface Shopping { /** * @param int $productId * @param int $quantity * @return bool */ public function addToCart($productId, $quantity); /** * @param int $productId * @return bool */ public function removeItem($productId); /** * @param int $productId * @param int $quantity * @return bool */ public function updateQuantity($productId, $quantity); /** * Customer checkout. * * @param string $firstName * @param string $lastName * @param string $emailAddress * @return bool */ public function checkout($firstName, $lastName, $emailAddress, .....etc); }
В основном вы просто группируете функциональность аналогичного слоя модели в сервисы и даете сервисам хорошее название, которое в общих чертах объясняет, какую работу/функциональность он выполняет.
Теперь ваши контроллеры просто извлекают данные из запроса и отправляют их в службу для выполнения работы.Некоторый метод контроллера для добавления товара в корзину:
Теперь ваши контроллеры могут быть тощими и свободными от логики. Как вы реализуете обслуживание зависит от вас. Сервисы часто могут зависеть от других сервисов для взаимодействия с различными функциональными возможностями слоя модели.$productId = (int)$this->request->post('productId'); $quantity = (int)$this->request->post('quantity'); // Now send the data to the shopping service to do the work. $this->shopping->addToCart($productId, $quantity);
Edit
Для вашего сценария я не могу придумать описательное имя для службы, потому что я не знаю достаточно информации о том, почему вы удаляете изображение, с чем связано изображение и т. д. Поэтому я просто назову его
Services\Image
. Это может считаться плохим именем для службы, поскольку она слишком специфична, но это только для демонстрации цели.class Image extends AbstractService { /** * This is assuming you have an ID for a row in the database containing data * about the image like the path to the image so it can be deleted from the server. * * @param int $id * @return bool */ public function delete($id) { $mapper = $this->mapperFactory->build('Image'); $image = $mapper->fetch($id); if( $image === null ) { return $this->fail('Image does not exist.'); } try { $mapper->delete($image); // Delete the image row in the database. unlink( $image->getPath() ); // Delete the image file from the server. return $this->success('Image deleted successfully.'); } catch(\RuntimeException $ex) { return $this->fail('Failed to delete the image.'); } } }
Методы
success()
иfail
находятся в родительской службе. Они обновляют состояние слоя модели и устанавливают сообщение, чтобы показать пользователю, если это необходимо. Методfailed()
исходит от родительскогоAbstractService
, который возвращает true, если вы вызвали$this->fail()
в любом дочернем сервисе.Тогда в представлении вы можете иметь что-то вроде:
Как вы можете видеть, вид имеет мозги и может выполнять логику. Это та область, где CI плох. Представления в основном являются шаблонами без мозги, поэтому логика, которая должна быть в представлении, выталкивается в контроллер, уровень обслуживания и т. д. В основном контроллер связывается с сервисом изображений с помощью методаif( $this->imageService->hasState() ) { if( $this->imageService->failed() ) { // If deleting the image failed do whatever you want here. // Switch templates, redirect or whatever. } else { // The image was deleted successfully so do whatever you want here. // Again, switch templates, redirect or whatever. } // Bind the message to the template. }
delete($id)
, который пытается удалить изображение и устанавливает состояние слоя модели, затем представление обращается к сервису изображений и спрашивает его, в каком состоянии он находится, и продолжает делать все, что ему нужно, основываясь на состоянии слоя модели.На мой взгляд услуги в целом не следует ничего знать об ответе или о том, как отправить редирект, это ответственность views.
Symfony, вероятно, лучший фреймворк PHP, но многие говорят, что он имеет одну из самых крутых кривых обучения. Я сделал это на нескольких страницах в документации, пока не начал видеть вещи, с которыми я не был согласен, поэтому я решил прекратить исследовать его. Создатель PHP, Расмус Лердорф, даже сам говорит, что все нынешние фреймворки PHP ужасны.Лучший из удача.