After some time without knowing how to do this properly, and avoid duplicating code in several controllers, I searched and again to seek, but can not find a clear answer.
One case in particular, need to calculate several statistics data completed of an entity. This calculation will use in 3 different controllers.
In two of them, I'll show broken down into different layouts, and on the third, I will use this data to make a global calculation.
business logic for each calculation, involves more than 100 lines of code, I would have to triple in the different controllers.
A scheme could be:
Calculation fields completed "Data A"
Calculation fields completed "Data B"
Calculation fields completed "Data C"
With these 3 values, I make a later total calculation.
The options that I could find are:
Define a controller as a service for reuse later in other controllers but I am not clear whether it is a good practice, here's a good article analyzing this issue Symfony2: Make my Controllers Services?
on the one hand How to Define Controllers as Services
and on the other a comment for Fabien Potencier Mention best practice "controller as a service" in chapter Controller # 457 and The 'New' symfony Best Practices
Create an abstract BaseController. Of which it is spoken here, but the idea is not developed.Symfony2 and be DRY approach in controllers
Any idea how to solve this scenario?
thanks a lot
The Services seem to be much corresponding with the described usage.
Recently, I worked on an accounting solution. I used a lot of complex algorithms and I soon had very long methods, even trying to optimise code.
Services are easily callable, and their usage can make controllers so much sexier, lighter, and make big methods readable and more cuttable by using separated services corresponding to specific actions.
And they can be used in other components, as long as DependencyInjection is present, it's a sufficient raison to move your logic if you may need apply it in another context that a controller.
It's simple to declare it :
services:
acmeapp.calculation:
class: Acme\AppBundle\Services\CalculationService
arguments: ["#doctrine.orm.entity_manager", "#acmeapp.anotherservice"]
And the service
class CalculationService {
protected $em;
protected $another;
public function __constructor(EntityManager $entityManager, AnotherService $anotherService)
{
$this->em = $entityManager;
$this->another = $anotherService;
}
//...
}
The Controller-Service approach is primarily a service, with all its advantages.
A method of your service can render a view and have a route associated using the _controller attribute, like this :
display_data_a:
path: /data/A
methods: GET
defaults: { _controller: acmeapp.calculation:dealWithData }
Without extending your service from the Symfony\Bundle\FrameworkBundle\Controller\Controller, but, of course, you can use it.
Also, an abstract BaseController can be a very clean alternative, if you have many duplicated code with a few different characters between your controllers.
It's what I'm doing before use services, if the methods are corresponding with my definition of a controller, which is corresponding to what #fabpot says in your link.
The DIC mostly helps manage "global" objects. Controllers are not global objects. Moreover, a controller should be as thin as possible. It's mainly the glue between your Model and the View/Templates. So, if you need to be able to customize then, it probably means that you need to refactor them and extract the business logic from them.
More about BaseController in OOP,
The way is simple, if you have a line of code that repeats itself two or three times in a method, you use a variable.
Same for a block of code, you will use a method.
For controllers it's the same, if you have two or more objects of the same type (here a controller), you should use an AbstractController (or BaseController), move your duplicated methods in it (only once, of course), and remove them from the child controllers.
BaseController :
class BaseController extends Controller
{
/**
* Shortcut for get doctrine entity manager.
*/
public function getEntityManager()
{
return $this->getDoctrine->getEntityManager();
}
/**
* Shortcut for locate a resource in the application.
*/
public function locateResource($path)
{
return $this->get('kernel')->locateResource($path);
}
// ...
}
And use it as part of your child controllers
class ChildController extends BaseController
{
public function helloAction()
{
$em = $this->getEntityManager();
$file = $this->locateResource('#AcmeAppBundle/Resources/config/hello.yml');
// ...
}
}
Hope this helps you to avoid a lot of a duplicated code.
Related
I'm a PHP Developer, and I'm working with Symfony2 at the moment.
I would like to present my issue as follow:
I have 4 entities: User, Account, Customer, Merchant. All of them have status.
I want to build a common method named 'isValid' for them, but don't want to modify their code.
The method logic is very simple
<!-- language: php -->
public function isValid()
{
return self::STATUS_ACTIVE == $this->status;
}
By separate them and apply a HAS-A relation between it with entities, I think it will more flexible and maintainable. I don't have to duplicate my code to any entity need it, even in the future.
If you have experience. Could you please help me to pick a suitable pattern for this situation?
Creating a has-a relation between these entities makes no sense, since they are not related.
However, code duplication is almost never justifiable. I would solve it by creating a common interface (User is-a Validatable entity, Customer is-a Validatable entity) and make a trait to encapsulate the common behavior.
Create the common interface:
interface Validatable
{
public function isValid(): bool;
}
Create a trait to implement the common behaviour:
trait HasStatus
{
/**
* #var int
* #ORM\Column(type="integer")
*/
private $status;
public function isValid(): bool
{
return $this->status === EntityStatus::STATUS_ACTIVE;
}
}
Make your entities implement the new interface and put the trait to use to avoid duplication:
class User implements Validatable {
use HasStatus;
}
And use it:
/** #var Validatable[] $validatables */
$validatables = [new User(), new Merchant(), new Customer()];
foreach ($validatables as $validatable) {
var_dump($validatable->isValid());
}
Why do we need the interface? Well technically we do not need it, but I like to include it because it allows to refer to User, Customer, Merchant with a common "Validatable" typehint and it conveys your intention in code.
Messing with this it's not a good idea, the entity has status value, and setters/getters should be in entity file declaration.
I understand the DRY principle but doing it on this level... it's IMHO not a good idea.
But if you are sure that all of them have status, then use a trait in a separate file:
trait CheckStatusTrait{
return $this->status;
}
And you just add the trait to your classes:
class User {
use CheckStatusTrait
}
For that simple kind of code, it would be okay do leave it duplicated in each entity, you can add an interface with "isValid" to treat them like the same from outside if necessary.
Maybe your code to check Validation would become more complex and it makes sense to have a single class which is responsible.
Then you could make a StatusValidator class which checks if the status of a given object ist valid. It would make sense to add an interface to that kind of objects, which has a "getStatus" method, let's say the "getStatusInterface". Afterwords you can inject the StatusValidator and use it in your isValid method. Because your objects are entities, you need to use doctrine's postLoad event to inject the StatusValidator.
You also can do the same i little bit less complex by not inject the StatusValidator but ask the StatusValidator if the obejct with the getStatusInterface is valid.
Thank all for the supports. I'm also using trait to solve code duplication. However, I see that trait seem to be not a perfect one. I had to fact to disadvantages below:
Hiding the field in trait makes entity enigmatic. In real, not only will status field is available on many entities but also updatedDate, createdDate, type... It also looks mess when a class use many traits.
After a development period, the trait collects more and more method, for ex. StatusTrait can have isValid, hasStatus, setStatusDefault. But not all of entities use them. I mean some entities use isValid, some use setStatusDefault.., so we will have more mixed methods in traits. In this issue, I think that if I can implement a HAS-A relationship class, I can easily setup them at the runtime when an entity need.
By using trait, the entity class is modified, not extension. It isn't a good practice in OOP design. The entity class isn't consistent to reference with database table. Honestly, I prefer to build logic method outside the entity class.
Aboves are my vision. I only try to find a better way to implement this issue. I hope it's also useful for everyone. I had hear about ValueObject but not really understand it obviously. I will try to figure it out!
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 have read a number of sources that hint that laravel facade's ultimately exist for convenience and that these classes should instead be injected to allow loose coupling. Even Taylor Otwell has a post explaining how to do this. It seems I am not the only one to wonder this.
use Redirect;
class Example class
{
public function example()
{
return Redirect::route("route.name");
}
}
would become
use Illuminate\Routing\Redirector as Redirect;
class Example class
{
protected $redirect;
public function __constructor(Redirect $redirect)
{
$this->redirect = $redirect
}
public function example()
{
return $this->redirect->route("route.name");
}
}
This is fine except that I am starting to find that some constructors and methods are beginning to take four+ parameters.
Since the Laravel IoC seems to only inject into class constructors and certain methods (controllers), even when I have fairly lean functions and classes, I am finding that constructors of the classes are becoming packed out with the needed classes that then get injected into the needed methods.
Now I am finding that if I continue down this approach that I will need my own IoC container, which feels like reinventing the wheel if I am using a framework like laravel?
For example I use services to control the business / view logic rather than controllers dealing with them - they simply route the views. So a controller will first take its corresponding service, then then the parameter in its url. One service function also needs to check the values from a form, so then I need Request and Validator. Just like that, I have four parameters.
// MyServiceInterface is binded using the laravel container
use Interfaces\MyServiceInterface;
use Illuminate\Http\Request;
use Illuminate\Validation\Factory as Validator;
...
public function exampleController(MyServiceInterface $my_service, Request $request, Validator $validator, $user_id)
{
// Call some method in the service to do complex validation
$validation = $my_service->doValidation($request, $validator);
// Also return the view information
$viewinfo = $my_service->getViewInfo($user_id);
if ($validation === 'ok') {
return view("some_view", ['view_info'=>$viewinfo]);
} else {
return view("another_view", ['view_info'=>$viewinfo]);
}
}
This is a single example. In reality, many of my constructors already have multiple classes being injected (Models, Services, Parameters, Facades). I have started to 'offload' the constructor injection (when applicable) to method injection, and have the classes calling those methods use their constructors to inject dependencies instead.
I have been told that more than four parameters for a method or class constructor as a rule of thumb is bad practice / code smell. However I cannot see how you can really avoid this if you choose the path of injecting laravel facades.
Have I got this idea wrong? Are my classes / functions not lean enough? Am I missing the point of laravels container or do I really need to think of creating my own IoC container? Some others answers seems to hint at the laravel container being able to eliminate my issue?
That said, there doesn't seem to be a definitive consensus on the issue...
This is one of the benefits of constructor injection - it becomes obvious when you class is doing to much, because the constructor parameters grow too large.
1st thing to do is split up controllers that have too many responsibilities.
Say you have a page controller:
Class PageController
{
public function __construct(
Request $request,
ClientRepositoryInterface $clientrepo,
StaffRepositortInterface $staffRepo
)
{
$this->clientRepository = $clientRepo;
//etc etc
}
public function aboutAction()
{
$teamMembers = $this->staffRepository->getAll();
//render view
}
public function allClientsAction()
{
$clients = $this->clientRepository->getAll();
//render view
}
public function addClientAction(Request $request, Validator $validator)
{
$this->clientRepository->createFromArray($request->all() $validator);
//do stuff
}
}
This is a prime candidate for splitting into two controllers, ClientController and AboutController.
Once you have done that, if you still have too many* dependencies, its time to look for what i will call indirect dependancies (because i cant think of the proper name for them!) - dependencies that are not directly used by the dependant class, but instead passed on to another dependency.
An example of this is addClientAction - it requires a request and a validator, just to pass them to the clientRepostory.
We can re factor by creating a new class specifically for creating clients from requests, thus reducing our dependencies, and simplifying both the controller and the repository:
//think of a better name!
Class ClientCreator
{
public function __construct(Request $request, validator $validator){}
public function getClient(){}
public function isValid(){}
public function getErrors(){}
}
Our method now becomes:
public function addClientAction(ClientCreator $creator)
{
if($creator->isValid()){
$this->clientRepository->add($creator->getClient());
}else{
//handle errors
}
}
There is no hard and fast rule as to what number of dependencies are too many.
The good news is if you have built your app using loose-coupling, re-factoring is relatively simple.
I would much much rather see a constructor with 6 or 7 dependencies than a parameterless one and a bunch of static calls hidden throughout the methods
One issue with facades is that additional code has to be written to support them when doing automated unit testing.
As for solutions:
1. Resolving dependencies manually
One way of resolving dependencies, if you do not wish to do it via. constructors or methods injection, is to call app() directly:
/* #var $email_services App\Contracts\EmailServicesContract
$email_services = app('App\Contracts\EmailServicesContract');
2. Refactoring
Sometimes when I find myself passing too many services, or dependencies into a class, maybe I have violated the Single Responsibility Principe. In those cases, maybe a re-design is needed, by breaking the service or dependency into smaller classes. I would use another service to wrap up a related group of classes to serve something as a facade. In essence, it'll be a hierarchy of services/logic classes.
Example: I have a service that generate recommended products and send it out to users via email. I call the service WeeklyRecommendationServices, and it takes in 2 other services as dependency - a Recommendation services which is a black-box for generating the recommendations (and it has its own dependencies -- perhaps a repo for products, a helper or two), and an EmailService which maybe has Mailchimp as a dependency). Some lower-level dependencies, such as redirects, validators, etc. will be in those child services instead of the service that acts as the entry point.
3. Use Laravel global functions
Some of the Facades are available as function calls in Laravel 5. For instance, you can use redirect()->back() instead of Redirect::back(), as well as view('some_blade) instead of View::make('some_blade'). I believe it's the same for dispatch and some other commonly used facades.
(Edited to Add) 4. Using traits
As I was working on queued jobs today, I also observe that another way to inject dependencies is by using traits. For instance, the DispathcesJobs trait in Laravel has the following lines:
protected function dispatch($job)
{
return app('Illuminate\Contracts\Bus\Dispatcher')->dispatch($job);
}
Any class that uses the traits will have access to the protected method, and access to the dependency. It's neater than having many dependencies in the constructor or method signatures, is clearer (about what dependencies are involved) than globals and easier to customize than manual DI container calls. The drawback is that each time you invoke the function you have to retrieve the dependency from the DI container,
Class methods that form a part of the routing mechanism in Laravel (middleware, controllers, etc.) also have their type-hints used to inject dependencies - they don't all need to be injected in the constructor. This may help to keep your constructor slim, even though I'm not familiar with any four parameter limit rule of thumb; PSR-2 allows for the method definition to be stretched over multiple lines presumably because it's not uncommon to require more than four parameters.
In your example you could inject the Request and Validator services in the constructor as a compromise, since they're often used by more than one method.
As for establishing a consensus - Laravel would have to be more opinionated for applications to be similar enough to utilise a one-size-fits-all approach. An easier call though is that I think facades will go the way of the dodo in a future version.
Not so much an answer but some food for thought after talking to my colleagues who have made some very valid points;
If the internal structure of laravel is changed between versions (which has happened in the past apparently), injecting the resolved facade class paths would break everything on an upgrade - while using the default facades and helper methods mostly (if not completely) avoids this issue.
Although decoupling code is generally a good thing, the overhead of injecting these resolved facade class paths makes classes cluttered - For developers taking over the project, more time is spent trying to follow the code which could be spent better on fixing bugs or testing. New developers have to remember which injected classes are a developers and which are laravels. Developers unfamiliar with laravel under the hood have to spend time looking up the API. Ultimately the likelihood of introducing bugs or missing key functionality increases.
Development is slowed and testability isn't really improved since facades are already testable. Rapid development is a strong-point of using laravel in the first place. Time is always a constraint.
Most of the other projects use laravel facades. Most people with experience using laravel use facades. Creating a project that doesn't follow the existing trends of previous projects slows things down in general. Future inexperienced (or lazy!) developers may ignore facade injection and the project may end up with a mixed format. (Even code reviewers are human)
Well your thoughts and concerns and correct and I had them as well.
There are some benefits of Facades ( I generally dont use them ), but if you do use just I would suggest using them only in the controllers, as the controllers are just entry and exit points for me at least.
For the example you gave I'll show how I generally handle it:
// MyServiceInterface is binded using the laravel container
use Interfaces\MyServiceInterface;
use Illuminate\Http\Request;
use Illuminate\Validation\Factory as Validator;
...
class ExampleController {
protected $request;
public function __constructor(Request $request) {
// Do this if all/most your methods need the Request
$this->request = $request;
}
public function exampleController(MyServiceInterface $my_service, Validator $validator, $user_id)
{
// I do my validation inside the service I use,
// the controller for me is just a funnel for sending the data
// and returning response
//now I call the service, that handle the "business"
//he makes validation and fails if data is not valid
//or continues to return the result
try {
$viewinfo = $my_service->getViewInfo($user_id);
return view("some_view", ['view_info'=>$viewinfo]);
} catch (ValidationException $ex) {
return view("another_view", ['view_info'=>$viewinfo]);
}
}
}
class MyService implements MyServiceInterface {
protected $validator;
public function __constructor(Validator $validator) {
$this->validator = $validator;
}
public function getViewInfo($user_id, $data)
{
$this->validator->validate($data, $rules);
if ($this->validator->fails()) {
//this is not the exact syntax, but the idea is to throw an exception
//with the errors inside
throw new ValidationException($this->validator);
}
echo "doing stuff here with $data";
return "magic";
}
}
Just remember to break your code to small individual pieces that each one handles his own responsibility.
When you properly break your code, in most cases you will not have so many constructor parameters, and code will be easily testable and mocked.
Just one last note, if you are building a small application or even a page in a huge application for example a "contact page" and "contact page submit", you can surely do everything in the controller with facades, it simply depends on the complexity of the project.
I love the laravel due to its beautiful architecture.Now as from my approach i wouldnt inject all the facades in to the controller method only why? Injecting Redirect facades only in controller wrong practices as it might need in other. And mainly the things that are mostly used should be declared for all while for those who uses some or only then its best practice to inject them via method as when you declare at top it will hamper in your memory optimization as well as the speed of your code. Hope this would help
let's take two example.
Example 1 (Repository pattern)
Interface
interface FooInterface {
public function all();
}
Model(Using it in a loose term)
class FooModel implements FooInterface {
public function all()
{
return DB::('sometable')->get();
}
}
Service Provider
class FooServiceProvider extends ServiceProvider {
public function register()
{
$this->app->bind(
'Foo\FooInterface',
'Foo\FooModel'
);
}
config/app.php
'providers' => array(
// --
'Foo\FooServiceProvider'
),
And at last the controller:
use Foo\FooInterface as Model;
public function __construct(Model $model)
{
$this->model = $model;
}
Now i can access the methods as $this->model->all(). that's great! Let's look at the 2nd example.
Example 2:
controller:
public function __construct()
{
$this->model = new \Foo\FooModel();
}
now i can also access the same method as $this->model->all();
Question
As i read, the advantage of using repository pattern is, in future, easily configurable/changeable interface system. e.g.
if i change the db system, i just need to change, the bindings in the service provider.
But, i can also just easily change the model instaintiation in the controller construct to achieve the same. like, changing $this->model = new \Foo\FooModel() to $this->model = new \Bar\BarModel(); where BarModel will hold the methods of different system.
What exactly i am missing here in the aspect of advantages of a repository pattern.? or in this particular case, repository pattern doesn't give much advantage yet, in some other case it may? if that's a yes, what can be that situation?
p.s. the term model is used just for the convenince.
Being prepared for switching databases is one of the most annoying arguments one can give for the repository pattern. This one is usually followed by the ignorant "I'll never switch databases." If i had an upvote for each time I had this conversation...
Now imagine you want to add a back-end like caching or some search engine to optimize searches. This would fit really well in a repository pattern.
The general key benefit of the repository pattern is that all changes related to the back-end are more manageable than otherwise.
To demonstrate why you wouldn't want this stuff in a model; If you want to migrate a model's attributes the model needs to be fetched from the back-end differently. You might need two models in some cases. When you have this all in one model you need to apply a lot of hackery to make this even work. If the repository manages these changes the models stay clear and your code becomes manageable again.
It really comes down to how you have set-up your code. In your particular case, there wouldn't appear to be much benefit.
But what if your code required you to have multiple instantiations of your model across many different controllers? For example, maybe you have a model to your user repository. There may be many controllers which need to get information about the user.
Then it would be a hassle to go through all your controllers changing all the references (i.e. your example 2). Much better to just change the repository once (i.e. your example 1).
There is never one size fits all in coding. The best you can do is code for what you need now, with an awareness of any potential solutions which may aid flexibility in the future. My view is that the repository pattern is one of those solutions which aids flexibility. You may never need to change the model, or move to a different database, but the effort in coding with it now is minimal compared to the hassle you will have if you ever did want to change your db.
So i'm working on a framework (Yes i know it's overdone) and i was brainstorming what would be the best possible approach to achieve dynamic object creation inside a base controller. So i came up with the following solution:
Base controller
abstract class Controller extends Container
{
public function __get($obj)
{
$this->$obj = $this->get($obj)
return $this->obj;
}
{
App controller
class Welcome extends Controller
{
public function actionIndex()
{
$this->view->render('welcome');
}
}
So now let me explain whats happening. The base controller extends a container which is a dependency injection class. It holds closures for creating objects. So when we try to access undefined property in welcome controller it calls the magic __get method.
Then the base controller gets the binding from the DI container and defines it as a property so we can use it.
So everything works exactly as i wanted, but i know that magic methods are slow. I was wondering how would it impact performance when there is dozens of __get calls. Is there a better way of achieving the same thing without defining all classes manually in the base controller?
First of all, that is not a DI Container. What you have there is a Service Locator, which you have inherited. If you user Service Locator with some care, it is a quite good pattern, but people usually abuse it and it turns into an architectural anti-pattern.
When you write extends in your code, it means that when you write class B extends A, you are stating that B is just a special case of A. Controllers are not service locators.
Next .. emm. You seem to be missing the point of controllers withing MVC and MVC-inspired architectures.
A controller can send commands to the model to update the model's state (e.g., editing a document). It can also send commands to its associated view to change the view's presentation of the model (e.g., by scrolling through a document).
source: wikipedia
Basically, what you are trying to attemt would both violate the basic principles of the pattern and also ignore Single Responsibility Principle. You would be turning a controller in some variation on Factory.
What this boils down to is: why is your controller producing instance and returning them?