Completed
Push — master ( 5ddcc0...9e0ead )
by Carlos
42s
created

Material   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 261
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 98.51%

Importance

Changes 6
Bugs 2 Features 0
Metric Value
wmc 24
c 6
b 2
f 0
lcom 1
cbo 5
dl 0
loc 261
ccs 66
cts 67
cp 0.9851
rs 10

13 Methods

Rating   Name   Duplication   Size   Complexity  
A uploadImage() 0 4 1
A uploadVoice() 0 4 1
A uploadThumb() 0 4 1
A uploadVideo() 0 13 1
A uploadArticle() 0 19 4
A updateArticle() 0 10 3
A uploadArticleImage() 0 4 1
A get() 0 21 4
A delete() 0 4 1
A lists() 0 10 1
A stats() 0 4 1
A uploadMedia() 0 8 3
A getAPIByType() 0 12 2
1
<?php
2
3
/*
4
 * This file is part of the overtrue/wechat.
5
 *
6
 * (c) overtrue <[email protected]>
7
 *
8
 * This source file is subject to the MIT license that is bundled
9
 * with this source code in the file LICENSE.
10
 */
11
12
/**
13
 * Material.php.
14
 *
15
 * @author    overtrue <[email protected]>
16
 * @copyright 2015 overtrue <[email protected]>
17
 *
18
 * @link      https://github.com/overtrue
19
 * @link      http://overtrue.me
20
 */
21
namespace EasyWeChat\Material;
22
23
use EasyWeChat\Core\AbstractAPI;
24
use EasyWeChat\Core\Exceptions\InvalidArgumentException;
25
use EasyWeChat\Message\Article;
26
27
/**
28
 * Class Material.
29
 */
30
class Material extends AbstractAPI
31
{
32
    /**
33
     * Allow media type.
34
     *
35
     * @var array
36
     */
37
    protected $allowTypes = ['image', 'voice', 'video', 'thumb', 'news_image'];
38
39
    const API_GET = 'https://api.weixin.qq.com/cgi-bin/material/get_material';
40
    const API_UPLOAD = 'https://api.weixin.qq.com/cgi-bin/material/add_material';
41
    const API_DELETE = 'https://api.weixin.qq.com/cgi-bin/material/del_material';
42
    const API_STATS = 'https://api.weixin.qq.com/cgi-bin/material/get_materialcount';
43
    const API_LISTS = 'https://api.weixin.qq.com/cgi-bin/material/batchget_material';
44
    const API_NEWS_UPLOAD = 'https://api.weixin.qq.com/cgi-bin/material/add_news';
45
    const API_NEWS_UPDATE = 'https://api.weixin.qq.com/cgi-bin/material/update_news';
46
    const API_NEWS_IMAGE_UPLOAD = 'https://api.weixin.qq.com/cgi-bin/media/uploadimg';
47
48
    /**
49
     * Upload image.
50
     *
51
     * @param string $path
52
     *
53
     * @return string
54
     */
55 1
    public function uploadImage($path)
56
    {
57 1
        return $this->uploadMedia('image', $path);
58
    }
59
60
    /**
61
     * Upload voice.
62
     *
63
     * @param string $path
64
     *
65
     * @return string
66
     */
67 1
    public function uploadVoice($path)
68
    {
69 1
        return $this->uploadMedia('voice', $path);
70
    }
71
72
    /**
73
     * Upload thumb.
74
     *
75
     * @param string $path
76
     *
77
     * @return string
78
     */
79 1
    public function uploadThumb($path)
80
    {
81 1
        return $this->uploadMedia('thumb', $path);
82
    }
83
84
    /**
85
     * Upload video.
86
     *
87
     * @param string $path
88
     * @param string $title
89
     * @param string $description
90
     *
91
     * @return string
92
     */
93 1
    public function uploadVideo($path, $title, $description)
94
    {
95
        $params = [
96 1
            'description' => json_encode(
97
                [
98 1
                    'title' => $title,
99 1
                    'introduction' => $description,
100
                ]
101 1
            ),
102 1
        ];
103
104 1
        return $this->uploadMedia('video', $path, $params);
105
    }
106
107
    /**
108
     * Upload articles.
109
     *
110
     * @param array|Article $articles
111
     *
112
     * @return string
113
     */
114 1
    public function uploadArticle($articles)
115
    {
116 1
        if (!empty($articles['title']) || $articles instanceof Article) {
117 1
            $articles = [$articles];
118 1
        }
119
120 1
        $params = ['articles' => array_map(function ($article) {
121 1
            if ($article instanceof Article) {
122 1
                return $article->only([
123 1
                    'title', 'thumb_media_id', 'author', 'digest',
124 1
                    'show_cover_pic', 'content', 'content_source_url',
125 1
                    ]);
126
            }
127
128 1
            return $article;
129 1
        }, $articles)];
130
131 1
        return $this->parseJSON('json', [self::API_NEWS_UPLOAD, $params]);
132
    }
133
134
    /**
135
     * Update article.
136
     *
137
     * @param string $mediaId
138
     * @param array  $article
139
     * @param int    $index
140
     *
141
     * @return bool
142
     */
143 1
    public function updateArticle($mediaId, $article, $index = 0)
144
    {
145
        $params = [
146 1
            'media_id' => $mediaId,
147 1
            'index' => $index,
148 1
            'articles' => isset($article['title']) ? $article : (isset($article[$index]) ? $article[$index] : []),
149 1
        ];
150
151 1
        return $this->parseJSON('json', [self::API_NEWS_UPDATE, $params]);
152
    }
153
154
    /**
155
     * Upload image for article.
156
     *
157
     * @param string $path
158
     *
159
     * @return string
160
     */
161 1
    public function uploadArticleImage($path)
162
    {
163 1
        return $this->uploadMedia('news_image', $path);
164
    }
165
166
    /**
167
     * Fetch material.
168
     *
169
     * @param string $mediaId
170
     *
171
     * @return mixed
172
     */
173 1
    public function get($mediaId)
174
    {
175 1
        $response = $this->getHttp()->json(self::API_GET, ['media_id' => $mediaId]);
176
177 1
        foreach ($response->getHeader('Content-Type') as $mime) {
178 1
            if (preg_match('/(image|video|audio)/i', $mime)) {
179 1
                return $response->getBody();
180
            }
181 1
        }
182
183 1
        $json = $this->getHttp()->parseJSON($response);
184
185
        // XXX: 微信开发这帮混蛋,尼玛文件二进制输出不带header,简直日了!!!
186 1
        if (!$json) {
187
            return $response->getBody();
188
        }
189
190 1
        $this->checkAndThrow($json);
191
192 1
        return $json;
193
    }
194
195
    /**
196
     * Delete material by media ID.
197
     *
198
     * @param string $mediaId
199
     *
200
     * @return bool
201
     */
202 1
    public function delete($mediaId)
203
    {
204 1
        return $this->parseJSON('json', [self::API_DELETE, ['media_id' => $mediaId]]);
205
    }
206
207
    /**
208
     * List materials.
209
     *
210
     * example:
211
     *
212
     * {
213
     *   "total_count": TOTAL_COUNT,
214
     *   "item_count": ITEM_COUNT,
215
     *   "item": [{
216
     *             "media_id": MEDIA_ID,
217
     *             "name": NAME,
218
     *             "update_time": UPDATE_TIME
219
     *         },
220
     *         // more...
221
     *   ]
222
     * }
223
     *
224
     * @param string $type
225
     * @param int    $offset
226
     * @param int    $count
227
     *
228
     * @return array
229
     */
230 1
    public function lists($type, $offset = 0, $count = 20)
231
    {
232
        $params = [
233 1
            'type' => $type,
234 1
            'offset' => intval($offset),
235 1
            'count' => min(20, $count),
236 1
        ];
237
238 1
        return $this->parseJSON('json', [self::API_LISTS, $params]);
239
    }
240
241
    /**
242
     * Get stats of materials.
243
     *
244
     * @return array
245
     */
246 1
    public function stats()
247
    {
248 1
        return $this->parseJSON('get', [self::API_STATS]);
249
    }
250
251
    /**
252
     * Upload material.
253
     *
254
     * @param string $type
255
     * @param string $path
256
     * @param array  $form
257
     *
258
     * @return string
259
     *
260
     * @throws InvalidArgumentException
261
     */
262 5
    protected function uploadMedia($type, $path, array $form = [])
263
    {
264 5
        if (!file_exists($path) || !is_readable($path)) {
265 1
            throw new InvalidArgumentException("File does not exist, or the file is unreadable: '$path'");
266
        }
267
268 5
        return $this->parseJSON('upload', [$this->getAPIByType($type), ['media' => $path], $form, ['type' => $type]]);
269
    }
270
271
    /**
272
     * Get API by type.
273
     *
274
     * @param string $type
275
     *
276
     * @return string
277
     */
278 5
    public function getAPIByType($type)
279
    {
280
        switch ($type) {
281 5
            case 'news_image':
282 1
                $api = self::API_NEWS_IMAGE_UPLOAD;
283 1
                break;
284 4
            default:
285 4
                $api = self::API_UPLOAD;
286 4
        }
287
288 5
        return $api;
289
    }
290
}
291