in a 'native' Zend Framework application I would enable the use of ezComponents by adding the autoloader of ezComponents to Zends autoloader:
$autoLoader = Zend_Loader_Autoloader::getInstance();
require_once('../library/EZComponents/Base/src/base.php');
$autoLoader->pushAutoloader(array('ezcBase', 'autoload'), 'ezc');
Now, I'm wondering how I could do the same with Magento.
Is there a way to extend Varien_Autoload (magentos autoloader) to enable easy integration of ezComponents?
OR:
Is there a way to use Zends autoloader beside the one from Magento without interfering each other?
edit:
Well, I implemented a workaround, by adding the following to function autoload() in Varien_Autoload:
if(substr($class, 0, 3) == 'ezc'){
require_once('EZComponents/Base/src/base.php');
return ezcBase::autoload($class);
}
I consider this as a very bad hack though, because it will be overwritten, when upgrading Magento. Does anyone has a better idea?
My basic approach here would be to create a custom module with an observer for the
controller_front_init_before
event. In the event observer, you'd be able to setup your autoloader however you want. There's a Magento Wiki article on Setting up Event Observers. The controller_front_init_before event is one of the first non-generic events to fire in Magento. That's why we're using it.
The big problem we need to solve is this: Magento's autoloader is on the stack first, and if it doesn't find a file (which will be the case with the EZComponent classes), its include will raise a error that will halt execution.
So, what we need to do in our event observer above is to
Remove the Varien_Autoloader from the spl_autoload stack
Register our own autoloader (we'll use Zend_Autoloader, since it ships with Magento and you seem familiar with it)
Re-add the Varien_Autoloader to the stack
There'll be a little extra jiggery-pokery we'll need to do since loading of the classes in the Zend namespace is normally handled by the autoloader we'll be removing. See comments for more details
//we need to manually include Zend_Loader, or else our zend autoloader
//will try to use it, won't find it, and then try to use Zend_Loader to
//load Zend_Loader
require_once('lib/Zend/Loader.php');
//instantiate a zend autoloader first, since we
//won't be able to do it in an unautoloader universe
$autoLoader = Zend_Loader_Autoloader::getInstance();
//get a list of call the registered autoloader callbacks
//and pull out the Varien_Autoload. It's unlikely there
//are others, but famous last words and all that
$autoloader_callbacks = spl_autoload_functions();
$original_autoload=null;
foreach($autoloader_callbacks as $callback)
{
if(is_array($callback) && $callback[0] instanceof Varien_Autoload)
{
$original_autoload = $callback;
}
}
//remove the Varien_Autoloader from the stack
spl_autoload_unregister($original_autoload);
//register our autoloader, which gets on the stack first
require_once('library/EZComponents/Base/src/base.php');
$autoLoader->pushAutoloader(array('ezcBase', 'autoload'), 'ezc');
//lets just make sure we can instantiate an EZ class
#$test = new ezcBaseFile();
#var_dump(get_class($test));
//IMPORANT: add the Varien_Autoloader back to the stack
spl_autoload_register($original_autoload);
Put the above code in an observer method and you should be good to go.
The other approach you could take, one that would fit in more with Magento patterns, would be to create a custom module that implemented an EZComponent loader.
$o = Mypackage_Mymodule_Loader::getModel('ezcBaseFile');
You'd then implement autoloader style require code in your static getModel method, and use it whenever you wanted an ezcBaseFile class. You'd probably want methods for loading a class without instantiating an object in case you wanted to call a static method on an ezcBaseFile base class.
$o = Mypackage_Mymodule_Loader::getLoadclass('ezcBaseFile');
I took a quick look at the code for Varien's autoloader and it appears to use a call to spl_autoload_register, which is a stack for performing autoloads. While I don't think you'll have much success adding to the default Magento autoloader, this means that you should be able to push another autoloader on top of Magento's.
Hope that helps!
Thanks,
Joe
I've just integrated the Sailthru_Client class into Magento, thought this might help.
I have sailthru.php, the Sailthru Client API, which contains Sailthru_Client class.
I created magentoroot/lib/Sailthru folder then copy sailthru.php into it, then renamed to Client.php making it magentoroot/lib/Sailthru/Client.php. This pattern is auto-loaded by Varien_Autoload class.
Related
How would I override the View::make('cashier::receipt'); view so that when that particular namespace is called like that, it checks my folder first and then defaults back to the vendor path.
View::addNamespace('cashier', [
'/path/to/my/views', // check first
'/path/to/original/views' // check second
]);
I believe that's how Laravel handles custom views for packages already. https://laravel.com/docs/5.2/packages#views - see Overriding Package Views here.
Laravel registers two locations to load views so they can be easily customised, the standard vendor path and something customisable.
Laravel will first check if a custom version of the view has been provided by you, for example in
resources/views/vendor/cashier.
Let me know if there was something more specific you were trying to achieve but I believe the info there will get you going.
I am running a Symfony2 app and I have a question about caching.
There is a comment on an answer here in SO that says:
you could create a command that only updates this one cached route. or
maybe consider using a kernel event listener that newly registers the
route on every request if you can afford the performance impact.
How could I update only this one cached route?
Where are cached routes stored?
The cache classes for url matching/generation can be found in app/cache/environment and are called appEnvironmentUrlGenerator.php and appEnvironmentUrlGenerator.php with "environment" being one of dev,prod, .. etc.
API reference:
http://api.symfony.com/2.3/Symfony/Component/Routing/Matcher/UrlMatcher.html
http://api.symfony.com/2.3/Symfony/Component/Routing/Generator/UrlGenerator.html
How does it work?
The router service receives a url-matcher and a url-generator when being constructed. Those are then being used inside the match() and generate() methods of the router.
https://github.com/symfony/symfony/blob/2.3/src/Symfony/Component/Routing/Router.php
For warming up the cache the RoutingCacheWarmer uses the router's warmUp() method (if it implements WarmableInterface).
Everything written by nifr is true, but doesn't really help you.
Symfony's built in router designed to support 'static' routes, so on the first cache warmup the routes will be generated and cached. If you check the mentioned cache files you will see that the routes saved in a static private variable.
There is no simple way to update a route (or change routes).
Using Symfony2 CMF
This a bit complex solution for your simple problem: http://symfony.com/doc/master/cmf/index.html
Clearing (invalidating) the cache
If you check the CacheClearCommand you will see that the implementation is quite complex. Some suggest to delete the whole cache dir, which I don't recommend, it is quite heavy and makes your site hang on until the cache is regenerated (even you can get exceptions of missing files / and logged out users if the sessions saved under the cache folder)
Calling the cache_warmer warmup has no effect if the cache already delegated.
If you just remove the two related cache file and then call the warmUp on the router would be a better solution, but also not nice one..
$cacheDir = $this->container->getParameter("kernel.cache_dir");
// Delete routing cache files
$filesystem = $this->container->get('filesystem');
$finder = new Finder();
/** #var File $file */
foreach ($finder->files()->depth('== 0')->in($cacheDir) as $file) {
if (preg_match('/UrlGenerator|UrlMatcher/', $file->getFilename()) == 1) {
$filesystem->remove($file->getRealpath());
}
}
$router = $this->container->get('router');
$router->warmUp($cacheDir);
Override the default Router class
As of 2.8 the Router class is defined with a parameter router.class
See here: https://github.com/symfony/framework-bundle/blob/v2.8.2/Resources/config/routing.xml#L63
Add something like this to your config.yml
parameters:
router.class: "My\Fancy\Router"
You can implement your own Router class, extending the original Router, and also you will need to extend the UrlMatcher and UrlGenerator classes to call the parent implementation and add your own routes to match against / generate with. This way you don't need to refresh the cache, because you can add your routes dynamically.
Note: I'm not sure if you can rely on this on long term, if you check master, the definition has changed, the parameter is not there anymore:
https://github.com/symfony/framework-bundle/blob/master/Resources/config/routing.xml#L54
More of a best practice question as I don't want to start down the wrong path.
The following link from the Magento Wiki shows how to add Attribute sets programmatically: here.
It also seems you can use the class Mage_Eav_Model_Entity_Setup and access the methods within to add the attributes etc i.e
$groupSetup = new Mage_Eav_Model_Entity_Setup('core_setup');
$groupSetup->addAttributeSet($entityTypeId, $name);
In my mind, the second option is quicker and simpler but is there a rule on how this data should be added? i.e Is one option likely to change whereas another isn't?
I am getting interested in how hole punching might work in magento inside a full page cache situation. This is not directly related to the enterprise edition and how its full page cache and hole punching mechanism might work, just in general.
Due to the way that the messages block is generated by magento i am really very curious as to how to deal with the messages block in a hole punching situation?
Have any magento devs out there tackled this before and can maybe explain to me how this particular block can be hole punched?
You will need to link a cache container to the core/messages block to be able to prevent the block from caching. To reach your goal you will need a basic module, or add this to one of your existing module, whichever is the best (read: more logical) place for you.
Within your_module/etc/ you will need to create cache.xml file:
<config>
<placeholders>
<your_module_messages>
<block>core/messages</block>
<placeholder>SYSTEM_MESSAGES</placeholder>
<container>Your_Module_Model_PageCache_NoCache</container>
</your_module_messages>
</placeholders>
</config>
The Your_Module_Model_PageCache_NoCache needs to be an extend of Enterprise_PageCache_Model_Container_Abstract and in that extend you need to overwrite the saveCache() method and directly return $this instead triggering the underlying $this->_saveCache(). Perhaps with more logic you can make this punch hole a bit smarter, but for now assume that you never know when there is a new messages, thus leaving the hole open at all times.
public function saveCache($blockContent)
{
return $this;
}
The only thing left is to trigger Magento to load the core/messages block from within the whole. This you can accomplish by adding the following method to your class.
protected function _renderBlock()
{
$block = $this->_placeholder->getAttribute('block');
//$template = $this->_placeholder->getAttribute('template');
$block = new $block;
//$block->setTemplate($template);
$block->setLayout(Mage::app()->getLayout());
return $block->toHtml();
}
It will fetch the block information from the cache.xml file and return the output of the block. Since core/messages actually generated it's own HTML you don't need to provide a template. So might as well remove those commented lines from the code.
Hopefully this helps you with your task at hand!
I created a module with an observer for the sales module with event hook ‘sales_order_shipment_save_after’ ,
My module has the following files
Company/Modulename/etc/config.xml
Company/Modulename/etc/system.xml
Company/Modulename/Model/Observer.php
there are four fields in the modules admin configuration fields
I want to get those saved data in the Observer class.
using $this->getConfigData(’password’); gives a
Call to undefined method
error
Any suggestions?
Magento uses a static method on the global Mage application object to get configuration values
$config = Mage::getStoreConfig('section_name/group/field'); //value
$config = Mage::getStoreConfig('section_name/group'); //array
An amendment to Alan's completely correct answer.
Along with path as first parameter, getStoreConfig also accepts storeid as second parameter(optional).
Well, this is useful when you want to retrieve store-wise values.
Alan has mentioned this point in his own tutorial. I guess, he has not mentioned here just because OP has not mentioned this requirement in his question.
Please refer this
In a shipment module I can use $this->getConfigData for fields in system.xml, but in another kind of modules sometimes not, e.g. extends Mage_Core_Model_Abstract, than I must use getStoreConfig. So the answer is you don't have to use always getStoreConfig. But I don't know why ...
Answer: getConfigData is just defined in a shipment class and uses getStoreConfig too. A little confusing that some functions are extra defined and unneeded in fact ...