Completed
Push — v1.ns ( 96d67d...676682 )
by Timo
04:33
created

XMLContext::buildAndModify()   C

Complexity

Conditions 11
Paths 25

Size

Total Lines 29
Code Lines 22

Duplication

Lines 11
Ratio 37.93 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 11
eloc 22
c 1
b 1
f 0
nc 25
nop 3
dl 11
loc 29
rs 5.2653

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace PEIP\Context;
4
5
namespace PEIP\Context;
6
7
/*
8
 * This file is part of the PEIP package.oBuild
9
 * (c) 2009-2016 Timo Michna <timomichna/yahoo.de>
10
 * 
11
 * For the full copyright and license information, please view the LICENSE
12
 * file that was distributed with this source code.
13
 */
14
15
/**
16
 * XMLContext 
17
 *
18
 * @author Timo Michna <timomichna/yahoo.de>
19
 * @package PEIP 
20
 * @subpackage context 
21
 * @implements \PEIP\INF\Context\Context, \PEIP\INF\Channel\ChannelResolver
22
 */
23
24
25
use PEIP\Handler\CallableHandler;
26
use PEIP\Service\HeaderServiceActivator;
27
use PEIP\Channel\ChannelRegistry;
28
use PEIP\Service\ServiceProvider;
29
use PEIP\Plugins\BasePlugin;
30
use PEIP\Factory\ServiceFactory;
31
use PEIP\Base\GenericBuilder;
32
use PEIP\Channel\PollableChannel;
33
use PEIP\Channel\PublishSubscribeChannel;
34
use PEIP\Gateway\SimpleMessagingGateway;
35
use PEIP\Listener\Wiretap;
36
use PEIP\Service\ServiceActivator;
37
use PEIP\Context\XMLContextReader;
38
39
class XMLContext 
0 ignored issues
show
Bug introduced by
There is one abstract method buildAndModify in this class; you could implement it, or declare this class as abstract.
Loading history...
40
    implements 
41
        \PEIP\INF\Context\Context,
42
        \PEIP\INF\Channel\ChannelResolver {
43
44
    protected 
45
        $services = array(),
46
        $configs = array(),
47
        $gateways = array(),
48
        $nodeBuilders = array(),
49
        $channelRegistry,
50
        $serviceProvider;
51
          
52
    /**
53
     * constructor
54
     * 
55
     * @access public
56
     * @param string $string the configuration string 
57
     * @return 
58
     */
59
    public function __construct($string){
60
        $this->initNodeBuilders();
61
        $reader = new XMLContextReader($string);
62
 
63
64
        $serviceActivator = new HeaderServiceActivator(array($this, 'addConfig'), 'NODE');
65
66
        $reader->connect('read_node',  $serviceActivator);
0 ignored issues
show
Documentation introduced by
$serviceActivator is of type object<PEIP\Service\HeaderServiceActivator>, but the function expects a callable.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
67
        $reader->read();
68
69
       
70
    }
71
72
    public function addConfig($config){ 
73
        return $this->getServiceProvider()->addConfig($config);
74
    }
75
76
    public function handleReadConfig(\PEIP\INF\Event\Event $event){
77
        $this->addConfig($event->getHeader('NODE'));
78
    }
79
80
    /**
81
     * Creates and returns a XMLContext instance from a given config-string.
82
     * 
83
     * @access public
84
     * @param string $string the configuration string 
85
     * @return XMLContext the context instance
86
     * @throws RuntimeException 
87
     */      
88
    public static function createFromString($string){
89
        return new XMLContext($string);
90
    }
91
92
    /**
93
     * Creates and returns a XMLContext instance from a given config-file.
94
     * 
95
     * @access public
96
     * @param string $file the path to the configuration file 
97
     * @return XMLContext the context instance
98
     * @throws RuntimeException 
99
     */    
100
    public static function createFromFile($file){
101
        if(file_exists($file)){
102
            return self::createFromString(file_get_contents($file));
103
        }else{
104
            throw new \RuntimeException('Cannot open file  "'.$file.'".');
105
        }
106
    }
107
           
108
    /**
109
     * Initializes the context.
110
     * 
111
     * @access protected
112
     * @return void
113
     */
114
    protected function init(){
115
        $xml = $this->simpleXML;
0 ignored issues
show
Bug introduced by
The property simpleXML does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
116
        $this->channelRegistry = ChannelRegistry::getInstance();
117
        // register this context as a service if id is set.
118
        if($xml['id']){
119
            $this->services[(string)$xml['id']] = $this;    
120
        }
121
        // build services
122
        foreach($xml->children() as $entry){
123
            $this->buildNode($entry);
124
        }
125
    }    
126
     
127
    /**
128
     * Registers a callable as builder for given node-name
129
     * 
130
     * @implements \PEIP\INF\Context\Context
131
     * @access public
132
     * @param string $nodeName the name of the node 
133
     * @param callable $callable a callable which creates instances for node-name 
134
     */
135
    public function registerNodeBuilder($nodeName, $callable){
136
       return  $this->getServiceProvider()->registerNodeBuilder($nodeName, $callable);
137
    }
138
   
139
    /**
140
     * Registers a context-plugin instance.
141
     * 
142
     * @implements \PEIP\INF\Context\Context
143
     * @access public
144
     * @param \PEIP\INF\Context\Context_Plugin $plugin a plugin instance
145
     */
146
    public function addPlugin(\PEIP\INF\Context\ContextPlugin $plugin){ 
147
        $plugin->init($this);   
148
    }
149
  
150
    /**
151
     * Creates a registers a context-plugin instance from a config object.
152
     * 
153
     * @access public
154
     * @param array $config configuration for the plugin 
155
     * @return 
156
     */
157
    public function createPlugin(array $config){
158
        $plugin = $this->createService($config);    
159
        $this->addPlugin($plugin);
160
    }
161
  
162
    /**
163
     * Adds a context instance to the services stack.
164
     * Note: Object instances registered with the included context will
165
     * overwrite any instance with the same id on the including context.
166
     * If you need a different behavior, please, make use
167
     * of an include-tag in your configuration before your main
168
     * configuration part. 
169
     * eg.:
170
     * <config>
171
     *    <include file="path/to/include/context/config.xml"/>
172
     *    <!-- main configuration -->
173
     * </config>     
174
     * 
175
     * @access public
176
     * @param XMLContext $config the config to include
0 ignored issues
show
Bug introduced by
There is no parameter named $config. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
177
     */    
178
    public function includeContext(XMLContext $context){
179
        $this->services = array_merge($this->services, $context->getServices());
180
    }
181
182
    /**
183
     * Creates and adds a context from file. 
184
     * 
185
     * @see XMLContext::includeContext
186
     * @access public
187
     * @param XMLContext $context the config to include
0 ignored issues
show
Bug introduced by
There is no parameter named $context. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
188
     */    
189
    public function includeContextFromFile($filePath){
190
        if(file_exists($filePath)){
191
            $this->includeContextFromString(file_get_contents($filePath));
192
        }           
193
    }
194
195
    /**
196
     * Creates and adds a context from string. 
197
     * 
198
     * @see XMLContext::includeContext
199
     * @access public
200
     * @param string $configString the config to include
201
     */    
202
    public function includeContextFromString($configString){
203
        $context = new XMLContext($configString);
204
        $this->includeContext($context);            
205
    }   
206
    
207
    /**
208
     * Creates a context instance from a config object and includes it. 
209
     * 
210
     * @see XMLContext::includeContext
211
     * @access protected
212
     * @param object $config the configuration for the context
213
     */    
214
    protected function createContext($config){
215
        if((string)$config['file'] != ''){
216
            $this->includeContextFromFile((string)$config['file']);
217
        }           
218
    }   
219
     
220
221
    public function getServiceProvider(){
222
        return isset($this->serviceProvider)
223
            ? $this->serviceProvider
224
            : $this->serviceProvider = new ServiceProvider();
225
    }
226
227
    /**
228
     * Registers the build-methods for the main-components with this context.
229
     * Note: This method and subsequent registered methods of this class are
230
     * candidates for refactoring. Because this class has grown much to large
231
     * and for better design and flexibility the core builder-methods should be
232
     * put into a core context-plugin. 
233
     * 
234
     * @see XMLContext::includeContext
235
     * @access protected
236
     */     
237
    protected function initNodeBuilders(){
238
        $builders = array(
0 ignored issues
show
Unused Code introduced by
$builders is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
239
            'include' => 'createContext',
240
            'plugin' => 'createPlugin',
241
            'channel' => 'createChannel',
242
            'publish_subscribe_channel' => 'createSubscribableChannel',
243
            'service' => 'initService',
244
            'service_activator' => 'createServiceActivator',
245
            'gateway' => 'createGateway',
246
            'splitter' => 'createSplitter',
247
            'transformer' => 'createTransformer',
248
            'router' => 'createRouter',
249
            'aggregator' => 'createAggregator',
250
            'wiretap' => 'createWiretap'
251
                
252
        );
253
        $plugin = new BasePlugin();
254
        $this->addPlugin($plugin); return;
255
        foreach($builders as $nodeName => $method){
0 ignored issues
show
Unused Code introduced by
foreach ($builders as $n...ray($this, $method)); } does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
256
            $this->registerNodeBuilder($nodeName, array($this, $method));   
257
        }       
258
    }
259
260
    /**
261
     * Builds a specific configuration-node. Calls the build-method which
262
     * is registered with the node-name. If none is registered does nothing. 
263
     * 
264
     * @see XMLContext::doCreateChannel
265
     * @access protected
266
     * @param object $node configuration-node
267
     * @return void
268
     */
269
    protected function buildNode($node){
270
        $nodeName = $node->getName();
271
        // call the builder method registered for the node.
272
        if(array_key_exists($nodeName, $this->nodeBuilders)){
273
            call_user_func($this->nodeBuilders[$nodeName], $node);
274
        }           
275
    }
276
   
277
    /**
278
     * Resolves a channel-name and returns channel-instace if found.
279
     * Main purpose is to allow the context to act as a channel-resolver for 
280
     * mainly routers, hence implement the \PEIP\INF\Channel\ChannelResolver pattern.
281
     * Note: Channels are registerd globally in a registry per thread/process.
282
     * This allows to connect many context instances through channels without
283
     * coupling them by in a include in configuration.  
284
     * 
285
     * @see \PEIP\INF\Channel\ChannelResolver
286
     * @implements \PEIP\INF\Channel\ChannelResolver
287
     * @access public
288
     * @param string $channelName the name/id of the channel to return 
289
     * @return \PEIP\INF\Channel\Channel
290
     */
291
    public function resolveChannelName($channelName){
292
        return $this->channelRegistry->get($channelName);
293
    }   
294
     
295
    /**
296
     * returns a service for a given id
297
     * 
298
     * @implements \PEIP\INF\Context\Context
299
     * @access public
300
     * @param mixed $id the id for the service
301
     * @return object the service instance if found
302
     */
303
    public function getService($id){     
304
        return $this->getServiceProvider()->provideService($id);
305
    }
306
             
307
    /**
308
     * returns all registered services
309
     * 
310
     * @access public
311
     * @return array registered services
312
     */
313
    public function getServices(){    
314
        return $this->getServiceProvider()->getServices();
315
    }  
316
    
317
    /**
318
     * Checks wether a service with a given id is registered
319
     * 
320
     * @access public
321
     * @param mixed $id the id for the service 
322
     * @return boolean wether service is registered
323
     */
324
    public function hasService($id){
325
        return isset($this->services[$id]);
326
    }
327
      
328
    /**
329
     * Tries to receive a service for a given id.
330
     * Throws RuntimeException if no service is found
331
     * 
332
     * @access protected
333
     * @throws RuntimeException
334
     * @param mixed $id the id for the service 
335
     * @return object the service instance if found
336
     * 
337
     */
338
    protected function requestService($id){
339
        $service = $this->getService($id);
340
        if($service === NULL){
341
            throw new \RuntimeException('Service "'.$id.'" not found.');
342
        } 
343
        return $service;
344
    }
345
    
346
    /**
347
     * Creates and initializes service instance from a given configuration.
348
     * Registers instance if id is set in config.
349
     * 
350
     * @access protected
351
     * @param object $config 
352
     * @return object the initialized service instance
353
     */
354
    protected function initService($config){
355
        $id = trim((string)$config['id']);
356
        if($id != ''){
357
            return $this->services[$id] = $this->createService($config);    
0 ignored issues
show
Documentation introduced by
$config is of type object, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
358
        }   
359
    }
360
 
361
    /**
362
     * Creates and initializes service instance from a given configuration. 
363
     * 
364
     * @access public
365
     * @param $config 
366
     * @return object the initialized service instance
367
     */
368
    public function createService(array $config){
369
        return ServiceFactory::createService($config);      
370
    }
371
 
372
      
373
    /**
374
     * returns gateway instance forgiven id.
375
     * the use of this method is deprecated. Use getService instead.
376
     * 
377
     * @deprecated 
378
     * @access public
379
     * @param mixed $id the id ofthe gateway 
380
     * @return object the gateway instance
381
     */
382
    public function getGateway($id){ 
383
        return $this->getServiceProvider()->provideService($id); 
384
    }   
385
  
386
    /**
387
     * Creates a pollable channel from a configuration object.
388
     * 
389
     * @see XMLContext::doCreateChannel
390
     * @access public
391
     * @param object $config configuration object for the pollable channel. 
392
     * @return \PEIP\INF\Channel\Channel the created pollable channel instance
393
     */
394
    public function createChannel($config){
395
        return $this->doCreateChannel($config, 'PollableChannel');        
396
    }
397
  
398
    /**
399
     * Creates a subscribable channel from a configuration object.
400
     * 
401
     * @see XMLContext::doCreateChannel
402
     * @access public
403
     * @param object $config configuration object for the subscribable channel. 
404
     * @return \PEIP\INF\Channel\Channel the created subscribable channel instance
405
     */
406
    public function createSubscribableChannel($config){
407
        return $this->doCreateChannel($config, 'PublishSubscribeChannel');       
408
    }   
409
   
410
    /**
411
     * Creates and registers arbitrary channel from a configuration object and additional information.
412
     * 
413
     * @access public
414
     * @param object $config configuration object for the channel. 
415
     * @param string $defaultChannelClass the channel class to use if none is set in config 
416
     * @param $additionalArguments additional arguments for the channel constructor (without first arg = id)
417
     * @return \PEIP\INF\Channel\Channel the created channel instance
418
     */
419
    public function doCreateChannel($config, $defaultChannelClass, array $additionalArguments = array()){
420
        $id = (string)$config['id'];
421
        if($id != ''){ 
422
            array_unshift($additionalArguments, $id);
423
            $channel = ServiceFactory::buildAndModify($config, $additionalArguments, $defaultChannelClass);
0 ignored issues
show
Documentation introduced by
$config is of type object, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
424
            $this->channelRegistry->register($channel);
425
            return $channel;
426
        }
427
    }
428
       
429
    /**
430
     * Creates and registers gateway from a configuration object.
431
     * 
432
     * @see XMLContext::initNodeBuilders
433
     * @access public
434
     * @param object $config configuration object for the gateway. 
435
     * @param string $defaultClass the class to use if none is set in config. 
436
     * @return object the gateway instance
437
     */
438 View Code Duplication
    public function createGateway($config, $defaultClass = false){
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
439
        $args = array(
440
            $this->getRequestChannel($config), 
441
            $this->getReplyChannel($config)
442
        );
443
        $defaultClass = $defaultClass ? $defaultClass : 'SimpleMessagingGateway';
444
        $gateway = ServiceFactory::buildAndModify($config, $args, $defaultClass);
0 ignored issues
show
Documentation introduced by
$config is of type object, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
445
        $id = (string)$config["id"];
446
        $this->gateways[$id] = $gateway;
447
        return $gateway;    
448
    }
449
  
450
    /**
451
     * Creates and registers router from a configuration object.
452
     * Adds this context instance as channel-resolver to the router if
453
     * none is set in config. 
454
     * 
455
     * @see XMLContext::resolveChannelName
456
     * @see XMLContext::initNodeBuilders
457
     * @access public
458
     * @param object $config configuration object for the gateway. 
459
     * @param string $defaultClass the class to use if none is set in config. 
460
     * @return object the router instance
461
     */
462 View Code Duplication
    public function createRouter($config, $defaultClass = false){
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
463
        $resolver = $config['channel_resolver'] ? (string)$config['channel_resolver'] : $this->channelRegistry;
464
        return ServiceFactory::buildAndModify($config, array(
0 ignored issues
show
Documentation introduced by
$config is of type object, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
465
            $resolver,
466
            $this->doGetChannel('input', $config)
467
        ), $defaultClass);
0 ignored issues
show
Bug introduced by
It seems like $defaultClass defined by parameter $defaultClass on line 462 can also be of type false; however, PEIP\Factory\ServiceFactory::buildAndModify() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
468
    }
469
470
    /**
471
     * Creates and registers splitter from a configuration object.
472
     * 
473
     * @see XMLContext::initNodeBuilders
474
     * @see XMLContext::createReplyMessageHandler
475
     * @access public
476
     * @param object $config configuration object for the splitter. 
477
     * @return object the splitter instance
478
     */    
479
    public function createSplitter($config){
480
        return $this->createReplyMessageHandler($config);           
481
    }   
482
 
483
    /**
484
     * Creates and registers transformer from a configuration object.
485
     * 
486
     * @see XMLContext::initNodeBuilders
487
     * @see XMLContext::createReplyMessageHandler
488
     * @access public
489
     * @param object $config configuration object for the transformer. 
490
     * @return object the transformer instance
491
     */    
492
    public function createTransformer($config){
493
        return $this->createReplyMessageHandler($config);           
494
    } 
495
      
496
    /**
497
     * Creates aggregator from a configuration object.
498
     * 
499
     * @see XMLContext::initNodeBuilders
500
     * @see XMLContext::createReplyMessageHandler
501
     * @access public
502
     * @param object $config configuration object for the aggregator. 
503
     * @return object the aggregator instance
504
     */  
505
    public function createAggregator($config){
506
        return $this->createReplyMessageHandler($config);       
507
    }
508
  
509
    /**
510
     * Creates wiretap from a configuration object.
511
     * 
512
     * @see XMLContext::initNodeBuilders
513
     * @see XMLContext::createReplyMessageHandler
514
     * @access public
515
     * @param object $config configuration object for the wiretap. 
516
     * @return object the wiretap instance
517
     */ 
518
    public function createWiretap($config){
519
        return $this->createReplyMessageHandler($config, 'Wiretap');       
520
    }
521
  
522
    /**
523
     * Creates a reply-message-handler from a configuration object.
524
     * 
525
     * @see XMLContext::initNodeBuilders
526
     * @access public
527
     * @param object $config configuration object for the reply-message-handler. 
528
     * @param string $defaultClass the class to use if none is set in config.
529
     * @return object the reply-message-handler instance
530
     */ 
531
    public function createReplyMessageHandler($config, $defaultClass = false){
532
        return ServiceFactory::buildAndModify($config, $this->getReplyHandlerArguments($config), $defaultClass); 
0 ignored issues
show
Documentation introduced by
$config is of type object, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Bug introduced by
It seems like $defaultClass defined by parameter $defaultClass on line 531 can also be of type false; however, PEIP\Factory\ServiceFactory::buildAndModify() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
533
    }
534
    
535
    /**
536
     * Creates and registers service-activator from a configuration object.
537
     * 
538
     * @see XMLContext::initNodeBuilders
539
     * @access public
540
     * @param object $config configuration object for the service-activator. 
541
     * @param string $defaultClass the class to use if none is set in config. 
542
     * @return object the service-activator instance
543
     */
544 View Code Duplication
    public function createServiceActivator($config, $defaultClass = false){
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
545
        $method = (string)$config['method'];
546
        $service = $this->getService((string)$config['ref']);
547
        if($method && $service){        
548
            $args = $this->getReplyHandlerArguments($config);
549
            array_unshift($args,array(
550
                $service,
551
                $method             
552
            )); 
553
            $defaultClass = $defaultClass ? $defaultClass : 'ServiceActivator';
554
            return ServiceFactory::buildAndModify($config, $args, $defaultClass);                
0 ignored issues
show
Documentation introduced by
$config is of type object, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
555
        }
556
    }   
557
    
558
    
559
    /**
560
     * Provides a service for a configuration object.
561
     * Returns reference to a service if configured, otherwise
562
     * creates new service instance.
563
     * 
564
     * @see XMLContext::getService
565
     * @see XMLContext::createService
566
     * @access protected
567
     * @param object $config configuration object for the service. 
568
     * @return 
569
     */
570
    protected function provideService($config){
571
        $ref = trim((string)$config['ref']);
572
        if($ref != ''){
573
            $service = $this->getService($ref); 
574
        }else{
575
            $service = $this->createService($config);
0 ignored issues
show
Documentation introduced by
$config is of type object, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
576
        }
577
        return $service;
578
    }
579
580
    /**
581
     * Utility method to return a (camel-cased) setter method-name for a property of a config-obect.
582
     * Returns setter-name if set in configuration, otherwise if name of property is set, returns
583
     * camel-cased setter-name build from property-name.
584
     * 
585
     * @see XMLContext::getService
586
     * @see XMLContext::createService
587
     * @access protected
588
     * @param object $config configuration object for the setter-method. 
589
     * @return string camel-cased 
590
     */    
591
    protected static function getSetter($config){
592
        if($config['setter']){
593
            $setter = (string)$config['setter'];
594
        }elseif($config['name']){
595
            $setter = 'set'.ucfirst((string)$config['name']);   
596
        }
597
        return $setter;     
0 ignored issues
show
Bug introduced by
The variable $setter does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
598
    }
599
    
600
    /**
601
     * Builds single argument (to call a method with later) from a config-obect.
602
     * 
603
     * @access protected
604
     * @param object $config configuration object to create argument from.  
605
     * @return mixed build argument 
606
     */
607 View Code Duplication
    protected function buildArg($config){ 
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
608
        if(trim((string)$config['value']) != ''){
609
            $arg = (string)$config['value'];
610
        }elseif($config->getName() == 'value'){
611
            $arg = (string)$config;
612
        }elseif($config->getName() == 'list'){
613
            $arg = array();
614
            foreach($config->children() as $entry){ 
615
                if($entry->getName() == 'value'){
616
                    if($entry['key']){
617
                        $arg[(string)$entry['key']] = (string)$entry;   
618
                    }else{
619
                        $arg[] = (string)$entry;
620
                    }
621
                }elseif($entry->getName() == 'service'){
622
                    $arg[] = $this->provideService($entry);
623
                }
624
            }
625
        }elseif($config->getName() == 'service'){
626
            $arg = $this->provideService($config);
627
        }elseif($config->list){
628
            $arg = $this->buildArg($config->list);
629
        }elseif($config->service){
630
            $arg = $this->buildArg($config->service);
631
        } 
632
        return $arg; 
0 ignored issues
show
Bug introduced by
The variable $arg does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
633
    }       
634
635
    
636
    /**
637
     * Utility method to create arguments for a reply-handler constructor from a config-obect.
638
     * 
639
     * @access protected
640
     * @param object $config configuration object to create arguments from.  
641
     * @return mixed build arguments 
642
     */
643 View Code Duplication
    protected function getReplyHandlerArguments($config){
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
644
        $args = array(
645
            $this->doGetChannel('input', $config),
646
            $this->doGetChannel('output', $config)
647
        );
648
        if($args[0] == NULL){
649
            throw new \RuntimeException('Could not receive input channel.');
650
        }
651
        return $args;
652
    }
653
    
654
    
655
    /**
656
     * Utility method to return a request-channel from a config-obect.
657
     * 
658
     * @see XMLContext::doGetChannel
659
     * @access protected
660
     * @param object $config configuration object to return request-channel from. 
661
     * @return \PEIP\INF\Channel\Channel request-channel
662
     */
663
    protected function getRequestChannel($config){
664
        return $this->doGetChannel('request', $config); 
665
    }
666
    
667
    
668
    /**
669
     * Utility method to return a reply-channel from a config-obect.
670
     * 
671
     * @see XMLContext::doGetChannel
672
     * @access protected
673
     * @param object $config configuration object to return reply-channel from. 
674
     * @return \PEIP\INF\Channel\Channel reply-channel
675
     */
676
    protected function getReplyChannel($config){
677
        return $this->doGetChannel('reply', $config);   
678
    }
679
    
680
    
681
    /**
682
     * Utility method to return a certainn channel from a config-obect.
683
     * 
684
     * @access protected
685
     * @param string the configuration type ofthe channel (e.g.: 'reply', 'request')
686
     * @param object $config configuration object to return channel from. 
687
     * @return \PEIP\INF\Channel\Channel reply-channel
688
     */
689 View Code Duplication
    public function doGetChannel($type, $config){
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
690
        $channelName = $config[$type."_channel"] 
691
            ? $config[$type."_channel"] 
692
            : $config["default_".$type."_channel"];
693
        return $this->serviceProvider->provideService(trim((string)$channelName));
694
        $channel =  $this->services[trim((string)$channelName)];
0 ignored issues
show
Unused Code introduced by
$channel = $this->servic...string) $channelName)]; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
695
        if($channel instanceof \PEIP\INF\Channel\Channel){
0 ignored issues
show
Bug introduced by
The variable $channel seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
696
            return $channel;    
697
        }else{
698
            return NULL;
699
        }       
700
    }
701
702
703
704
    /**
705
     * Builds an arbitrary service/object instance from a config-obect.
706
     * 
707
     * @static
708
     * @access protected
709
     * @param object $config configuration object to build a service instance from. 
710
     * @param array $arguments arguments for the service constructor 
711
     * @param string $defaultClass class to create instance for if none is set in config 
712
     * @return object build and modified srvice instance
713
     */    
714
    protected static function doBuild($config, $arguments, $defaultClass = false){
715
        $cls = $config["class"] ? trim((string)$config["class"]) : (string)$defaultClass;
716
        if($cls != ''){
717
            try {
718
                $constructor = (string)$config["constructor"];
719
        if($constructor != ''){
720
            $service = call_user_func_array(array($cls, $constructor), $arguments); 
721
        }else{
722
            $service = self::build($cls, $arguments); 
0 ignored issues
show
Documentation introduced by
$cls is of type string, but the function expects a object.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
723
        }        
724
            }catch(\Exception $e){
725
                throw new \RuntimeException('Could not create Service "'.$cls.'" -> '.$e->getMessage());
726
            }           
727
        }
728
        if(is_object($service)){
729
            return $service;
0 ignored issues
show
Bug introduced by
The variable $service does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
730
        }       
731
        throw new \RuntimeException('Could not create Service "'.$cls.'". Class does not exist.');           
732
    }   
733
734
    /**
735
     * Utility function to build an object instance for given class with given constructor-arguments.
736
     * 
737
     * @see GenericBuilder
738
     * @static
739
     * @access protected
740
     * @param object $className name of class to build instance for. 
741
     * @param array $arguments arguments for the constructor 
742
     * @return object build and modified srvice instance
743
     */     
744
    protected static function build($className, $arguments){
745
        return GenericBuilder::getInstance($className)->build($arguments);
0 ignored issues
show
Documentation introduced by
$className is of type object, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
746
    }
747
748
    protected static function hasPublicProperty($service, $type, $name){
749
        $reflection = GenericBuilder::getInstance(get_class($service))->getReflectionClass();
750
        if($reflection->{'has'.$type}($name) && $reflection->{'get'.$type}($name)->isPublic()){
751
                return true;
752
        }
753
        return false;
754
    }
755
756
} 
757