• 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

84.13
/lib/SearchResult.php
1
<?php
2

3
namespace Stripe;
4

5
/**
6
 * Search results for an API resource.
7
 *
8
 * This behaves similarly to <code>Collection</code> in that they both wrap
9
 * around a list of objects and provide pagination. However the
10
 * <code>SearchResult</code> object paginates by relying on a
11
 * <code>next_page</code> token included in the response rather than using
12
 * object IDs and a <code>starting_before</code>/<code>ending_after</code>
13
 * parameter. Thus, <code>SearchResult</code> only supports forwards pagination.
14
 *
15
 * The {@see $total_count} property is only available when
16
 * the `expand` parameter contains `total_count`.
17
 *
18
 * @template TStripeObject of StripeObject
19
 * @template-implements \IteratorAggregate<TStripeObject>
20
 *
21
 * @property string $object
22
 * @property string $url
23
 * @property string $next_page
24
 * @property int $total_count
25
 * @property bool $has_more
26
 * @property TStripeObject[] $data
27
 */
28
class SearchResult extends StripeObject implements \Countable, \IteratorAggregate
29
{
30
    const OBJECT_NAME = 'search_result';
31

32
    use ApiOperations\Request;
33

34
    /** @var array */
35
    protected $filters = [];
36

37
    /**
38
     * @return string the base URL for the given class
39
     */
40
    public static function baseUrl()
6✔
41
    {
42
        return Stripe::$apiBase;
6✔
43
    }
44

45
    /**
46
     * Returns the filters.
47
     *
48
     * @return array the filters
49
     */
50
    public function getFilters()
×
51
    {
52
        return $this->filters;
×
53
    }
54

55
    /**
56
     * Sets the filters, removing paging options.
57
     *
58
     * @param array $filters the filters
59
     */
60
    public function setFilters($filters)
6✔
61
    {
62
        $this->filters = $filters;
6✔
63
    }
64

65
    /**
66
     * @return mixed
67
     */
68
    #[\ReturnTypeWillChange]
1✔
69
    public function offsetGet($k)
70
    {
71
        if (\is_string($k)) {
1✔
72
            return parent::offsetGet($k);
×
73
        }
74
        $msg = "You tried to access the {$k} index, but SearchResult " .
1✔
75
                   'types only support string keys. (HINT: Search calls ' .
1✔
76
                   'return an object with a `data` (which is the data ' .
1✔
77
                   "array). You likely want to call ->data[{$k}])";
1✔
78

79
        throw new Exception\InvalidArgumentException($msg);
1✔
80
    }
81

82
    /**
83
     * @param null|array $params
84
     * @param null|array|string $opts
85
     *
86
     * @throws Exception\ApiErrorException
87
     *
88
     * @return SearchResult<TStripeObject>
89
     */
90
    public function all($params = null, $opts = null)
6✔
91
    {
92
        self::_validateParams($params);
6✔
93
        list($url, $params) = $this->extractPathAndUpdateParams($params);
6✔
94

95
        list($response, $opts) = $this->_request('get', $url, $params, $opts);
6✔
96
        $obj = Util\Util::convertToStripeObject($response, $opts);
6✔
97
        if (!($obj instanceof \Stripe\SearchResult)) {
6✔
98
            throw new \Stripe\Exception\UnexpectedValueException(
×
99
                'Expected type ' . \Stripe\SearchResult::class . ', got "' . \get_class($obj) . '" instead.'
×
100
            );
×
101
        }
102
        $obj->setFilters($params);
6✔
103

104
        return $obj;
6✔
105
    }
106

107
    /**
108
     * @return int the number of objects in the current page
109
     */
110
    #[\ReturnTypeWillChange]
1✔
111
    public function count()
112
    {
113
        return \count($this->data);
1✔
114
    }
115

116
    /**
117
     * @return \ArrayIterator an iterator that can be used to iterate
118
     *    across objects in the current page
119
     */
120
    #[\ReturnTypeWillChange]
5✔
121
    public function getIterator()
122
    {
123
        return new \ArrayIterator($this->data);
5✔
124
    }
125

126
    /**
127
     * @return \Generator|TStripeObject[] A generator that can be used to
128
     *    iterate across all objects across all pages. As page boundaries are
129
     *    encountered, the next page will be fetched automatically for
130
     *    continued iteration.
131
     */
132
    public function autoPagingIterator()
3✔
133
    {
134
        $page = $this;
3✔
135

136
        while (true) {
3✔
137
            foreach ($page as $item) {
3✔
138
                yield $item;
3✔
139
            }
140
            $page = $page->nextPage();
3✔
141

142
            if ($page->isEmpty()) {
3✔
143
                break;
3✔
144
            }
145
        }
146
    }
147

148
    /**
149
     * Returns an empty set of search results. This is returned from
150
     * {@see nextPage()} when we know that there isn't a next page in order to
151
     * replicate the behavior of the API when it attempts to return a page
152
     * beyond the last.
153
     *
154
     * @param null|array|string $opts
155
     *
156
     * @return SearchResult
157
     */
158
    public static function emptySearchResult($opts = null)
4✔
159
    {
160
        return SearchResult::constructFrom(['data' => []], $opts);
4✔
161
    }
162

163
    /**
164
     * Returns true if the page object contains no element.
165
     *
166
     * @return bool
167
     */
168
    public function isEmpty()
4✔
169
    {
170
        return empty($this->data);
4✔
171
    }
172

173
    /**
174
     * Fetches the next page in the resource list (if there is one).
175
     *
176
     * This method will try to respect the limit of the current page. If none
177
     * was given, the default limit will be fetched again.
178
     *
179
     * @param null|array $params
180
     * @param null|array|string $opts
181
     *
182
     * @return SearchResult<TStripeObject>
183
     */
184
    public function nextPage($params = null, $opts = null)
5✔
185
    {
186
        if (!$this->has_more) {
5✔
187
            return static::emptySearchResult($opts);
3✔
188
        }
189

190
        $params = \array_merge(
5✔
191
            $this->filters ?: [],
5✔
192
            ['page' => $this->next_page],
5✔
193
            $params ?: []
5✔
194
        );
5✔
195

196
        return $this->all($params, $opts);
5✔
197
    }
198

199
    /**
200
     * Gets the first item from the current page. Returns `null` if the current page is empty.
201
     *
202
     * @return null|TStripeObject
203
     */
204
    public function first()
1✔
205
    {
206
        return \count($this->data) > 0 ? $this->data[0] : null;
1✔
207
    }
208

209
    /**
210
     * Gets the last item from the current page. Returns `null` if the current page is empty.
211
     *
212
     * @return null|TStripeObject
213
     */
214
    public function last()
1✔
215
    {
216
        return \count($this->data) > 0 ? $this->data[\count($this->data) - 1] : null;
1✔
217
    }
218

219
    private function extractPathAndUpdateParams($params)
6✔
220
    {
221
        $url = \parse_url($this->url);
6✔
222

223
        if (!isset($url['path'])) {
6✔
224
            throw new Exception\UnexpectedValueException("Could not parse list url into parts: {$url}");
×
225
        }
226

227
        if (isset($url['query'])) {
6✔
228
            // If the URL contains a query param, parse it out into $params so they
229
            // don't interact weirdly with each other.
230
            $query = [];
×
231
            \parse_str($url['query'], $query);
×
232
            $params = \array_merge($params ?: [], $query);
×
233
        }
234

235
        return [$url['path'], $params];
6✔
236
    }
237
}
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