WebserviceRequest::getInput()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
namespace Agavi\Request;
3
4
// +---------------------------------------------------------------------------+
5
// | This file is part of the Agavi package.                                   |
6
// | Copyright (c) 2005-2011 the Agavi Project.                                |
7
// |                                                                           |
8
// | For the full copyright and license information, please view the LICENSE   |
9
// | file that was distributed with this source code. You can also view the    |
10
// | LICENSE file online at http://www.agavi.org/LICENSE.txt                   |
11
// |   vi: set noexpandtab:                                                    |
12
// |   Local Variables:                                                        |
13
// |   indent-tabs-mode: t                                                     |
14
// |   End:                                                                    |
15
// +---------------------------------------------------------------------------+
16
use Agavi\Core\Context;
17
18
/**
19
 * AgaviWebserviceRequest is the base class for Web Service requests
20
 *
21
 * @package    agavi
22
 * @subpackage request
23
 *
24
 * @author     David Zülke <[email protected]>
25
 * @copyright  Authors
26
 * @copyright  The Agavi Project
27
 *
28
 * @since      0.11.0
29
 *
30
 * @version    $Id$
31
 */
32
abstract class WebserviceRequest extends Request
33
{
34
    /**
35
     * @var        string The Input Data.
36
     */
37
    protected $input = '';
38
    
39
    /**
40
     * @var        string The method called by the web service request.
41
     */
42
    protected $invokedMethod = '';
43
    
44
    /**
45
     * Constructor.
46
     *
47
     * @author     David Zülke <[email protected]>
48
     * @since      0.11.0
49
     */
50
    public function __construct()
51
    {
52
        parent::__construct();
53
        $this->setParameters(array(
54
            'request_data_holder_class' => 'AgaviWebserviceRequestDataHolder',
55
        ));
56
    }
57
    
58
    /**
59
     * Initialize this Request.
60
     *
61
     * @param      Context $context    A Context instance.
62
     * @param      array   $parameters An associative array of initialization parameters.
63
     *
64
     * @throws     <b>AgaviInitializationException</b> If an error occurs while
65
     *                                                 initializing this Request.
66
     *
67
     * @author     David Zülke <[email protected]>
68
     * @since      0.11.0
69
     */
70
    public function initialize(Context $context, array $parameters = array())
0 ignored issues
show
Coding Style introduced by
initialize uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
71
    {
72
        // empty $_POST just to be sure
73
        $_POST = array();
74
        
75
        // grab the POST body
76
        $this->input = file_get_contents('php://input');
77
        
78
        parent::initialize($context, $parameters);
79
    }
80
    
81
    /**
82
     * Get the input data, usually the request from the POST body.
83
     *
84
     * @return     string The input data.
85
     *
86
     * @author     David Zülke <[email protected]>
87
     * @since      0.11.0
88
     */
89
    public function getInput()
90
    {
91
        return $this->input;
92
    }
93
    
94
    /**
95
     * Set the input data. Useful for debugging purposes.
96
     *
97
     * @param      string $input The input data.
98
     *
99
     * @author     David Zülke <[email protected]>
100
     * @since      0.11.0
101
     */
102
    public function setInput($input)
103
    {
104
        $this->input = $input;
105
    }
106
    
107
    /**
108
     * Set the name of the method called by the web service request.
109
     *
110
     * @return     string $method A method name.
111
     *
112
     * @author     David Zülke <[email protected]>
113
     * @since      0.11.0
114
     */
115
    public function setInvokedMethod($method)
116
    {
117
        $this->invokedMethod = $method;
118
        
119
        // let the routing update its input
120
        $this->context->getRouting()->updateInput();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Agavi\Routing\Routing as the method updateInput() does only exist in the following sub-classes of Agavi\Routing\Routing: Agavi\Routing\SoapRouting, Agavi\Routing\WebserviceRouting, Agavi\Routing\XmlrpcepiphpRouting. 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...
121
    }
122
    
123
    /**
124
     * Get the name of the method called by the web service request.
125
     *
126
     * @return     string A method name.
127
     *
128
     * @author     David Zülke <[email protected]>
129
     * @since      0.11.0
130
     */
131
    public function getInvokedMethod()
132
    {
133
        return $this->invokedMethod;
134
    }
135
}
136