I have been reading about how to make my controllers clean and simple by moving business logic into a service layer. The problem I am encountering is that if I:
Align the service layer towards models e.g. UserService, AuthenticationService, then that reduces redundancy but it also assumes that each method of the UserService e.g. update() is going to be used in the same way but business logic as we know is different in different parts of the application. Methods that serve multiple scenarios are usually dirty because if 3 different parts of the application use the same method then you have to satisfy all 3 parts.
Align the service layer to reflect the controllers and their methods. This way has the potential to increase redundancy but it also makes it so you don't build single golden bullet methods that are supposed to encompass any scenario they're needed.
I have shown 2 examples below:
Reflecting models
class UserController extends Controller {
public function update(Request $request){
// Load user service and create history
$user_service = new UserService();
$user_service->update($request);
// Load user history service and create history
$user_history_service = new UserHistoryService();
$user_history_service->createHistory($request);
// json response with success
return response()->json([]);
}
}
Reflecting controllers
class UserController extends Controller {
public function update(Request $request){
// Load user controller service, update user and create history
$service = new UserControllerService();
$service->updateUser($request);
$service->createHistory($request);
// return json response with success
return response()->json([]);
}
}
The 2 ways I have identified are just what I have been gathering from reading and also a bit of my own thinking. Which way scales properly and I guess has the least sacrifice?
Related
I'm new to Laravel and am working on a collection of API endpoints that fetch data from a variety of database tables, transforms and processes that data, and then returns it as a JSON response. What I'm struggling to decide, from reading the documentation, is where my processing/transformation code should live.
I've setup my routes in routes/api.php, and have them point towards a Controller subclass, but from here things get a little murky because I'm not currently looking to make use of Eloquent ORM. It seems like typically I'd generate Model subclasses for each database table, and have a Repository call into those and transform the returned data, like so:
Route => Controller => Repository => Model
But where should I be placing both the database query code, and the logic required to process/transform that data (the business logic), when not making use of Eloquent ORM or the Model paradigm? Making the controller fat with DB queries and logic seems like a messy solution, but at the same time a lot of the Laravel DB example code does place logic in Controller subclasses.
So I'll offer an approach that is I think accomplishes what you are asking. In the API I developed, I used the route/api.php file to create the API endpoints. Each of these point to a Controller where the authentication and request validation is performed. The Controller then calls a Service class that handles all the business logic of the application and these are the real heavy lifting parts. The Service class makes calls to a Repository, which actually performs Model changes and saving.
I saw this used in another project several years ago and mimicked it for my projects. The code flow is shown below. Not sure if it will work for you, but I find it to be a very neat and keeps the code grouped together in logical ways.
Route => Controller => Service => Repository => Model
Here is an example of how you can setup your project without Eloquent.
Models are just data containers (records). They don't know how or where to store themselves. They are instantiated with some data and provide access for it:
class OrderRecord
{
protected $id;
protected $createdAt;
public function __construct($id, $createdAt = null)
{
$this->id = $id;
$this->createdAt = $createdAt ?: date('d-m-Y H:i:s');
}
public function getID()
{
return $this->id;
}
...
}
You read and write models only via repositories. Repository is just a class with your typical methods to retrieve/write one or multiple records (find, findAll, update, delete etc). It reads data, instantiates record(s) with it or take record(s), gets data from them and writes it. For example:
class OrderRepository
{
public function find($id): OrderRecord
{
// Here goes your querying. StdClass will be returned in this case
// that will be used to create new record.
$row = DB::table('orders')->find($id);
if ($row) {
return (new OrderRecord($row->id, $row->created_at));
} else {
// If not found you can throw an exception or return null
// (return type should be ?OrderRecord then) depending on
// how you want to design your workflow with repositories.
...
}
}
...
}
Lastly your business logic can be in your controllers. Your controllers should use repositories to get your model objects, work with them and the use repositories to store result if needed.
Obviously, you will need to implement base classes/interfaces for all your entities. Use dependency injection and Laravel's service container to glue everything together.
You can also extend this design by separating querying and mapping in your repository - you will have Repository classes that know only how to retrieve/store raw data and you will have Mapper classes that know how to create/retrieve raw data to/from your records (and serve as factories that repository will use to generate record objects from query results). If business logic also need to be interchangeable then you can also take business logic out of your controllers and put it into separate classes that your controller can utilize.
Here is an excellent article about repository-based approach and how you can extend it.
After developing a few projects using Codeigniter since 2 years, I stared to learn Laravel.
I downloaded a few projects lo learn how they are coded. As I understood, many of them are using only models, views and controllers which is same as Codeigniter.
But one project has used repositories and interfaces. It is really hard to understand whats going on that project. So what is the usage of repositories and interfaces in Laravel? When should I use them?
I will try to explain as clearly as possible the two concepts.
Interfaces\Contracts
In general OOP interfaces are used to describe which methods/functionalities the class that implements that interface is offering without caring about the actual implementation.
Laravel uses Contracts mainly to separate a service from the actual implementation. To be more clear let's make an example
<?php
namespace App\Orders;
class OrdersCache
{
protected $cache;
public function __construct(\SomePackage\Cache\Memcached $cache)
{
$this->cache = $cache;
}
public function find($id)
{
if ($this->cache->has($id)) {
//
}
}
}
As you can see in this class the code is tightly coupled to a cache implementation (i.e. \SomePackage\Cache\Memcached) so if the API of that Cache class changes our code also must be changed accordingly. The same thing happens if we want to change the Cache implementation with another one (e.g. redis).
Instead of doing that, our code could depend on an interface that is agnostic from the implementation:
<?php
namespace App\Orders;
use Illuminate\Contracts\Cache\Repository as Cache;
class OrdersCache
{
public function __construct(Cache $cache)
{
$this->cache = $cache;
}
public function find($id)
{
if ($this->cache->has($id)) {
//
}
}
}
Now our code is not coupled with any specific implementation because Cache is actually an interface. So basically in our class we are requiring an instance of a class that behaves like described in the Cache interface, but we are not really interested in how it works internally. Doing that if we want to change the cache implementation we could write a class that implements the interface Cache without changing any line of code in our OrdersCache class. Doing that our code is easier to understand and maintain and your packages are a lot more reusable. See the section Loose Coupling in the Laravel documentation for further examples.
Interfaces and Service Container
One of the main features of Laravel is its Service Container, it is used to manage dependencies and performing dependency injection. Please take a look at Service Container definition from Laravel documentation.
Dependency Injection is widely used by Laravel also to bind interfaces to implementation. Let's make an example:
$app->bind('App\Contracts\EventPusher', 'App\Services\RedisEventPusher');
And let our class be
<?php
namespace App\Http\Controllers;
use App\Contracts\EventPusher;
class EventsController extends Controller
{
protected $pusher;
public function __construct(EventPusher $pusher)
{
$this->pusher = $pusher;
}
}
Without declaring anything else we are basically saying everytime that someone need an EventPusher instance, please Laravel, provide an instance of RedisEventPusher class. In this case everytime that your controller is instantiated, Laravel will pass an instance of RedisEventPusher to your controller without specifying anything else.
You can dig into that by looking at Binding Interfaces to Implementation section on the Laravel documentation.
Repositories
Repositories is a concept applicable to the MVC pattern independently from any specific framework. Typically you have your Model that is the data layer (e.g. interacts with the database directly), your Controller that handles the access logic to the data layer and your View that shows the data provided by the Controller.
Repositories instead could be defined as follows:
To put it simply, Repository pattern is a kind of container where data access logic is stored. It hides the details of data access logic from business logic. In other words, we allow business logic to access the data object without having knowledge of underlying data access architecture.
Soruce: https://bosnadev.com/2015/03/07/using-repository-pattern-in-laravel-5
To know how to use them within Laravel please take a look at this great article.
That's all, i hope it helps to clear up your mind.
Interfaces are what any implementing class should call.
interface CanFlyInterface
{
public function fly();
}
Think of it like programming without bothering with logic.
if ($object instanceof CanFlyInterface) {
$obj->fly();
}
Now we could have passed a Bird object, or an Aeroplane object! PHP DOESN'T CARE, so long as it implements the interface!
class Bird implements CanFlyInterface
{
public function fly()
{
return 'flap flap!';
}
}
class Aeroplane implements CanFlyInterface
{
public function fly()
{
return 'roar! whoosh!';
}
}
Your other question, what a Repository class is. It's just a class that keeps all your DB queries in the one place. Check this interface as an example:
interface RepositoryInterface
{
public function insert(array $data);
public function update(array $data);
public function findById($id);
public function deleteById($id);
}
Hopefully this should clear things up for you! Good luck with all your PHP coding :-D
Let's start with the easier one, the interface:
You normally use interfaces to implement classes with required methods:
http://php.net/manual/en/language.oop5.interfaces.php
Laravel's Contracts are a set of interfaces that define the core services provided by the framework. For example, a Illuminate\Contracts\Queue\Queue contract defines the methods needed for queueing jobs, while the Illuminate\Contracts\Mail\Mailer contract defines the methods needed for sending e-mail.
https://laravel.com/docs/5.4/contracts#introduction
When Laravel is running it can check if a class implements a special interface:
if ($cls instanceof IInterface) {
$cls->interfaceFunction();
}
Since Laravel is able to work with queues it will check if the event should be queued or not by checking for an exiting interface.
To inform Laravel that a given event should be broadcast, implement the Illuminate\Contracts\Broadcasting\ShouldBroadcast interface on the event class.
https://laravel.com/docs/5.4/broadcasting#defining-broadcast-events
Repository:
I didn't found that much about this:
Our repository should not have so much knowledge regarding who is providing them data or how they are providing it. https://laravel.com/docs/5.4/contracts#loose-coupling
But I found some other information on a webpage:
a Repository will connect Factories with Gateways
https://code.tutsplus.com/tutorials/the-repository-design-pattern--net-35804
The link will give you more information about the the details.
Hope I could help you :)
First of all, using Repository and Interface in larger application is not only beneficiary in Laravel but in all technology for coding standard as well as for separation of concern.
According to Microsoft (I found best explanation here)
Why to use Repository:
Use a repository to separate the logic that retrieves the data and
maps it to the entity model from the business logic that acts on the
model. The business logic should be agnostic to the type of data that
comprises the data source layer. The repository mediates between the
data source layer and the business layers of the application. It
queries the data source for the data, maps the data from the data
source to a business entity, and persists changes in the business
entity to the data source.
A repository separates the business logic
from the interactions with the underlying data source or Web service.
The separation between the data and business tiers has three benefits:
It centralizes the data logic or Web service access logic. It provides
a substitution point for the unit tests. It provides a flexible
architecture that can be adapted as the overall design of the
application evolves. There are two ways that the repository can query
business entities. It can submit a query object to the client's
business logic or it can use methods that specify the business
criteria. In the latter case, the repository forms the query on the
client's behalf. The repository returns a matching set of entities
that satisfy the query.
For Interface, you have a lot of answers above, hope you have understand.
First of all, repositories and interfaces are not specific to Laravel but common coding standards in most of the languages.
Below Laracasts videos will be useful to understand the basics if you don't mind spend few dollars.
https://laracasts.com/lessons/repositories-and-inheritance
https://laracasts.com/series/object-oriented-bootcamp-in-php
I am no expert in the MVC architecture, however I have been working using the mentioned architecture on some JAVA projects. Now I'm getting into PHP MVC Frameworks, (like CakePHP and Laravel) and I decided to go for CakePHP.
Going deep into it, I see Models in CakePHP are in charge of operations like querying and some others while data itself is managed in arrays (i.e. $user['User']['first_name']).
The way I am familiar with, Model classes are just for storing model data, in other words, what arrays do in CakePHP
public Class User {
private String firstName;
public void setFirstName(String firstName) { this.firstName = firstName; }
public String getFirstName() { return this.firstName; }
}
And Controller classes are in charge of querying and other model-building operation, in other words, what models do in CakePHP:
public Class UserManager {
public User getById(int id) { /* */ }
public boolean save(User user) { /* */ }
}
So, are CakePHP, and simillar MVC Frameworks, Models actually controllers? also if yes, shouldn't this be a new type of architecture, something like Router-View-Controller, since controller class actually routes request ?
I think the official documentation explains it already pretty well:
Models are the classes that sit as the business layer in your
application. This means that they should be responsible for managing
almost everything that happens regarding your data, its validity,
interactions and evolution of the information workflow in your domain
of work.
Usually model classes represent data and are used in CakePHP
applications for data access, more specifically they represent a
database table but they are not limited to this, but can be used to
access anything that manipulates data such as files, external web
services, iCal events, or rows in a CSV file.
Actually a model in CakePHP 2.0 is basically thought to do any kind of data manipulation.
Need to turn an array into a CSV string? Model job.
Need to validate an uploaded image? Model job.
Need to save an uploaded file? Model job.
Need to somehow manipulate your POST data? Model job.
...
None of the tasks above is thought to be done in a controller, we want to respect separation of concerns (SoC). The controller just manages the request but doesn't process data, that's the models job. Also models are more easy to unit test than controllers plus you can share them in a shell, you cant do that with controllers without MVC violations: Here is an example:
You should always keep your models fat and controllers thin:
/** CONTROLLER **/
if ($this->request->is('post')) {
if ($this->Model->doSomething($this->request->data)) {
$this->Session->setFlash(__('Something was done right!'));
$this->redirect(['view' => $this->Model->data['Model']['id']);
}
}
/** MODEL **/
public function doSomething($data) {
$this->create();
$result = $this->save($data);
if ($result) {
$result[$this->alias][$this->primaryKey] = $this->getLastInsertId();
$this->data = $result;
return true;
}
return false;
}
No, models are not controllers, not in any php framework out there.
Models just present a collection of your data, a controller at the other hand controls the flow between models and view. For example, the controller calls your model to get data, then process that somehow and push to to the view, so you can pick it up there and do something with it.
Are you willing to tell why you choosed for cakePHP ?
I have created a login system and I am trying to stick to the rules of MVC as much as possible.
I have a simple login form that uses AJAX to submit the form data to small script, which then calls the controller for the processing of the username and password:
function __autoload($classname) {
include("../classes/$classname.php");
}
$username = $_POST['username'] ;
$password = $_POST['password'] ;
$AC = new AccessControl ;
$result = $AC->login($username, $password) ;
if($result !== 0)
{
echo $result ;
exit() ;
}
AccessControl is my class for user authentication and account management operations, the code is here in my other post: MVC Relationships and DRY
Have I done this wrong because this small script isn't a controller or a model? All it does is relay information returned from the controller back to the interface/view, such as error messages.
First, don't let any particular paradigm prevent you from doing things the best way possible in your particular situation.
That said, your small script is a controller. It's processing an action and returning a result. It may not be managing a specific view but it's delegating processing and handing off the result to a view.
In my oppinion, haven't used the MVC structre to the blood, this is about right, with some minor changings.
I usually prefeer something like :
$AC = new AccessControl ;
$AC->setUsername($_POST['username']);
$AC->setPassword($_POST['password']);
if ( $AC->login() )
echo $result // if all is ok from login method return true
else
// manage some error handling here if not true
Maybe you want to user that Username and Password in more places and other methods, so you can use getPassword() / getUsername()
You are mixing authentication and authorization. Structures like AccessControl should be dealing with authorization, not authentication .. you choice of names .. emm ... leaves room for improvement. To learn more about the authorization in context of MVC, i would recommend to read this post.
Authentication, in context of MVC and MVC inspired design patterns, should be part of the model layer and handled by some form of Recognition service.
What you have on the code snipper looks a bot like code from controller's method, but it has several issues.
Ok .. lets pike apart to code:
The use of __autoload() function is not recommended. You should instead learn how to utilize spl_autoload_register() function. It would let you code to use multiple leaders.
Also, since release of 5.3, it is possible to use namespaces in PHP. In combination with autoloaders, it would let you better organize you code. Lately it is common practices to map project directory structures (at least partially) to namespaces.
The most known implementation would be PSR-0, though it should not be considered even close to ideal. It has some serious flaws, but it will make for a good example to illustrate use of namespaces in autoloading.
You should avoid use of new deep in the application call graph. This causes tight coupling to the name of class from which you are creating the new instance.
Instead your controller should have a factory injected into constructor, which then is responsible for initialization of new instances.
namespace Controller;
class Foo
{
protected $serviceFactory = null;
protected $view = null;
// --- SNIP ---
public function __construct( HasSomeFactoryInterface $factory, $view )
{
$this->serviceFactory = $factory;
$this->view = $view;
}
public function postLogin( $request )
{
$recognition = $this->serviceFactory->create('AccessControl');
// --- SNIP ---
}
Controller in MVC design pattern should only change the state of model layer and current view. It does not return anything nor passes data from model layer to view. You seem to confuse classical MVC, Model2 MVC, MVP, MVVP and the Rails parody of MVC pattern.
In the Model2 MVC (also known as Web MVC) design pattern the controller take the incoming user request, and, by passing data from said request to the respective parts of triad, changes their state.
namespace Controller;
class Foo
{
// --- SNIP ---
public function postLogin( $request )
{
$recognition = $this->serviceFactory->create('AccessControl');
$recognition->login( $request->getPost( 'username' ),
$request->getPost( 'password' ) );
$this->view->prepare( $request->getMethod() );
}
// --- SNIP ---
}
In this example view receives notification, that the POST request was received, which means, that, instead of generating HTML from several of templates, it has to only send HTTP header as a response.
To see a short overview about the MVC-related patterns, try this post.
If you are aiming for Model2 MVC design pattern, then view should retrieve information from model layer on its own. But all MVC-inspired design patterns view is supposed to be responsible for the presentation logic.
That also includes dealing with error state in model layer. Domain business logic has nothing to do with how view represents errors.
When implementing models using the MVC pattern, how complex should my models be?
Let's say I have got a few tables like so:
User (id, password, created ...)
Emails(user_id, email ...)
Addresses (user_id, address ...)
I have got a controller called UserController. This controller should allow me to log users in, create users, etc.
<!-- language: php -->
class UserController{
public function create($array){
...
}
public function login($email, $password){
...
}
}
Should my models be very primitive, implemeting only CRUD operations via ORM? This would result in code like:
<!-- language: php -->
class UserController{
public function create($array){
$userModel->username = 'blah';
$userModel->blah = 'blah';
$id = $userModel->save();
$emailModel->id = $id;
$emailModel->email = "emailhere";
$emailModel->save();
//Do the same for addresses
}
public function login($email, $password){
...
}
}
Or, alternatively, I could have models that are more complex:
<!-- language: php -->
UserModel{
public function login($email, $password){
//Do the joining and checking here, then return true or false to the controller
}
}
Then in my controller:
<!-- language: php -->
userModel->login($mail, $password);
So, which is the better way? To stuff all the logic into models, or should I have models doing only the basic CRUD operations? Finally, how do I deal with table joins? Should they be dealt within the model, or in the controller?
Cheers
Most people think of the "Fat Models, skinny controllers" paradigm, and it works better in the long run.
A great rule of thumb is to think about your Models as their own entity, in the sense that if you were to move your models to a different framework for example, they would still be functional.
A simple example would be saving information about an order on an e-commerce website. Let's say you want to save information about Tax, namely how much Tax is on the order. An abstract way of doing this is...
$tax_amount = $order_amount * (TAX_PERCENTAGE / 100);
Should we do this in the controller or the model? Suppose we did it in the controller, well... in our create action and our update action we would be calculating the tax, which makes for harder to maintain code and should the business rules of the e-commerce website change (say, we start selling to Tax exempt businesses or overseas business) then we would have to change any controller that saves order information.
If we were to calculate Tax in our Order model however, we would be doing it once in our save() method, which would be called when editing and adding orders.
public function save() {
//calculate tax first
$q = $this->db->query($sql);
}
Imo, it's better to enforce business rules in your model because it makes for more portable code and far less headaches when it comes to maintaining your code. Of course, there are people who will disagree, and this is a very subjective area.
EDIT:
Applying this to the specific question you asked, think about whether you would ever need the login() method anywhere else but your User model? It's possible you might want to split your models into different, more specific ones. But you could extend from your User model in that case.
What about if you were to take away your controller completely? Or if you wanted to interface with your models in an entirely different way (say via a different framework in the future). Thinking in this way you would be far better off with your login method in your User model.
Personally, I would be creating a login method on my model because it is an operation on data and that is what our models are for. I would also be creating a loginAction() method on my controller which would initiate the login() method on our model and perform any other action (for example, log failed attempts/redirect) that has to happen on post-login, should it be successful or unsuccessful. An example loginAction() may look as follows...
class UserController extends GenericController {
public function loginAction() {
$post = $this->form->getPost();
if(UserModel::login($post)) {
//do something
} else {
//do something else
}
}
}
All functionality which will or could be reused at different parts in the application should be accessbile globally, so that the coupling is low and there is no need to redeclare it.
I think you need an additional model for authorization and/or the current system parameters. The AuthModel could store information about the different authorization roles and the SysModel stores application parameters like the default login settings (e.g. use cookies yes or no).
The login method could be placed in the AuthModel then, which should be a good place in my opinion. Also the models are responsible to validate the inputted data, so the creation of new users should be in the UserModel.