SoapResponse   A
last analyzed

Complexity

Total Complexity 28

Size/Duplication

Total Lines 291
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 0
Metric Value
dl 0
loc 291
rs 10
c 0
b 0
f 0
wmc 28
lcom 1
cbo 2

18 Methods

Rating   Name   Duplication   Size   Complexity  
A merge() 0 12 4
A setRedirect() 0 4 1
A getRedirect() 0 4 1
A hasRedirect() 0 4 1
A clearRedirect() 0 4 1
A isContentMutable() 0 4 1
A clearContent() 0 5 1
A send() 0 6 1
A clear() 0 5 1
A clearSoapHeaders() 0 4 1
A sendSoapHeaders() 0 8 2
A getSoapHeaders() 0 4 1
A getSoapHeader() 0 6 2
A addSoapHeader() 0 5 1
A setSoapHeader() 0 9 2
A removeSoapHeader() 0 6 2
A hasSoapHeader() 0 4 1
A searchSoapHeader() 0 9 4
1
<?php
2
namespace Agavi\Response;
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\Dispatcher\OutputType;
17
18
/**
19
 * SoapResponse handles SOAP Web Service responses using the PHP SOAP ext.
20
 *
21
 * @package    agavi
22
 * @subpackage response
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
class SoapResponse extends Response
33
{
34
    /**
35
     * @var        mixed The content to send back with this response.
36
     */
37
    protected $content = null;
38
    
39
    /**
40
     * @var        array An array of SOAP headers to send with the response.
41
     */
42
    protected $soapHeaders = array();
43
    
44
    /**
45
     * Import response metadata (SOAP headers) from another response.
46
     *
47
     * @param      Response $otherResponse The other response to import information from.
48
     *
49
     * @author     David Zülke <[email protected]>
50
     * @since      0.11.0
51
     */
52
    public function merge(Response $otherResponse)
53
    {
54
        parent::merge($otherResponse);
55
        
56
        if ($otherResponse instanceof SoapResponse) {
57
            foreach ($otherResponse->getSoapHeaders() as $soapHeader) {
58
                if (!$this->hasSoapHeader($soapHeader->namespace, $soapHeader->name)) {
59
                    $this->addSoapHeader($soapHeader);
60
                }
61
            }
62
        }
63
    }
64
    
65
    /**
66
     * Redirect externally. Not implemented here.
67
     *
68
     * @param      mixed $to Where to redirect.
69
     *
70
     * @throws     \BadMethodCallException
71
     *
72
     * @author     David Zülke <[email protected]>
73
     * @since      0.11.0
74
     */
75
    public function setRedirect($to)
76
    {
77
        throw new \BadMethodCallException('Redirects are not implemented for SOAP.');
78
    }
79
    
80
    /**
81
     * Get info about the set redirect. Not implemented here.
82
     *
83
     * @return     array An assoc array of redirect info, or null if none set.
84
     *
85
     * @throws     \BadMethodCallException
86
     *
87
     * @author     David Zülke <[email protected]>
88
     * @since      0.11.0
89
     */
90
    public function getRedirect()
91
    {
92
        throw new \BadMethodCallException('Redirects are not implemented for SOAP.');
93
    }
94
95
    /**
96
     * Check if a redirect is set. Not implemented here.
97
     *
98
     * @return     bool true, if a redirect is set, otherwise false
99
     *
100
     * @throws     \BadMethodCallException
101
     *
102
     * @author     David Zülke <[email protected]>
103
     * @since      0.11.0
104
     */
105
    public function hasRedirect()
106
    {
107
        throw new \BadMethodCallException('Redirects are not implemented for SOAP.');
108
    }
109
110
    /**
111
     * Clear any set redirect information. Not implemented here.
112
     *
113
     * @throws     \BadMethodCallException
114
     *
115
     * @author     David Zülke <[email protected]>
116
     * @since      0.11.0
117
     */
118
    public function clearRedirect()
119
    {
120
        throw new \BadMethodCallException('Redirects are not implemented for SOAP.');
121
    }
122
    
123
    /**
124
     * @see        Response::isMutable()
125
     *
126
     * @author     David Zülke <[email protected]>
127
     * @since      0.11.0
128
     */
129
    public function isContentMutable()
130
    {
131
        return false;
132
    }
133
    
134
    /**
135
     * Clear the content for this Response
136
     *
137
     * @return     bool Whether or not the operation was successful.
138
     *
139
     * @author     David Zülke <[email protected]>
140
     * @since      0.11.0
141
     */
142
    public function clearContent()
143
    {
144
        $this->content = null;
145
        return true;
146
    }
147
    
148
    /**
149
     * Send all response data to the client.
150
     *
151
     * @author     David Zülke <[email protected]>
152
     * @since      0.11.0
153
     */
154
    public function send(OutputType $outputType = null)
155
    {
156
        $this->sendSoapHeaders();
157
        // don't send content, that's done by returning it from Dispatcher::dispatch(), so SoapServer::handle() deals with the rest
158
        // $this->sendContent();
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
159
    }
160
    
161
    /**
162
     * Clear all response data.
163
     *
164
     * @author     David Zülke <[email protected]>
165
     * @since      0.11.0
166
     */
167
    public function clear()
168
    {
169
        $this->clearContent();
170
        $this->clearSoapHeaders();
171
    }
172
    
173
    /**
174
     * Clear all SOAP headers from the response.
175
     *
176
     * @author     David Zülke <[email protected]>
177
     * @since      0.11.0
178
     */
179
    public function clearSoapHeaders()
180
    {
181
        $this->soapHeaders = array();
182
    }
183
    
184
    /**
185
     * Send SOAP Headers.
186
     *
187
     * @author     David Zülke <[email protected]>
188
     * @since      0.11.0
189
     */
190
    public function sendSoapHeaders()
191
    {
192
        $server = $this->context->getDispatcher()->getSoapServer();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Agavi\Dispatcher\Dispatcher as the method getSoapServer() does only exist in the following sub-classes of Agavi\Dispatcher\Dispatcher: Agavi\Dispatcher\SoapDispatcher. 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...
193
        
194
        foreach ($this->soapHeaders as $soapHeader) {
195
            $server->addSoapHeader($soapHeader);
196
        }
197
    }
198
    
199
    /**
200
     * Get an array of all SOAP headers set on this response.
201
     *
202
     * @return     array An array of SoapHeader objects.
203
     *
204
     * @author     David Zülke <[email protected]>
205
     * @since      0.11.0
206
     */
207
    public function getSoapHeaders()
208
    {
209
        return $this->soapHeaders;
210
    }
211
    
212
    /**
213
     * Get a SOAP Header from this response based on its namespace and name.
214
     *
215
     * @param      string $namespace The namespace of the SOAP header element.
216
     * @param      string $name The name of the SOAP header element.
217
     *
218
     * @return     \SoapHeader A SoapHeader, if found, otherwise null.
219
     *
220
     * @author     David Zülke <[email protected]>
221
     * @since      0.11.0
222
     */
223
    public function getSoapHeader($namespace, $name)
224
    {
225
        if (($key = $this->searchSoapHeader($namespace, $name)) !== false) {
226
            return $this->soapHeaders[$key];
227
        }
228
    }
229
    
230
    /**
231
     * Add a SOAP Header to this response.
232
     *
233
     * @param      \SoapHeader $soapHeader The SOAP header to set.
234
     *
235
     * @author     David Zülke <[email protected]>
236
     * @since      0.11.0
237
     */
238
    public function addSoapHeader(\SoapHeader $soapHeader)
239
    {
240
        $this->removeSoapHeader($soapHeader->namespace, $soapHeader->name);
0 ignored issues
show
Bug introduced by
The property namespace does not seem to exist in SoapHeader.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
Bug introduced by
The property name does not seem to exist in SoapHeader.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
241
        $this->soapHeaders[] = $soapHeader;
242
    }
243
    
244
    /**
245
     * Set a SOAP header into this response.
246
     *
247
     * This method has the same signature as PHP's SoapHeader->__construct().
248
     *
249
     * @param      string $namespace The namespace of the SOAP header element.
250
     * @param      string $name The name of the SOAP header element.
251
     * @param      mixed  $data A SOAP header's content. It can be a PHP value or a
252
     *                    SoapVar object.
253
     * @param      bool   $mustUnderstand Value of the mustUnderstand attribute of the SOAP header
254
     *                    element.
255
     * @param      mixed  $actor Value of the actor attribute of the SOAP header element.
256
     *
257
     * @author     David Zülke <[email protected]>
258
     * @since      0.11.0
259
     */
260
    public function setSoapHeader($namespace, $name, $data = null, $mustUnderstand = false, $actor = null)
261
    {
262
        if ($actor === null) {
263
            $h = new \SoapHeader($namespace, $name, $data, $mustUnderstand);
264
        } else {
265
            $h = new \SoapHeader($namespace, $name, $data, $mustUnderstand, $actor);
266
        }
267
        $this->addSoapHeader($h);
268
    }
269
    
270
    /**
271
     * Remove a SOAP Header from this response based on its namespace and name.
272
     *
273
     * @param      string $namespace The namespace of the SOAP header element.
274
     * @param      string $name The name of the SOAP header element.
275
     *
276
     * @author     David Zülke <[email protected]>
277
     * @since      0.11.0
278
     */
279
    public function removeSoapHeader($namespace, $name)
280
    {
281
        if (($key = $this->searchSoapHeader($namespace, $name)) !== false) {
282
            unset($this->soapHeaders[$key]);
283
        }
284
    }
285
    
286
    /**
287
     * Check if a SOAP Header has been set based on its namespace and name.
288
     *
289
     * @param      string $namespace The namespace of the SOAP header element.
290
     * @param      string $name The name of the SOAP header element.
291
     *
292
     * @return     bool true, if this SOAP header has been set, false otherwise.
293
     *
294
     * @author     David Zülke <[email protected]>
295
     * @since      0.11.0
296
     */
297
    public function hasSoapHeader($namespace, $name)
298
    {
299
        return $this->searchSoapHeader($namespace, $name) !== false;
300
    }
301
    
302
    /**
303
     * Find the key of a SOAP Header based on its namespace and name.
304
     *
305
     * @param      string $namespace The namespace of the SOAP header element.
306
     * @param      string $name The name of the SOAP header element.
307
     *
308
     * @return     int The key of the SOAP header in the array, otherwise false.
309
     *
310
     * @author     David Zülke <[email protected]>
311
     * @since      0.11.0
312
     */
313
    protected function searchSoapHeader($namespace, $name)
314
    {
315
        foreach ($this->soapHeaders as $key => $soapHeader) {
316
            if ($soapHeader->namespace == $namespace && $soapHeader->name == $name) {
317
                return $key;
318
            }
319
        }
320
        return false;
321
    }
322
}
323