• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

stripe / stripe-php / 6471862601

10 Oct 2023 04:02PM UTC coverage: 69.665% (-0.5%) from 70.141%
6471862601

push

github

web-flow
Merge pull request #1570 from localheinz/feature/coveralls

Enhancement: Use `coverallsapp/github-action` to report code coverage

2393 of 3435 relevant lines covered (69.67%)

3.5 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.9
/lib/Collection.php
1
<?php
2

3
namespace Stripe;
4

5
/**
6
 * Class Collection.
7
 *
8
 * @template TStripeObject of StripeObject
9
 * @template-implements \IteratorAggregate<TStripeObject>
10
 *
11
 * @property string $object
12
 * @property string $url
13
 * @property bool $has_more
14
 * @property TStripeObject[] $data
15
 */
16
class Collection extends StripeObject implements \Countable, \IteratorAggregate
17
{
18
    const OBJECT_NAME = 'list';
19

20
    use ApiOperations\Request;
21

22
    /** @var array */
23
    protected $filters = [];
24

25
    /**
26
     * @return string the base URL for the given class
27
     */
28
    public static function baseUrl()
9✔
29
    {
30
        return Stripe::$apiBase;
9✔
31
    }
32

33
    /**
34
     * Returns the filters.
35
     *
36
     * @return array the filters
37
     */
38
    public function getFilters()
×
39
    {
40
        return $this->filters;
×
41
    }
42

43
    /**
44
     * Sets the filters, removing paging options.
45
     *
46
     * @param array $filters the filters
47
     */
48
    public function setFilters($filters)
6✔
49
    {
50
        $this->filters = $filters;
6✔
51
    }
52

53
    /**
54
     * @return mixed
55
     */
56
    #[\ReturnTypeWillChange]
1✔
57
    public function offsetGet($k)
58
    {
59
        if (\is_string($k)) {
1✔
60
            return parent::offsetGet($k);
×
61
        }
62
        $msg = "You tried to access the {$k} index, but Collection " .
1✔
63
                   'types only support string keys. (HINT: List calls ' .
1✔
64
                   'return an object with a `data` (which is the data ' .
1✔
65
                   "array). You likely want to call ->data[{$k}])";
1✔
66

67
        throw new Exception\InvalidArgumentException($msg);
1✔
68
    }
69

70
    /**
71
     * @param null|array $params
72
     * @param null|array|string $opts
73
     *
74
     * @throws Exception\ApiErrorException
75
     *
76
     * @return Collection<TStripeObject>
77
     */
78
    public function all($params = null, $opts = null)
6✔
79
    {
80
        self::_validateParams($params);
6✔
81
        list($url, $params) = $this->extractPathAndUpdateParams($params);
6✔
82

83
        list($response, $opts) = $this->_request('get', $url, $params, $opts);
6✔
84
        $obj = Util\Util::convertToStripeObject($response, $opts);
6✔
85
        if (!($obj instanceof \Stripe\Collection)) {
6✔
86
            throw new \Stripe\Exception\UnexpectedValueException(
×
87
                'Expected type ' . \Stripe\Collection::class . ', got "' . \get_class($obj) . '" instead.'
×
88
            );
×
89
        }
90
        $obj->setFilters($params);
6✔
91

92
        return $obj;
6✔
93
    }
94

95
    /**
96
     * @param null|array $params
97
     * @param null|array|string $opts
98
     *
99
     * @throws Exception\ApiErrorException
100
     *
101
     * @return TStripeObject
102
     */
103
    public function create($params = null, $opts = null)
2✔
104
    {
105
        self::_validateParams($params);
2✔
106
        list($url, $params) = $this->extractPathAndUpdateParams($params);
2✔
107

108
        list($response, $opts) = $this->_request('post', $url, $params, $opts);
2✔
109

110
        return Util\Util::convertToStripeObject($response, $opts);
2✔
111
    }
112

113
    /**
114
     * @param string $id
115
     * @param null|array $params
116
     * @param null|array|string $opts
117
     *
118
     * @throws Exception\ApiErrorException
119
     *
120
     * @return TStripeObject
121
     */
122
    public function retrieve($id, $params = null, $opts = null)
1✔
123
    {
124
        self::_validateParams($params);
1✔
125
        list($url, $params) = $this->extractPathAndUpdateParams($params);
1✔
126

127
        $id = Util\Util::utf8($id);
1✔
128
        $extn = \urlencode($id);
1✔
129
        list($response, $opts) = $this->_request(
1✔
130
            'get',
1✔
131
            "{$url}/{$extn}",
1✔
132
            $params,
1✔
133
            $opts
1✔
134
        );
1✔
135

136
        return Util\Util::convertToStripeObject($response, $opts);
1✔
137
    }
138

139
    /**
140
     * @return int the number of objects in the current page
141
     */
142
    #[\ReturnTypeWillChange]
1✔
143
    public function count()
144
    {
145
        return \count($this->data);
1✔
146
    }
147

148
    /**
149
     * @return \ArrayIterator an iterator that can be used to iterate
150
     *    across objects in the current page
151
     */
152
    #[\ReturnTypeWillChange]
4✔
153
    public function getIterator()
154
    {
155
        return new \ArrayIterator($this->data);
4✔
156
    }
157

158
    /**
159
     * @return \ArrayIterator an iterator that can be used to iterate
160
     *    backwards across objects in the current page
161
     */
162
    public function getReverseIterator()
2✔
163
    {
164
        return new \ArrayIterator(\array_reverse($this->data));
2✔
165
    }
166

167
    /**
168
     * @return \Generator|TStripeObject[] A generator that can be used to
169
     *    iterate across all objects across all pages. As page boundaries are
170
     *    encountered, the next page will be fetched automatically for
171
     *    continued iteration.
172
     */
173
    public function autoPagingIterator()
3✔
174
    {
175
        $page = $this;
3✔
176

177
        while (true) {
3✔
178
            $filters = $this->filters ?: [];
3✔
179
            if (\array_key_exists('ending_before', $filters)
3✔
180
                && !\array_key_exists('starting_after', $filters)) {
3✔
181
                foreach ($page->getReverseIterator() as $item) {
1✔
182
                    yield $item;
1✔
183
                }
184
                $page = $page->previousPage();
1✔
185
            } else {
186
                foreach ($page as $item) {
2✔
187
                    yield $item;
2✔
188
                }
189
                $page = $page->nextPage();
2✔
190
            }
191

192
            if ($page->isEmpty()) {
3✔
193
                break;
3✔
194
            }
195
        }
196
    }
197

198
    /**
199
     * Returns an empty collection. This is returned from {@see nextPage()}
200
     * when we know that there isn't a next page in order to replicate the
201
     * behavior of the API when it attempts to return a page beyond the last.
202
     *
203
     * @param null|array|string $opts
204
     *
205
     * @return Collection
206
     */
207
    public static function emptyCollection($opts = null)
4✔
208
    {
209
        return Collection::constructFrom(['data' => []], $opts);
4✔
210
    }
211

212
    /**
213
     * Returns true if the page object contains no element.
214
     *
215
     * @return bool
216
     */
217
    public function isEmpty()
4✔
218
    {
219
        return empty($this->data);
4✔
220
    }
221

222
    /**
223
     * Fetches the next page in the resource list (if there is one).
224
     *
225
     * This method will try to respect the limit of the current page. If none
226
     * was given, the default limit will be fetched again.
227
     *
228
     * @param null|array $params
229
     * @param null|array|string $opts
230
     *
231
     * @return Collection<TStripeObject>
232
     */
233
    public function nextPage($params = null, $opts = null)
3✔
234
    {
235
        if (!$this->has_more) {
3✔
236
            return static::emptyCollection($opts);
2✔
237
        }
238

239
        $lastId = \end($this->data)->id;
3✔
240

241
        $params = \array_merge(
3✔
242
            $this->filters ?: [],
3✔
243
            ['starting_after' => $lastId],
3✔
244
            $params ?: []
3✔
245
        );
3✔
246

247
        return $this->all($params, $opts);
3✔
248
    }
249

250
    /**
251
     * Fetches the previous page in the resource list (if there is one).
252
     *
253
     * This method will try to respect the limit of the current page. If none
254
     * was given, the default limit will be fetched again.
255
     *
256
     * @param null|array $params
257
     * @param null|array|string $opts
258
     *
259
     * @return Collection<TStripeObject>
260
     */
261
    public function previousPage($params = null, $opts = null)
2✔
262
    {
263
        if (!$this->has_more) {
2✔
264
            return static::emptyCollection($opts);
1✔
265
        }
266

267
        $firstId = $this->data[0]->id;
2✔
268

269
        $params = \array_merge(
2✔
270
            $this->filters ?: [],
2✔
271
            ['ending_before' => $firstId],
2✔
272
            $params ?: []
2✔
273
        );
2✔
274

275
        return $this->all($params, $opts);
2✔
276
    }
277

278
    /**
279
     * Gets the first item from the current page. Returns `null` if the current page is empty.
280
     *
281
     * @return null|TStripeObject
282
     */
283
    public function first()
1✔
284
    {
285
        return \count($this->data) > 0 ? $this->data[0] : null;
1✔
286
    }
287

288
    /**
289
     * Gets the last item from the current page. Returns `null` if the current page is empty.
290
     *
291
     * @return null|TStripeObject
292
     */
293
    public function last()
1✔
294
    {
295
        return \count($this->data) > 0 ? $this->data[\count($this->data) - 1] : null;
1✔
296
    }
297

298
    private function extractPathAndUpdateParams($params)
9✔
299
    {
300
        $url = \parse_url($this->url);
9✔
301
        if (!isset($url['path'])) {
9✔
302
            throw new Exception\UnexpectedValueException("Could not parse list url into parts: {$url}");
×
303
        }
304

305
        if (isset($url['query'])) {
9✔
306
            // If the URL contains a query param, parse it out into $params so they
307
            // don't interact weirdly with each other.
308
            $query = [];
×
309
            \parse_str($url['query'], $query);
×
310
            $params = \array_merge($params ?: [], $query);
×
311
        }
312

313
        return [$url['path'], $params];
9✔
314
    }
315
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc