• Stars
    star
    729
  • Rank 62,157 (Top 2 %)
  • Language
    PHP
  • License
    MIT License
  • Created almost 3 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Customize code using closures

PHP Macro

The PHP Macro package offers closure (anonymous function) based setter dependency injection by providing a trait which can be included into any class.

composer req aimeos/macro

This package is for application, framework and library developers who want to allow customizing the behavior of their code by their users.

Why macros

In applications, frameworks or libraries which are build for customization it’s necessary to allow overwriting existing functionality to be able customize its behavior. This is where macros are very handy because they can add custom code using closures.

With the PHP Macro package, you can also allow users to overwrite methods in base classes without forcing your users to extend these classes. The PHP Macro package uses NO reflection or other hacks, just pure PHP methods.

There are some pros and cons when compared to class based depencency injection:

Pro:

  • Less code to write and much easier to implement for simple stuff
  • Custom closures can be inherited and overwritten like class methods

Con:

  • Limited static code analysis possibilities
  • Anonymous function can not be forced to implement an interface

Thus, it's not a replacement for class based depencency injection but a lightweight addition for small extension points where full-blown dependency injection using classes implementing interfaces are too much work.

Allow customization

The result of existing methods can be modified if the original method checks for an existing macro and use that instead its own implementation:

// original code

class Order
{
    use Aimeos\Macro\Macroable;

    private $id = '123';

    public function getOrderNumber()
    {
        $fcn = static::macro( 'orderNumber' );
        return $fcn ? $fcn( $this->id ) : $this->id;
    }
};

Now, you can add your custom orderNumber macro that will be used instead:

// user code

Order::macro( 'orderNumber', function( string $id ) {
   return date( 'Y' ) . '-' . $id;
} );

(new Order)->getOrderNumber(); // now returns '2020-123'

Thus, you can generate own output or pass a different result to subseqent methods within the application.

Access class properties

When macros are called in an object context, they can also access class properties:

// original code

class A
{
    use Aimeos\Macro\Macroable;
    private $name = 'A';
};

Here, the private property $name is available in the macro:

// user code

A::macro( 'concat', function( array $values ) {
   return $this->name . ':' . implode( '-', $values );
} );

(new A)->concat( ['1', '2', '3'] ); // returns 'A:1-2-3'

The macro can use the property as input for creating the returned value.

Use inherited macros

The PHP macro package also allows to inherit macros from parent classes. Then, they can access class properties of the child class just like regular class methods:

// original code

class A
{
    use Aimeos\Macro\Macroable;
    private $name = 'A';
};

class B extends A
{
    private $name = 'B';
};

Macros added to the parent class will be available in child classes too:

// user code

A::macro( 'concat', function( array $values ) {
   return $this->name . ':' . implode( '-', $values );
} );

(new B)->concat( ['1', '2', '3'] ); // returns 'B:1-2-3'

Class B extends from class A but provides a different $name property. The macro inherited from class A will now use the property of class B.

Overwrite inherited macros

It's also possible to overwrite macros inherited from parent classes as it's possible with regular class methods:

// original code

class A
{
    use Aimeos\Macro\Macroable;

    public function do() {
        return static::macro( 'concat' )( [1, 2, 3] );
    }
};

class B extends A {};

class C extends A {};

Now you can add macros to the parent class and one of the child classes:

// user code

A::macro( 'concat', function( array $values ) {
   return implode( ',', $values );
} );

C::macro( 'concat', function( array $values ) {
   return implode( '-', $values );
} );

(new B)->do(); // returns '1,2,3'

(new C)->do(); // returns '1-2-3'

This enables you to add special handling for single classes even if all other classes still use the macro added to class A.

Overwrite protected methods

Base classes often offer a set of methods that are used by the child classes. In PHP, replacing the methods of a base class is impossible and thus, you have to overwrite each child class with your own implementation.

To avoid that, the original method can use the call() method instead of calling the method of the parent class directly:

// original code

class A
{
    use Aimeos\Macro\Macroable;

    protected function getName( $prefix )
    {
        return $prefix . 'A';
    }
};

class B extends A
{
    public function do()
    {
        return $this->call( 'getName', 'B-' );
    }
};

This will check if there's a macro getName available and will call that instead of the getName() method:

// user code

(new B)->do(); // returns 'B-A'

A::macro( 'getName', function( $prefix ) {
   return $this->getName( $prefix ) . '-123';
} );

(new B)->do(); // returns 'B-A-123'

The original getName() method can still be used in the macro.

Reset macros

Sometimes, it may be necessary to remove macros from objects, especially when running automated tests. You can unset a macro by using:

class A
{
    use Aimeos\Macro\Macroable;
};

// add macro
A::macro( 'test', function() {
   return 'test';
} );

// remove macro
A::unmacro( 'test' );

More Repositories

1

aimeos-laravel

Laravel ecommerce package for ultra fast online shops, scalable marketplaces, complex B2B applications and #gigacommerce
PHP
6,508
star
2

aimeos-core

Aimeos PHP e-commerce framework for ultra fast online shops, scalable marketplaces, complex B2B applications and #gigacommerce
PHP
2,921
star
3

map

PHP arrays and collections made easy
PHP
2,613
star
4

upscheme

Database migrations and schema updates made easy
PHP
982
star
5

aimeos-headless

Aimeos cloud-native, API-first ecommerce headless distribution for ultra fast online shops, scalable marketplaces, complex B2B applications and #gigacommerce
JavaScript
759
star
6

aimeos-base

Aimeos abstraction layer for host applications
PHP
483
star
7

aimeos-symfony

Symfony e-commerce bundle for professional, ultra fast online shops, complex B2B applications and #gigacommerce
CSS
223
star
8

aimeos-typo3

TYPO3 e-commerce extension for ultra fast online shops, scalable marketplaces, complex B2B applications and #gigacommerce
PHP
204
star
9

aimeos-slim

Slim PHP package for professional, ultra fast online shops
PHP
100
star
10

ai-client-html

Aimeos e-commerce HTML client components
PHP
61
star
11

ai-admin-jqadm

Aimeos e-commerce Vue.js+Bootstrap based admin interface
PHP
60
star
12

aimeos-flow

Flow / NeosCMS e-commerce package for professional, ultra fast online shops and complex B2B applications
PHP
28
star
13

ai-laravel

Laravel adapter for Aimeos web shops and e-commerce solutions
PHP
27
star
14

ai-client-jsonapi

Aimeos frontend JSON API
PHP
24
star
15

ai-controller-jobs

Aimeos e-commerce job controllers
PHP
23
star
16

ai-controller-frontend

Aimeos frontend controler
PHP
23
star
17

ai-admin-jsonadm

Aimeos e-commerce JSON API for administrative tasks
PHP
22
star
18

ai-gettext

Gettext adapter for Aimeos core
PHP
19
star
19

ai-swiftmailer

SwiftMailer adapter for Aimeos web shops and e-commerce solutions
PHP
18
star
20

ai-cms-grapesjs

GrapesJS CMS integration into Aimeos
PHP
17
star
21

aimeos-docs

Aimeos documentation
HTML
14
star
22

ai-typo3

TYPO3 adapter for Aimeos web shops and e-commerce solutions
PHP
12
star
23

ai-admin-extadm

Aimeos e-commerce ExtJS based admin interface
PHP
11
star
24

laravel-cms

Easy, flexible and powerful API-first Laravel CMS package with JSON:API and GraphQL APIs
PHP
10
star
25

ai-fosuser

Adapter for the Symfony FOS user bundle to integrate into Aimeos online shops and e-commerce solutions
PHP
10
star
26

ai-symfony

Symfony adapter for Aimeos online shops and e-commerce solutions
PHP
10
star
27

ai-cache

Cache extension for Aimeos web shops and e-commerce solutions
PHP
9
star
28

aimeos-docker

Aimeos docker images
Dockerfile
9
star
29

ai-monolog

Monolog adapter for Aimeos web shops and e-commerce solutions
PHP
8
star
30

ai-twig

Adapter for Twig template engine
PHP
8
star
31

ai-mqueue

Aimeos message queue adapter
PHP
8
star
32

ai-filesystem

File system layer for Aimeos e-commerce components and online shop solution
PHP
8
star
33

aimeos-typo3-dist

TYPO3 e-commerce distribution for high performance web shops
PHP
7
star
34

aimeos-test

Test core and all extensions
6
star
35

ai-catsuggest

Include categories in search suggestions
PHP
5
star
36

ai-zend

Zend Framework adapter for Aimeos web shops and e-commerce solutions
PHP
4
star
37

ai-slim

Aimeos adapter for the Slim PHP micro framework
PHP
4
star
38

ai-zend2-i18n

Zend Framework 2 translation adapter for Aimeos web shops and e-commerce solutions
PHP
4
star
39

ai-container

Container extension for Aimeos web shops and e-commerce solutions
PHP
4
star
40

ai-admin-graphql

Aimeos GraphQL API admin interface
PHP
3
star
41

ai-zend2

Zend Framework 2 adapter for Aimeos web shops and e-commerce solutions
PHP
3
star
42

aimeos-vuestorefront

VueStorefront integration in Aimeos
3
star
43

ai-ezpublish

Aimeos adapter for the ezPublish platform and CMS
PHP
3
star
44

ai-flow

Flow/NeosCMS adapter for Aimeos web shops and e-commerce solutions
PHP
3
star
45

ai-shippings

Logsta connector
PHP
2
star
46

ai-lexoffice

Aimeos Lexoffice adapter: Push orders from Aimeos to Lexoffice
PHP
2
star
47

react-commerce

React.js ecommerce PWA for Aimeos
1
star