Welcome Guest, Not a member yet? Register   Sign In
When to put code in Controller and when in Model
#1

MVC pattern seems quite clear but sometimes I'm not sure where certain things should go - controller or model.

Examples that feel clear enough:
  • I want to fetch an order I also want to JOIN it with its items.
    Makes sense that this goes into model because it's a direct database interaction.
  • I'm trying to add a new user I need to make sure that username is at least 5 characters long and that email is valid.
    CodeIgniter gives a bit of a hint here because it allows to validate things in models specifically when you try to call insert/update/save function. So ok, it goes in a model.
Specific issue:
  1. User creates an order with a photo attached.
  2. That photo first needs to be validated to make sure that it's not too big.
  3. Then it gets saved in a specific folder and after ensuring that it got moved successfully we're storing only the name of the file in the database.
What's the correct approach here?
  1. Photo upload and validation should be done in Controller and the Model should only handle final database interaction.
    What if I want to reuse photo validation and move in another controller? Where do I put it?
  2. Put photo validation, moving and stroing in database in Model since it's all related. Use
    Code:
    $model->uploadPhoto($this->request->getFile('photo'))
    in the Controller. That way logic is reusable, but Model has to deal with an
    Code:
    UploadedFile
    instance which feels.. weird?
Reply
#2

(01-21-2023, 10:42 AM)Rinart Wrote:
  1. Photo upload and validation should be done in Controller and the Model should only handle final database interaction.
    What if I want to reuse photo validation and move in another controller? Where do I put it?

You can move the logic to:
- a library class
- parent controller class
- a trait
Reply
#3

(This post was last modified: 01-21-2023, 07:27 PM by Rinart.)

(01-21-2023, 07:02 PM)kenjis Wrote:
(01-21-2023, 10:42 AM)Rinart Wrote:
  1. Photo upload and validation should be done in Controller and the Model should only handle final database interaction.
    What if I want to reuse photo validation and move in another controller? Where do I put it?

You can move the logic to:
- a library class
- parent controller class
- a trait

Would it be a bad idea to move logic into an Entity?
Like this:

PHP Code:
// App/Entities/Order.php

namespace App\Entities;

use 
CodeIgniter\Entity\Entity;

class 
Order extends Entity
{
    protected $datamap = [];
    protected $dates  = ['created_at'];
    protected $casts  = [];
    
    
protected $errors = [];

    public function setPhoto(string|UploadedFile $photo)
    {
        // when Entity is loaded from database
    
        
if (is_string($photo)) {
            $this->attributes['photo'] = $photo;

            return $this;
        }
        
        
// when new order is created

        // check if photo is not too big, is correct format and size
        
        
if (! $this->validatePhoto($photo)) {
            return $this;
        }
        
        
// attempt to move image to the uploads folder
        
        $newName 
$this->savePhoto($photo);
        if ($newName) {
            $this->attributes['photo'] = $newName;
        }

        return $this;
    }
    
    
protected validatePhoto(UploadedFile $photo): bool
    
{
        if (validationLogicFailed()) {
            $this->errors[] = "Photo doesn't match the requirements";
            
            
return false;
        }
        
        
return true;
    }
    
    
protected savePhoto(UploadedFile $photo): string|bool
    
{
        try {
            return movePhotoAndGetNewName();
        } catch (RuntimeException $e) {
            $this->errors[] = "Error during photo upload";
        }

        return false;
    }
    
    
public function isValid(): string
    
{
        return empty($this->errors);
    }
    
    
public function errors(): array
    {
        return $this->errors;
    }
}


// somewhere in Controller

$postData $this->request->getPost();
$order = new \App\Entities\Order($postData);

if (! 
$order->isValid()) {
    displayErrorsLogic($order->errors());

Reply
#4

An entity represents a database record.
I think it should not know about File Uploading.
Reply
#5

Create a new layer in folder Services, Helpers...:
class OrderService or class OrderCreator
Add a method to it with your desired parameters:

public function createOrderFromUser($user, $order, $file, $options, ...)

and inside you work with several models (namely with a database), upload a picture, check validation and so on. 

In response, return either true/false or a new order with a picture. In controller call:


PHP Code:
 $orderHelper = new OrderService();
 $order $orderHelper->createOrderFromUser(...); 
Reply




Theme © iAndrew 2016 - Forum software by © MyBB