Safely Using Magento's Pre-configuration Events - php

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.

Related

Handling MySQL transactions from PHP side: strategy and best practices

Let's say I have following dummy code that actually copy-pastes company (client) information with all related objects:
class Company extends BaseModel{
public function companyCopyPaste($existingCompanyId)
{
$this->db->transaction->start();
try{
$newCompanyId = $this->createNewCompany($existingCompanyId);
$this->copyPasteClientObjects($companyId, $newCompanyId)
$this->db->transaction->commit();
} catch(Exception $e){
this->db->transaction->rollback();
}
}
...
}
Method copyPasteClientObjects contains a lot of logic inside, like selecting/updating existing data, aggregating it and saving it.
Also whole process may take up to 10 seconds to complete (due to loads of information to process)
Easiest way is to start transaction in the begging of the method and commit it when its done. But I guess this is not the
right way to do it, but still I want to keep everything integral, also to avoid deadlocks as well. So if one of the steps fail, I want previous steps to be rolled back.
Any good advice how to handle such situations properly?
This is not an answer but some opinion.
If I get you right, you want to implement create-new-from-existing kind operation.
There is nothing really dangerous yet happen while you create new records.
I would suggest you to transform code this way:
try{
$newCompanyId = $this->createNewCompany($existingCompanyId);
$this->copyPasteClientObjects($companyId, $newCompanyId)
} catch(Exception $e){
this->deleteNewCompany($newCompanyId);
}
This way you don't need any transaction, but your deleteNewCompany should revert everything that was done but not finished. Yes it is more work to create that functionality, but to me it makes more sense then to block DB for 10 sec.
And } catch(Exception $e){ imho is not the best practice, you need to define some custom case specific Exception type. Like CopyPasteException or whatever.

SOA in Symfony2

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)

Creating a Plugin System with Phalcon

I have been looking into how to create a plugin system with Phalcon. I have checked INVO tutorial, Events Management to be more specific. It doesn't look like this is what I exactly need.
In this example it is loading the plugins manually and before establishing database connection.
I need to be able to access the database to check if the plugin actually installed and activated. So I can retrieve settings of installed & activated plugins as well as dynamically add them to the app.
I need to be able to attach the plugins pretty much anywhere; controllers (before / after / within method execution), models (before, after, within method execution) etc.
Does Phalcon provide such feature or do I have to ahead and try to create my own logic without using any framework feature?
Do you have any examples of what you would have plugins do? Or specifics about where Events Management is lacking?
I think you should be able able to get a very flexible system using dependency injection and events management.
It appears you can use the phalcon models before running the application, as long as you place the code after setting the db in the injector.
$plugins = \Plugin::find([
'active = :active:',
'bind'=>[
'active'=>1
]
]);
foreach($plugins as $plugin){
if(file_exists($plugin->filename)){
include $plugin->filename;
}
}
and in the file you could have code to subscribe to events, and/or add new dependencies.
// plugin file - for a db logger
$eventsManager = new \Phalcon\Events\Manager();
$logger = new \PhalconX\Logger\Adapter\Basic();
$profiler = $phalconDi->getProfiler();
$eventsManager->attach('db', function($event, $phalconConnection) use ($logger, $profiler) {
if ($event->getType() == 'beforeQuery') {
$profiler->startProfile($phalconConnection->getSQLStatement());
$logger->log($phalconConnection->getSQLStatement(), \Phalcon\Logger::INFO, $phalconConnection->getSQLVariables());
}
if ($event->getType() == 'afterQuery') {
$profiler->stopProfile();
}
});
or
class myHelper{ ... }
$phalconDi->set('myHelper', function() use ($phalconConfig, $phalconDi) {
$helper = new myHelper();
$helper->setDi( $phalconDi );
return $helper;
});

Dependency injection php website

The more I read about dependency injection the more I get confused. I know what it is for, that is not the problem. Trying to do some design on paper this is what I came up with and somehow it seems to me I am overlooking something.
First I imagined building an actual server that would accept incoming requests and returns responses to the user.
class Server {
private $responseBuilder;
public function __construct($responseBuilder) {
$this->responseBuilder = $responseBuilder;
}
public function run() {
// create socket, receive request
$response = $this->responsebuilder->build($request);
// send response
}
}
class Response {
private $method;
private $message;
private $url;
// getters & setters
}
class ServerBuilder {
public build() {
// construction logic
return new Server(new ResponseBuilder());
}
}
Since Apache is used to handle server requests we could replace the server with something that just send the response.
$bldr = new ResponseBuilder();
$response = $bldr->build();
// send response some way
Note that ResponseBuilder has direct access to the request ($_SERVER['..'])
and so it has everything it needs to choose the right response.
PHP however allows us to build and send responses inline. So we could have a Controller object for each page or something else that send the response and have a builder for that.
$bldr = new ControllerBuilder();
$controller = $bldr->build();
$controller->run();
class ExampleController implements Controller {
public function run() {
header("HTTP/1.1 404 Not Found");
echo 'sorry, page not found';
}
}
This all makes sense to me. But let's look at the server example again.
It calls $responseBuilder->build() and gets a response back. But this would mean that the builder (or other builders if we split it) is also responsible for anything else that might occur like authenticating a user, writing to the database,... and I can't get my head around the fact that writing to a database would be part of the object graph construction.
It would be like: Send me your request. Oh you want the homepage? I will build you your response and while I'm at it I will also do some things that have nothing to do with building it like logging what I just did and saving some of your data in a cookie and sending a mail to the administrator that you are the first visitor on this page ever, ...
You should decouple them. You have a few assumptions that I think are a bit strange. Let's start with them.
The main purpose of an incoming http request is to give back some html
I have built PHP backends that only return JSON, instead of HTML. I had a really strong border between back and front end. I only used the backend to give me data from the database, or add/edit data in the databse. The front end was just a PHP script that would build the pages any way i wanted.
Since it is the web there is in theory no use for setters since
everything can be injected in the constructor
You could use the constructor, but you don't have too. You can use setters. Dependency injection is actually just turning the flow around.
You are on the right track though. You want some class that is responsible for building your pages. So, make it only responsible for your building your pages, and take out the other responsibilities. Things like logging, authentication etc should be outside of that.
For instance if you want logging, you could have your builder create your page, and your logger could then listen to all the things your builder is doing (with the observer pattern for instance). So if your builder says: "i created the home page", you can log it with your logger, who is actually listening to your builder.
Authentication for instance should happen even before your builder starts. You don't want your builder to go to work if you can already figure out that a user is not supposed to be on a page. You could use a database for that, and whitelist any usertype/pagerequest combination.
Then for data handling, i would create a backend, that only handles requests that are supposed to give back data, or save it. The front end could then communicate to get it's content by pulling it.
I hope this clears up a few things, but I'll be happy to answer more indept questions.

Hooking into the Error processing cycle

I'm building a monitoring solution for logging PHP errors, uncaught exceptions and anything else the user wants to log to a database table. Kind of a replacement for the Monitoring solution in the commercial Zend Server.
I've written a Monitor class which extends Zend_Log and can handle all the mentioned cases.
My aim is to reduce configuration to one place, which would be the Bootstrap. At the moment I'm initializing the monitor like this:
protected function _initMonitor()
{
$config = Zend_Registry::get('config');
$monitorDb = Zend_Db::factory($config->resources->db->adapter, $config->resources->db->params);
$monitor = new Survey_Monitor(new Zend_Log_Writer_Db($monitorDb, 'logEntries'), $config->projectName);
$monitor->registerErrorHandler()->logExceptions();
}
The registerErrorHandler() method enables php error logging to the DB, the logExceptions() method is an extension and just sets a protected flag.
In the ErrorController errorAction I add the following lines:
//use the monitor to log exceptions, if enabled
$monitor = Zend_Registry::get('monitor');
if (TRUE == $monitor->loggingExceptions)
{
$monitor->log($errors->exception);
}
I would like to avoid adding code to the ErrorController though, I'd rather register a plugin dynamically. That would make integration into existing projects easier for the user.
Question: Can I register a controller plugin that uses the postDispatch hook and achieve the same effect? I don't understand what events trigger the errorAction, if there are multiple events at multiple stages of the circuit, would I need to use several hooks?
Register your plugin with stack index 101. Check for exceptions in response object on routeShutdown and postDispatch.
$response = $this->getResponse();
if ($response->isException()) {
$exceptions = $response->getException();
}
to check if exception was thrown inside error handler loop you must place dispatch() in a try-catch block
The accepted answer by Xerkus got me on the right track. I would like to add some more information about my solution, though.
I wrote a Controller Plugin which looks like that:
class Survey_Controller_Plugin_MonitorExceptions extends Zend_Controller_Plugin_Abstract
{
public function postDispatch(Zend_Controller_Request_Abstract $request)
{
$response = $this->getResponse();
$monitor = Zend_Registry::get('monitor');
if ($response->isException())
{
$monitor->log($response);
}
}
}
Note that you get an Array of Zend_Exception instances if you use $response->getException(). After I had understood that, I simply added a foreach loop to my logger method that writes each Exception to log separately.
Now almost everything works as expected. At the moment I still get two identical exceptions logged, which is not what I would expect. I'll have to look into that via another question on SO.

Categories