Completed
Push — master ( 9be0de...4e104c )
by Enrico
06:20
created

ServiceProvider::boot()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 15
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 15
ccs 0
cts 8
cp 0
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 7
nc 2
nop 1
crap 6
1
<?php
2
3
namespace Resourceful;
4
5
use Pimple\Container;
6
use Pimple\ServiceProviderInterface;
7
use Silex\Provider\ServiceControllerServiceProvider;
8
use Silex\Provider\TwigServiceProvider;
9
use Silex\Application;
10
use Silex\Api\BootableProviderInterface;
11
use Twig_Loader_Filesystem;
12
use SchemaStore;
13
use JDesrosiers\Silex\Provider\ContentNegotiationServiceProvider;
14
use JDesrosiers\Silex\Provider\CorsServiceProvider;
15
use Resourceful\Stores\FileCache;
16
use Symfony\Component\Debug\ErrorHandler;
17
18
class ServiceProvider implements ServiceProviderInterface, BootableProviderInterface
19
{
20
    const ERROR_HANDLER_PRIORITY = 0;
21
22
23 17
    public function register(Container $app)
24
    {
25 17
    	$app->register(new TwigServiceProvider());
26
		
27
		// if true, create schema from templates
28 17
		$app["createDefault"] = true;
29
		
30 17
		$app['data.dir'] = sys_get_temp_dir() . '/resourceful';
31
		
32
		// create a storage service for data and schema
33
		$app['data.store'] = function($app) {
34
			return new FileCache($app['data.dir']);
35
		};
36
		
37
        // JSON Schema application
38
        $app["schema.cache"] = function () {
39 8
            return new SchemaStore();
40
        };
41
42 17
        $app["uniqid"] = $app->protect(function ($data) {
1 ignored issue
show
Unused Code introduced by
The parameter $data is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
43
            return uniqid();
44 17
        });
45
				
46
    	// JSON/REST application
47 17
        $app->register(new ContentNegotiationServiceProvider(), array(
48 17
            "conneg.responseFormats" => array("json"),
49
            "conneg.requestFormats" => array("json"),
50
            "conneg.defaultFormat" => "json",
51
        ));
52
		
53
		// cors support
54 17
        $app->register(new CorsServiceProvider());
55
		
56
		// allow to create controllers as a service 
57 17
		$app->register(new ServiceControllerServiceProvider());
58
59
		//=====================================================		
60
		// set application middleware
61
		//=====================================================	
62
		
63
		// manage cors
64 17
		$app->after($app["cors"]);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Pimple\Container as the method after() does only exist in the following sub-classes of Pimple\Container: Silex\Application, Silex\Tests\Application\FormApplication, Silex\Tests\Application\MonologApplication, Silex\Tests\Application\SecurityApplication, Silex\Tests\Application\SwiftmailerApplication, Silex\Tests\Application\TranslationApplication, Silex\Tests\Application\TwigApplication, Silex\Tests\Application\UrlGeneratorApplication, Silex\Tests\SpecialApplication. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
65 17
    }
66
67
68
    public function boot(Application $app)
69
    {
70
    	assert( isset($app["twig.loader"]));
71
72
		// ensure that schema route exists
73
		if( !isset($app['schema.controller'])) {
74
    		$app->abort('Schema endpoint not found. Do you have mounted a schema?');
75
    	}
76
				
77
		$app["twig.loader"]->addLoader(new Twig_Loader_Filesystem(__DIR__ . "/../templates"));
78
79
		// Error Handling
80
        ErrorHandler::register();
81
        $app->error(new JsonErrorHandler($app), self::ERROR_HANDLER_PRIORITY);
82
    }
83
}
84