Failed Conditions
Pull Request — master (#191)
by Emanuele
03:09
created

AdImage::read()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 22
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 22
rs 8.9197
cc 4
eloc 14
nc 4
nop 2
1
<?php
2
/**
3
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
4
 *
5
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
6
 * use, copy, modify, and distribute this software in source code or binary
7
 * form for use in connection with the web services and APIs provided by
8
 * Facebook.
9
 *
10
 * As with any software that integrates with the Facebook platform, your use
11
 * of this software is subject to the Facebook Developer Principles and
12
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
13
 * shall be included in all copies or substantial portions of the software.
14
 *
15
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21
 * DEALINGS IN THE SOFTWARE.
22
 *
23
 */
24
25
namespace FacebookAds\Object;
26
27
use FacebookAds\Api;
28
use FacebookAds\Cursor;
29
use FacebookAds\Http\RequestInterface;
30
use FacebookAds\Object\Fields\AdImageFields;
31
use FacebookAds\Object\Traits\CannotUpdate;
32
use FacebookAds\Object\Traits\FieldValidation;
33
34
class AdImage extends AbstractCrudObject
35
{
36
    use FieldValidation;
37
    use CannotUpdate;
38
39
    /**
40
     * Uploads images from a zip file and returns a cursor of results
41
     *
42
     * @param string $file_path
43
     * @param string $account_id
44
     * @param array $params
45
     * @param Api $api
46
     * @return array
47
     */
48
    public static function createFromZip(
49
        $file_path, $account_id, array $params = array(), Api $api = null)
50
    {
51
        $image = new AdImage(null, $account_id, $api);
52
        $image->{AdImageFields::FILENAME} = $file_path;
53
        return $image->arrayFromZip($params);
54
    }
55
56
    /**
57
     * @return string
58
     */
59
    protected function getEndpoint()
60
    {
61
        return 'adimages';
62
    }
63
64
    /**
65
     * @return AdImageFields
66
     */
67
    public static function getFieldsEnum()
68
    {
69
        return AdImageFields::getInstance();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return \FacebookAds\Obje...eFields::getInstance(); (FacebookAds\Object\Fields\AdImageFields) is incompatible with the return type of the parent method FacebookAds\Object\AbstractObject::getFieldsEnum of type FacebookAds\Enum\EmptyEnum.

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...
70
    }
71
72
    /**
73
     * @return string
74
     */
75
    protected function getNodePath()
76
    {
77
        return '/'.$this->assureParentId().'/'.$this->getEndpoint();
78
    }
79
80
    /**
81
     * Create function for the object.
82
     *
83
     * @param array $params Additional parameters to include in the request
84
     * @return $this
85
     * @throws \Exception
86
     * @throws \RuntimeException
87
     */
88
    public function create(array $params = array())
89
    {
90
        if ($this->data[static::FIELD_ID]) {
91
            throw new \Exception("Object has already an ID");
92
        }
93
94
        if ($this->isZipFile($this->data[AdImageFields::FILENAME])) {
95
            throw new \RuntimeException(
96
                "use AdImage::createFromZip to create zip files");
97
        }
98
99
        $data = $this->exportData();
100
        $filename = $data[AdImageFields::FILENAME];
101
        unset($data[AdImageFields::FILENAME]);
102
        $params = array_merge($data, $params);
103
104
        $request = $this->getApi()->prepareRequest(
105
            '/'.$this->assureParentId().'/'.$this->getEndpoint(),
106
            RequestInterface::METHOD_POST,
107
            $params
108
        );
109
110
        $request->getFileParams()->offsetSet(AdImageFields::FILENAME, $filename);
111
        $response = $this->getApi()->executeRequest($request);
112
113
        $this->clearHistory();
114
        $data = $response->getContent()['images']
115
            [basename($this->{AdImageFields::FILENAME})];
116
117
        $this->data[AdImageFields::HASH] = $data[AdImageFields::HASH];
118
119
        $this->data[static::FIELD_ID]
120
            = substr($this->getParentId(), 4).':'.$this->data[AdImageFields::HASH];
121
122
        return $this;
123
    }
124
125
    /**
126
     * Read object data from the graph
127
     *
128
     * @param string[] $fields Fields to request
129
     * @param array $params Additional request parameters
130
     * @return $this
131
     */
132
    public function read(array $fields = array(), array $params = array())
133
    {
134
        $fields = implode(',', $fields ?: static::getDefaultReadFields());
135
        if ($fields) {
136
            $params['fields'] = $fields;
137
        }
138
        $params['hashes'] = array(explode(':', $this->assureId())[1]);
139
140
        $response = $this->getApi()->call(
141
            $this->getNodePath(),
142
            RequestInterface::METHOD_GET,
143
            $params);
144
145
        $data = $response->getContent()['data'];
146
        if ($data) {
147
            $this->setDataWithoutValidation((array) $data[0]);
148
        }
149
150
        $this->clearHistory();
151
152
        return $this;
153
    }
154
155
    /**
156
     * Delete this object from the graph
157
     *
158
     * @param array $params
159
     * @return void
160
     * @throws \Exception
161
     */
162
    public function delete(array $params = array())
163
    {
164
        if (!$this->data[AdImageFields::HASH]) {
165
            throw new \Exception("AdImage hash is required to delete");
166
        }
167
168
        $params
169
            = array_merge($params, array('hash' => $this->data[AdImageFields::HASH]));
170
171
        parent::delete($params);
172
    }
173
174
    /**
175
     * Uploads images from a zip file and returns a cursor of results
176
     *
177
     * @param array $params
178
     * @return array
179
     * @throws \RuntimeException
180
     */
181
    protected function arrayFromZip($params = array())
182
    {
183
        if (!$this->isZipFile($this->data[AdImageFields::FILENAME])) {
184
            throw new \RuntimeException(
185
                $this->data[AdImageFields::FILENAME]." doesn't resolve to a zip file");
186
        }
187
188
        $data = $this->exportData();
189
        $filename = $data[AdImageFields::FILENAME];
190
        unset($data[AdImageFields::FILENAME]);
191
        $params = array_merge($data, $params);
192
193
        $request = $this->getApi()->prepareRequest(
194
            '/'.$this->assureParentId().'/'.$this->getEndpoint(),
195
            RequestInterface::METHOD_POST,
196
            $params
197
        );
198
199
        $request->getFileParams()->offsetSet(AdImageFields::FILENAME, $filename);
200
        $response = $this->getApi()->executeRequest($request);
201
202
        $result = array();
203
        foreach ($response->getContent()['images'] as $image) {
204
            $adimage = new AdImage(
205
                substr($this->getParentId(), 4).':'.$image[AdImageFields::HASH],
206
                $this->getParentId(),
207
                $this->getApi());
208
209
            $adimage->{AdImageFields::HASH} = $image[AdImageFields::HASH];
210
211
            $result[] = $adimage;
212
        }
213
214
        return $result;
215
    }
216
217
    /**
218
     * Checks if a given path is a zip file
219
     *
220
     * @param string $file_path
221
     * @return bool
222
     */
223
    protected function isZipFile($file_path)
224
    {
225
        $finfo = finfo_open(FILEINFO_MIME_TYPE);
226
        $file_mime_type = finfo_file($finfo, $file_path);
227
        return $file_mime_type == 'application/zip' ||
228
            $file_mime_type == 'multipart/x-zip';
229
    }
230
}
231