Note: I refer to the Symfony Console component quite a lot in my question, but I think this question could be considered broader if thought about in the context of any user interface.
I am using the Symfony Console component to create a console application. I am trying to keep class coupling to a minimum, as it makes unit testing easier and is generally better practice.
My app has some processes which may take some time to complete, so I want to keep the user informed as to what is happening using progress bars and general text output as it runs. Symfony requires an instance of the Symfony Console OutputInterface to be passed to any command's execute method. So far so good; I can create progress bars and output text as I please. However, all of the heavy lifting of my app doesn't happen in the commands' execute methods and is instead within the core classes of my application. These classes shouldn't and don't know they are being used in a console application.
I am struggling to keep it this way because I don't know how to provide feedback to the console (or whatever user interface) without injecting the output class into my core. Doing so would result in tight coupling between the console output class and my application core. I have thought about using an event dispatcher (Symfony has one), but that too means my core will be coupled with the dispatcher (maybe that's fine). Ideally, I need to sort of "bubble" my application state back up to the execute method of the invoked command, where I can then perform output.
Could someone point me in the right direction, please? I feel like this must actually be quite a common case but can't find much about it.
Thanks for your time in advance!
I have succesfully used the event dispatcher approach before. You can trigger events at the start, progress, and end of processing for example, and have an event listener update the progress bar based on that.
<?php
$progress = $this->getHelperSet()->get('progress');
$dispatcher = $this->getContainer()->get('event_dispatcher');
$dispatcher->addListener('my_start_event', function (GenericEvent $event) use ($progress, $output) {
$progress->start($output, $event->getArgument('total'));
});
$dispatcher->addListener('my_progress_event', function () use ($progress) {
$progress->advance();
});
$dispatcher->addListener('my_finish_event', function () use ($progress) {
$progress->finish();
});
If you really want to avoid coupling of the event dispatcher in your service, you could extend or decorate your class (probably implementing a shared interface), and only use the event dispatcher there. You would need an extension point (public or protected method) in the base class however to be able to notify of any progress.
Related
I'm writing an yii2 app that is mainly used as an console application. I have components or (micro)services that fetches some data from a server, handle them and save the information I need to db. Of course there are several for loops and in these loops I output my current progress with the use of yii\helpers\Console::updateProgress or just echo to watch the progress and testing output (like starting with xxx products). On some events I log important informations with Yii::info() or Yii::error() and so on. Normally a cron handling tasks like pullProductUpdates or something else and i.
However in some cases I need the method (i.e. pullProductUpdates) in my webapplication too. But then there must not be any echo command active or Console::updateProgress commands.
Of course I don't have problems with the logging methods from Yii because I configured the log targets and they will not echoing something. But I'm uncertain how to handle the echo commands...
One way is to check wether $_SERER['REMOTE_ADDR'] is set or not. In console it will evaluate to null so I can warp an if {} else {} around. A probably better solution is to write a log() or progress() method. A trait could be useful?
So how should I design a solution? Is there any pattern for this? Should my services implement an interface like loggable or proressable? Or use an Logger/ Progress objects and use some kind of DI (dependency injection)? Because I don't want to write those log() or progress() methods functions more than one time. Besides I can't use a progress function in a webapplication. One reason is I don't know how to to that (if its possible with php here), but this would be another question.
Thanks in advance.
As a PHP programmer you should be aware of and use the PSR. In this case you should use dependency injection and the LoggerInterfaces.
For web application you should configure your composition root to use a logger implementation that logs to a file. For console application you should log to the terminal.
The composition root is the place where you configure your Dependency Injection Container (DIC). See more about Yii DIC here.
In order to do that you should be able to switch between these two composition roots by an environment variable or by php_sapi_name.
I am trying to refactor controllers and have taken a look at Laravel's command bus.
After reading a bunch of articles and watching a few videos, it seems that this may be a great way to refactor my controllers.
However, it also seems that I shouldn't be returning anything from a command.
When using commands
you follow the Command-query separation (CQS) principle: a function is
either a query (i.e. it returns something) or a command (i.e. it
affects state). Both are mutually exclusive. So a command is not
supposed to return anything and a query is not supposed to modify
anything.
source
I have created command CreateCustomerCommand:
namespace App\Commands;
use QuickBooks_IPP_Service_Customer;
use App\Commands\Command;
use Illuminate\Contracts\Bus\SelfHandling;
class CreateCustomer extends Command implements SelfHandling
{
private $qb;
private $customer_service;
private $customer;
private $is_same_address;
private $name;
private $primary_phone;
...
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
$this->qb = Quickbooks::Instance();
$this->qb->ipp->version(QuickBooks_IPP_IDS::VERSION_3);
$this->customer_service = new QuickBooks_IPP_Service_Customer();
$this->is_same_address = $request->input('customer.isSameAddress');
$this->name = ucwords(strtolower($request->input('customer.name')));
$this->primary_phone = $request->input('customer.primaryPhone');
}
...
/**
* Execute the command.
*
* #return void
*/
public function handle()
{
$this->customer->setDisplayName($this->name);
...
$this->customer_service->add(...);
}
}
Three questions regarding best practices:
After calling $this->customer_service->add(), a customer id is returned. How can I send this id back to the controller?
Where would it be best to incorporate an activity log?
Activity:
$activity = new Activity();
$activity->event = 'Created Customer: ' . $this->name;
$activity->user = Auth::user()->name;
$activity->save();
Would it be best to just include this at the end of CreateCustomerCommand?
What about an event?
Event:
event(new CustomerWasCreatedOrUpdated);
I am new to application architecture and am looking for a way to keep my controllers simple and maintainable. I would love if someone could point me in the right direction.
First, kudos to you for striving to keep your controllers "simple and maintainable". You may not always achieve this goal, but reaching towards it will more often than not pay off.
How can I send the ID back to the controller?
A command is a specialized case of a general service. Your command is free to declare additional public methods that interrogate the result of changing state. If the command were used by a CLI application, that application might do something like echo $this->command->getAddedCustomerId(). A web-based controller could use it similiarly.
However, the advice you quoted -- to either change state with no output or to query with output -- is sage. If you're changing state and you need to know the result of changing that state, you're probably abusing a command.
As an analogy consider the Linux command "useradd", which you would invoke like useradd -m 'Clara Barton' cbarton. That command runs and gives you just a success or failure indication. But note that you gave it the primary key, "cbarton". You can independently query for that key, like grep cbarton /etc/passwd, but importantly useradd didn't create an ID for you.
In summary, a command that changes state should at most tell you success or failure. If you wish to inspect the result of that state change, you should have given the command the keys necessary to locate the state change.
So what you probably want is a general service. A command might use that service, a controller might use the service, a model might use the service. But a service is just a general class that performs one job, and gives you the necessary API.
Where to incorporate an activity log?
Assuming you're not using PHP-AOP, a careful and rigorous practice for activity logging should be established up front and followed throughout the development lifecycle.
To a large extent, the location of the activity log depends upon the major architectural model of your system. If you rely heavily on events, then a good place might be in an extension of the Event facade or a log event. If you rely on DI extensively, then you might pass the Logger in code you decide needs logging.
In the specific case of a command, you would go either way, again depending upon your major architectural model. If you eschewed events, then you would inject the logger via Laravel's normal type-hinting DI. If you leveraged events, then you might do something like Event::fire('log', new LogState('Blah Blah', compact ($foo, $bar)));
That said, the most important thing is that you rely on a pluggable and configurable logging service, one that you can swap out and tweak for testing, QA, and production needs.
What about events?
Well, events are great. Until they're not. In my experience, events can really get complicated as they're, IMO, abused for passing data around and affecting state.
Events are like teleporters: you're going down a path, then the event fires, and suddenly you're teleported all the way across the code base and pop up in a totally different place, then you do something and get dropped right back where you were. You have to think a certain way and be efficient at following the code when Events are at play.
If Laravel events are your first introduction to events, I would discourage you from leveraging them heavily. Instead, I would suggest you limit them to one particular package or portion of your application until you get a feel for the power they offer, and the architectural and developmental rigor they require.
The problem with many design patterns for me always seems to be the best way to implement them within an existing code base.
The code base is PHP4 which is being migrated to PHP5 OOP. However this is an on going process unlikely to be completed any time soon (users always want new features!).
With the Mediator pattern where should events be registered?
Should a directory be created with lots of scripts that register events, this could then be loaded via the bootstrap.
//bootstrap.php
..
new \Listener\Something();
new \Listener\SomethingElse();
new \Listener\SomethingOtherThing();
Or would it be better to register events just before they might be triggered, there is the risk an event is triggered but has never been registered though.
//user.php
class User {
..
function ageChange() {
new \Listener\UserAge();
..
}
..
}
Or is there a different approach?
It's difficult to answer this question. It depends on case (and your case looks more like Observer pattern)
In my opinion it's better to create observer/listeners/mediator objects before they might be triggered.
You don't populate the global nameespace with lot's of classes
you don't waste memory to store objects that at the end probably won't be used
you don't waste cpu to create lot's of classes.
it's easy to modify a code behaviour and pass/create a different class. When everything is created in bootstrap you have to stick with that set
In some cases it's good to create everything during bootstrapping application. But to do that use a Service Locator pattern or Dependency Injection Pattern to inject patterns. For Dependency Injection I recommend Pimple library (http://pimple.sensiolabs.org/).
And my example of Mediator pattern written in PHP :
https://github.com/piotrmiazga/design_patterns/blob/master/src/Patterns/Mediator/Example.php
I am trying to use the new Eventmanager of the Zend Framework 2. I do understand the basic usage. But i´m not sure how to use this in a real project or rather where to go with the code.
For example:
In the introduction from Rob Allen (link above) he triggers two events in the "findById" Method. Where should the code for the listeners go to? In my opinion it doesn´t make sense to put this code also in the PhotoMapper class or am i wrong?
I confess that I have not played with it strongly yet, but I think you are right that the listener code should probably not be in the mapper. Rather, it can stand alone in an external class so it can really be a single-responsibility object - handling the events to which he subscribes - and the code can stay as DRY as possible.
As a first step, we can define what the listener needs to to do his job. Some things he knows on instantiation, others need to passed when the event is triggered.
For example, for a cache listener, I might instantiate him at Bootstrap with info about where to cache, lifetime, etc. Perhaps even grab a cache instance fully configured and ready to go from the cachemanager resource. These could be constructor params for the listener object.
Then, still probably at Bootstrap, I would register this listener with the event manager, subscribing to your event and attaching the method you wish to run when the event is triggered. Of course, that method signature needs to be compatible with the information that the event manager will give you.
I guess the idea is that this listener object has the potential benefits of:
being single-responsibilty, so lower complexity and easier to test
hopefully being sufficiently general so that this single listener can handle multiple events.
There is a little wrinkle here. It might seem like unreasonable performance hit to instantiate and register a listener just on the chance that some downstream process might trigger the event to which he is subscribed. That's where static listeners come in. Again, the registration is done early (like Bootstrap), but the listener is not instantiated until he is really needed.
Disclosure: I might have this completely wrong. So if someone wants to straighten me out, that would be great. ;-)
An Observer Design Pattern is the solution to loosely coupling objects so they can work together. In PHP you can easily implement this using just two classes.
Basically, you have a subject which is able to notify and update a list of observers of its state changes.
The problem I'm trying to solve is to know how to handler alerting the observers about different states of the object they are watching.
For example, lets say we have a file upload class to which we attach a logging class, websockets class, and a image resize class. Each of these classes that are watching want to know about different events in the upload process.
This file upload class might have three places where it needs to notify the classes listening that something has happend.
Error With Upload (alert logging class)
Upload success (alert websockets class)
Upload success and is image file (alert image resize class)
This is a very basic example, but how do you handle multiple events that different observers may need to know about? Calling notifyObservers() alone wouldn't be enough since each observer needs to know what it is being notified about.
One thought is that I could state with the call what type of event is being observed:
$this->notifyObservers('upload.error', this);
However, that would mean I would have to add custom switching to the observers themselves to know how to handle different events.
function observe($type, $object)
{
if($type === 'upload.error') $this->dosomething();
elseif($type === 'something.else') $this->otherthing();
...etc...
}
I find that very ugly as it starts to couple the observers back to the class they are observing.
Then again, if I just notify Observers without passing any information about what event just happens - they have to guess themselves what is going on which means more if() checks.
The observers aren't actually coupled to the class they are observing. The connection between the observer's handler and the observed object is made using literal string values (e.g. `upload.error'), which means that:
If you want to observe a specific object, you have to know from beforehand the names of the events it will publishing; this is the "coupling" that you don't like.
On the other hand, if you are interested in a specific event only, you can observe any type of object for that event without having any knowledge about that object.
Item 2 above is a benefit that you care about, but what to do about item 1?
If you think about it, there needs to be some way to differentiate between callbacks to the same observer if they represent different events taking place. These "identifiers", no matter what form they take, need to be packaged either into the observed object or be a part of the observer library code.
In the first instance (inside observed object) you would probably need a way for observers to query "do you ever publish event X?" before starting to observe a target for that event. The target can answer this question just fine. This leaves a bitter taste of coupling, but if you want any object to observe any other, and you have no idea what you will be observing beforehand, I don't think you can do any better.
In the second approach, you would have a number of well-known events defined (as const inside a class?) in your library. Presumably such a list of events can be made because the library tackles a concrete application domain, and that domain offers obvious choices for the events. Then, classes both internal to your library (which would end up being observed) and external to it (the observers which plug into the framework) would use these identifiers to differentiate between events. Many callback-based APIs (such as Win32) use an approach practically identical to this.