Completed
Push — master ( 80d650...6d5780 )
by Ryosuke
02:39
created

UploaderTrait::uploadStep2()   C

Complexity

Conditions 13
Paths 66

Size

Total Lines 43
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 43
rs 5.1234
cc 13
eloc 31
nc 66
nop 3

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace mpyw\Cowitter\Traits;
4
5
use mpyw\Cowitter\HttpException;
6
use mpyw\Co\Co;
7
use mpyw\Cowitter\ResponseInterface;
8
9
trait UploaderTrait
10
{
11
    abstract public function getAsync($endpoint, array $params = [], $return_response_object = false);
12
    abstract public function postAsync($endpoint, array $params = [], $return_response_object = false);
13
    abstract public function postMultipartAsync($endpoint, array $params = [], $return_response_object = false);
14
15
    protected static function validateChunkSize($value)
16
    {
17
        if (false === $value = filter_var($value, FILTER_VALIDATE_INT)) {
18
            throw new \InvalidArgumentException('Chunk size must be integer.');
19
        }
20
        if ($value < 10000) {
21
            throw new \LengthException('Chunk size must be no less than 10000 bytes.');
22
        }
23
        return $value;
24
    }
25
26
    protected static function getMimeType(\SplFileObject $file)
27
    {
28
        $finfo = new \finfo(FILEINFO_MIME_TYPE);
29
        $type = $finfo->buffer($file->fread(1024));
30
        $file->rewind();
31
        return $type;
32
    }
33
34
    public function uploadAsync(\SplFileObject $file, $media_category = null, callable $on_progress = null, $chunk_size = 300000)
35
    {
36
        $response = (yield $this->uploadStep1($file, $media_category, $chunk_size));
37
        if (!isset($response->getContent()->processing_info)) {
38
            yield Co::RETURN_WITH => $response->getContent();
39
        }
40
        yield Co::RETURN_WITH => (yield $this->uploadStep2($response, $file, $on_progress));
41
    }
42
43
    protected function uploadStep1(\SplFileObject $file, $media_category = null, $chunk_size = 300000)
44
    {
45
        $chunk_size = static::validateChunkSize($chunk_size);
46
        $info = (yield $this->postAsync('media/upload', [
47
            'command' => 'INIT',
48
            'media_type' => static::getMimeType($file),
49
            'total_bytes' => $file->getSize(),
50
            'media_category' => $media_category,
51
        ]));
52
        $tasks = [];
53
        for ($i = 0; '' !== $buffer = $file->fread($chunk_size); ++$i) {
54
            $tasks[] = $this->postMultipartAsync('media/upload', [
55
                'command' => 'APPEND',
56
                'media_id' => $info->media_id_string,
57
                'segment_index' => $i,
58
                'media' => $buffer,
59
            ]);
60
        }
61
        yield $tasks;
62
        yield Co::RETURN_WITH => (yield $this->postAsync('media/upload', [
63
            'command' => 'FINALIZE',
64
            'media_id' => $info->media_id_string,
65
        ], true));
66
    }
67
68
    protected function uploadStep2(ResponseInterface $response, \SplFileObject $file, callable $on_progress = null)
0 ignored issues
show
Unused Code introduced by
The parameter $file is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
69
    {
70
        $info = $response->getContent();
71
        $canceled = false;
72
        while ($info->processing_info->state === 'pending' || $info->processing_info->state === 'in_progress') {
73
            $percent = isset($info->processing_info->progress_percent)
74
                ? $info->processing_info->progress_percent
75
                : null
76
            ;
77
            if ($on_progress && (new \ReflectionFunction($on_progress))->isGenerator()) {
78
                Co::async(function () use ($on_progress, $percent, $response, &$canceled) {
79
                    if (false === (yield $on_progress($percent, $response))) {
80
                        $canceled = true;
81
                    }
82
                });
83
            } elseif ($on_progress) {
84
                if (false === $on_progress($percent, $response)) {
85
                    yield Co::RETURN_WITH => $info;
86
                }
87
            }
88
            if ($canceled) yield Co::RETURN_WITH => $info;
89
            yield Co::DELAY => $info->processing_info->check_after_secs;
90
            if ($canceled) yield Co::RETURN_WITH => $info;
91
            $response = (yield $this->getAsync('media/upload', [
92
                'command' => 'STATUS',
93
                'media_id' => $info->media_id_string,
94
            ], true));
95
            $info = $response->getContent();
96
        }
97
98
        if ($info->processing_info->state === 'failed') {
99
            throw new HttpException(
100
                isset($info->processing_info->error->message)
101
                    ? $info->processing_info->error->message
102
                    : $info->processing_info->error->name,
103
                $info->processing_info->error->code,
104
                $response->getHandle(),
105
                $response
106
            );
107
        }
108
109
        yield Co::RETURN_WITH => $info;
110
    }
111
112
    public function uploadImageAsync(\SplFileObject $file, callable $on_progress = null, $chunk_size = 300000)
113
    {
114
        return $this->uploadAsync($file, 'tweet_image', $on_progress, $chunk_size);
115
    }
116
117
    public function uploadAnimeGifAsync(\SplFileObject $file, callable $on_progress = null, $chunk_size = 300000)
118
    {
119
        return $this->uploadAsync($file, 'tweet_gif', $on_progress, $chunk_size);
120
    }
121
122
    public function uploadVideoAsync(\SplFileObject $file, callable $on_progress = null, $chunk_size = 300000)
123
    {
124
        return $this->uploadAsync($file, 'tweet_video', $on_progress, $chunk_size);
125
    }
126
}
127