Passed
Push — master ( 7ab43b...7480b4 )
by Paweł
03:52
created

AccountQuery::findOneById()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 4
nc 1
nop 1
1
<?php
2
/**
3
 * Created for IG Client.
4
 * User: jakim <[email protected]>
5
 * Date: 14.03.2018
6
 */
7
8
namespace Jakim\Query;
9
10
11
use Jakim\Base\Query;
12
use Jakim\Helper\JsonHelper;
13
use jakim\ig\Endpoint;
14
use jakim\ig\Url;
15
use Jakim\Mapper\AccountDetails;
16
use Jakim\Mapper\AccountInfo;
17
use Jakim\Mapper\AccountMedia;
18
use Jakim\Model\Account;
19
use Jakim\Model\Post;
20
21
class AccountQuery extends Query
22
{
23
    const MAX_POSTS_PER_PAGE = 100;
24
    public $postsPerPage = 100;
25
26
    protected $accountDetailsMapper;
27
    protected $accountMediaMapper;
28
    protected $accountInfoMapper;
29
30
    public function __construct($httpClient, AccountDetails $accountDetailsMapper = null, AccountMedia $accountMediaMapper = null, AccountInfo $accountInfoMapper = null)
31
    {
32
        parent::__construct($httpClient);
33
        $this->accountDetailsMapper = $accountDetailsMapper ?? new AccountDetails();
34
        $this->accountMediaMapper = $accountMediaMapper ?? new AccountMedia();
35
        $this->accountInfoMapper = $accountInfoMapper ?? new AccountInfo();
36
    }
37
38
    /**
39
     * @param mixed $ident username or account id
40
     * @return \Jakim\Model\Account
41
     */
42
    public function findOne($ident): Account
43
    {
44
        if (is_numeric($ident)) {
45
            return $this->findOneById($ident);
46
        }
47
48
        return $this->findOneByUsername($ident);
49
    }
50
51
    public function findOneByUsername(string $username)
52
    {
53
        $url = Url::account($username);
54
        $data = $this->fetchContentAsArray($url);
55
56
        $data = $this->accountDetailsMapper->normalizeData(Account::class, $data);
57
58
        return $this->accountDetailsMapper->populate(Account::class, $data);
59
    }
60
61
    public function findOneById($accountId)
62
    {
63
        $url = Endpoint::accountInfo($accountId);
64
        $data = parent::fetchContentAsArray($url);
65
66
        $data = $this->accountInfoMapper->normalizeData(Account::class, $data);
67
68
        return $this->accountInfoMapper->populate(Account::class, $data);
69
    }
70
71
    /**
72
     * @param string $username
73
     * @param int $limit Max 12, for more see findPosts()
74
     * @return \Generator
75
     *
76
     * @see \Jakim\Query\AccountQuery::findPosts
77
     */
78
    public function findLastPosts(string $username, int $limit = 12)
79
    {
80
        $url = Url::account($username);
81
        $data = $this->fetchContentAsArray($url);
82
83
        $items = $this->accountDetailsMapper->normalizeData(Post::class, $data);
84
85
        $n = 0;
86
        foreach ($items as $item) {
87
            $model = $this->accountDetailsMapper->populate(Post::class, $item);
88
89
            yield $model;
90
91
            if (++$n >= $limit) {
92
                break;
93
            }
94
        }
95
    }
96
97
    public function findPosts(string $username, int $limit = 100)
98
    {
99
        if ($limit <= 12) {
100
            yield from $this->findLastPosts($username, $limit);
101
102
            return;
103
        }
104
105
        $account = $this->findOne($username);
106
107
        $n = 0;
108
        $nextPage = '';
109
        $this->postsPerPage = (int)$this->postsPerPage > self::MAX_POSTS_PER_PAGE ? self::MAX_POSTS_PER_PAGE : $this->postsPerPage;
110
111
        while ($nextPage !== null) {
112
            $url = Endpoint::accountMedia($account->id, $this->postsPerPage, [
113
                'variables' => ['after' => $nextPage],
114
            ]);
115
            $data = parent::fetchContentAsArray($url);
116
117
            $nextPage = $this->accountMediaMapper->nextPage($data);
118
119
            $items = $this->accountMediaMapper->normalizeData(Post::class, $data);
120
121
            foreach ($items as $item) {
122
123
                yield $this->accountMediaMapper->populate(Post::class, $item);
124
125
                if (++$n >= $limit) {
126
                    break 2;
127
                }
128
            }
129
        }
130
    }
131
132
    protected function fetchContentAsArray(string $url): ?array
133
    {
134
        $res = $this->httpClient->get($url);
135
        $content = $res->getBody()->getContents();
136
137
        preg_match('/\_sharedData \= (.*?)\;\<\/script\>/s', $content, $matches);
138
139
        return JsonHelper::decode($matches['1']);
140
    }
141
}