Completed
Push — v1.ns ( 7eab28...a6bb16 )
by Timo
03:47
created

XMLContext::createRouter()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 6

Duplication

Lines 7
Ratio 100 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 7
loc 7
rs 9.4285
cc 2
eloc 6
nc 2
nop 2
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\Service\HeaderServiceActivator;
26
use PEIP\Channel\ChannelRegistry;
27
use PEIP\Service\ServiceProvider;
28
use PEIP\Plugins\BasePlugin;
29
use PEIP\Factory\ServiceFactory;
30
use PEIP\Base\GenericBuilder;
31
use PEIP\Context\XMLContextReader;
32
33
class XMLContext 
34
    implements 
35
        \PEIP\INF\Context\Context,
36
        \PEIP\INF\Channel\ChannelResolver {
37
38
    protected 
39
        $services = array(),
40
        $configs = array(),
41
        $gateways = array(),
42
        $nodeBuilders = array(),
43
        $channelRegistry,
44
        $serviceProvider;
45
          
46
    /**
47
     * constructor
48
     * 
49
     * @access public
50
     * @param string $string the configuration string 
51
     * @return 
52
     */
53
    public function __construct($string){
54
        $this->initNodeBuilders();
55
        $reader = new XMLContextReader($string);
56
 
57
58
        $serviceActivator = new HeaderServiceActivator(array($this, 'addConfig'), 'NODE');
59
60
        $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...
61
        $reader->read();
62
63
       
64
    }
65
66
    public function addConfig($config){ 
67
        return $this->getServiceProvider()->addConfig($config);
68
    }
69
70
    public function handleReadConfig(\PEIP\INF\Event\Event $event){
71
        $this->addConfig($event->getHeader('NODE'));
72
    }
73
74
    /**
75
     * Creates and returns a XMLContext instance from a given config-string.
76
     * 
77
     * @access public
78
     * @param string $string the configuration string 
79
     * @return XMLContext the context instance
80
     * @throws RuntimeException 
81
     */      
82
    public static function createFromString($string){
83
        return new XMLContext($string);
84
    }
85
86
    /**
87
     * Creates and returns a XMLContext instance from a given config-file.
88
     * 
89
     * @access public
90
     * @param string $file the path to the configuration file 
91
     * @return XMLContext the context instance
92
     * @throws RuntimeException 
93
     */    
94
    public static function createFromFile($file){
95
        if(file_exists($file)){
96
            return self::createFromString(file_get_contents($file));
97
        }else{
98
            throw new \RuntimeException('Cannot open file  "'.$file.'".');
99
        }
100
    }
101
           
102
    /**
103
     * Initializes the context.
104
     * 
105
     * @access protected
106
     * @return void
107
     */
108
    protected function init(){
109
        $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...
110
        $this->channelRegistry = ChannelRegistry::getInstance();
111
        // register this context as a service if id is set.
112
        if($xml['id']){
113
            $this->services[(string)$xml['id']] = $this;    
114
        }
115
        // build services
116
        foreach($xml->children() as $entry){
117
            $this->buildNode($entry);
118
        }
119
    }    
120
     
121
    /**
122
     * Registers a callable as builder for given node-name
123
     * 
124
     * @implements \PEIP\INF\Context\Context
125
     * @access public
126
     * @param string $nodeName the name of the node 
127
     * @param callable $callable a callable which creates instances for node-name 
128
     */
129
    public function registerNodeBuilder($nodeName, $callable){
130
       return  $this->getServiceProvider()->registerNodeBuilder($nodeName, $callable);
131
    }
132
   
133
    /**
134
     * Registers a context-plugin instance.
135
     * 
136
     * @implements \PEIP\INF\Context\Context
137
     * @access public
138
     * @param \PEIP\INF\Context\Context_Plugin $plugin a plugin instance
139
     */
140
    public function addPlugin(\PEIP\INF\Context\ContextPlugin $plugin){ 
141
        $plugin->init($this);   
142
    }
143
  
144
    /**
145
     * Creates a registers a context-plugin instance from a config object.
146
     * 
147
     * @access public
148
     * @param object $config configuration object for the plugin 
149
     * @return 
150
     */
151
    public function createPlugin($config){
152
        $plugin = $this->createService($config);    
153
        $this->addPlugin($plugin);
154
    }
155
  
156
    /**
157
     * Adds a context instance to the services stack.
158
     * Note: Object instances registered with the included context will
159
     * overwrite any instance with the same id on the including context.
160
     * If you need a different behavior, please, make use
161
     * of an include-tag in your configuration before your main
162
     * configuration part. 
163
     * eg.:
164
     * <config>
165
     *    <include file="path/to/include/context/config.xml"/>
166
     *    <!-- main configuration -->
167
     * </config>     
168
     * 
169
     * @access public
170
     * @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...
171
     */    
172
    public function includeContext(XMLContext $context){
173
        $this->services = array_merge($this->services, $context->getServices());
174
    }
175
176
    /**
177
     * Creates and adds a context from file. 
178
     * 
179
     * @see XMLContext::includeContext
180
     * @access public
181
     * @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...
182
     */    
183
    public function includeContextFromFile($filePath){
184
        if(file_exists($filePath)){
185
            $this->includeContextFromString(file_get_contents($filePath));
186
        }           
187
    }
188
189
    /**
190
     * Creates and adds a context from string. 
191
     * 
192
     * @see XMLContext::includeContext
193
     * @access public
194
     * @param string $configString the config to include
195
     */    
196
    public function includeContextFromString($configString){
197
        $context = new XMLContext($configString);
198
        $this->includeContext($context);            
199
    }   
200
    
201
    /**
202
     * Creates a context instance from a config object and includes it. 
203
     * 
204
     * @see XMLContext::includeContext
205
     * @access protected
206
     * @param object $config the configuration for the context
207
     */    
208
    protected function createContext($config){
209
        if((string)$config['file'] != ''){
210
            $this->includeContextFromFile((string)$config['file']);
211
        }           
212
    }   
213
     
214
215
    public function getServiceProvider(){
216
        return isset($this->serviceProvider)
217
            ? $this->serviceProvider
218
            : $this->serviceProvider = new ServiceProvider();
219
    }
220
221
    /**
222
     * Registers the build-methods for the main-components with this context.
223
     * Note: This method and subsequent registered methods of this class are
224
     * candidates for refactoring. Because this class has grown much to large
225
     * and for better design and flexibility the core builder-methods should be
226
     * put into a core context-plugin. 
227
     * 
228
     * @see XMLContext::includeContext
229
     * @access protected
230
     */     
231
    protected function initNodeBuilders(){
232
        $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...
233
            'include' => 'createContext',
234
            'plugin' => 'createPlugin',
235
            'channel' => 'createChannel',
236
            'publish_subscribe_channel' => 'createSubscribableChannel',
237
            'service' => 'initService',
238
            'service_activator' => 'createServiceActivator',
239
            'gateway' => 'createGateway',
240
            'splitter' => 'createSplitter',
241
            'transformer' => 'createTransformer',
242
            'router' => 'createRouter',
243
            'aggregator' => 'createAggregator',
244
            'wiretap' => 'createWiretap'
245
                
246
        );
247
        $plugin = new BasePlugin();
248
        $this->addPlugin($plugin); return;
249
        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...
250
            $this->registerNodeBuilder($nodeName, array($this, $method));   
251
        }       
252
    }
253
254
    /**
255
     * Builds a specific configuration-node. Calls the build-method which
256
     * is registered with the node-name. If none is registered does nothing. 
257
     * 
258
     * @see XMLContext::doCreateChannel
259
     * @access protected
260
     * @param object $node configuration-node
261
     * @return void
262
     */
263
    protected function buildNode($node){
264
        $nodeName = $node->getName();
265
        // call the builder method registered for the node.
266
        if(array_key_exists($nodeName, $this->nodeBuilders)){
267
            call_user_func($this->nodeBuilders[$nodeName], $node);
268
        }           
269
    }
270
   
271
    /**
272
     * Resolves a channel-name and returns channel-instace if found.
273
     * Main purpose is to allow the context to act as a channel-resolver for 
274
     * mainly routers, hence implement the \PEIP\INF\Channel\ChannelResolver pattern.
275
     * Note: Channels are registerd globally in a registry per thread/process.
276
     * This allows to connect many context instances through channels without
277
     * coupling them by in a include in configuration.  
278
     * 
279
     * @see \PEIP\INF\Channel\ChannelResolver
280
     * @implements \PEIP\INF\Channel\ChannelResolver
281
     * @access public
282
     * @param string $channelName the name/id of the channel to return 
283
     * @return \PEIP\INF\Channel\Channel
284
     */
285
    public function resolveChannelName($channelName){
286
        return $this->channelRegistry->get($channelName);
287
    }   
288
     
289
    /**
290
     * returns a service for a given id
291
     * 
292
     * @implements \PEIP\INF\Context\Context
293
     * @access public
294
     * @param mixed $id the id for the service
295
     * @return object the service instance if found
296
     */
297
    public function getService($id){     
298
        return $this->getServiceProvider()->provideService($id);
299
    }
300
             
301
    /**
302
     * returns all registered services
303
     * 
304
     * @access public
305
     * @return array registered services
306
     */
307
    public function getServices(){    
308
        return $this->getServiceProvider()->getServices();
309
    }  
310
    
311
    /**
312
     * Checks wether a service with a given id is registered
313
     * 
314
     * @access public
315
     * @param mixed $id the id for the service 
316
     * @return boolean wether service is registered
317
     */
318
    public function hasService($id){
319
        return isset($this->services[$id]);
320
    }
321
      
322
    /**
323
     * Tries to receive a service for a given id.
324
     * Throws RuntimeException if no service is found
325
     * 
326
     * @access protected
327
     * @throws RuntimeException
328
     * @param mixed $id the id for the service 
329
     * @return object the service instance if found
330
     * 
331
     */
332
    protected function requestService($id){
333
        $service = $this->getService($id);
334
        if($service === NULL){
335
            throw new \RuntimeException('Service "'.$id.'" not found.');
336
        } 
337
        return $service;
338
    }
339
    
340
    /**
341
     * Creates and initializes service instance from a given configuration.
342
     * Registers instance if id is set in config.
343
     * 
344
     * @access protected
345
     * @param object $config 
346
     * @return object the initialized service instance
347
     */
348
    protected function initService($config){
349
        $id = trim((string)$config['id']);
350
        if($id != ''){
351
            return $this->services[$id] = $this->createService($config);    
352
        }   
353
    }
354
 
355
    /**
356
     * Creates and initializes service instance from a given configuration. 
357
     * 
358
     * @access public
359
     * @param $config 
360
     * @return object the initialized service instance
361
     */
362
    public function createService($config){
363
        return ServiceFactory::createService($config);      
364
    }
365
 
366
    /**
367
     * Modifies a service instance from configuration.
368
     *  - Sets properties on the instance.
369
     *  -- Calls a public setter method if exists.
370
     *  -- Else sets a public property if exists.
371
     *  - Calls methods on the instance.
372
     *  - Registers listeners to events on the instance
373
     * 
374
     * @access protected
375
     * @param object $service the service instance to modify 
376
     * @param object $config configuration to get the modification instructions from. 
377
     * @return object the modificated service
378
     */
379
    protected function modifyService($service, $config){ 
380
        $reflection = GenericBuilder::getInstance(get_class($service))->getReflectionClass();
0 ignored issues
show
Unused Code introduced by
$reflection 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...
381
        // set instance properties
382 View Code Duplication
        if($config->property){          
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
383
            foreach($config->property as $property){                          
384
                $arg = $this->buildArg($property);
385
                if($arg){
386
                    $setter = self::getSetter($property);               
387
                    if($setter &&  self::hasPublicProperty($service, 'Method', $setter)){
388
                        $service->{$setter}($arg);  
389
                    }elseif(in_array($property, self::hasPublicProperty($service, 'Property', $setter))){
390
                        $service->$setter = $arg;
391
                    }                   
392
                }
393
            }
394
        }   
395
        // call instance methods
396 View Code Duplication
        if($config->action){            
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
397
            foreach($config->action as $action){
398
                $method = (string)$action['method'] != '' ? (string)$action['method'] : NULL;
399
                if($method && self::hasPublicProperty($service, 'Method', $method)){
0 ignored issues
show
Bug Best Practice introduced by
The expression $method of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
400
                    $args = array(); 
401
                    foreach($action->children() as $argument){
402
                        $args[] = $this->buildArg($argument);
403
                    } 
404
                    call_user_func_array(array($service, (string)$action['method']), $args);
405
                }
406
            }
407
        }       
408
        // register instance listeners
409 View Code Duplication
        if($service instanceof \PEIP\INF\Event\Connectable){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
410
            if($config->listener){
411
                foreach($config->listener as $listenerConf){
412
                    $event = (string)$listenerConf['event'];
413
                    $listener = $this->provideService($listenerConf);  
414
                    $service->connect($event, $listener);   
415
                }
416
            }
417
        }
418
        return $service;
419
    }   
420
      
421
    /**
422
     * returns gateway instance forgiven id.
423
     * the use of this method is deprecated. Use getService instead.
424
     * 
425
     * @deprecated 
426
     * @access public
427
     * @param mixed $id the id ofthe gateway 
428
     * @return object the gateway instance
429
     */
430
    public function getGateway($id){ 
431
        return $this->getServiceProvider()->provideService($id); 
432
    }   
433
  
434
    /**
435
     * Creates a pollable channel from a configuration object.
436
     * 
437
     * @see XMLContext::doCreateChannel
438
     * @access public
439
     * @param object $config configuration object for the pollable channel. 
440
     * @return \PEIP\INF\Channel\Channel the created pollable channel instance
441
     */
442
    public function createChannel($config){
443
        return $this->doCreateChannel($config, 'PollableChannel');        
444
    }
445
  
446
    /**
447
     * Creates a subscribable channel from a configuration object.
448
     * 
449
     * @see XMLContext::doCreateChannel
450
     * @access public
451
     * @param object $config configuration object for the subscribable channel. 
452
     * @return \PEIP\INF\Channel\Channel the created subscribable channel instance
453
     */
454
    public function createSubscribableChannel($config){
455
        return $this->doCreateChannel($config, 'PublishSubscribeChannel');       
456
    }   
457
   
458
    /**
459
     * Creates and registers arbitrary channel from a configuration object and additional information.
460
     * 
461
     * @access public
462
     * @param object $config configuration object for the channel. 
463
     * @param string $defaultChannelClass the channel class to use if none is set in config 
464
     * @param $additionalArguments additional arguments for the channel constructor (without first arg = id)
465
     * @return \PEIP\INF\Channel\Channel the created channel instance
466
     */
467 View Code Duplication
    public function doCreateChannel($config, $defaultChannelClass, array $additionalArguments = array()){
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...
468
        $id = (string)$config['id'];
469
        if($id != ''){ 
470
            array_unshift($additionalArguments, $id);
471
            $channel = $this->buildAndModify($config, $additionalArguments, $defaultChannelClass);
472
            $this->channelRegistry->register($channel);
473
            return $channel;
474
        }
475
    }
476
       
477
    /**
478
     * Creates and registers gateway from a configuration object.
479
     * 
480
     * @see XMLContext::initNodeBuilders
481
     * @access public
482
     * @param object $config configuration object for the gateway. 
483
     * @param string $defaultClass the class to use if none is set in config. 
484
     * @return object the gateway instance
485
     */
486 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...
487
        $args = array(
488
            $this->getRequestChannel($config), 
489
            $this->getReplyChannel($config)
490
        );
491
        $defaultClass = $defaultClass ? $defaultClass : 'SimpleMessagingGateway';
492
        $gateway = $this->buildAndModify($config, $args, $defaultClass);
493
        $id = (string)$config["id"];
494
        $this->gateways[$id] = $gateway;
495
        return $gateway;    
496
    }
497
  
498
    /**
499
     * Creates and registers router from a configuration object.
500
     * Adds this context instance as channel-resolver to the router if
501
     * none is set in config. 
502
     * 
503
     * @see XMLContext::resolveChannelName
504
     * @see XMLContext::initNodeBuilders
505
     * @access public
506
     * @param object $config configuration object for the gateway. 
507
     * @param string $defaultClass the class to use if none is set in config. 
508
     * @return object the router instance
509
     */
510 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...
511
        $resolver = $config['channel_resolver'] ? (string)$config['channel_resolver'] : $this->channelRegistry;
512
        return $this->buildAndModify($config, array(
513
            $resolver,
514
            $this->doGetChannel('input', $config)
515
        ), $defaultClass);
516
    }
517
518
    /**
519
     * Creates and registers splitter from a configuration object.
520
     * 
521
     * @see XMLContext::initNodeBuilders
522
     * @see XMLContext::createReplyMessageHandler
523
     * @access public
524
     * @param object $config configuration object for the splitter. 
525
     * @return object the splitter instance
526
     */    
527
    public function createSplitter($config){
528
        return $this->createReplyMessageHandler($config);           
529
    }   
530
 
531
    /**
532
     * Creates and registers transformer from a configuration object.
533
     * 
534
     * @see XMLContext::initNodeBuilders
535
     * @see XMLContext::createReplyMessageHandler
536
     * @access public
537
     * @param object $config configuration object for the transformer. 
538
     * @return object the transformer instance
539
     */    
540
    public function createTransformer($config){
541
        return $this->createReplyMessageHandler($config);           
542
    } 
543
      
544
    /**
545
     * Creates aggregator from a configuration object.
546
     * 
547
     * @see XMLContext::initNodeBuilders
548
     * @see XMLContext::createReplyMessageHandler
549
     * @access public
550
     * @param object $config configuration object for the aggregator. 
551
     * @return object the aggregator instance
552
     */  
553
    public function createAggregator($config){
554
        return $this->createReplyMessageHandler($config);       
555
    }
556
  
557
    /**
558
     * Creates wiretap from a configuration object.
559
     * 
560
     * @see XMLContext::initNodeBuilders
561
     * @see XMLContext::createReplyMessageHandler
562
     * @access public
563
     * @param object $config configuration object for the wiretap. 
564
     * @return object the wiretap instance
565
     */ 
566
    public function createWiretap($config){
567
        return $this->createReplyMessageHandler($config, 'Wiretap');       
568
    }
569
  
570
    /**
571
     * Creates a reply-message-handler from a configuration object.
572
     * 
573
     * @see XMLContext::initNodeBuilders
574
     * @access public
575
     * @param object $config configuration object for the reply-message-handler. 
576
     * @param string $defaultClass the class to use if none is set in config.
577
     * @return object the reply-message-handler instance
578
     */ 
579
    public function createReplyMessageHandler($config, $defaultClass = false){
580
        return $this->buildAndModify($config, $this->getReplyHandlerArguments($config), $defaultClass); 
581
    }
582
    
583
    /**
584
     * Creates and registers service-activator from a configuration object.
585
     * 
586
     * @see XMLContext::initNodeBuilders
587
     * @access public
588
     * @param object $config configuration object for the service-activator. 
589
     * @param string $defaultClass the class to use if none is set in config. 
590
     * @return object the service-activator instance
591
     */
592 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...
593
        $method = (string)$config['method'];
594
        $service = $this->getService((string)$config['ref']);
595
        if($method && $service){        
596
            $args = $this->getReplyHandlerArguments($config);
597
            array_unshift($args,array(
598
                $service,
599
                $method             
600
            )); 
601
            $defaultClass = $defaultClass ? $defaultClass : 'ServiceActivator';
602
            return $this->buildAndModify($config, $args, $defaultClass);                
603
        }
604
    }   
605
    
606
    
607
    /**
608
     * Provides a service for a configuration object.
609
     * Returns reference to a service if configured, otherwise
610
     * creates new service instance.
611
     * 
612
     * @see XMLContext::getService
613
     * @see XMLContext::createService
614
     * @access protected
615
     * @param object $config configuration object for the service. 
616
     * @return 
617
     */
618
    protected function provideService($config){
619
        $ref = trim((string)$config['ref']);
620
        if($ref != ''){
621
            $service = $this->getService($ref); 
622
        }else{
623
            $service = $this->createService($config);
624
        }
625
        return $service;
626
    }
627
628
    /**
629
     * Utility method to return a (camel-cased) setter method-name for a property of a config-obect.
630
     * Returns setter-name if set in configuration, otherwise if name of property is set, returns
631
     * camel-cased setter-name build from property-name.
632
     * 
633
     * @see XMLContext::getService
634
     * @see XMLContext::createService
635
     * @access protected
636
     * @param object $config configuration object for the setter-method. 
637
     * @return string camel-cased 
638
     */    
639
    protected static function getSetter($config){
640
        if($config['setter']){
641
            $setter = (string)$config['setter'];
642
        }elseif($config['name']){
643
            $setter = 'set'.ucfirst((string)$config['name']);   
644
        }
645
        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...
646
    }
647
    
648
    /**
649
     * Builds single argument (to call a method with later) from a config-obect.
650
     * 
651
     * @access protected
652
     * @param object $config configuration object to create argument from.  
653
     * @return mixed build argument 
654
     */
655 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...
656
        if(trim((string)$config['value']) != ''){
657
            $arg = (string)$config['value'];
658
        }elseif($config->getName() == 'value'){
659
            $arg = (string)$config;
660
        }elseif($config->getName() == 'list'){
661
            $arg = array();
662
            foreach($config->children() as $entry){ 
663
                if($entry->getName() == 'value'){
664
                    if($entry['key']){
665
                        $arg[(string)$entry['key']] = (string)$entry;   
666
                    }else{
667
                        $arg[] = (string)$entry;
668
                    }
669
                }elseif($entry->getName() == 'service'){
670
                    $arg[] = $this->provideService($entry);
671
                }
672
            }
673
        }elseif($config->getName() == 'service'){
674
            $arg = $this->provideService($config);
675
        }elseif($config->list){
676
            $arg = $this->buildArg($config->list);
677
        }elseif($config->service){
678
            $arg = $this->buildArg($config->service);
679
        } 
680
        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...
681
    }       
682
683
    
684
    /**
685
     * Utility method to create arguments for a reply-handler constructor from a config-obect.
686
     * 
687
     * @access protected
688
     * @param object $config configuration object to create arguments from.  
689
     * @return mixed build arguments 
690
     */
691 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...
692
        $args = array(
693
            $this->doGetChannel('input', $config),
694
            $this->doGetChannel('output', $config)
695
        );
696
        if($args[0] == NULL){
697
            throw new \RuntimeException('Could not receive input channel.');
698
        }
699
        return $args;
700
    }
701
    
702
    
703
    /**
704
     * Utility method to return a request-channel from a config-obect.
705
     * 
706
     * @see XMLContext::doGetChannel
707
     * @access protected
708
     * @param object $config configuration object to return request-channel from. 
709
     * @return \PEIP\INF\Channel\Channel request-channel
710
     */
711
    protected function getRequestChannel($config){
712
        return $this->doGetChannel('request', $config); 
713
    }
714
    
715
    
716
    /**
717
     * Utility method to return a reply-channel from a config-obect.
718
     * 
719
     * @see XMLContext::doGetChannel
720
     * @access protected
721
     * @param object $config configuration object to return reply-channel from. 
722
     * @return \PEIP\INF\Channel\Channel reply-channel
723
     */
724
    protected function getReplyChannel($config){
725
        return $this->doGetChannel('reply', $config);   
726
    }
727
    
728
    
729
    /**
730
     * Utility method to return a certainn channel from a config-obect.
731
     * 
732
     * @access protected
733
     * @param string the configuration type ofthe channel (e.g.: 'reply', 'request')
734
     * @param object $config configuration object to return channel from. 
735
     * @return \PEIP\INF\Channel\Channel reply-channel
736
     */
737 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...
738
        $channelName = $config[$type."_channel"] 
739
            ? $config[$type."_channel"] 
740
            : $config["default_".$type."_channel"];
741
        return $this->serviceProvider->provideService(trim((string)$channelName));
742
        $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...
743
        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...
744
            return $channel;    
745
        }else{
746
            return NULL;
747
        }       
748
    }
749
750
    
751
    /**
752
     * Builds and modifies an arbitrary service/object instance from a config-obect.
753
     * 
754
     * @see XMLContext::doBuild
755
     * @see XMLContext::modifyService
756
     * @implements \PEIP\INF\Context\Context
757
     * @access public
758
     * @param object $config configuration object to build a service instance from. 
759
     * @param array $arguments arguments for the service constructor 
760
     * @param string $defaultClass class to create instance for if none is set in config 
761
     * @return object build and modified srvice instance
762
     */
763
    public function buildAndModify($config, $arguments, $defaultClass = false){   
764
        return ServiceFactory::buildAndModify($config, $arguments, $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 763 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...
765
    }
766
767
    /**
768
     * Builds an arbitrary service/object instance from a config-obect.
769
     * 
770
     * @static
771
     * @access protected
772
     * @param object $config configuration object to build a service instance from. 
773
     * @param array $arguments arguments for the service constructor 
774
     * @param string $defaultClass class to create instance for if none is set in config 
775
     * @return object build and modified srvice instance
776
     */    
777
    protected static function doBuild($config, $arguments, $defaultClass = false){
778
        $cls = $config["class"] ? trim((string)$config["class"]) : (string)$defaultClass;
779
        if($cls != ''){
780
            try {
781
                $constructor = (string)$config["constructor"];
782
        if($constructor != ''){
783
            $service = call_user_func_array(array($cls, $constructor), $arguments); 
784
        }else{
785
            $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...
786
        }        
787
            }catch(\Exception $e){
788
                throw new \RuntimeException('Could not create Service "'.$cls.'" -> '.$e->getMessage());
789
            }           
790
        }
791
        if(is_object($service)){
792
            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...
793
        }       
794
        throw new \RuntimeException('Could not create Service "'.$cls.'". Class does not exist.');           
795
    }   
796
797
    /**
798
     * Utility function to build an object instance for given class with given constructor-arguments.
799
     * 
800
     * @see GenericBuilder
801
     * @static
802
     * @access protected
803
     * @param object $className name of class to build instance for. 
804
     * @param array $arguments arguments for the constructor 
805
     * @return object build and modified srvice instance
806
     */     
807
    protected static function build($className, $arguments){
808
        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...
809
    }
810
811
    protected static function hasPublicProperty($service, $type, $name){
812
        $reflection = GenericBuilder::getInstance(get_class($service))->getReflectionClass();
813
        if($reflection->{'has'.$type}($name) && $reflection->{'get'.$type}($name)->isPublic()){
814
                return true;
815
        }
816
        return false;
817
    }
818
819
} 
820