Completed
Pull Request — master (#294)
by Robbie
01:49
created

InitStateMiddleware::detectSubsiteId()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 18
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 18
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 9
nc 4
nop 1
1
<?php
2
3
namespace SilverStripe\Subsites\Middleware;
4
5
use SilverStripe\Admin\AdminRootController;
6
use SilverStripe\Control\HTTPRequest;
7
use SilverStripe\Control\Middleware\HTTPMiddleware;
8
use SilverStripe\Core\Config\Configurable;
9
use SilverStripe\Core\Injector\Injector;
10
use SilverStripe\ORM\Connect\DatabaseException;
11
use SilverStripe\Subsites\Model\Subsite;
12
use SilverStripe\Subsites\State\SubsiteState;
13
14
class InitStateMiddleware implements HTTPMiddleware
15
{
16
    use Configurable;
17
18
    /**
19
     * URL paths that should be considered as admin only, i.e. not frontend
20
     *
21
     * @config
22
     * @var array
23
     */
24
    private static $admin_url_paths = [
0 ignored issues
show
Unused Code introduced by
The property $admin_url_paths is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
25
        'dev/',
26
        'graphql/',
27
    ];
28
29
    public function process(HTTPRequest $request, callable $delegate)
30
    {
31
        try {
32
            // Initialise and register the State
33
            $state = SubsiteState::create();
34
            Injector::inst()->registerService($state);
35
36
            // Detect whether the request was made in the CMS area (or other admin-only areas)
37
            $isAdmin = $this->getIsAdmin($request);
38
            $state->setUseSessions($isAdmin);
39
40
            // Detect the subsite ID
41
            $subsiteId = $this->detectSubsiteId($request);
42
            $state->setSubsiteId($subsiteId);
43
44
            // Persist to the session if using the CMS
45
            if ($state->getUseSessions()) {
46
                $originalSubsiteId = $request->getSession()->get('SubsiteID');
47
            }
48
49
            return $delegate($request);
50
        } catch (DatabaseException $ex) {
51
            // No-op, database is not ready
52
        } finally {
53
            if ($state->getUseSessions()) {
54
                // Track session changes
55
                $request->getSession()->set('SubsiteID', $subsiteId);
0 ignored issues
show
Bug introduced by
The variable $subsiteId 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...
56
57
                $state->setSessionWasChanged($subsiteId === $originalSubsiteId);
0 ignored issues
show
Bug introduced by
The variable $originalSubsiteId 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...
58
            }
59
        }
60
    }
61
62
    /**
63
     * Determine whether the website is being viewed from an admin protected area or not
64
     *
65
     * @param  HTTPRequest $request
66
     * @return bool
67
     */
68
    public function getIsAdmin(HTTPRequest $request)
69
    {
70
        $adminPaths = static::config()->get('admin_url_paths');
71
        $adminPaths[] = AdminRootController::config()->get('url_base') . '/';
72
        $currentPath = rtrim($request->getURL(), '/') . '/';
73
        foreach ($adminPaths as $adminPath) {
74
            if (substr($currentPath, 0, strlen($adminPath)) === $adminPath) {
75
                return true;
76
            }
77
        }
78
        return false;
79
    }
80
81
    /**
82
     * Use the given request to detect the current subsite ID
83
     *
84
     * @param  HTTPRequest $request
85
     * @return int
86
     */
87
    protected function detectSubsiteId(HTTPRequest $request)
88
    {
89
        if ($request->getVar('SubsiteID') !== null) {
90
            return (int) $request->getVar('SubsiteID');
91
        }
92
93
        if (SubsiteState::singleton()->getUseSessions() && $request->getSession()->get('SubsiteID') !== null) {
94
            return (int) $request->getSession()->get('SubsiteID');
95
        }
96
97
        $subsiteIdFromDomain = Subsite::getSubsiteIDForDomain();
98
        if ($subsiteIdFromDomain !== null) {
99
            return (int) $subsiteIdFromDomain;
100
        }
101
102
        // Default fallback
103
        return 0;
104
    }
105
}
106