I'm building a Zend Framework application wherein the Model layer is separated into Services and Models. Controller actions call service methods, which in turn call model methods.
For instance: LanguagesController::addAction() checks if a form is submitted and valid. If so, it passes the form data to Service_Language::add(), where some business logic is applied to the data before calling Model_Language::add(), which effectively adds the record to the database.
This means that most controller actions will need an instance of a service class, and most methods in the service class will need an instance of a model class.
I used to do it like this (example of a Service class)
class Service_Language
{
public function add()
{
$languageModel = new Model_Language;
// perform some business logic and add record
}
public function edit()
{
$languageModel = new Model_Language;
// perform some business logic and edit record
}
public function delete()
{
$languageModel = new Model_Language;
// perform some business logic and delete record
}
}
Not only does it become cumbersome, in more complex applications where your controller actions call multiple Service methods, there's going to be multiple instances of the same Model class, which is just unnecessary.
A colleague told me to look into two options:
keep a Model instance in a property of the Service
keep a Model instance in Zend_Registry
I think the best solution would be the first option. The reason being that Zend_Registry acts as a global container. We don't want our Model instances to be available in our Controller actions, it's bad architecture. What are your opinions on this?
The first option could be implemented as follows:
class Service_Language
{
protected $_model = null;
function setModel()
{
$this->_model = new Model_Language();
}
function getModel()
{
if($this->_model == null)
{
$this->setModel();
}
return $this->_model;
}
public function add()
{
$languageModel = $this->getModel();
// perform some business logic and add
}
}
From your explanation it sounds like your services classes require tightly coupled models.
In which case I don't think public a public getter/setter for your model is necessary - would there ever realistically be a situation where you would need to set another model for the service?
In which case, assigning the model to a property makes sense - why not do this in the constructor?
class Service_Language
{
protected $_model = null;
public function __construct()
{
$this->_model = new Model_Language();
}
public function add()
{
// perform some business logic and add
$this->_model->add($data);
}
public function edit()
{
// perform some business logic and add
$this->_model->edit($data);
}
}
The constructor would have been a good option, but not every method in the service layer needs to have a model instance to do its job, so I ended up doing it like this. I'm relatively new to OOP programming, so I'm wondering if this is a good solution. Any thoughts are more than welcome.
class Service_Language
{
protected $_model = null;
protected function setModel()
{
$this->_model = new Model_Language();
}
protected function getModel()
{
if($this->_model == null)
{
$this->setModel();
}
return $this->_model;
}
// Function where model is needed
public function add($data)
{
// Perform some business logic
$this->getModel()->add($data);
// return something
}
// Function where no model is needed
public function add($data)
{
// Perform some business logic
// return something
}
}
Related
Currently, I have a service that fulfills a contract promise to our resource controller's constructor parameter list, however the contract that is provided to the controller from the service is based upon the route that is being accessed (the contract is for an action file.)
Because of that, I currently have a switch statement reading the route and making logic choices off of that in the service file. I would much prefer to have something akin to middleware handle the action contract choice, in the same way that the router provides a controller file. As you may already know, Laravel now loads in the controller's constructor before any middleware is loaded, and I need a new way of tying the route to the action, if possible.
Example set up:
// WHAT I HAVE:
// Router
Route::apiResource('foo', App\Http\Controllers\FooController::class);
Route::apiResource('bar', App\Http\Controllers\BarController::class);
Route::apiResource('foo-bar', App\Http\Controllers\FooBarController::class);
// Service
...
switch ($this->getResourceNameFromRoute()) {
case 'foo':
switch ($request->getMethod()) {
case 'GET':
return new FooShowActionContract();
case 'POST':
return new FooUpdateActionContract();
...
}
case 'bar':
...
}
// FooController
public function __construct(?ActionContract $action = null)
{
$this->action = $action;
}
how i would have like to solve this (but obviously, this will never work):
// Router
Route::apiResource('foo-bar', App\Http\Controllers\FooBarController::class)->middleware('actionMap:FooBarActionMap::class');
// Service
...
public function resolveContract()
{
return app()->make(ActionContract::class, $request);
}
// FooController
public function __construct(?ActionContract $action = null)
{
$this->action = $action;
}
// Middleware
public function handle($request, $next, $actionClassName)
{
// bind an instance of the passed in class to the app for service to instantiate
}
Do you know of a way to do this, where I can pass in the contract class name from the route call? There has to be something more elegant than a switch statement that I'm not thinking of.
my question is : How to take my business logic out of controller and transfer it to a service ???
I am currently using two separate controllers for Post model in Laravel. One for user-related logic and one for administrator-related logic.
pseudo code for AdminPostController :
class AdminPostController
{
public function index(MaybyIndexRequest $request)
{
$something = do lines of calculation
return return PostResource::collection($something);
}
public function storeAdminPost(StorePostRequest $request)
{
$something = do lines of calculation
return return PostStoreResource::collection($something);
}
}
pseudo code for UserPostController :
class UserPostController
{
public function maybyUserindex(AnotherIndexRequest $request)
{
$something = do lines of calculation
return return UserPostResource::collection($something);
}
public function storeUserPost(OtherStorePostRequest $request)
{
$something = do lines of calculation
return return UserPostStoreResource::collection($something);
}
}
I want to transfer the business logic of these two controllers to another class and call them with the help of, for example, a Facade like :
class AdminPostController
{
public function index(MaybyIndexRequest $request)
{
$something = PostService::($request);
return return PostResource::collection($something);
}
public function storeUserPost(StorePostRequest $request)
{
$something = PostService::Store($request);
return return PostStoreResource::collection($something);
}
}
But I do not know with what design patterns I should do this. Or what I'm looking for is not a good way to get the code out of the controller !!!
The way to solve this problem came to my mind :
factory pattern : a class that has two methods called user() and admin().
class PostFactory
{
public function AdminCommands()
{
return new AdminPostCommands(); // a class that contains admin
}
public function UserCommands()
{
return new UserPostCommands(); // a class that contains user related logics
}
}
That the user method returns an instance of UserPostCommands class (including the user's logic) and the AdminCommands class method (contains the's post logic) .... or :
class PostFactory
{
public function Factory(User $user)
{
if ($user->isAdmin){
return new AdminPostCommands(); // a class that contains admin
}else{
return new UserPostCommands(); // a class that contains user related logics
}
}
a class that it takes an instance of the authorized user to decide whether the AdminPostCommands OR UserPostCommands class should be Returned. each of these two classes(AdminPostCommands or UserPostCommands ) has different methods. For example, the user may not be able to delete a post . Of course, user-related methods will only be used in the user controller and vice versa.
Look's like you are deviating from the standard conventions of Laravel.
Perhaps, it might be worthwhile spending some time learning about them. For example, https://laravel.com/docs/8.x/controllers#resource-controllers on how to structure controllers.
storeUserPost should simply be store, you are in the UserPost controller, so it's implied that what you are storing will be a UserPost. Any logic required can be moved to an event or a service/utility class.
https://laravel.com/docs/8.x/events#introduction
A controller shouldn't, usually, be doing more than querying/storing/updating the model with the new data or calling other classes that perform logic and returning a view or redirect, generally speaking.
I have an issue with my app, that is "hybrid", what I mean by "hybrid" controllers have to manage both views ans APIs.
So, basically, for each controller, I must check:
if $request->wantsJson(){
... // Client rendering using Angular, return json
}else{
// Server rendering Using blade, return view
}
I don't like the fact to have a conditional in every controller method.
I also wouldn't like to have a API folder with a copy of all my controller, there would be a lot of duplicated code.
How should I do it?
I would suggest to create a separate class to handle output ex: class ResultOutput with the method, output.
So, in your controller, when you are ready to output your data, just create a new instance of ResultOutput class, and call method output with relevant data.
In ResultOutput class, inject Request object so you can determine the method of the output based on above logic.
Ex: In your controller:
return (new ResultOutput())->output($data);
In ResultOutput class:
class ResultOutput()
{
private $type;
public __construct(Request $request) {
$this->output = 'view';
if ($request->wantsJson()) {
$this->output = 'json';
}
}
public method output($data) {
if ($this->type =='view') {
// return the view with data
} else {
// return the json output
}
}
}
In this way, if you need to introduce new output method (ex: xml), you can do it without changing all your controllers.
I have a problem. I try to get the Entity-Manager without a Controller, but I found no way.
At this time, I get the Entity-Manager like this:
(Controller)
public function getEntityManager()
{
if (null === $this->_em) {
$this->_em = $this->getServiceLocator()->get('Doctrine\ORM\EntityManager');
}
return $this->_em;
}
(Plugin)
public function getEntityManager()
{
if($this->_em == null){
$this->_em = $this->getController()->getServiceLocator()->get('doctrine.entitymanager.orm_default');
}
return $this->_em;
}
You see, I need allways a controller. But, if I need the EntityManager in a model, i have a problem. I can give the model the controller, but I think this is really a bad way.
Have you any idea to get the EntityManager without a controller?
The way I handle Doctrine is through Services, i do it like the following:
//some Controller
public function someAction()
{
$service = $this->getServiceLocator()->get('my_entity_service');
return new ViewModel(array(
'entities' => $service->findAll()
));
}
The Service->findAll() would look something like this:
public function findAll()
{
return $this->getEntityRepository()->findAll();
}
Now we need to define the my_entity_service. I do this inside my Module.php
public function getServiceConfig()
{
return array(
'factories' => array(
'my_entity_service' => 'Namespace\Factory\MyServiceFactory'
)
);
}
Next I create the Factory (note: this could also be done via anonymous function inside the Module.php)
<?php
namespace Namespace\Factory;
use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\ServiceManager\FactoryInterface;
use Namespace\Model\MyModel;
class MyServiceFactory implements FactoryInterface
{
/**
* Create service
*
* #param ServiceLocatorInterface $serviceLocator
* #return mixed
*/
public function createService(ServiceLocatorInterface $serviceLocator)
{
$myModel= new MyModel();
$myModel->setEntityManager($serviceLocator->get('Doctrine\ORM\EntityManager'));
return $myModel;
}
}
Now this is a lot to chew :D I totally get that. What is happening here is actually very simple though. Instead of creating your model and somehow get to the EntityManager, you call ZF2's ServiceManager to create the Model for you and inject the EntityManager into it.
If this is still confusing to you, I'll gladly try to explain myself better. For further clarification however I'd like to know about your use case. I.e.: what for do you need the EntityManager or where exactly do u need it.
This code example is outside of the question scope
Just to give you a live example of something I do via ServiceFactories with forms:
public function createService(ServiceLocatorInterface $serviceLocator)
{
$form = new ReferenzwertForm();
$form->setHydrator(new DoctrineEntity($serviceLocator->get('Doctrine\ORM\EntityManager')))
->setObject(new Referenzwert())
->setInputFilter(new ReferenzwertFilter())
->setAttribute('method', 'post');
return $form;
}
Your real question is "How to get an Instance of ServiceManager in my own classes"
For this, take a look at the docu: (bottom of page http://zf2.readthedocs.org/en/latest/modules/zend.service-manager.quick-start.html)
By default, the Zend Framework MVC registers an initializer that will
inject the ServiceManager instance, which is an implementation of
Zend\ServiceManager\ServiceLocatorInterface, into any class
implementing Zend\ServiceManager\ServiceLocatorAwareInterface. A
simple implementation looks like the following.
so implent the ServiceLocatorInterface in your classes and then inside your class you can call:
$this->getServiceLocator()->get('doctrine.entitymanager.orm_default');
or any other service you have registered.
I have a web site I'm converting to Codeigniter and I want to simplify and decouple. I like what I've read about the Observer pattern for things like "new survey created" (which triggers a new help ticket, which triggers an email, etc).
But how do I implement such a thing in Code Igniter? I see the Symfony component but at this point I'm not concerned about understanding the system as much as figuring out how to use it in controllers and models. I have extended both CI_Model and CI_Controller already for other reasons. Would putting Observer pattern code there be the best?
I imagine a point like this: someone hits the web site and spawns a request which gets routed to a controller/action: http://localhost/test/save_changes
// warning, pseudo-code!
class Test extends MY_Model
{
public function __construct ()
{
// do I put this here?!? - or maybe in MY_Model?
// Should it be a singleton?
$this->load->library('dispatcher');
// where do I attach what I want... here?
$this->load->library('emailer');
$this->dispatcher->attach($this->emailer);
// what if I have 50 possible things that might happen
// based on any given event, from adding a user to
// deleting a survey or document? There has got to be a
// way to attach a bunch of observers that trickle
// down to each object, right?
}
public function save_changes ()
{
$this->load->model('user');
$this->user->init($this->session->userdata('user.id'))->save();
}
}
class User extends MY_Model
{
public function __construct ()
{
parent::__construct ();
// do I put this here?!?
$this->load->library('dispatcher'); // just something to call it
}
public function init($id)
{
if($this->_loadUser ($id))
{
$this->dispatcher->notify($this, 'user.loaded');
}
}
public function save($id)
{
if(parent::save())
{
$this->dispatcher->notify($this, 'user.saved');
}
}
}
class Emailer
{
public function update ($caller,$msg)
{
switch ($msg)
{
case 'user.saved':
// send user an email
// re-cache some stuff
// other things that we might want to do, including more of these:
$this->dispatch->notify('user-saved-email-sent');
break;
}
}
}
class Dispatcher
{
public function notify ($caller, $msg) { ...foreach attached do $obj->update($caller,$msg) ...}
public function attach ($obj) { ... }
public function detach ($obj) { ... }
}
I can see how powerful that would be. But I'm not sure how to simplify the setup and attaching of all of these listener/observers.
Maybe I should have a factory to create them all? It just seems like yes, they would be decoupled from the way it currently works, but it seems managing all the different objects that I'd have to 'attached' in each controller or method would become coupled in a different way.
Thanks,
Hans
Your proposed structure would have to be something like:
$this->load->library('observer_factory', 'of'); // factory for creating observers
// Observer_factory would have knowledge/access to different classes which relate
// to the pattern.
$ync = $this->of->getNotifier( $some_variable ) );
$ync->attach( $this->of->getObserver( $some_other_variable ) );
$ync->attach( $this->of->getObserver( $some_final_variable ) );
$ync->someMethod(); // someMethod calls notify
But I wonder about it. You'd have a factory class that slowly becomes all-knowing. It starts usurping the functionality of the Loader. Why load a library when my Observer_factory can handle it by doing exactly the same thing?
I think you're better off with a library or a model that knows what it is supposed to do and is well designed, then adding this class structure. I do not see the gains outweighing the costs.