Completed
Push — master ( f0e0ca...79ebae )
by Christopher
04:17
created

getResourceFromRelatedResourceSet()   C

Complexity

Conditions 9
Paths 20

Size

Total Lines 46
Code Lines 34

Duplication

Lines 26
Ratio 56.52 %

Importance

Changes 0
Metric Value
dl 26
loc 46
rs 5.0942
c 0
b 0
f 0
cc 9
eloc 34
nc 20
nop 5
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 12 and the first side effect is on line 9.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
3
use POData\UriProcessor\ResourcePathProcessor\SegmentParser\KeyDescriptor;
4
use POData\Providers\Metadata\ResourceSet;
5
use POData\Providers\Metadata\ResourceProperty;
6
use POData\Providers\Query\IQueryProvider;
7
use POData\Common\ODataException;
8
9
require_once 'NorthWindMetadata.php';
10
require_once "POData\Providers\Query\IDataServiceQueryProvider2.php";
11
require_once 'NorthWindDSExpressionProvider.php';
12
define('DATABASE', 'Northwind');
13
// Note: The instance name of your sql server [How to find instance name]
14
// Start ->All progrmas->Microsoft SQL Server 2008 -> Configuration Tools -> SQL Server Configuration Manager
15
// In Configuration Manager -> SQL Server 2008 Services -> double click the SQL Service -> click the Service Tab.
16
define('SERVER', '.\SQLEXPRESS');
17
// Note: If your database access require credentials then un-comment
18
// the following two lines [definition of UID and PWD] and provide db user name
19
// as value for UID and password as value for PWD.
20
// define('UID',  '');
21
// define('PWD',  '');
22
23
class NorthWindQueryProvider implements IQueryProvider
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
Bug introduced by
There is at least one abstract method in this class. Maybe declare it as abstract, or implement the remaining methods: createResourceforResourceSet, deleteResource, updateResource
Loading history...
24
{
25
    /**
26
     * Handle to connection to Database.
27
     */
28
    private $_connectionHandle = null;
29
30
    /**
31
     * Reference to the custom expression provider.
32
     *
33
     * @var NorthWindDSExpressionProvider
34
     */
35
    private $_northWindSQLSRVExpressionProvider;
36
37
    /**
38
     * Constructs a new instance of NorthWindQueryProvider.
39
     */
40
    public function __construct()
41
    {
42
        $connectionInfo = array('Database' => DATABASE);
43
        if (defined('UID')) {
44
            $connectionInfo['UID'] = UID;
45
            $connectionInfo['PWD'] = PWD;
46
        }
47
48
        $this->_connectionHandle = sqlsrv_connect(SERVER, $connectionInfo);
49
        if ($this->_connectionHandle) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
50
        } else {
51
            $errorAsString = self::_getSQLSRVError();
52
            throw ODataException::createInternalServerError($errorAsString);
53
        }
54
55
        $this->_northWindSQLSRVExpressionProvider = null;
56
    }
57
58
    /**
59
     * (non-PHPdoc).
60
     *
61
     * @see POData\Providers\Query.IQueryProvider::canApplyQueryOptions()
62
     */
63
    public function handlesOrderedPaging()
64
    {
65
        return true;
66
    }
67
68
    /**
69
     * (non-PHPdoc).
70
     *
71
     * @see POData\Providers\Query.IQueryProvider::getExpressionProvider()
72
     */
73
    public function getExpressionProvider()
74
    {
75
        if (is_null($this->_northWindSQLSRVExpressionProvider)) {
76
            $this->_northWindSQLSRVExpressionProvider = new NorthWindDSExpressionProvider();
77
        }
78
79
        return $this->_northWindSQLSRVExpressionProvider;
80
    }
81
82
    /**
83
     * Gets collection of entities belongs to an entity set.
84
     *
85
     * @param ResourceSet $resourceSet  The entity set whose entities
86
     *                                  needs to be fetched
87
     * @param string      $filterOption Contains the filter condition
88
     * @param string      $select       For future purpose,no need to pass it
89
     * @param string      $orderby      For future purpose,no need to pass it
90
     * @param string      $top          For future purpose,no need to pass it
91
     * @param string      $skip         For future purpose,no need to pass it
92
     *
93
     * @return array(Object)
0 ignored issues
show
Documentation introduced by
The doc-type array(Object) could not be parsed: Expected "|" or "end of type", but got "(" at position 5. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
94
     */
95
    public function getResourceSet(
96
        ResourceSet $resourceSet,
97
        $filterOption = null,
98
        $select = null,
99
        $orderby = null,
100
        $top = null,
101
        $skip = null
102
    ) {
103
        $resourceSetName = $resourceSet->getName();
104 View Code Duplication
        if ($resourceSetName !== 'Customers'
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...
105
            && $resourceSetName !== 'Orders'
106
            && $resourceSetName !== 'Order_Details'
107
            && $resourceSetName !== 'Employees'
108
        ) {
109
            throw ODataException::createInternalServerError('(NorthWindQueryProvider) Unknown resource set ' . $resourceSetName . '! Contact service provider');
110
        }
111
112
        if ($resourceSetName === 'Order_Details') {
113
            $resourceSetName = 'Order Details';
114
        }
115
116
        $query = "SELECT * FROM [$resourceSetName]";
117
        if ($filterOption != null) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $filterOption of type string|null against null; this is ambiguous if the string can be empty. Consider using a strict comparison !== instead.
Loading history...
118
            $query .= ' WHERE ' . $filterOption;
119
        }
120
        $stmt = sqlsrv_query($this->_connectionHandle, $query);
121
        if ($stmt === false) {
122
            $errorAsString = self::_getSQLSRVError();
123
            throw ODataException::createInternalServerError($errorAsString);
124
        }
125
        $returnResult = array();
126 View Code Duplication
        switch ($resourceSetName) {
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...
127
            case 'Customers':
128
                $returnResult = $this->_serializeCustomers($stmt);
129
                break;
130
            case 'Orders':
131
                $returnResult = $this->_serializeOrders($stmt);
132
                break;
133
            case 'Order Details':
134
                $returnResult = $this->_serializeOrderDetails($stmt);
135
                break;
136
            case 'Employees':
137
                $returnResult = $this->_serializeEmployees($stmt);
138
                break;
139
        }
140
        sqlsrv_free_stmt($stmt);
141
142
        return $returnResult;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $returnResult; (array) is incompatible with the return type declared by the interface POData\Providers\Query\I...rovider::getResourceSet of type POData\Providers\Query\QueryResult.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
143
    }
144
145
    /**
146
     * Gets an entity instance from an entity set identifed by a key.
147
     *
148
     * @param ResourceSet   $resourceSet   The entity set from which
149
     *                                     an entity needs to be fetched
150
     * @param KeyDescriptor $keyDescriptor The key to identify the entity to be fetched
151
     *
152
     * @return object|null Returns entity instance if found else null
153
     */
154
    public function getResourceFromResourceSet(ResourceSet $resourceSet, KeyDescriptor $keyDescriptor)
155
    {
156
        $resourceSetName = $resourceSet->getName();
157 View Code Duplication
        if ($resourceSetName !== 'Customers'
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...
158
            && $resourceSetName !== 'Orders'
159
            && $resourceSetName !== 'Order_Details'
160
            && $resourceSetName !== 'Products'
161
            && $resourceSetName !== 'Employees'
162
        ) {
163
            die('(NorthWindQueryProvider) Unknown resource set ' . $resourceSetName);
0 ignored issues
show
Coding Style Compatibility introduced by
The method getResourceFromResourceSet() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
164
        }
165
166
        if ($resourceSetName === 'Order_Details') {
167
            $resourceSetName = 'Order Details';
168
        }
169
170
        $namedKeyValues = $keyDescriptor->getValidatedNamedValues();
171
        $condition = null;
172
        foreach ($namedKeyValues as $key => $value) {
173
            $condition .= $key . ' = ' . $value[0] . ' and ';
174
        }
175
176
        $len = strlen($condition);
177
        $condition = substr($condition, 0, $len - 5);
178
        $query = "SELECT * FROM [$resourceSetName] WHERE $condition";
179
        $stmt = sqlsrv_query($this->_connectionHandle, $query);
180
        if ($stmt === false) {
181
            $errorAsString = self::_getSQLSRVError();
182
            throw ODataException::createInternalServerError($errorAsString);
183
        }
184
185
        //If resource not found return null to the library
186
        if (!sqlsrv_has_rows($stmt)) {
187
            return null;
188
        }
189
190
        $result = null;
191
        while ($record = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
192 View Code Duplication
            switch ($resourceSetName) {
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...
193
                case 'Customers':
194
                    $result = $this->_serializeCustomer($record);
195
                    break;
196
                case 'Orders':
197
                    $result = $this->_serializeOrder($record);
198
                    break;
199
                case 'Order Details':
200
                    $result = $this->_serializeOrderDetail($record);
201
                    break;
202
                case 'Employees':
203
                    $result = $this->_serializeEmployee($record);
204
                    break;
205
            }
206
        }
207
        sqlsrv_free_stmt($stmt);
208
209
        return $result;
210
    }
211
212
    /**
213
     * Gets a related entity instance from an entity set identifed by a key.
214
     *
215
     * @param ResourceSet      $sourceResourceSet    The entity set related to
216
     *                                               the entity to be fetched
217
     * @param object           $sourceEntityInstance The related entity instance
218
     * @param ResourceSet      $targetResourceSet    The entity set from which
219
     *                                               entity needs to be fetched
220
     * @param ResourceProperty $targetProperty       The metadata of the target
221
     *                                               property
222
     * @param KeyDescriptor    $keyDescriptor        The key to identify the entity
223
     *                                               to be fetched
224
     *
225
     * @return object|null Returns entity instance if found else null
226
     */
227
    public function getResourceFromRelatedResourceSet(
228
        ResourceSet $sourceResourceSet,
229
        $sourceEntityInstance,
230
        ResourceSet $targetResourceSet,
231
        ResourceProperty $targetProperty,
232
        KeyDescriptor $keyDescriptor
233
    ) {
234
        $result = array();
235
        $srcClass = get_class($sourceEntityInstance);
236
        $navigationPropName = $targetProperty->getName();
237
        $key = null;
238
        foreach ($keyDescriptor->getValidatedNamedValues() as $keyName => $valueDescription) {
239
            $key = $key . $keyName . '=' . $valueDescription[0] . ' and ';
240
        }
241
242
        $key = rtrim($key, ' and ');
243
        if ($srcClass === 'Customer') {
244 View Code Duplication
            if ($navigationPropName === 'Orders') {
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...
245
                $query = "SELECT * FROM Orders WHERE CustomerID = '$sourceEntityInstance->CustomerID' and $key";
246
                $stmt = sqlsrv_query($this->_connectionHandle, $query);
247
                if ($stmt === false) {
248
                    $errorAsString = self::_getSQLSRVError();
249
                    throw ODataException::createInternalServerError($errorAsString);
250
                }
251
252
                $result = $this->_serializeOrders($stmt);
253
            } else {
254
                die('Customer does not have navigation porperty with name: ' . $navigationPropName);
0 ignored issues
show
Coding Style Compatibility introduced by
The method getResourceFromRelatedResourceSet() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
255
            }
256 View Code Duplication
        } elseif ($srcClass === 'Order') {
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...
257
            if ($navigationPropName === 'Order_Details') {
258
                $query = "SELECT * FROM [Order Details] WHERE OrderID = $sourceEntityInstance->OrderID";
259
                $stmt = sqlsrv_query($this->_connectionHandle, $query);
260
                if ($stmt === false) {
261
                    $errorAsString = self::_getSQLSRVError();
262
                    throw ODataException::createInternalServerError($errorAsString);
263
                }
264
265
                $result = $this->_serializeOrderDetails($stmt);
266
            } else {
267
                die('Order does not have navigation porperty with name: ' . $navigationPropName);
0 ignored issues
show
Coding Style Compatibility introduced by
The method getResourceFromRelatedResourceSet() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
268
            }
269
        }
270
271
        return empty($result) ? null : $result[0];
272
    }
273
274
    /**
275
     * Get related resource set for a resource.
276
     *
277
     * @param ResourceSet      $sourceResourceSet    The source resource set
278
     * @param mixed            $sourceEntityInstance The resource
279
     * @param ResourceSet      $targetResourceSet    The resource set of
280
     *                                               the navigation property
281
     * @param ResourceProperty $targetProperty       The navigation property to be
282
     *                                               retrieved
283
     * @param string           $filterOption         Contains the filter condition
284
     *                                               to append with query
285
     * @param string           $select               For future purpose,no need to pass it
286
     * @param string           $orderby              For future purpose,no need to pass it
287
     * @param string           $top                  For future purpose,no need to pass it
288
     * @param string           $skip                 For future purpose,no need to pass it
289
     *
290
     * @return object[] Array of related resource if exists, if no
291
     *                  related resources found returns empty array
292
     */
293
    public function getRelatedResourceSet(
294
        ResourceSet $sourceResourceSet,
295
        $sourceEntityInstance,
296
        ResourceSet $targetResourceSet,
297
        ResourceProperty $targetProperty,
298
        $filterOption = null,
299
        $select = null,
300
        $orderby = null,
301
        $top = null,
302
        $skip = null
303
    ) {
304
        $result = array();
305
        $srcClass = get_class($sourceEntityInstance);
306
        $navigationPropName = $targetProperty->getName();
307
        if ($srcClass === 'Customer') {
308 View Code Duplication
            if ($navigationPropName === 'Orders') {
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...
309
                $query = "SELECT * FROM Orders WHERE CustomerID = '$sourceEntityInstance->CustomerID'";
310
                if ($filterOption != null) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $filterOption of type string|null against null; this is ambiguous if the string can be empty. Consider using a strict comparison !== instead.
Loading history...
311
                    $query .= ' AND ' . $filterOption;
312
                }
313
                $stmt = sqlsrv_query($this->_connectionHandle, $query);
314
                if ($stmt === false) {
315
                    $errorAsString = self::_getSQLSRVError();
316
                    throw ODataException::createInternalServerError($errorAsString);
317
                }
318
319
                $result = $this->_serializeOrders($stmt);
320
            } else {
321
                die('Customer does not have navigation porperty with name: ' . $navigationPropName);
0 ignored issues
show
Coding Style Compatibility introduced by
The method getRelatedResourceSet() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
322
            }
323 View Code Duplication
        } elseif ($srcClass === 'Order') {
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...
324
            if ($navigationPropName === 'Order_Details') {
325
                $query = "SELECT * FROM [Order Details] WHERE OrderID = $sourceEntityInstance->OrderID";
326
                if ($filterOption != null) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $filterOption of type string|null against null; this is ambiguous if the string can be empty. Consider using a strict comparison !== instead.
Loading history...
327
                    $query .= ' AND ' . $filterOption;
328
                }
329
                $stmt = sqlsrv_query($this->_connectionHandle, $query);
330
                if ($stmt === false) {
331
                    $errorAsString = self::_getSQLSRVError();
332
                    throw ODataException::createInternalServerError($errorAsString);
333
                }
334
335
                $result = $this->_serializeOrderDetails($stmt);
336
            } else {
337
                die('Order does not have navigation porperty with name: ' . $navigationPropName);
0 ignored issues
show
Coding Style Compatibility introduced by
The method getRelatedResourceSet() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
338
            }
339
        }
340
341
        return $result;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $result; (array) is incompatible with the return type declared by the interface POData\Providers\Query\I...::getRelatedResourceSet of type POData\Providers\Query\QueryResult.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
342
    }
343
344
    /**
345
     * Get related resource for a resource.
346
     *
347
     * @param ResourceSet      $sourceResourceSet    The source resource set
348
     * @param mixed            $sourceEntityInstance The source resource
349
     * @param ResourceSet      $targetResourceSet    The resource set of
350
     *                                               the navigation property
351
     * @param ResourceProperty $targetProperty       The navigation property to be
352
     *                                               retrieved
353
     *
354
     * @return object|null The related resource if exists else null
355
     */
356
    public function getRelatedResourceReference(
357
        ResourceSet $sourceResourceSet,
358
        $sourceEntityInstance,
359
        ResourceSet $targetResourceSet,
360
        ResourceProperty $targetProperty
361
    ) {
362
        $result = null;
363
        $srcClass = get_class($sourceEntityInstance);
364
        $navigationPropName = $targetProperty->getName();
365
        if ($srcClass === 'Order') {
366 View Code Duplication
            if ($navigationPropName === 'Customer') {
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...
367
                if (empty($sourceEntityInstance->CustomerID)) {
368
                    $result = null;
369
                } else {
370
                    $query = "SELECT * FROM Customers WHERE CustomerID = '$sourceEntityInstance->CustomerID'";
371
                    $stmt = sqlsrv_query($this->_connectionHandle, $query);
372
                    if ($stmt === false) {
373
                        $errorAsString = self::_getSQLSRVError();
374
                        throw ODataException::createInternalServerError($errorAsString);
375
                    }
376
377
                    if (!sqlsrv_has_rows($stmt)) {
378
                        $result = null;
0 ignored issues
show
Unused Code introduced by
$result 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...
379
                    }
380
381
                    $result = $this->_serializeCustomer(sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC));
382
                }
383
            } else {
384
                die('Customer does not have navigation porperty with name: ' . $navigationPropName);
0 ignored issues
show
Coding Style Compatibility introduced by
The method getRelatedResourceReference() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
385
            }
386 View Code Duplication
        } elseif ($srcClass === 'Order_Details') {
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...
387
            if ($navigationPropName === 'Order') {
388
                if (empty($sourceEntityInstance->OrderID)) {
389
                    $result = null;
390
                } else {
391
                    $query = "SELECT * FROM Orders WHERE OrderID = $sourceEntityInstance->OrderID";
392
                    $stmt = sqlsrv_query($this->_connectionHandle, $query);
393
                    if ($stmt === false) {
394
                        $errorAsString = self::_getSQLSRVError();
395
                        throw ODataException::createInternalServerError($errorAsString);
396
                    }
397
398
                    if (!sqlsrv_has_rows($stmt)) {
399
                        $result = null;
0 ignored issues
show
Unused Code introduced by
$result 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...
400
                    }
401
402
                    $result = $this->_serializeOrder(sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC));
403
                }
404
            } else {
405
                die('Order_Details does not have navigation porperty with name: ' . $navigationPropName);
0 ignored issues
show
Coding Style Compatibility introduced by
The method getRelatedResourceReference() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
406
            }
407
        }
408
409
        return $result;
410
    }
411
412
    /**
413
     * Serialize the sql result array into Customer objects.
414
     *
415
     * @param array(array) $result result of the sql query
0 ignored issues
show
Documentation introduced by
The doc-type array(array) could not be parsed: Expected "|" or "end of type", but got "(" at position 5. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
416
     *
417
     * @return array(Object)
0 ignored issues
show
Documentation introduced by
The doc-type array(Object) could not be parsed: Expected "|" or "end of type", but got "(" at position 5. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
418
     */
419
    private function _serializeCustomers($result)
420
    {
421
        $customers = array();
422
        while ($record = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC)) {
423
            $customers[] = $this->_serializeCustomer($record);
424
        }
425
426
        return $customers;
427
    }
428
429
    /**
430
     * Serialize the sql row into Customer object.
431
     *
432
     * @param array $record each row of customer
433
     *
434
     * @return Customer
435
     */
436
    private function _serializeCustomer($record)
437
    {
438
        $customer = new Customer();
439
        $customer->CustomerID = $record['CustomerID'];
440
        $customer->CompanyName = $record['CompanyName'];
441
        $customer->ContactName = $record['ContactName'];
442
        $customer->ContactTitle = $record['ContactTitle'];
443
        $customer->Phone = $record['Phone'];
444
        $customer->Fax = $record['Fax'];
445
        $customer->Address = new Address();
446
        $customer->Address->StreetName = ($record['Address']);
447
        $customer->Address->City = $record['City'];
448
        $customer->Address->Region = $record['Region'];
449
        $customer->Address->PostalCode = $record['PostalCode'];
450
        $customer->Address->Country = $record['Country'];
451
        //Set alternate address
452
        $customer->Address->AltAddress = new Address();
453
        $customer->Address->AltAddress->StreetName = 'ALT_' . $customer->Address->StreetName;
454
        $customer->Address->AltAddress->City = 'ALT_' . $customer->Address->City;
455
        $customer->Address->AltAddress->Region = 'ALT_' . $customer->Address->Region;
456
        $customer->Address->AltAddress->PostalCode = 'ALT_' . $customer->Address->PostalCode;
457
        $customer->Address->AltAddress->Country = 'ALT_' . $customer->Address->Country;
458
        $customer->EmailAddresses = array();
459
        for ($i = 1; $i < 4; ++$i) {
460
            $customer->EmailAddresses[] = $customer->CustomerID . $i . '@live.com';
461
        }
462
463
        $customer->OtherAddresses = array();
464
        for ($i = 0; $i < 2; ++$i) {
465
            $customer->OtherAddresses[$i] = new Address();
466
            $this->_copyAddress($customer->Address, $customer->OtherAddresses[$i], $i + 1);
467
        }
468
469
        return $customer;
470
    }
471
472
    /**
473
     * copy address.
474
     *
475
     * @param object  &$src    source
476
     * @param object  &$target target
477
     * @param int     $tag     tag
478
     * @param Address $target
479
     */
480
    private function _copyAddress(&$src, &$target, $tag)
481
    {
482
        $target->StreetName = $src->StreetName . $tag;
483
        $target->City = $src->City . $tag;
484
        $target->Region = $src->Region . $tag;
485
        $target->PostalCode = $src->PostalCode . $tag;
486
        $target->Country = $src->Country . $tag;
487
488
        $target->AltAddress = new Address();
489
        $target->AltAddress->StreetName = $target->AltAddress->StreetName . $tag;
490
        $target->AltAddress->City = $target->AltAddress->City . $tag;
491
        $target->AltAddress->Region = $target->AltAddress->Region . $tag;
492
        $target->AltAddress->PostalCode = $target->AltAddress->PostalCode . $tag;
493
        $target->AltAddress->Country = $target->AltAddress->Country . $tag;
494
    }
495
496
    /**
497
     * Serialize the sql result array into Order objects.
498
     *
499
     * @param array(array) $result result of the sql query
0 ignored issues
show
Documentation introduced by
The doc-type array(array) could not be parsed: Expected "|" or "end of type", but got "(" at position 5. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
500
     *
501
     * @return array(Object)
0 ignored issues
show
Documentation introduced by
The doc-type array(Object) could not be parsed: Expected "|" or "end of type", but got "(" at position 5. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
502
     */
503
    private function _serializeOrders($result)
504
    {
505
        $orders = array();
506
        while ($record = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC)) {
507
            $orders[] = $this->_serializeOrder($record);
508
        }
509
510
        return $orders;
511
    }
512
513
    /**
514
     * Serialize the sql row into Order object.
515
     *
516
     * @param array $record each row of customer
517
     *
518
     * @return Order
519
     */
520
    private function _serializeOrder($record)
521
    {
522
        $order = new Order();
523
        $order->OrderID = $record['OrderID'];
524
        $order->CustomerID = $record['CustomerID'];
525
        $order->EmployeeID = $record['EmployeeID'];
526
        $order->OrderDate = !is_null($record['OrderDate']) ? $record['OrderDate']->format('Y-m-d\TH:i:s') : null;
527
        $order->RequiredDate = !is_null($record['RequiredDate']) ? $record['RequiredDate']->format('Y-m-d\TH:i:s') : null;
528
        $order->ShippedDate = !is_null($record['ShippedDate']) ? $record['ShippedDate']->format('Y-m-d\TH:i:s') : null;
529
        $order->ShipVia = $record['ShipVia'];
530
        $order->Freight = $record['Freight'];
531
        $order->ShipName = $record['ShipName'];
532
        $order->ShipAddress = $record['ShipAddress'];
533
        $order->ShipCity = $record['ShipCity'];
534
        $order->ShipRegion = $record['ShipRegion'];
535
        $order->ShipPostalCode = $record['ShipPostalCode'];
536
        $order->ShipCountry = $record['ShipCountry'];
537
538
        return $order;
539
    }
540
541
    /**
542
     * Serialize the sql result array into Employee objects.
543
     *
544
     * @param array(array) $result result of the sql query
0 ignored issues
show
Documentation introduced by
The doc-type array(array) could not be parsed: Expected "|" or "end of type", but got "(" at position 5. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
545
     *
546
     * @return array(Object)
0 ignored issues
show
Documentation introduced by
The doc-type array(Object) could not be parsed: Expected "|" or "end of type", but got "(" at position 5. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
547
     */
548
    private function _serializeEmployees($result)
549
    {
550
        $employees = array();
551
        while ($record = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC)) {
552
            $employees[] = $this->_serializeEmployee($record);
553
        }
554
555
        return $employees;
556
    }
557
558
    /**
559
     * Serialize the sql row into Employee object.
560
     *
561
     * @param array $record each row of employee
562
     *
563
     * @return Employee
564
     */
565
    private function _serializeEmployee($record)
566
    {
567
        $employee = new Employee();
568
        $employee->EmployeeID = $record['EmployeeID'];
569
        $employee->FirstName = $record['FirstName'];
570
        $employee->LastName = $record['LastName'];
571
        $employee->Title = $record['Title'];
572
        $employee->TitleOfCourtesy = $record['TitleOfCourtesy'];
573
        $employee->BirthDate = !is_null($record['BirthDate']) ? $record['BirthDate']->format('Y-m-d\TH:i:s') : null;
574
        $employee->HireDate = !is_null($record['HireDate']) ? $record['HireDate']->format('Y-m-d\TH:i:s') : null;
575
        $employee->Address = $record['Address'];
576
        $employee->City = $record['City'];
577
        $employee->Region = $record['Region'];
578
        $employee->PostalCode = $record['PostalCode'];
579
        $employee->Country = $record['Country'];
580
        $employee->HomePhone = $record['HomePhone'];
581
        $employee->Extension = $record['Extension'];
582
        $employee->Notes = $record['Notes'];
583
        $employee->ReportsTo = $record['ReportsTo'];
584
        //$employee->Photo = $record['Photo'];
0 ignored issues
show
Unused Code Comprehensibility introduced by
64% 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...
585
        $employee->Emails = array($employee->FirstName . '@hotmail.com', $employee->FirstName . '@live.com');
586
587
        return $employee;
588
    }
589
590
    /**
591
     * Serialize the sql result array into Order_Details objects.
592
     *
593
     * @param array(array) $result result of the sql query
0 ignored issues
show
Documentation introduced by
The doc-type array(array) could not be parsed: Expected "|" or "end of type", but got "(" at position 5. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
594
     *
595
     * @return array(Object)
0 ignored issues
show
Documentation introduced by
The doc-type array(Object) could not be parsed: Expected "|" or "end of type", but got "(" at position 5. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
596
     */
597
    private function _serializeOrderDetails($result)
598
    {
599
        $order_details = array();
600
        while ($record = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC)) {
601
            $order_details[] = $this->_serializeOrderDetail($record);
602
        }
603
604
        return $order_details;
605
    }
606
607
    /**
608
     * Serialize the sql row into Order_Details object.
609
     *
610
     * @param array $record each row of order detail
611
     *
612
     * @return Order_Details
613
     */
614
    private function _serializeOrderDetail($record)
615
    {
616
        $order_details = new Order_Details();
617
        $order_details->Discount = $record['Discount'];
618
        $order_details->OrderID = $record['OrderID'];
619
        $order_details->ProductID = $record['ProductID'];
620
        $order_details->Quantity = $record['Quantity'];
621
        $order_details->UnitPrice = $record['UnitPrice'];
622
623
        return $order_details;
624
    }
625
626
    /**
627
     * Gets the last sql server error as a string.
628
     *
629
     * @return string
630
     */
631
    private static function _getSQLSRVError()
632
    {
633
        $result = null;
634
        $errors = sqlsrv_errors();
635
        self::_getSQLSRVError1($errors, $result);
636
637
        return $result;
638
    }
639
640
    /**
641
     * Rescursive function to get the sql server error as string.
642
     *
643
     * @param array/string $errors
0 ignored issues
show
Documentation introduced by
The doc-type array/string could not be parsed: Unknown type name "array/string" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
644
     * @param string       $result
645
     */
646
    private static function _getSQLSRVError1($errors, &$result)
647
    {
648
        if (is_array($errors)) {
649
            foreach ($errors as $error) {
650
                self::_getSQLSRVError1($error, $result);
651
            }
652
        } else {
653
            $result .= $errors;
654
        }
655
    }
656
657
    /**
658
     * The destructor.
659
     */
660
    public function __destruct()
661
    {
662
        if ($this->_connectionHandle) {
663
            sqlsrv_close($this->_connectionHandle);
664
        }
665
    }
666
}
667