• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

aimeos / aimeos-core / 4f8b7e8d-5595-43b2-ba5c-df9921830178

17 May 2026 07:32AM UTC coverage: 92.581%. Remained the same
4f8b7e8d-5595-43b2-ba5c-df9921830178

push

circleci

aimeos
Fixed PHPStan issues

896 of 980 new or added lines in 165 files covered. (91.43%)

35 existing lines in 29 files now uncovered.

9734 of 10514 relevant lines covered (92.58%)

80.53 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

77.55
/src/MAdmin.php
1
<?php
2

3
/**
4
 * @license LGPLv3, https://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2015-2026
6
 * @package MShop
7
 */
8

9

10
namespace Aimeos;
11

12

13
/**
14
 * Factory which can create all MAdmin managers
15
 *
16
 * @package MAdmin
17
 */
18
class MAdmin
19
{
20
        private static ?\Aimeos\MShop\ContextIface $context = null;
21
        private static bool $cache = true;
22
        private static array $objects = [];
23

24

25
        /**
26
         * Enables or disables caching of class instances and clears cache
27
         *
28
         * @param bool $value True to enable caching, false to disable it
29
         * @return void
30
         */
31
        public static function cache( bool $value ) : void
32
        {
33
                self::$cache = (bool) $value;
1✔
34
                self::$context = null;
1✔
35
                self::$objects = [];
1✔
36
        }
37

38

39
        /**
40
         * Creates the required manager specified by the given path of manager names
41
         *
42
         * Domain managers are created by providing only the domain name, e.g.
43
         * "product" for the \Aimeos\MAdmin\Log\Manager\Standard or a path of names to
44
         * retrieve a specific sub-manager.
45
         * Please note, that only the default managers can be created. If you need
46
         * a specific implementation, you need to use the factory class of the
47
         * domain or the getSubManager() method to hand over specifc implementation
48
         * names.
49
         *
50
         * @param \Aimeos\MShop\ContextIface $context Context object required by managers
51
         * @param string $path Name of the domain (and sub-managers) separated by slashes, e.g "log"
52
         * @param string|null $name Name of the controller implementation ("Standard" if null)
53
         * @return \Aimeos\MShop\Common\Manager\Iface MAdmin manager object
54
         * @throws \Aimeos\MAdmin\Exception If the given path is invalid or the manager wasn't found
55
         */
56
        public static function create( \Aimeos\MShop\ContextIface $context,
57
                string $path, ?string $name = null ) : \Aimeos\MShop\Common\Manager\Iface
58
        {
59
                if( empty( $path ) ) {
8✔
60
                        throw new \LogicException( 'Manager path is empty', 400 );
×
61
                }
62

63
                if( preg_match( '/^[a-z0-9\/]+$/', $path ) !== 1 ) {
8✔
64
                        throw new \LogicException( sprintf( 'Invalid component path "%1$s"', $path ), 400 );
2✔
65
                }
66

67
                if( self::$context !== null && self::$context !== $context ) {
6✔
68
                        self::$objects = []; // clear cached objects on context change
4✔
69
                }
70
                self::$context = $context;
6✔
71

72
                $parts = explode( '/', $path );
6✔
73

74
                if( ( $domain = array_shift( $parts ) ) === null ) {
6✔
NEW
75
                        throw new \LogicException( sprintf( 'Manager path "%1$s" is empty', $path ), 400 );
×
76
                }
77

78
                if( empty( $name ) ) {
6✔
79
                        $name = $context->config()->get( 'madmin/' . $domain . '/manager/name', 'Standard' );
6✔
80
                }
81

82
                $classname = '\\Aimeos\\MAdmin\\' . ucfirst( $domain ) . '\\Manager\\' . $name;
6✔
83

84
                if( self::$cache === false || !isset( self::$objects[$classname] ) )
6✔
85
                {
86
                        $iface = '\\Aimeos\\MAdmin\\' . ucfirst( $domain ) . '\\Manager\\Iface';
6✔
87

88
                        $manager = self::createManager( $context, $classname, interface_exists( $iface ) ? $iface : null );
6✔
89
                        $manager = self::addManagerDecorators( $context, $manager, $domain );
5✔
90

91
                        self::$objects[$classname] = $manager;
5✔
92
                }
93

94
                // @phpstan-ignore return.type
95
                return self::$objects[$classname];
5✔
96
        }
97

98

99
        /**
100
         * Injects a manager object for the given path of manager names
101
         *
102
         * This method is for testing only and you must call \Aimeos\MAdmin::cache( false )
103
         * afterwards!
104
         *
105
         * @param string $classname Full name of the class for which the object should be returned
106
         * @param \Aimeos\MShop\Common\Manager\Iface|null $object Manager object for the given manager path or null to clear
107
         * @return void
108
         */
109
        public static function inject( string $classname, ?\Aimeos\MShop\Common\Manager\Iface $object = null ) : void
110
        {
111
                self::$objects['\\' . ltrim( $classname, '\\' )] = $object;
×
112
        }
113

114

115
        /**
116
         * Adds the decorators to the manager object.
117
         *
118
         * @param \Aimeos\MShop\ContextIface $context Context instance with necessary objects
119
         * @param \Aimeos\MShop\Common\Manager\Iface $manager Manager object
120
         * @param array $decorators List of decorator names that should be wrapped around the manager object
121
         * @param string $classprefix Decorator class prefix, e.g. "\Aimeos\MShop\Product\Manager\Decorator\"
122
         * @return \Aimeos\MShop\Common\Manager\Iface Manager object
123
         * @throws \LogicException If class isn't found
124
         */
125
        protected static function addDecorators( \Aimeos\MShop\ContextIface $context,
126
                \Aimeos\MShop\Common\Manager\Iface $manager, array $decorators, string $classprefix ) : \Aimeos\MShop\Common\Manager\Iface
127
        {
128
                $interface = \Aimeos\MShop\Common\Manager\Decorator\Iface::class;
5✔
129

130
                foreach( $decorators as $name )
5✔
131
                {
132
                        if( ctype_alnum( $name ) === false )
×
133
                        {
134
                                $classname = is_string( $name ) ? $classprefix . $name : '<not a string>';
×
135
                                throw new \LogicException( sprintf( 'Invalid class name "%1$s"', $classname ), 400 );
×
136
                        }
137

138
                        $classname = $classprefix . $name;
×
139

140
                        $manager = \Aimeos\Utils::create( $classname, [$manager, $context], $interface );
×
141
                }
142

143
                // @phpstan-ignore return.type
144
                return $manager;
5✔
145
        }
146

147

148
        /**
149
         * Adds the decorators to the manager object.
150
         *
151
         * @param \Aimeos\MShop\ContextIface $context Context instance with necessary objects
152
         * @param \Aimeos\MShop\Common\Manager\Iface $manager Manager object
153
         * @param string $domain Domain name in lower case, e.g. "product"
154
         * @return \Aimeos\MShop\Common\Manager\Iface Manager object
155
         */
156
        protected static function addManagerDecorators( \Aimeos\MShop\ContextIface $context,
157
                \Aimeos\MShop\Common\Manager\Iface $manager, string $domain ) : \Aimeos\MShop\Common\Manager\Iface
158
        {
159
                $config = $context->config();
5✔
160

161
                $classprefix = '\Aimeos\MShop\\' . ucfirst( $domain ) . '\Manager\Decorator\\';
5✔
162
                $decorators = array_reverse( (array) $config->get( 'madmin/' . $domain . '/manager/decorators/local', [] ) );
5✔
163
                $manager = self::addDecorators( $context, $manager, $decorators, $classprefix );
5✔
164

165
                $classprefix = '\Aimeos\MShop\Common\Manager\Decorator\\';
5✔
166
                $decorators = array_reverse( (array) $config->get( 'madmin/' . $domain . '/manager/decorators/global', [] ) );
5✔
167
                $manager = self::addDecorators( $context, $manager, $decorators, $classprefix );
5✔
168

169
                /** madmin/common/manager/decorators/default
170
                 * Configures the list of decorators applied to all admin managers
171
                 *
172
                 * Decorators extend the functionality of a class by adding new aspects
173
                 * (e.g. log what is currently done), executing the methods of the underlying
174
                 * class only in certain conditions (e.g. only for logged in users) or
175
                 * modify what is returned to the caller.
176
                 *
177
                 * This option allows you to configure a list of decorator names that should
178
                 * be wrapped around the original instances of all created managers:
179
                 *
180
                 *  madmin/common/manager/decorators/default = array( 'decorator1', 'decorator2' )
181
                 *
182
                 * This would wrap the decorators named "decorator1" and "decorator2" around
183
                 * all controller instances in that order. The decorator classes would be
184
                 * "\Aimeos\MShop\Common\Manager\Decorator\Decorator1" and
185
                 * "\Aimeos\MShop\Common\Manager\Decorator\Decorator2".
186
                 *
187
                 * @type array List of decorator names
188
                 * @since 2014.03
189
                 */
190
                $decorators = array_reverse( (array) $config->get( 'madmin/common/manager/decorators/default', [] ) );
5✔
191
                $excludes = (array) $config->get( 'madmin/' . $domain . '/manager/decorators/excludes', [] );
5✔
192

193
                foreach( $decorators as $key => $name )
5✔
194
                {
195
                        if( in_array( $name, $excludes ) ) {
×
196
                                unset( $decorators[$key] );
×
197
                        }
198
                }
199

200
                $classprefix = '\Aimeos\MShop\Common\Manager\Decorator\\';
5✔
201
                $manager = self::addDecorators( $context, $manager, $decorators, $classprefix );
5✔
202

203
                return $manager;
5✔
204
        }
205

206

207
        /**
208
         * Creates a manager object.
209
         *
210
         * @param \Aimeos\MShop\ContextIface $context Context instance with necessary objects
211
         * @param string $classname Name of the manager class
212
         * @param string $interface Name of the manager interface
213
         * @return \Aimeos\MShop\Common\Manager\Iface Manager object
214
         */
215
        protected static function createManager( \Aimeos\MShop\ContextIface $context,
216
                string $classname, ?string $interface ) : \Aimeos\MShop\Common\Manager\Iface
217
        {
218
                if( isset( self::$objects[$classname] ) ) {
6✔
219
                        // @phpstan-ignore return.type
UNCOV
220
                        return self::$objects[$classname];
×
221
                }
222

223
                // @phpstan-ignore return.type
224
                return \Aimeos\Utils::create( $classname, [$context], $interface );
6✔
225
        }
226
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc