eloquent ORM controller or model - php

I am writing a web application, and I am a self proclaimed disorganised developer, I write things quickly and worry about maintenance later. I am working with laravel at the moment, I have quite alot of database interaction, all the examples of eloquent seem to interacting with database object directly in the controller. Is this the best option, or is it more organised to wrap these eloquent methods in a function in the Model for that relevant query. e.g.
class HomeController extends \BaseController {
public function index()
{
$user = User::find(1);
return $user;
}
}
would this be better served as,
class HomeController extends \BaseController {
public function index()
{
$user = new User;
$result = $user->getSingleUser(1); //Being a method in the User.php model
return $result;
}
}
I realise this is very very basic example, but for organisational purposes is it best to seperate the database and "business logic" away from the controller?

but for organisational purposes is it best to seperate the database
and "business logic" away from the controller?
Yes
would this be better served as,
Yes - you should separate your logic into the correct areas, to make the code more manageable.

That's why MVC pattern is for. Store your db requests deep inside, also you can separate your model layer from db layer if you wish. If you more decouple your application structure then more manageable is your code.

Related

PHP MVC: Where should I put the model searching logic?

I'm building a MVC PHP framework from scratch, and I have some problems regarding the model layer.
What I have right now is a relatively basic MVC implementation, here's my entry point ( index.php ):
//get the URI
$uri = isset($_SERVER['REQUEST_URI'])
? $_SERVER['REQUEST_URI']
: '/';
//Initializes the request abstraction from URI
$request = new request($uri);
//getting the view class from the request
$viewFactory = new viewFactory();
$view = $viewFactory->getView($request);
$view->setDefaultTemplateLocation(__DIR__ . '/templates');
//getting the data mapper from the connection string
$connectionString = "mysql:host=localhost;dbname=test;username=root;";
$dataMapperFactory = new dataMapperFactory($connectionString);
$dataMapper = $dataMapperFactory->getDataMapper();
$modelFactory = new modelFactory($dataMapper);
//getting controller and feeding it the view, the request and the modelFactory.
$controllerFactory = new controllerFactory();
$controller = $controllerFactory->getController($request,$view,$modelFactory);
//Execute the necessary command on the controller
$command = $request->getCommand();
$controller->{$command}($request);
//Produces the response
echo $view->render();
I think this is self explanatory, but if you don't get something, or if you think I did some horrible mistake, feel free to tell me.
Anyway, the modelFactory is in charge of returning whatever model the controller could require. I now need to implement the "model research" logic, and in my opinion there's two ways of doing it:
First way: Implementing a modelSearch class containing all research logic, then make my model inheriting it ( like in Yii2 ). I don't like this method because it would make me instantiate some model and have it returning other instance of itself. So I have the same model instantiated once to research and once ( or more ) with all datas, and no use of search methods.
so my controller would look like that:
class site extends controller{
public function __construct($view, $modelFactory){
parent::__construct($view, $modelFactory);
/* code here */
}
public function index()
{
$searchModel = $this->modelFactory->buildModel("exemple");
$model = $searchModel->get(["id"=>3])->one();
$this->render('index',['model' => $model]);
}
}
Second way: Implementing a modelSearch class containing all research logic, then in the entry point, instead of instantiating the modelFactory, I could istantiate the modelSearch, and feeding it the dataMapper. Then I give the modelSearch to the controller, and the controller would get any model he wants by asking the modelSearch ( which would use the modelFactory to instantiate models and return them ), like that:
class site extends controller{
public function __construct($view, $searchModel){
parent::__construct($view, $searchModel);
}
public function index()
{
$model = $this->searchModel->get("exemple",["id"=>3])->one();
$this->render('index',['model' => $model]);
}
}
This way seems more correct to me, but has the disadvantage of having to call the modelSearch class to return any model, even empty ones.
Thoughts?
TL;DR: modelSearch: Do I use it as independant tool to get models, or do I make models inherit from it?
Searching logic should be within the model itself as the MVC describes model,view & controller. Model should have only one responsibilities that is work with database itself. While as controller should be responsible for manipulating of data and passing the data.
First read any MVC pattern PHP framework as CI, CakePHP and YII, and then you will see the model (how it works with database). and you can create there self model searching logic and you can see YII framework for best searching logic in model and usability in controllers.

Is it a good practice to extend Laravel models more than one layer?

I'm reworking a project on Laravel 5.1
What I realize is that the old classes have become much complicated and do not really follow the 'single responsibility' principle anymore.
So I'm planning to do such:
<?php
class User extends Model
{
}
class SocialUser extends User
{
}
So I have a few questions,
Is it possible to achieve that?
If yes, then does the SocialUser class link back to the same database table which is Users and would it conflict with the User model itself?
Is this all a good design practice at the first place? Or I better make use of traits?
Thank you.
What you’re doing (extending the User model) is perfectly fine, and an approach I use myself in projects.
For example, if an application I’m building has shop-like functionality, then I may create a Customer model that extends my User model, and contains say, order-related relations:
class Customer extends User
{
public function orders()
{
return $this->hasMany(Order::class, 'customer_id');
}
public function worth()
{
return $this->orders()->sum(function ($order) {
return $order->total();
});
}
}
In a recent project, I’ve been working on email campaign functionality and created a Recipient class that extends the User model to add campaign-related methods:
class Recipient extends User
{
public function campaigns()
{
return $this->belongsToMany(Campaign::class, 'recipient_id');
}
}
Because both of these classes extend the User model, I get all of those (and Eloquent) methods:
$customers = Customer::with('orders')->get();
So long as you set the table in your base User model, any classes that inherit it will use that same table, even though the model may be named differently (i.e. Customer, Recipient, Student etc).
IMHO I would go for the Repository pattern. It make's a lot of sense in your situation.
I would do the following:
interface UserRepository {
public function find($id);
public function getAll();
public function create(array $attributes);
public function destroy($id);
//you get the point
}
class CoreUserRepository implements UserRepository
{
//implement the interface rules
}
class SocialUserRepository extends CoreUserRepository
{
//implement the specific logic related to a SocialUser
}
Update
As Mjh described in the comments simply implementing the interface on all UserTypeRepository caused repetition - probably not what you want!
By extending your CoreUser you avoid repetition & maintain a design that will work for your situation.
Although, in your case it could be argued that you are still following SRP because everything in the User model is relating to a user, it's only the type of user which is differing.
Why go for the Repository Pattern?
You are ensuring you have a contractual agreement that all User
Repositories need to implement.
Code is easier to maintain.
Business and data access logic can be tested separately
Should you extend your User model?
Here you are in danger of model pollution. While you can do anything with a model - not everything is a good idea.
Defining relationships on this approach would be a headache due to the confusion caused.

Are there concrete benefits to injecting Controllers with Data opposed to injecting Controllers with Model?

My goal of asking this question is to ferret out whether there are benefits to injecting Controller directly with the data it needs (more specific approach) opposed to injecting a Model into a Controller (more generic approach). Or to establish whether or not it is just a matter of preference.
Injecting Controller with Model:
Model can be used to run all kinds of queries to retrieve various bits of data, but it is a heavier-weight construct than the data itself. Model essentially contains data, or at least it can access all the data you may need. Example:
class CategoryControllerWithModel
{
private $model;
public function __construct($model)
{
$this->model = $model;
}
// generates HTML for input form
public function genHtml()
{
/* retrieve data */
$categories = $this->model->getCategories();
//...
}
}
//instantiation within Factory Method:
class Factory
{
$model = new CategoryModel();
$controller = new CategoryControllerWithModel($model);
return $controller;
}
Injecting Controller with Data:
Here we do a bit more upfront with in the Factory method but we get a leaner Controller that only receives exactly the data it needs and is so completely separated from the Model that it is not even aware of its existence.
class CategoryControllerWithData
{
private $categories;
public function __construct($categories)
{
$this->categories = $categories;
}
public function genHtml()
{
$categories = $this->categories;
}
}
//instantiation within Factory Method:
class Factory
{
$model = new CategoryModel();
//a bit more work to get the data Controller needs
//benefit: Controller not tied to the Model
$categories = $model->getCategories():
$controller = new CategoryControllerWithData($categories);
return $controller;
}
Question:
I suppose MVC stands for exactly that -- Model, View, Controller, so injecting Model is probably considered to be an "okay" thing to do. If so, am I taking this too far by trying to remove Controller dependency on Model?
Suppose I insist that I want to inject Data into my Controllers rather than the Model. Is this a purely preferential issue do you see any concrete benefits of doing so?
From my point of view, Factory shouldn't be responsible for domain logic. It should only be responsible for building things up.
In this case, where you are injecting data, Factory has to know what categories controller is searching for, are there any filtering and so on.
So I think for controller you should only inject model, keep Factory single responsibility only for building things and controller should be responsible for it's data.
I think it's a matter of "separation of concerns" also I do not think that would be a good example of using MVC. I would think more along these lines:
class FooController
{
public function actionView($alias){
$category = Category::loadByAlias($alias);
..... load and render layouts etc .....
}
public function actionList(){
$categories = Category::loadAll();
..... etc ......
}
}
like this the neither the Controller nor the Factory need to know what needs to be done when you load a category nor do they have to handle active/inactive status, even User access ... etc this is all Model Logic, Model can have beforeLoad and afterLoad functions, conditions for listing all categories, eager or lazy loading of related models etc...

separating relationships and model functions in Laravel

Everytime I'm writing a Laravel model it just gives me a feeling of messy code. I have relationships and other model functions specially when using domain driven design. So I though about separating relationships and functions.
Example I have a User class that extends Eloqeunt:
class User extends Eloquent{}
and inside this class I have register functions and password hashing functions etc. Also, we can declare the relationships so:
class User extends Eloquent{
function post(){
return $this->hasMany('POST');
}
}
For some reason this smells funky to me. My solution was to create a Entities folder and inside create a User folder which will hold 2 files one would be UserRelationship which would hold of the the relationships for this class:
class UserRelationship extends Eloquent{
function post(){
return $this->hasMany('POST');
}
}
and a second which would be the actual User class where I would write all of the functions and this class would extend the UserRelationship class instead of Eloquent:
class User extends UserRelationship{
public static function register($email, $password, $activate_token)
{
$user = new static(compact('email', 'password', 'activate_token'));
$user->raise(new UserWasRegistered($user));
return $user;
}
}
What do you guys think of this approach I am relatively new to all this so I don't know if this is bad practice or to much work for little reward. What do you guys recommend?
For a user model, it is too much work. The easiest way and still a better approach is to define the relationship in the user model. If for example it is a post model where you have relationships for post to "user, comment, reply etc" then you can attempt splitting your relationships

Controllers structuring in PHP frameworks

I'm going for an example to make the question easier:
If you are implementing facebook, you want to separate user information from account information, from posts, from from from, that means there will be a model for user, a model for user info, a model for posts, a model for for for.
now if you go to user profile, it loads information from all these models, the question is how would you structure the controllers, of course you need controllers for each model to define it's unique actions, but how do i handle the rendering?
do i make a new controller that takes care of all renderings? or do i just put render profile in the user controller - which means it will have access to other models - or do i put in each controller a rendering of it's own and then combine them together...
or maybe if you have a better approach?
i just do not know the consequences of each approach that i thought of, and i don't know if there is a better approach that i didn't think of.
As others mentioned, you don't need a controller specifically for each model. However, given your Facebook example, it's quite simply done through relationships.
An oversimplification would be:
A User model to hold the user's account information and relationships
class User extends Eloquent {
public function posts() {
return $this->hasMany('posts', 'from_user_id');
}
}
A Post model to hold the content and from/to relationships to User
class Post extends Eloquent {
public function from() {
return $this->belongsTo('user', 'from_user_id');
}
public function to() {
return $this->belongsTo('user', 'to_user_id');
}
}
Then perhaps you'd have UserController load a view like so:
class UserController extends BaseController {
public function index($id) {
$user = User::find($id);
return View::make('user_page', array(
'user' => $user,
'posts' => $user->posts()->with('to')->get()
));
}
}
of course you need controllers for each model to define it's unique actions
No, this is wrong.
Controllers are part of your presentation layer, some might say you need a controller for each view object which is okay but for the model layer, it has nothing to do with the number of controllers you have.
a View is an object that toggles multiple templates and once again this has nothing to do with your controller, rendering is a view responsibility.
to understand it more, take a look here , here and here
those are really useful information to start with.
Wrong answer - controllers are not part of presentation layer - they are part of transport layer. Their task is to react on HTTP request.
Request is dispatched by Router. To proof take a look at Laravel source. Controller is a part of Routing package. When you call for example:
Route::get("/","HomeController");
You are just registering request parameters in RouteCollection. But everything is happening inside Router. Controllers can exist without any kind of view layer.

Categories