SOA in Symfony2 - php

I'm currently implementing a Services Oriented Architecture in Symfony2, and I would like to have our recommandations about it.
I want to know what I need to handle in the Controller, and what I need to handle in the service.
An extreme solution would be to pass the Request to the service, and it will implement all the logic (mostly Doctrine, as I'm developping an API and not a "full" site with Twig for example), and then send back a Responsein the controller.
That means I would have to create code like this :
In the service :
if (null === $entity) {
throw new \Exception('Not found.', self::NOT_FOUND);
}
And in the controller :
try {
$service->doThings();
}
catch (\Exception $e) {
if ($e->getCode() === Service::NOT_FOUND) {
return new Response($e->getMessage(), 404);
}
}
With potentially one condition for every exception I need to throw.
Is this a good way to go ? Am I completly wrong about the implementation ?

Everything that is related to controllers logic (such as, take a request, response to a request, make a form, bind parameters, extract an entity from db (better with ParamConverter), get and set session objects, redirects, and so on) should be kept into controllers.
Everything else could be migrated into services (or other classes)

Related

Laravel custom ModelNotFoundException handling per route group

I have two route groups in my Laravel application, one for an API and one for the website itself. I've added the following code in global.php for error handling of my API.
App::error(function(ModelNotFoundException $e)
{
return Response::json('', 404);
});
But not this obviously also has effect on my normal website, where I want to return a normal view when the ModelNotFoundException occurs. Like so:
App::error(function(ModelNotFoundException $e)
{
return Response::view('404.html', [], 404);
});
How can I setup different error handlers for different route groups?
I think you shouldn't care what part of the site that threw the error, but instead respond with whatever format the client requested. In general this is set in the Accepts header of the request and can be accessed in Laravel by:
if (Request::format() == 'json')
{
//
}
(above is taken from the documentation)
In your case, this would turn your error handling function to this:
App::error(function(ModelNotFoundException $e)
{
if (Request::format() == 'json') {
return Response::json('', 404);
} else {
return Response::view('404.html', [], 404);
}
});
This automatically covers you if, for instance, you add an non-API AJAX request to the main portion of your website (for whatever reason) that could potentially trigger a ModelNotFoundException. As long as your client sends the appropriate request headers, you're good.
You could try with changing environment. For selected group you could change environment using:
$app->setEnvironment('enviromentname');
and create new environmentname.php file in start directory
But I don't know if it will work.
You could also create a session variable and in App:error add code depending on this session variable:
$value = Session::get('type');
if ($value == 'onetype') {
// something
}
else {
// something else
}

How to set RESTful methods in API URL for web services in PHP?

I am working on one project where following things are expected,
To write a web service to get users list and individual users information
To write a web service to do CRUD operations.
I understand that GET method will be useful for fetching information and execution of that API call via browser but can any one help me for following items?,
To make API call if I want to use "PUT", or "POST" or "DELETE" methods? How to do it via browser? or what would be best way to do it?
I have to use Stored procedure to fetch the information from DB for GET method?
I suggest you to use a slim Php microframework, it provides a powerful, extensible framework for building a REST API.
So, The typical REST conventions for URL requests you'll use:
GET /items: Retrieve a list of items
GET /items/22: Retrieve item 22
POST /items: Create a new item
PUT /items/22: Update item 22
DELETE /items/22: Remove item 22
Slim's URL router will help you to make it easier.
And YES, you have to create your data object to fetch from server's side, one tipycall example to get it:
// handle GET requests for /articles/:id
$app->get('/items/:id', function ($id) use ($app) {
try {
// query database for single items
$items = R::findOne('items', 'id=?', array($id));
if ($items) {
// if found, return JSON response
$app->response()->header('Content-Type', 'application/json');
echo json_encode(R::exportAll($items));
} else {
// else throw exception
throw new ResourceNotFoundException();
}
} catch (ResourceNotFoundException $e) {
// return 404 server error
$app->response()->status(404);
} catch (Exception $e) {
$app->response()->status(400);
$app->response()->header('X-Status-Reason', $e->getMessage());
}
});
Finally, this tutorial may help you to a total work around
[http://www.androidhive.info/2014/01/how-to-create-rest-api-for-android-app-using-php-slim-and-mysql-day-12-2/][1]

The best way to deal with 404 errors in MVC?

So I wrote my PHP MVC framework, and have Dispatcher class that can instantiate appropriate Controller class and call defined method passing arguments.
Now inside Dispatcher I check if this Controller exists and if method exists, what should I do if controller or method does not exist?
At the moment I just return HTTP Object that prints 404 - Page not found.
But there is no way for me to customize this message from inside application, and I want to provide users a way to customize 404 messages without editing dispatcher.
Is a good way to go to always have Error controller that would get instantiated when there is a error, and that would load lets say Error404.html view file?
So users would be able to customize this view file to fit their application design.
Is there any other way to achive this? And what would be the best way to return error from dispatcher, and let "users" or developers that are working on that MVC to easily customize 404 and other messages?
Thanks!
Since i do not know your API, I am going to guess. Lets assume that you have a bootstrap stage in your application, when the dispatcher is actually used. Something like:
$dispatcher->dispatch( $request );
Then for handling request, that try to access non-existent controllers or methods within those controllers, you can do something like this:
try
{
$dispatcher->dispatch( $request );
}
catch ( ClassNotFoundException $e )
{
$dispatcher->dispatch( new Request('/error/404/controller'));
}
catch ( MethodNotFoundException $e )
{
$dispatcher->dispatch( new Request('/error/404/method'));
}
The ClassNotFoundException can be thrown by your classloader, while dispatcher itself would always be responsible for throwing the MethodNotFoundException.
You can check, whether controller has a particular method, with method_exists(), before executing it in your dispatcher.
P.S. in my humble opinion, the Dispatcher conept is better suited for event driven architectures and not for MVC-inspired patterns in web applications.
I would propose you have an error controller that takes in an error code (number or string) as an argument. This allows you to gracefully handle various kinds of errors and be able to provide a stack trace if necessary. You can even utilize this work for 500 errors.
My answer comes with the assumption that a controller can return various actions and each action can have it's own template.
Symfony also seems to handle errors in a similar fashion. They have a separate module and action for each error.
sfContext::getInstance()->getController()->forward(sfConfig::get('sf_error_404_m‌​odule'), sfConfig::get('sf_error_404_action'));

Safely Using Magento's Pre-configuration Events

In the Magento Ecommerce System, there are three events that fire before the system is fully bootstrapped
resource_get_tablename
core_collection_abstract_load_before
core_collection_abstract_load_after
These events also fire after Magento has bootstrapped.
What's a safe and elegant (and maybe event Mage core team blessed) way to detect when Magento has fully bootstrapped so you may safely use these events?
If you attempt to use certain features in the pre-bootstrapped state, the entire request will 404. The best I've come up with (self-link for context) so far is something like this
class Packagename_Modulename_Model_Observer
{
public function observerMethod($observer)
{
$is_safe = true;
try
{
$store = Mage::app()->getSafeStore();
}
catch(Exception $e)
{
$is_safe = false;
}
if(!$is_safe)
{
return;
}
//if we're still here, we could initialize store object
//and should be well into router initialization
}
}
but that's a little unwieldy.
I don't think there is any event tailored for that.
You could add you own and file a pull request / Magento ticket to include a good one.
Until then I think the only way is to use one of the events you found and do some checks on how far Magento is initialized.
Did you try to get Mage::app()->getStores()? This might save you from the Exception catching.

OO Patterns and/or Structured Approach for "Self Healing"?

Many web application projects I've been involved with reach a point where
The application expects persisted data to be in a particular format
The application will barf if the persisted data strays from that format
Old "mystery code" is persisting data in the bad format
This usually results in the application developers cluttering the model code with lots of validation conditionals. That is
function save()
{
if($model->getSomeProp() == 'bad value')
{
$model->setSomeProp('good default value');
}
return parent::save();
}
Are there better patterns and/or systems for dealing with these situations, with said patterns and/or systems not relying on having the developers writing perfect migration scripts and/or validation code for every release? My specific interest is in how other developers approach cleaning up these sorts of (in my experience) common long-term problems.
Specifically looking for a LAMP Stack/PHP solution, but solutions and approaches from other common middleware languages/platforms (ruby, python, etc.) are more than welcome.
We use configuration-file provided list of steps that should be performed on every processed item. That enables validation, slight changes of data, lookups, retrieval and merging of certain attributes from external sources etc.
Although right now it is based on a set of Ruby classes that implement abstract Step, working according to yaml configuration, I guess that in the next rewrite I would go with pure Ruby DSL.
So at the end, you would have something like this:
HealingProcessor.on(impure_data) {
replace_bad_value :field => :some_prop, :bad_value => 'bad value', :good_value => 'good_default_value'
# etc
}
At least you are handling this type of behavior as close to the db interaction as possible, it could be a lot worse if your code-base were littered with these types of checks.
If I were tasked with cleaning this type of thing up, I think the first thing I would do is set the method to throw a custom exception code, that way I can log the calling code and find which part of my application is formatting data in an incorrect fashion.
For example you could do something like:
class CustomException extends Exception
{
const CODE_BAD_FORMAT = 1;
protected code;
public function setCode($code)
{
$this->code = $code;
}
public function getCode()
{
return $this->code;
}
}
class Model extends ParentModel
{
function save()
{
if ($model->getSomeProp() == 'bad value') {
$badValueFound = true;
$model->setSomeProp('good default value');
}
// Now that you are using try/catches you don't need a return value
parent::save();
if ($badValueFound) {
$e = new CustomException();
$e->setCode(CustomException::CODE_BAD_FORMAT);
throw $e;
}
}
}
// Calling code
try {
$model = new Model();
$model->setSomeProp('ohnoes im bad format');
$model->save();
} catch (Exception $e) {
if ($e->getCode() === CustomException::CODE_BAD_FORMAT) {
error_log(__METHOD__ . ': Called save with bad format');
} else {
throw $e; // Some other exception occurred b/c the code() didn't line up so bubble up
}
}
// All is well b/c made it through the try / catch block... so onto the next logic
Now, you can make the call to save(), and if a bad format is encountered, you can throw an exception and check the code from the call, if the code matches (expected bad format) then you can implement some logging track calling code-points.
Plus, you don't break anything in the process, because the save is still going to happen, however you will have to ensure any calls to save() are wrapped in a try/catch block, otherwise you will get exceptions if not caught properly.
Another idea might be track the bad format constructs in the model classes so you don't end up copying the same strings all over the place:
class Model
{
const BAD_FORMAT_MALFORMED_NAME = 'format for a malformed name';
const BAD_FORMAT_MALFORMED_ADDRESS = 'format for malformed address';
}
....
if($model->getSomeProp() === self::BAD_FORMAT_MALFORMED_NAME) {
....

Categories