21

The problem is well known: lib classes are loaded exclusively through the autoloader, and we cannot change them other than:

  • Copying them entirely to a codePool that is checked earlier than lib.
  • Installing the PSR-0 autoloader, specifying an autoload classmap, and then copying the file entirely into that folder structure instead. [ my current solution ]

I'm in a tough spot because I want to potentially touch many of these files - but for the sake of my sanity and stability/upgradeability of the store don't want to copy entire library classes.

Now obviously there are potential solutions to this problem, but they all come with their own set of problems:

  • Go the AOP route and use a PHP-based library like Go! AOP: Last I checked this will require Magento classes to be loaded by the composer autoloader, not just one being available. Flyingmana has done some work in this area but it's definitely not ready for production usage and my needs are more immediate. I also want to ship as an extension, and that would require more composer setup.
  • Go the AOP route and use a native PHP extension: Probably the most favorable at this point, but it would require installing a separate extension, not to mention that it would not work with HHVM.
  • Use PHP's classkit and/or runkit: It's another native PHP extension so it has the same problem as above.
  • Patch call sites to use my own namespaced (\Danslo\Varien_X) version, then extend from the original (\Varien_X): There are just way too many callsites to patch and it would require a silly amount of rewrites. Not an option.
  • Roll my own: It should be possible to:

    1. Write my own autoloader.
    2. Copy the original class to a separate folder ({root_dir}/var/tmp), wrap it in namespace \Magento { < original contents > }.
    3. Include that file.
    4. Include my modified class OriginalClass extends Magento\OriginalClass {}

The downside of this is obvious: dynamic code generation, regex, a little overhead for loading rewritten classes. But I'm almost sure that at this point it would beat copying ~5000 lines of code when I just want to touch/add ~100 lines.

I know I'm asking a lot, but is there something modern and relatively clean out there that helps solve this problem?

9

Decided to implement Go! AOP framework in Magento.

See Danslo_Aop on github.

2

Go the AOP route and use a PHP-based library like Go! AOP: Last I checked this will require Magento classes to be loaded by the composer autoloader, not just one being available. Flyingmana has done some work in this area but it's definitely not ready for production usage and my needs are more immediate. I also want to ship as an extension, and that would require more composer setup.

I want to add that Go! AOP framework can work without composer, I can help with configuration (just create an issue on github for that). Composer is needed only for transparent integration with modern applications.

Just replace an include $filename or require $filename in your bootstrap with include FilterInjectorTransformer::rewrite($filename) and configure an autoloader for Go! AOP itself.

  • 1
    Wow, nice. I will definitely try this. – Daniel Sloof Oct 13 '14 at 13:27
0

Go with the autoloader approach. Rename /all/ classes in lib with a prefix:

find lib -name '*.php' -exec sed -e 's,^class ,class Oldlib_,' {} +

Run the following "override fixer" anytime you add a file to mylib:

find lib -name '*.php' -print | while read FILE
do
    classname=$(echo ${FILE}|sed -e 's,^lib/,,' -e 's,\.php$,,' -e 's,/,_,g')
    if [ ! -f mylib/${FILE#lib/} ]; then
        # ensure is_a works by providing a stub with correct classname
        echo "class ${classname} extends Oldlib_${classname} {}" > mylib/${classname}.php
    elif [ -f mylib/${classname}.php ]; then
        # we have a new override, but the old file still exists
        rm mylib/${classname}.php
    fi
done

Teach the autoloader to return mylib/${classname}.php if it exists and mylib/full/path/to/class.php if it doesn't and mylib/full/path/to/class.php does.

Put your overrides in mylib/full/path/to/class.php and extend Oldlib_ version.

Upgrades simply rollback the prefix in lib/ upgrade it, reapply the prefix, re-run the override fixer. What's left is stuff that got moved in lib/ and was previously overridden, but that's not related to the problem. Your issue may be the number of files of the mylib/ directory, but I trust you can solve that :).

  • This approach introduces a lot of risks and things to maintain especially in regards to upgrades. It also breaks the "don't touch the core" rule. Additionally, it is not a viable option for extension developers. – beeplogic Oct 10 '14 at 0:05
  • With all due respect ~ though your solution works... it cannot be considered a modern way of rewriting lib files. Imperative programming is old school ;) – Eddie B Jul 19 '15 at 4:08
0

Also you can define custom Stream and add it on top of autoload path. It work with any autoloader and minimal adoption require. See example

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.