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.
Related
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've been researching and reading a lot about working with separate layers in PHP to create maintainable and readable code.
However, I see a lot of code where the entity and the database access is placed in one class.
For example:
class User{
public $id;
public $username;
public $database;
function add(){
$database->query ....
}
}
I find this rather strange because here you are mixing the User class with database elements which makes it more difficult to maintain.
I like working like this:
a separate database class
a user class
a userData class
This works like this:
$database = new Database();
$database->openConnection();
$dataUser = new DataUser($db);
$user = new User(1,"myname");
$dataUser->saveUser($user);
So I'm wondering, am I working the right way or is the first way a better way to create code?
I find may way very easy to maintain because you have a separate entity and a separate database class to handle the database actions.
What i do :
My models are not Entities linked to the database(when i'm not using doctrine) , so no "active record" methods. An object doesnt know how to fetch its dependencies ( for instance , a user may have n comments, my model doesnt know how to get comments ).
class User{
private $name;
private $password;
// getter and setters
}
i have services that hold some business logic that can fetch models from providers, a service can have many providers.
class UserService{
function __construct(IUserProvider $userProvider){
$this->userProvider = $userProvider
}
function getUsers(){
// return an array of user objects
return $this->userProvider->getUsers();
}
}
finally i have a data provider that knows how to request datas from the database , a text file , a json file , a webservice :
class UserProvider implements IUserProvider{
function __construct(Connection $connection){
$this->connection = $connection;
}
function getUsers(){
return $this->toUsers($this->connection->fetchAssoc("Select * from users"));
}
function toUsers(array $datas){
// convert user records to an array of User
(...)
return $users;
}
}
then the interface
interface IUserProvider{
/**#return array an array of User */
function getUsers();
}
if i need to get a user comments , then my comment service knows how fetch comments from a user id. So to get a user and its comments , i need 2 requests to the database. one from the UserProvider , the other from the CommentProvider.
so i have 3 layers :
my application layer ( display users , respond to requests whatever ... )
my service layer ( which has to work with a command line interface and is not aware of my web application , except for password encoding which is usually binded to the framework i use , and ACL stuffs maybe ...)
my data access layer which knows nothing about the other layers ,
the only way my layers communicate is through Models i pass from layer to layer.
And all my classes are built with a dependency injection container, so the wiring is not a problem.
Here is an exemple of an app i made,it's open source : https://github.com/Mparaiso/silex-bookmarkly
Any thoughts welcome.
easy to maintain because you have a separate entity and a separate
database class
It appears you're saying that you wish to move away from an Active Record approach to a Data Mapper/Entity/Repository approach. That's a good direction to move in because it employs better separation of concerns. You can build this yourself but you might want to take a look at solutions like Doctrine where it allows you to do something along the lines of:
$product = new Product();
$product->setName($newProductName);
$entityManager->persist($product);
The $product entity is just a POPO (Plain Old PHP Object) that contains the record data and is unaware of how it's persisted and, when persistence is needed, is passed into the entity manager to take care of the storing.
Personally, I think abstracting UserData from User is likely to be overkill. As, in this case, UserData is likely to be very similar to ProductData for example - they're still going to contain an add($data), find($id) etc.
In your case, User is a model in the MVC approach, and is totally acceptable to contain Database store/retrieve logic. You will however likely find that you are, again recreating the same DB methods in the User class that you have in other Models. This is where you may start to look at an ORM implementation. Whereby the common DB access methods are defined in an abstract class that all your models then extend and override as necessary.
I'm building a web application that needs to be able to write data to either a mysql db or an xml file, depending on the online status of the application.
In my model, I have a super class (Dao is data access object)...
abstract class Dao {
static function getInstance($online_status) {
if $online_status = 'online' {
return new DaoMySQL;
} else {
return new DaoXML;
}
}
abstract function dao_select();
abstract function dao_insert();
abstract function dao_update();
abstract function dao_delete();
}
Now, here is the part I'm confused about. I have a domain model/entity class that selects the appropriate Dao using:
$this->dao = Dao::getInstance($online_status);
So, now I have the correct data access object selected. But, the problem is I still two implementations of dao_select() and the other functions. Now, the main implementations are in the respective classes DaoMySQL and DaoXML, but dao_select() in each of those classes require different things. i.e. the DaoMySQL version needs two parameters, $table and $where_statement. DaoXML (which I haven't implemented) will need the element name, and maybe another argument, I don't know.
So, in my domain model class, after calling
$this->dao = Dao::getInstance($online_status);
is this where I need to include two separate local implementations (pertaining to the domain model/entity class only) of dao_select(), or this wrong? It just seems like I'm taking the elegance out of the process by doing something like this:
class EntityModel {
$this->dao = Dao::getInstance($online_status);
if($this->dao->type = 'mysql') {
$result = $this->dao->dao_select($table, $where);
} else {
$result = $this->dao->dao_select($xml_params);
}
}
I feel like I'm taking the simplicity out of the system... Does this approach make sense, or is there a better one?
You are doing it wrong.
Few notes to begin with:
in OOP the extends statement signifies is a relationship. Which means that, while class Duck extends Bird is all fine, writing class User extends Table is NOT.
in MVC the Model is not a class or an instance of a class. Instead it is a layer of application, mostly made of two types of elements:
domain objects: containing domain business rules and logic
data access structures: usually datamapper dealing with storage and retrieval of information
I would argue, that the third significant part of Model layer are services. But there are options on whether it is part-of or above Model.
Currently what you are trying to do is forcing a ActiveRecord (which is fine for small things, but as project grows, it becomes a burden on architecture .. which is what you are face with now) patterns to work with dynamic data sources. And to do so you are resorting to procedural calls.
Anyway, the point is that you should inject your DAO instance into your Domain Objects (what you calls "models"). And you should leave the creating of your DAO to a separate factory instance, which would be responsible for initializing them and providing them with data source (instance of PDO or file path). This way you can, not only separate the responsibilities, but also swap the storage destination "on fly".
To learn more you should investigate what is dependency injection. Here are few video that might help:
Don't Look For Things!
Global State and Singletons
Here is a quick overview of the controllers functionality in most of the application:
controller loads a specific model, gets data from it, formats the data and passes the formatted data to the view.
Now there is a search page, which needs to do a search query over entire database (all models). It needs to show each type of data in its particular formatted output on a single page as a list.
The problem:
The search controller can do the search, dynamically load model for each record type, and get the data from model. Problem comes when the data needs to be formatted. I am trying to load the specific controller from the search controller, which is causing problems.
What to do?
PS: I tried using the 'Wick' library, but it fails when the controller's format function tries to use its own model and session object, giving errors about call to a member on a non-object.
After much refactoring and trial/error, It appears that the best way to achieve the above is this way:
Keep the format function in the base controller from which all other controllers are derived. The format options are passed to the function along with the data object as arguments.
Make a static function in each derived controller, which returns the formatting options of the data.
Inside the search controller (which is itself derived from the base controller), for each data object, call the static function of its particular controller which returns the data formatting options, then use that to format the object for the view.
I guess I can say I will stick to using the model only for interaction with the database, and let everything else be done by controller. If anyone has a better solution still, I am all ears.
It sounds like you want to use the Factory design pattern
Make this a library:
class MyModelFactory {
static public function Factory($data) {
$type = key($data);
return new $type($data);
}
}
now, in your controller, you can do something like this:
$model = MyModelFactory::Factory(array($_REQUEST['model'] => $_REQUEST));
and now you have an object of whatever model was specified in $_REQUEST['model']. Be sure to take any security precautions you may need for your application to assure the user has permissions to use the model that they request
Now, since you want to be using common methods and stuff, your models should probably be based off an abstract class / interface.. so instead of
class MyModelOne extends Model {
// stuff
}
You probably want something like this, to ensure your required methods will always be available:
abstract class MyAbstractModel extends Model {
protected $search_params;
public function __construct($data = array()) {
$search_params = $data['search_params'];
}
protected function GetSearchParameters() {
return $this->search_params;
}
abstract public function GetData();
abstract public function GetColumns();
abstract public function DefineViewOptions();
}
class MyModelOne extends MyAbstractModel {
public function GetData() {
$params = array();
$params[] = $this->db->escape_str($this->GetSearchParameters());
// return whatever data you want, given the search parameter(s)
}
public function GetColumns() {
// return some columns
}
public function DefineViewOptions() {
// return some configuration options
}
}
In general you can't load another controller from within a controller in CodeIgniter (although there are mods that allow you to do something like this).
I would try creating a class for formatting your data and add it to the application/library folder. Then load, use and re-use this class throughout your various controllers.
Here is a page from the CodeIgniter documentation Creating Your Own Libraries that explains the details and conventions.
Also, if a class is overkill, creating helper functions is an even lighter approach.
The difference between libraries and helpers in CodeIgniter is that libraries are classes, helpers are just a group of php functions.
Once you have formatted your data, you can load any view from any controller, so you should still have all the re-usability you need so you DRY (don't repeat yourself)
There are a few simple approaches based on the principle of what's simpler (versus what's perfectly DRY). Here's one alternative approach I use with CodeIgniter:
Instead of trying to load multiple controllers, reuse the view fragments from your search controller (or search route, depending which you're using). This requires using the same naming conventions for your data elements so the views are interchangeable, but you should be doing this anyway.
Instead of using multiple models for search, add a single Search model that knows about the things that can be searched on. If you want to prevent duplicate SQL, reuse the SQL between models (this can be done using constants, or loading SQL from disk).
Controllers are not great candidates for reuse from your own PHP code: they route actions and requests for resources to the things themselves. They are intended to be called via HTTP, using the URI interface you've come up with. Calling them from code is a coupling you want to avoid. That said, reusing controllers from JavaScript (or via cURL) is a great, decoupled way to reuse things in any web framework.