Shipment::toXml()   C
last analyzed

Complexity

Conditions 7
Paths 16

Size

Total Lines 25
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 13
c 1
b 0
f 0
nc 16
nop 1
dl 0
loc 25
rs 6.7272
1
<?php namespace SimpleUPS;
2
3
use \SimpleUPS\Shipper;
4
5
use \SimpleUPS\InstructionalAddress;
6
7
/**
8
 * A shipment is associated with a tracking number and is made up of 1 or more packages
9
 * @internal
10
 * @since 1.0
11
 */
12
class Shipment extends Model
13
{
14
15
    private
16
        /* @var Shipper $shipper */
17
        $shipper,
18
19
        /* @var InstructionalAddress $destination */
20
        $destination,
21
22
        /* @var Service $service */
23
        $service,
24
25
        /* @var Package[] $packages */
26
        $packages;
27
28
    /**
29
     * @internal
30
     *
31
     * @param Shipper $shipper
32
     *
33
     * @return Shipment
34
     */
35
    public function setShipper(Shipper $shipper)
36
    {
37
        $this->shipper = $shipper;
38
        return $this;
39
    }
40
41
    /**
42
     * Information about the shipper
43
     * @return Shipper
44
     */
45
    public function getShipper()
46
    {
47
        return $this->shipper;
48
    }
49
50
    /**
51
     * @internal
52
     *
53
     * @param InstructionalAddress $destination
54
     *
55
     * @return Shipment
56
     */
57
    public function setDestination(InstructionalAddress $destination)
58
    {
59
        $this->destination = $destination;
60
        return $this;
61
    }
62
63
    /**
64
     * Delivery destination
65
     * @return InstructionalAddress
66
     */
67
    public function getDestination()
68
    {
69
        return $this->destination;
70
    }
71
72
    /**
73
     * @internal
74
     *
75
     * @param Service $service
76
     *
77
     * @return Shipment
78
     */
79
    public function setService(Service $service)
80
    {
81
        $this->service = $service;
82
        return $this;
83
    }
84
85
    /**
86
     * Shipping service used
87
     * @return Service
88
     */
89
    public function getService()
90
    {
91
        return $this->service;
92
    }
93
94
    /**
95
     * @internal
96
     *
97
     * @param Package $package
98
     *
99
     * @return Shipment
100
     */
101
    public function addPackage(Package $package)
102
    {
103
        if ($this->packages === null) {
104
            $this->packages = array();
105
        }
106
107
        $this->packages[] = $package;
108
        return $this;
109
    }
110
111
    /**
112
     * Packages in this shipment
113
     * @return Package[]
114
     */
115
    public function getPackages()
116
    {
117
        return $this->packages;
118
    }
119
120
    /**
121
     * @internal
122
     *
123
     * @param \DomDocument $dom
124
     *
125
     * @return \DOMElement
126
     */
127
    public function toXml(\DomDocument $dom)
128
    {
129
        $shipment = $dom->createElement('Shipment');
130
131
        if ($this->getShipper() != null) {
132
            $shipment->appendChild($this->getShipper()->toXml($dom));
133
        }
134
135
        if ($this->getDestination() != null) {
136
            $shipment->appendChild($shipFrom = $dom->createElement('ShipTo'));
137
            $shipFrom->appendChild($this->getDestination()->toXml($dom));
138
        }
139
140
        if ($this->getService() != null) {
141
            $shipment->appendChild($this->getService()->toXml($dom));
142
        }
143
144
        if ($this->getPackages() != null && count($this->getPackages()) > 0) {
145
            foreach ($this->getPackages() as $package) {
146
                $shipment->appendChild($package->toXml($dom));
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class SimpleUPS\Package as the method toXml() does only exist in the following sub-classes of SimpleUPS\Package: SimpleUPS\Rates\Package. 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...
147
            }
148
        }
149
150
        return $shipment;
151
    }
152
153
    /**
154
     * @internal
155
     *
156
     * @param \SimpleXMLElement $xml
157
     *
158
     * @return Shipment
159
     */
160
    public static function fromXml(\SimpleXMLElement $xml)
161
    {
162
        $shipment = new Shipment();
163
        $shipment->setIsResponse();
164
165
        if (isset($xml->Shipper)) {
166
            $shipment->setShipper(Shipper::fromXml($xml->Shipper));
167
        }
168
169
        if (isset($xml->ShipTo->Address)) {
170
            $shipment->setDestination(InstructionalAddress::fromXml($xml->ShipTo->Address));
171
        }
172
173
        if (isset($xml->Package)) {
174
            foreach ($xml->Package as $package) {
175
                $shipment->addPackage(Package::fromXml($package));
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class SimpleUPS\Package as the method fromXml() does only exist in the following sub-classes of SimpleUPS\Package: SimpleUPS\Track\SmallPackage\Package. 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...
176
            }
177
        }
178
179
        if (isset($xml->Service)) {
180
            $shipment->setService(Service::fromXml($xml->Service));
181
        }
182
183
        return $shipment;
184
    }
185
}