├── .gitignore
├── src
└── Strava
│ └── API
│ ├── Exception.php
│ ├── Service
│ ├── Exception.php
│ ├── ServiceInterface.php
│ ├── Stub.php
│ └── REST.php
│ ├── Factory.php
│ ├── OAuth.php
│ ├── Webhook.php
│ └── Client.php
├── tests
├── Strava
│ └── API
│ │ ├── TestCase.php
│ │ ├── FactoryTest.php
│ │ ├── ExceptionTest.php
│ │ ├── Service
│ │ ├── ExceptionTest.php
│ │ └── StubTest.php
│ │ ├── OAuthTest.php
│ │ ├── WebhookTest.php
│ │ └── ClientTest.php
└── _support
│ └── TestCase.php
├── phpstan.neon.dist
├── .github
├── workflows
│ ├── stale.yml
│ ├── phpmd.yml
│ └── php.yml
└── release.yml
├── LICENSE
├── composer.json
├── phpunit.xml.dist
├── examples
├── webhook-endpoint.php
└── webhook-example.php
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | .vscode/
3 | .project
4 | /vendor/
5 | /build/
6 | composer.lock
7 | example.php
8 | *.cache
9 |
--------------------------------------------------------------------------------
/src/Strava/API/Exception.php:
--------------------------------------------------------------------------------
1 | getOAuthClient('123', 'TOKEN', 'URL');
18 | $this->assertInstanceOf('Strava\API\OAuth', $client);
19 | }
20 |
21 | public function testGetAPIClientInstance()
22 | {
23 | $factory = new Strava\API\Factory();
24 | $client = $factory->getAPIClient('TOKEN');
25 | $this->assertInstanceOf('Strava\API\Client', $client);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/tests/Strava/API/ExceptionTest.php:
--------------------------------------------------------------------------------
1 | expectException('Strava\API\Exception');
17 | throw new Strava\API\Exception();
18 | }
19 |
20 | public function testInstanceOfException()
21 | {
22 | try {
23 | throw new Strava\API\Exception();
24 | } catch (Exception $ex) {
25 | $this->assertInstanceOf('Strava\API\Exception', $ex);
26 | $this->assertInstanceOf('\Exception', $ex);
27 | }
28 | }
29 |
30 | public function testExceptionMessageAndCode()
31 | {
32 | try {
33 | throw new Strava\API\Exception('test', 100);
34 | } catch (Exception $ex) {
35 | $this->assertEquals('test', $ex->getMessage());
36 | $this->assertEquals(100, $ex->getCode());
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/tests/Strava/API/Service/ExceptionTest.php:
--------------------------------------------------------------------------------
1 | expectException('Strava\API\Service\Exception');
17 | throw new Strava\API\Service\Exception();
18 | }
19 |
20 | public function testInstanceOfException()
21 | {
22 | try {
23 | throw new Strava\API\Service\Exception();
24 | } catch (Exception $ex) {
25 | $this->assertInstanceOf('Strava\API\Service\Exception', $ex);
26 | $this->assertInstanceOf('\Exception', $ex);
27 | }
28 | }
29 |
30 | public function testExceptionMessageAndCode()
31 | {
32 | try {
33 | throw new Strava\API\Service\Exception('test', 100);
34 | } catch (Exception $ex) {
35 | $this->assertEquals('test', $ex->getMessage());
36 | $this->assertEquals(100, $ex->getCode());
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014-2022 Bas van Dorst
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/src/Strava/API/Factory.php:
--------------------------------------------------------------------------------
1 | $client_id,
30 | 'clientSecret' => $client_secret,
31 | 'redirectUri' => $redirect_uri
32 | ];
33 | return new OAuth($options);
34 | }
35 |
36 | /**
37 | * Return a new instance of the API Client
38 | *
39 | * @param string $token
40 | * @return Client
41 | */
42 | public function getAPIClient(string $token): Client
43 | {
44 | $adapter = new \GuzzleHttp\Client(['base_uri' => self::$endpoint]);
45 | $service = new Service\REST($token, $adapter);
46 |
47 | return new Client($service);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "basvandorst/stravaphp",
3 | "description": "Strava V3 API PHP client with OAuth authentication",
4 | "keywords": [
5 | "Strava",
6 | "API",
7 | "OAuth",
8 | "PHP",
9 | "StravaPHP"
10 | ],
11 | "license": "MIT",
12 | "authors": [
13 | {
14 | "name": "Bas van Dorst",
15 | "email": "basvandorst@gmail.com"
16 | },
17 | {
18 | "name": "Bas Vredeling",
19 | "email": "bas@vredeling.nl"
20 | }
21 | ],
22 | "require": {
23 | "php": "^8.1",
24 | "ext-curl": "*",
25 | "ext-json": "*",
26 | "guzzlehttp/guzzle": "^6.3 || ^7.0.1",
27 | "league/oauth2-client": "~2.3"
28 | },
29 | "require-dev": {
30 | "friendsofphp/php-cs-fixer": "^3.4",
31 | "phpstan/phpstan": "^2.1",
32 | "phpunit/phpunit": "^9"
33 | },
34 | "autoload": {
35 | "psr-0": {
36 | "Strava": "src/"
37 | }
38 | },
39 | "autoload-dev": {
40 | "psr-4": {
41 | "Tests\\Support\\": "tests/_support"
42 | }
43 | },
44 | "minimum-stability": "stable",
45 | "scripts": {
46 | "analyze": "phpstan analyze",
47 | "ci": [
48 | "Composer\\Config::disableProcessTimeout",
49 | "@analyze",
50 | "@style",
51 | "@test"
52 | ],
53 | "style": "php-cs-fixer fix --verbose --ansi --using-cache=no src/",
54 | "test": "phpunit"
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/.github/workflows/phpmd.yml:
--------------------------------------------------------------------------------
1 | # This workflow uses actions that are not certified by GitHub.
2 | # They are provided by a third-party and are governed by
3 | # separate terms of service, privacy policy, and support
4 | # documentation.
5 | # PHPMD is a spin-off project of PHP Depend and
6 | # aims to be a PHP equivalent of the well known Java tool PMD.
7 | # What PHPMD does is: It takes a given PHP source code base
8 | # and look for several potential problems within that source.
9 | # These problems can be things like:
10 | # Possible bugs
11 | # Suboptimal code
12 | # Overcomplicated expressions
13 | # Unused parameters, methods, properties
14 | # More details at https://phpmd.org/
15 |
16 | name: PHPMD
17 |
18 | on:
19 | push:
20 | branches: [ "develop" ]
21 | pull_request:
22 | # The branches below must be a subset of the branches above
23 | branches: [ "develop" ]
24 | schedule:
25 | - cron: '20 3 * * 4'
26 |
27 | permissions:
28 | contents: read
29 |
30 | jobs:
31 | PHPMD:
32 | name: Run PHPMD scanning
33 | runs-on: ubuntu-latest
34 | permissions:
35 | contents: read # for checkout to fetch code
36 | security-events: write # for github/codeql-action/upload-sarif to upload SARIF results
37 | actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status
38 |
39 | steps:
40 | - name: Checkout code
41 | uses: actions/checkout@v4
42 |
43 | - name: Setup PHP
44 | uses: shivammathur/setup-php@aa1fe473f9c687b6fb896056d771232c0bc41161
45 | with:
46 | coverage: none
47 | tools: phpmd
48 |
49 | - name: Run PHPMD
50 | run: phpmd . sarif codesize --reportfile phpmd-results.sarif
51 | continue-on-error: true
52 |
53 | - name: Upload analysis results to GitHub
54 | uses: github/codeql-action/upload-sarif@v3
55 | with:
56 | sarif_file: phpmd-results.sarif
57 | wait-for-processing: true
58 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
23 |
24 |
25 | ./src/
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | ./tests/
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/examples/webhook-endpoint.php:
--------------------------------------------------------------------------------
1 | oauth = new Strava\API\OAuth(array());
24 | }
25 |
26 | private function getResponseMock()
27 | {
28 | $json = '{"id": 12345, "firstname": "mock_first_name", "lastname": "mock_last_name", "email": "mock_email", "country": "NL", "sex": "M", "profile": "profile_url"}';
29 | $response = json_decode($json);
30 | return $response;
31 | }
32 |
33 | public function testUrlAuthorize()
34 | {
35 | $url = $this->oauth->urlAuthorize();
36 | $this->assertNotEmpty($url);
37 | }
38 |
39 | public function testUrlAccessToken()
40 | {
41 | $url = $this->oauth->urlAccessToken();
42 | $this->assertNotEmpty($url);
43 | }
44 |
45 | public function testUrlUserDetails()
46 | {
47 | $url = $this->oauth->urlUserDetails();
48 | $this->assertNotEmpty($url);
49 | }
50 |
51 | public function testUserDetails()
52 | {
53 | $reponseMock = $this->getResponseMock();
54 |
55 | $output = $this->oauth->userDetails($reponseMock);
56 | $this->assertInstanceOf('stdClass', $output);
57 | }
58 |
59 | public function testUserUid()
60 | {
61 | $reponseMock = $this->getResponseMock();
62 |
63 | $output = $this->oauth->userUid($reponseMock);
64 | $this->assertEquals(12345, $output);
65 | }
66 |
67 | public function testUserEmail()
68 | {
69 | $reponseMock = $this->getResponseMock();
70 |
71 | $output = $this->oauth->userEmail($reponseMock);
72 | $this->assertEquals('mock_email', $output);
73 | }
74 |
75 | public function testUserScreenName()
76 | {
77 | $reponseMock = $this->getResponseMock();
78 |
79 | $output = $this->oauth->userScreenName($reponseMock);
80 | $this->assertEquals('mock_first_name mock_last_name', $output);
81 | }
82 |
83 | public function testBaseAuthorizationUrl()
84 | {
85 | $result = $this->oauth->getBaseAuthorizationUrl();
86 |
87 | $this->assertSame('https://www.strava.com/oauth/authorize', $result);
88 | }
89 |
90 | public function testBaseAccessTokenUrl()
91 | {
92 | $result = $this->oauth->getBaseAccessTokenUrl(array());
93 |
94 | $this->assertSame('https://www.strava.com/oauth/token', $result);
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/.github/workflows/php.yml:
--------------------------------------------------------------------------------
1 | name: PHP
2 |
3 | on:
4 | push:
5 | branches:
6 | - develop
7 | - master
8 | paths:
9 | - '**.php'
10 | - 'composer.*'
11 | - 'php*'
12 | - '.github/workflows/php.yml'
13 | pull_request:
14 | branches:
15 | - develop
16 | - master
17 | paths:
18 | - '**.php'
19 | - 'composer.*'
20 | - 'php*'
21 | - '.github/workflows/php.yml'
22 |
23 | jobs:
24 | build:
25 | name: PHP ${{ matrix.php-versions }}
26 | runs-on: ubuntu-latest
27 | strategy:
28 | matrix:
29 | php-versions: ['8.1', '8.2', '8.3', '8.4']
30 |
31 | steps:
32 | - uses: actions/checkout@v3
33 |
34 | - name: Set up PHP
35 | uses: shivammathur/setup-php@v2
36 | with:
37 | php-version: ${{ matrix.php-versions }}
38 | tools: composer, phpunit, phive
39 | extensions: intl, json, mbstring, xdebug
40 | coverage: xdebug
41 | env:
42 | COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }}
43 |
44 | - name: Validate composer.json
45 | run: composer validate
46 |
47 | - name: Cache Composer packages
48 | id: composer-cache
49 | run: |
50 | echo "::set-output name=dir::$(composer config cache-files-dir)"
51 | - uses: actions/cache@v3
52 | with:
53 | path: ${{ steps.composer-cache.outputs.dir }}
54 | key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
55 | restore-keys: |
56 | ${{ runner.os }}-composer-
57 |
58 | - name: Install dependencies
59 | if: steps.composer-cache.outputs.cache-hit != 'true'
60 | run: composer update --prefer-dist --no-progress --no-suggest
61 |
62 | - name: Run static analysis
63 | run: vendor/bin/phpstan analyze
64 | env:
65 | TERM: xterm-256color
66 |
67 | - name: Check code for standards compliance
68 | run: vendor/bin/php-cs-fixer fix --verbose --ansi --dry-run --using-cache=no --diff src/
69 |
70 | - name: Run test suite
71 | run: vendor/bin/phpunit --verbose
72 | env:
73 | TERM: xterm-256color
74 |
75 | - if: matrix.php-versions == '8.1'
76 | name: Run Coveralls
77 | continue-on-error: true
78 | run: |
79 | sudo phive --no-progress install --global --trust-gpg-keys E82B2FB314E9906E php-coveralls
80 | php-coveralls --verbose --coverage_clover=build/phpunit/clover.xml --json_path build/phpunit/coveralls-upload.json
81 | env:
82 | COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
83 | COVERALLS_PARALLEL: true
84 | COVERALLS_FLAG_NAME: PHP ${{ matrix.php-versions }}
85 |
86 | coveralls:
87 | needs: [build]
88 | name: Coveralls Finished
89 | runs-on: ubuntu-latest
90 | steps:
91 | - name: Upload Coveralls results
92 | uses: coverallsapp/github-action@master
93 | continue-on-error: true
94 | with:
95 | github-token: ${{ secrets.GITHUB_TOKEN }}
96 | parallel-finished: true
97 |
--------------------------------------------------------------------------------
/src/Strava/API/OAuth.php:
--------------------------------------------------------------------------------
1 | uid = $response->id;
57 | $user->name = implode(' ', [$response->firstname, $response->lastname]);
58 | $user->firstName = $response->firstname;
59 | $user->lastName = $response->lastname;
60 | $user->email = $response->email;
61 | $user->location = $response->country;
62 | $user->imageUrl = $response->profile;
63 | $user->gender = $response->sex;
64 |
65 | return $user;
66 | }
67 |
68 | /**
69 | * @see AbstractProvider::userUid
70 | */
71 | public function userUid($response)
72 | {
73 | return $response->id;
74 | }
75 |
76 | /**
77 | * @see AbstractProvider::userEmail
78 | */
79 | public function userEmail($response)
80 | {
81 | return isset($response->email) && $response->email ? $response->email : null;
82 | }
83 |
84 | /**
85 | * @see AbstractProvider::userScreenName
86 | */
87 | public function userScreenName($response): string
88 | {
89 | return implode(' ', [$response->firstname, $response->lastname]);
90 | }
91 |
92 | /**
93 | * @see AbstractProvider::getBaseAuthorizationUrl
94 | */
95 | public function getBaseAuthorizationUrl(): string
96 | {
97 | return 'https://www.strava.com/oauth/authorize';
98 | }
99 |
100 | /**
101 | * @see AbstractProvider::getBaseAccessTokenUrl
102 | */
103 | public function getBaseAccessTokenUrl(array $params): string
104 | {
105 | return 'https://www.strava.com/oauth/token';
106 | }
107 |
108 | /**
109 | * @see AbstractProvider::getResourceOwnerDetailsUrl
110 | */
111 | public function getResourceOwnerDetailsUrl(AccessToken $token): string
112 | {
113 | return '';
114 | }
115 |
116 | /**
117 | * @see AbstractProvider::getDefaultScopes
118 | */
119 | protected function getDefaultScopes(): array
120 | {
121 | return $this->scopes;
122 | }
123 |
124 | /**
125 | * @see AbstractProvider::checkResponse
126 | */
127 | protected function checkResponse(ResponseInterface $response, $data)
128 | {
129 | }
130 |
131 | /**
132 | * @see AbstractProvider::createResourceOwner
133 | */
134 | protected function createResourceOwner(array $response, AccessToken $token)
135 | {
136 | throw new RuntimeException('Not implemented');
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/examples/webhook-example.php:
--------------------------------------------------------------------------------
1 | 'https://www.strava.com/api/v3/']);
29 | $service = new REST($accessToken, $adapter);
30 | $client = new Client($service);
31 |
32 | try {
33 | // 1. Create a webhook subscription
34 | echo "Creating webhook subscription...\n";
35 | $subscription = $client->createWebhookSubscription(
36 | $clientId,
37 | $clientSecret,
38 | $callbackUrl,
39 | $verifyToken
40 | );
41 |
42 | echo "Subscription created successfully!\n";
43 | echo "Subscription ID: " . $subscription['id'] . "\n";
44 | echo "Callback URL: " . $subscription['callback_url'] . "\n";
45 | echo "Created at: " . $subscription['created_at'] . "\n\n";
46 |
47 | // 2. List existing webhook subscriptions
48 | echo "Listing webhook subscriptions...\n";
49 | $subscriptions = $client->listWebhookSubscriptions($clientId, $clientSecret);
50 |
51 | echo "Found " . count($subscriptions) . " subscription(s):\n";
52 | foreach ($subscriptions as $sub) {
53 | echo "- ID: " . $sub['id'] . ", URL: " . $sub['callback_url'] . "\n";
54 | }
55 | echo "\n";
56 |
57 | // 3. Delete a webhook subscription (uncomment to use)
58 | /*
59 | echo "Deleting webhook subscription...\n";
60 | $deleted = $client->deleteWebhookSubscription(
61 | $clientId,
62 | $clientSecret,
63 | $subscription['id']
64 | );
65 |
66 | if ($deleted) {
67 | echo "Subscription deleted successfully!\n";
68 | } else {
69 | echo "Failed to delete subscription.\n";
70 | }
71 | */
72 |
73 | } catch (Exception $e) {
74 | echo "Error: " . $e->getMessage() . "\n";
75 | }
76 |
77 | /**
78 | * Example webhook endpoint handler
79 | *
80 | * Save this as webhook-endpoint.php on your server
81 | */
82 | function webhookEndpointExample()
83 | {
84 | // Handle subscription challenge
85 | $verifyToken = 'your_verify_token_here'; // Same token used when creating subscription
86 |
87 | $challengeResult = Webhook::handleSubscriptionChallenge($verifyToken);
88 |
89 | if ($challengeResult['success']) {
90 | // Send challenge response to Strava
91 | Webhook::sendChallengeResponse($challengeResult['challenge']);
92 | } else {
93 | // Handle challenge error
94 | http_response_code(400);
95 | echo json_encode(['error' => $challengeResult['error']]);
96 | exit;
97 | }
98 |
99 | // Process webhook events
100 | $eventResult = Webhook::processEvent();
101 |
102 | if (!$eventResult['success']) {
103 | http_response_code(400);
104 | echo json_encode(['error' => $eventResult['error']]);
105 | exit;
106 | }
107 |
108 | $event = $eventResult['event'];
109 |
110 | // Handle different event types
111 | switch (Webhook::getEventType($event)) {
112 | case 'activity.create':
113 | echo "New activity created: " . $event['object_id'] . "\n";
114 | // Process new activity
115 | break;
116 |
117 | case 'activity.update':
118 | echo "Activity updated: " . $event['object_id'] . "\n";
119 | // Process activity update
120 | break;
121 |
122 | case 'activity.delete':
123 | echo "Activity deleted: " . $event['object_id'] . "\n";
124 | // Process activity deletion
125 | break;
126 |
127 | case 'athlete.update':
128 | echo "Athlete updated: " . $event['object_id'] . "\n";
129 | // Process athlete update
130 | break;
131 |
132 | default:
133 | echo "Unknown event type: " . Webhook::getEventType($event) . "\n";
134 | }
135 |
136 | // Send success response
137 | http_response_code(200);
138 | echo json_encode(['status' => 'success']);
139 | }
140 |
141 | // Uncomment to test the webhook endpoint
142 | // webhookEndpointExample();
143 |
--------------------------------------------------------------------------------
/tests/Strava/API/WebhookTest.php:
--------------------------------------------------------------------------------
1 | assertTrue($result['success']);
25 | $this->assertEquals('test_challenge_123', $result['challenge']);
26 | }
27 |
28 | public function testHandleSubscriptionChallengeInvalidMethod()
29 | {
30 | $_SERVER['REQUEST_METHOD'] = 'POST';
31 | $_SERVER['QUERY_STRING'] = '';
32 | $_GET = [];
33 |
34 | $result = Webhook::handleSubscriptionChallenge('test_verify_token');
35 |
36 | $this->assertFalse($result['success']);
37 | $this->assertEquals('Invalid request method. Expected GET.', $result['error']);
38 | }
39 |
40 | public function testHandleSubscriptionChallengeInvalidMode()
41 | {
42 | $_SERVER['REQUEST_METHOD'] = 'GET';
43 | $_SERVER['QUERY_STRING'] = 'hub_mode=unsubscribe&hub_challenge=test_challenge_123&hub_verify_token=test_verify_token';
44 | $_GET = [];
45 |
46 | $result = Webhook::handleSubscriptionChallenge('test_verify_token');
47 |
48 | $this->assertFalse($result['success']);
49 | $this->assertEquals('Invalid hub_mode. Expected "subscribe".', $result['error']);
50 | }
51 |
52 | public function testHandleSubscriptionChallengeMissingChallenge()
53 | {
54 | $_SERVER['REQUEST_METHOD'] = 'GET';
55 | $_SERVER['QUERY_STRING'] = 'hub_mode=subscribe&hub_verify_token=test_verify_token';
56 | $_GET = [];
57 |
58 | $result = Webhook::handleSubscriptionChallenge('test_verify_token');
59 |
60 | $this->assertFalse($result['success']);
61 | $this->assertEquals('Missing hub_challenge parameter.', $result['error']);
62 | }
63 |
64 | public function testHandleSubscriptionChallengeInvalidToken()
65 | {
66 | $_SERVER['REQUEST_METHOD'] = 'GET';
67 | $_SERVER['QUERY_STRING'] = 'hub_mode=subscribe&hub_challenge=test_challenge_123&hub_verify_token=wrong_token';
68 | $_GET = [];
69 |
70 | $result = Webhook::handleSubscriptionChallenge('test_verify_token');
71 |
72 | $this->assertFalse($result['success']);
73 | $this->assertEquals('Invalid verify token.', $result['error']);
74 | }
75 |
76 | public function testGetEventType()
77 | {
78 | $event = [
79 | 'object_type' => 'activity',
80 | 'aspect_type' => 'create',
81 | 'object_id' => 12345
82 | ];
83 |
84 | $eventType = Webhook::getEventType($event);
85 |
86 | $this->assertEquals('activity.create', $eventType);
87 | }
88 |
89 | public function testIsObjectType()
90 | {
91 | $event = [
92 | 'object_type' => 'activity',
93 | 'aspect_type' => 'create',
94 | 'object_id' => 12345
95 | ];
96 |
97 | $this->assertTrue(Webhook::isObjectType($event, 'activity'));
98 | $this->assertFalse(Webhook::isObjectType($event, 'athlete'));
99 | }
100 |
101 | public function testIsAspectType()
102 | {
103 | $event = [
104 | 'object_type' => 'activity',
105 | 'aspect_type' => 'create',
106 | 'object_id' => 12345
107 | ];
108 |
109 | $this->assertTrue(Webhook::isAspectType($event, 'create'));
110 | $this->assertFalse(Webhook::isAspectType($event, 'update'));
111 | }
112 |
113 | public function testVerifySignature()
114 | {
115 | $payload = '{"test": "data"}';
116 | $secret = 'test_secret';
117 | $signature = 'sha256=' . hash_hmac('sha256', $payload, $secret);
118 |
119 | $this->assertTrue(Webhook::verifySignature($payload, $signature, $secret));
120 | $this->assertFalse(Webhook::verifySignature($payload, 'wrong_signature', $secret));
121 | $this->assertTrue(Webhook::verifySignature($payload, $signature, '')); // No secret configured
122 | }
123 |
124 | public function testGenerateVerifyToken()
125 | {
126 | $token1 = Webhook::generateVerifyToken();
127 | $token2 = Webhook::generateVerifyToken();
128 |
129 | // Tokens should be 32 characters long by default
130 | $this->assertEquals(32, strlen($token1));
131 | $this->assertEquals(32, strlen($token2));
132 |
133 | // Tokens should be different
134 | $this->assertNotEquals($token1, $token2);
135 |
136 | // Test custom length
137 | $token3 = Webhook::generateVerifyToken(16);
138 | $this->assertEquals(16, strlen($token3));
139 | }
140 |
141 | public function testIsActivityCreationEvent()
142 | {
143 | $activityCreateEvent = [
144 | 'object_type' => 'activity',
145 | 'aspect_type' => 'create',
146 | 'object_id' => 12345,
147 | 'owner_id' => 67890
148 | ];
149 |
150 | $activityUpdateEvent = [
151 | 'object_type' => 'activity',
152 | 'aspect_type' => 'update',
153 | 'object_id' => 12345,
154 | 'owner_id' => 67890
155 | ];
156 |
157 | $athleteUpdateEvent = [
158 | 'object_type' => 'athlete',
159 | 'aspect_type' => 'update',
160 | 'object_id' => 67890,
161 | 'owner_id' => 67890
162 | ];
163 |
164 | $this->assertTrue(Webhook::isActivityCreationEvent($activityCreateEvent));
165 | $this->assertFalse(Webhook::isActivityCreationEvent($activityUpdateEvent));
166 | $this->assertFalse(Webhook::isActivityCreationEvent($athleteUpdateEvent));
167 | }
168 |
169 | public function testGetAthleteId()
170 | {
171 | $event = [
172 | 'object_type' => 'activity',
173 | 'aspect_type' => 'create',
174 | 'object_id' => 12345,
175 | 'owner_id' => 67890
176 | ];
177 |
178 | $this->assertEquals(67890, Webhook::getAthleteId($event));
179 |
180 | $eventWithoutOwner = [
181 | 'object_type' => 'activity',
182 | 'aspect_type' => 'create',
183 | 'object_id' => 12345
184 | ];
185 |
186 | $this->assertNull(Webhook::getAthleteId($eventWithoutOwner));
187 | }
188 |
189 | public function testGetObjectId()
190 | {
191 | $event = [
192 | 'object_type' => 'activity',
193 | 'aspect_type' => 'create',
194 | 'object_id' => 12345,
195 | 'owner_id' => 67890
196 | ];
197 |
198 | $this->assertEquals(12345, Webhook::getObjectId($event));
199 |
200 | $eventWithoutObject = [
201 | 'object_type' => 'activity',
202 | 'aspect_type' => 'create',
203 | 'owner_id' => 67890
204 | ];
205 |
206 | $this->assertNull(Webhook::getObjectId($eventWithoutObject));
207 | }
208 |
209 | public function testValidateEventPayload()
210 | {
211 | $validEvent = [
212 | 'object_type' => 'activity',
213 | 'aspect_type' => 'create',
214 | 'object_id' => 12345,
215 | 'owner_id' => 67890
216 | ];
217 |
218 | $result = Webhook::validateEventPayload($validEvent);
219 | $this->assertTrue($result['valid']);
220 | $this->assertNull($result['error']);
221 |
222 | // Test missing fields
223 | $invalidEvent = [
224 | 'object_type' => 'activity',
225 | 'aspect_type' => 'create'
226 | // Missing object_id and owner_id
227 | ];
228 |
229 | $result = Webhook::validateEventPayload($invalidEvent);
230 | $this->assertFalse($result['valid']);
231 | $this->assertStringContainsString('Missing required field', $result['error']);
232 |
233 | // Test invalid field types
234 | $invalidTypesEvent = [
235 | 'object_type' => 123, // Should be string
236 | 'aspect_type' => 'create',
237 | 'object_id' => 'not_numeric', // Should be numeric
238 | 'owner_id' => 67890
239 | ];
240 |
241 | $result = Webhook::validateEventPayload($invalidTypesEvent);
242 | $this->assertFalse($result['valid']);
243 | $this->assertStringContainsString('must be', $result['error']);
244 | }
245 |
246 | protected function tearDown(): void
247 | {
248 | // Clean up global variables after each test
249 | $_SERVER = [];
250 | $_GET = [];
251 | parent::tearDown();
252 | }
253 | }
254 |
--------------------------------------------------------------------------------
/tests/Strava/API/Service/StubTest.php:
--------------------------------------------------------------------------------
1 | getAthlete(1234);
18 | $this->assertTrue(is_array($output));
19 | }
20 |
21 | public function testGetAthleteStats()
22 | {
23 | $service = new Strava\API\Service\Stub();
24 | $output = $service->getAthleteStats(1234);
25 | $this->assertTrue(is_array($output));
26 | }
27 |
28 | public function testGetAthleteRoutes()
29 | {
30 | $service = new Strava\API\Service\Stub();
31 | $output = $service->getAthleteRoutes(1234);
32 | $this->assertTrue(is_array($output));
33 | }
34 |
35 | public function testGetAthleteClubs()
36 | {
37 | $service = new Strava\API\Service\Stub();
38 | $output = $service->getAthleteClubs();
39 | $this->assertTrue(is_array($output));
40 | }
41 |
42 | public function testGetAthleteActivities()
43 | {
44 | $service = new Strava\API\Service\Stub();
45 | $output = $service->getAthleteActivities();
46 | $this->assertTrue(is_array($output));
47 | }
48 |
49 | public function testGetAthleteFriends()
50 | {
51 | $service = new Strava\API\Service\Stub();
52 | $output = $service->getAthleteFriends();
53 | $this->assertTrue(is_array($output));
54 | }
55 |
56 | public function testGetAthleteFollowers()
57 | {
58 | $service = new Strava\API\Service\Stub();
59 | $output = $service->getAthleteFollowers();
60 | $this->assertTrue(is_array($output));
61 | }
62 |
63 | public function testGetAthleteBothFollowing()
64 | {
65 | $service = new Strava\API\Service\Stub();
66 | $output = $service->getAthleteBothFollowing(1234);
67 | $this->assertTrue(is_array($output));
68 | }
69 |
70 | public function testGetAthleteKom()
71 | {
72 | $service = new Strava\API\Service\Stub();
73 | $output = $service->getAthleteKom(1234);
74 | $this->assertTrue(is_array($output));
75 | }
76 |
77 | public function testGetAthleteZones()
78 | {
79 | $service = new Strava\API\Service\Stub();
80 | $output = $service->getAthleteZones();
81 | $this->assertTrue(is_array($output));
82 | }
83 |
84 | public function testGetAthleteStarredSegments()
85 | {
86 | $service = new Strava\API\Service\Stub();
87 | $output = $service->getAthleteStarredSegments();
88 | $this->assertTrue(is_array($output));
89 | }
90 |
91 | public function testUpdateAthlete()
92 | {
93 | $service = new Strava\API\Service\Stub();
94 | $output = $service->updateAthlete('Xyz', 'ABC', 'The Netherlands', 'M', 83.00);
95 | $this->assertTrue(is_array($output));
96 | }
97 |
98 | public function testGetActivity()
99 | {
100 | $service = new Strava\API\Service\Stub();
101 | $output = $service->getActivity(1234);
102 | $this->assertTrue(is_array($output));
103 | }
104 |
105 | public function testGetActivityComments()
106 | {
107 | $service = new Strava\API\Service\Stub();
108 | $output = $service->getActivityComments(1234);
109 | $this->assertTrue(is_array($output));
110 | }
111 |
112 | public function testGetActivityKudos()
113 | {
114 | $service = new Strava\API\Service\Stub();
115 | $output = $service->getActivityKudos(1234);
116 | $this->assertTrue(is_array($output));
117 | }
118 |
119 | public function testGetActivityPhotos()
120 | {
121 | $service = new Strava\API\Service\Stub();
122 | $output = $service->getActivityPhotos(1234, 1024);
123 | $this->assertTrue(is_array($output));
124 | }
125 |
126 | public function testGetActivityZones()
127 | {
128 | $service = new Strava\API\Service\Stub();
129 | $output = $service->getActivityZones(1234);
130 | $this->assertTrue(is_array($output));
131 | }
132 |
133 | public function testGetActivityLaps()
134 | {
135 | $service = new Strava\API\Service\Stub();
136 | $output = $service->getActivityLaps(1234);
137 | $this->assertTrue(is_array($output));
138 | }
139 |
140 | public function testGetActivityUploadStatus()
141 | {
142 | $service = new Strava\API\Service\Stub();
143 | $output = $service->getActivityUploadStatus(1234);
144 | $this->assertTrue(is_array($output));
145 | }
146 |
147 | public function testCreateActivity()
148 | {
149 | $service = new Strava\API\Service\Stub();
150 | $output = $service->createActivity('cycling ride', 'cycling', '20140101', 100);
151 | $this->assertTrue(is_array($output));
152 | }
153 |
154 | public function testUploadActivity()
155 | {
156 | $service = new Strava\API\Service\Stub();
157 | $output = $service->uploadActivity("abc23487fsdfds");
158 | $this->assertTrue(is_array($output));
159 | }
160 |
161 | public function testUpdateActivity()
162 | {
163 | $service = new Strava\API\Service\Stub();
164 | $output = $service->updateActivity(123);
165 | $this->assertTrue(is_array($output));
166 | }
167 |
168 | public function testDeleteActivity()
169 | {
170 | $service = new Strava\API\Service\Stub();
171 | $output = $service->deleteActivity(1234);
172 | $this->assertTrue(is_array($output));
173 | }
174 |
175 | public function testGetGear()
176 | {
177 | $service = new Strava\API\Service\Stub();
178 | $output = $service->getGear(1234);
179 | $this->assertTrue(is_array($output));
180 | }
181 |
182 | public function testGetClub()
183 | {
184 | $service = new Strava\API\Service\Stub();
185 | $output = $service->getClub(1234);
186 | $this->assertTrue(is_array($output));
187 | }
188 |
189 | public function testGetClubMembers()
190 | {
191 | $service = new Strava\API\Service\Stub();
192 | $output = $service->getClubMembers(1234);
193 | $this->assertTrue(is_array($output));
194 | }
195 |
196 | public function testGetClubActivities()
197 | {
198 | $service = new Strava\API\Service\Stub();
199 | $output = $service->getClubActivities(1234);
200 | $this->assertTrue(is_array($output));
201 | }
202 |
203 | public function testGetClubAnnouncements()
204 | {
205 | $service = new Strava\API\Service\Stub();
206 | $output = $service->getClubAnnouncements(1234);
207 | $this->assertTrue(is_array($output));
208 | }
209 |
210 | public function testGetClubGroupEvents()
211 | {
212 | $service = new Strava\API\Service\Stub();
213 | $output = $service->getClubGroupEvents(1234);
214 | $this->assertTrue(is_array($output));
215 | }
216 |
217 | public function testJoinClub()
218 | {
219 | $service = new Strava\API\Service\Stub();
220 | $output = $service->joinClub(1234);
221 | $this->assertTrue(is_array($output));
222 | }
223 |
224 | public function testLeaveClub()
225 | {
226 | $service = new Strava\API\Service\Stub();
227 | $output = $service->leaveClub(1234);
228 | $this->assertTrue(is_array($output));
229 | }
230 |
231 | public function testGetRoute()
232 | {
233 | $service = new Strava\API\Service\Stub();
234 | $output = $service->getRoute(1234);
235 | $this->assertTrue(is_array($output));
236 | }
237 |
238 | public function testGetRouteAsGPX()
239 | {
240 | $service = new Strava\API\Service\Stub();
241 | $output = $service->getRouteAsGPX(1234);
242 | $this->assertTrue(is_string($output));
243 | }
244 |
245 | public function testGetRouteAsTCX()
246 | {
247 | $service = new Strava\API\Service\Stub();
248 | $output = $service->getRouteAsTCX(1234);
249 | $this->assertTrue(is_string($output));
250 | }
251 |
252 | public function testGetSegment()
253 | {
254 | $service = new Strava\API\Service\Stub();
255 | $output = $service->getSegment(1234);
256 | $this->assertTrue(is_array($output));
257 | }
258 |
259 | public function testGetSegmentLeaderboard()
260 | {
261 | $service = new Strava\API\Service\Stub();
262 | $output = $service->getSegmentLeaderboard(1234);
263 | $this->assertTrue(is_array($output));
264 | }
265 |
266 | public function testGetSegmentExplorer()
267 | {
268 | $service = new Strava\API\Service\Stub();
269 | $output = $service->getSegmentExplorer("lng.lat");
270 | $this->assertTrue(is_array($output));
271 | }
272 |
273 | public function testGetSegmentEffort()
274 | {
275 | $service = new Strava\API\Service\Stub();
276 | $output = $service->getSegmentEffort(1234);
277 | $this->assertTrue(is_array($output));
278 | }
279 |
280 | public function testGetStreamsActivity()
281 | {
282 | $service = new Strava\API\Service\Stub();
283 | $output = $service->getStreamsActivity(1234, 'abc');
284 | $this->assertTrue(is_array($output));
285 | }
286 |
287 | public function testGetStreamsEffort()
288 | {
289 | $service = new Strava\API\Service\Stub();
290 | $output = $service->getStreamsEffort(1234, 'abc');
291 | $this->assertTrue(is_array($output));
292 | }
293 |
294 | public function testGetStreamsSegment()
295 | {
296 | $service = new Strava\API\Service\Stub();
297 | $output = $service->getStreamsSegment(1234, 'abc');
298 | $this->assertTrue(is_array($output));
299 | }
300 |
301 | public function testGetStreamsRoute()
302 | {
303 | $service = new Strava\API\Service\Stub();
304 | $output = $service->getStreamsRoute(1234);
305 | $this->assertTrue(is_array($output));
306 | }
307 | }
308 |
--------------------------------------------------------------------------------
/src/Strava/API/Service/ServiceInterface.php:
--------------------------------------------------------------------------------
1 | format($json);
17 | }
18 |
19 | public function getAthleteStats(int $id)
20 | {
21 | $json = '[ { "biggest_ride_distance": 175454.0, "biggest_climb_elevation_gain": 1882.6999999999998, "recent_ride_totals": { "count": 3, "distance": 12054.900146484375, "moving_time": 2190, "elapsed_time": 2331, "elevation_gain": 36.0, "achievement_count": 0 }, "recent_run_totals": { "count": 23, "distance": 195948.40002441406, "moving_time": 65513, "elapsed_time": 75232, "elevation_gain": 2934.3999996185303, "achievement_count": 46 }, "recent_swim_totals": { "count": 2, "distance": 1117.2000122070312, "moving_time": 1744, "elapsed_time": 1942, "elevation_gain": 0.0, "achievement_count": 0 }, "ytd_ride_totals": { "count": 134, "distance": 4927252, "moving_time": 659982, "elapsed_time": 892644, "elevation_gain": 49940 }, "ytd_run_totals": { "count": 111, "distance": 917100, "moving_time": 272501, "elapsed_time": 328059, "elevation_gain": 7558 }, "ytd_swim_totals": { "count": 8, "distance": 10372, "moving_time": 8784, "elapsed_time": 11123, "elevation_gain": 0 }, "all_ride_totals": { "count": 375, "distance": 15760015, "moving_time": 2155741, "elapsed_time": 2684286, "elevation_gain": 189238 }, "all_run_totals": { "count": 272, "distance": 2269557, "moving_time": 673678, "elapsed_time": 812095, "elevation_gain": 23780 }, "all_swim_totals": { "count": 8, "distance": 10372, "moving_time": 8784, "elapsed_time": 11123, "elevation_gain": 0} } ]';
22 | return $this->format($json);
23 | }
24 |
25 | public function getAthleteRoutes(int $id, ?string $type = null, ?int $after = null, ?int $page = null, ?int $per_page = null)
26 | {
27 | $json = '[{"athlete":{"id":19,"resource_state":2},"id":743064,"resource_state":2,"description":"","distance":17781.6,"elevation_gain":207.8}]';
28 | return $this->format($json);
29 | }
30 |
31 | public function getAthleteClubs()
32 | {
33 | $json = '[ { "id": 1, "resource_state": 2, "name": "Team Strava Cycling", "profile_medium": "http://pics.com/clubs/1/medium.jpg", "profile": "http://pics.com/clubs/1/large.jpg" } ]';
34 | return $this->format($json);
35 | }
36 |
37 | public function getAthleteActivities(?string $before = null, ?string $after = null, ?int $page = null, ?int $per_page = null)
38 | {
39 | $json = '{"response": 1}';
40 | return $this->format($json);
41 | }
42 |
43 | public function getAthleteFriends(?int $id = null, ?int $page = null, ?int $per_page = null)
44 | {
45 | $json = '{"response": 1}';
46 | return $this->format($json);
47 | }
48 |
49 | public function getAthleteFollowers(?int $id = null, ?int $page = null, ?int $per_page = null)
50 | {
51 | $json = '{"response": 1}';
52 | return $this->format($json);
53 | }
54 |
55 | public function getAthleteBothFollowing(int $id, ?int $page = null, ?int $per_page = null)
56 | {
57 | $json = '{"response": 1}';
58 | return $this->format($json);
59 | }
60 |
61 | public function getAthleteKom(int $id, ?int $page = null, ?int $per_page = null)
62 | {
63 | $json = '{"response": 1}';
64 | return $this->format($json);
65 | }
66 |
67 | public function getAthleteZones()
68 | {
69 | $json = '{"heart_rate":{"custom_zones":false,"zones":[{"min":0,"max":115},{"min":115,"max":152},{"min":152,"max":171},{"min":171,"max":190},{"min":190,"max":-1}]},"power":{"zones":[{"min":0,"max":180},{"min":181,"max":246},{"min":247,"max":295},{"min":296,"max":344},{"min":345,"max":393},{"min":394,"max":492},{"min":493,"max":-1}]}}';
70 | return $this->format($json);
71 | }
72 |
73 | public function getAthleteStarredSegments(?int $id = null, ?int $page = null, ?int $per_page = null)
74 | {
75 | $json = '{"response": 1}';
76 | return $this->format($json);
77 | }
78 |
79 | public function updateAthlete(string $city, string $state, string $country, string $sex, float $weight)
80 | {
81 | $json = '{"response": 1}';
82 | return $this->format($json);
83 | }
84 |
85 | public function getActivityFollowing($before = null, $page = null, $per_page = null)
86 | {
87 | $json = '{"response": 1}';
88 | return $this->format($json);
89 | }
90 |
91 | public function getActivity(int $id, ?bool $include_all_efforts = null)
92 | {
93 | $json = '{"response": 1}';
94 | return $this->format($json);
95 | }
96 |
97 | public function getActivityComments(int $id, ?bool $markdown = null, ?int $page = null, ?int $per_page = null)
98 | {
99 | $json = '{"response": 1}';
100 | return $this->format($json);
101 | }
102 |
103 | public function getActivityKudos(int $id, ?int $page = null, ?int $per_page = null)
104 | {
105 | $json = '{"response": 1}';
106 | return $this->format($json);
107 | }
108 |
109 | public function getActivityPhotos(int $id, int $size = 2048, string $photo_sources = 'true')
110 | {
111 | $json = '{"response": 1}';
112 | return $this->format($json);
113 | }
114 |
115 | public function getActivityZones(int $id)
116 | {
117 | $json = '{"response": 1}';
118 | return $this->format($json);
119 | }
120 |
121 | public function getActivityLaps(int $id)
122 | {
123 | $json = '{"response": 1}';
124 | return $this->format($json);
125 | }
126 |
127 | public function getActivityUploadStatus(int $id)
128 | {
129 | $json = '{"response": 1}';
130 | return $this->format($json);
131 | }
132 |
133 | public function createActivity(string $name, string $type, string $start_date_local, int $elapsed_time, ?string $description = null, ?float $distance = null, ?int $private = null, ?int $trainer = null)
134 | {
135 | $json = '{"response": 1}';
136 | return $this->format($json);
137 | }
138 |
139 | public function uploadActivity(string $file, ?string $activity_type = null, ?string $name = null, ?string $description = null, ?int $private = null, ?int $trainer = null, ?int $commute = null, ?string $data_type = null, ?string $external_id = null)
140 | {
141 | $json = '{"response": 1}';
142 | return $this->format($json);
143 | }
144 |
145 | public function updateActivity(int $id, ?string $name = null, ?string $type = null, bool $private = false, bool $commute = false, bool $trainer = false, ?string $gear_id = null, ?string $description = null)
146 | {
147 | $json = '{"response": 1}';
148 | return $this->format($json);
149 | }
150 |
151 | public function deleteActivity(int $id)
152 | {
153 | $json = '{"response": 1}';
154 | return $this->format($json);
155 | }
156 |
157 | public function getGear(int $id)
158 | {
159 | $json = '{"response": 1}';
160 | return $this->format($json);
161 | }
162 |
163 | public function getClub(int $id)
164 | {
165 | $json = '{"response": 1}';
166 | return $this->format($json);
167 | }
168 |
169 | public function getClubMembers(int $id, ?int $page = null, ?int $per_page = null)
170 | {
171 | $json = '{"response": 1}';
172 | return $this->format($json);
173 | }
174 |
175 | public function getClubActivities(int $id, ?int $page = null, ?int $per_page = null)
176 | {
177 | $json = '{"response": 1}';
178 | return $this->format($json);
179 | }
180 |
181 | public function getClubAnnouncements(int $id)
182 | {
183 | $json = '{"response": 1}';
184 | return $this->format($json);
185 | }
186 |
187 | public function getClubGroupEvents(int $id)
188 | {
189 | $json = '{"response": 1}';
190 | return $this->format($json);
191 | }
192 |
193 | public function joinClub(int $id)
194 | {
195 | $json = '{"response": 1}';
196 | return $this->format($json);
197 | }
198 |
199 | public function leaveClub(int $id)
200 | {
201 | $json = '{"response": 1}';
202 | return $this->format($json);
203 | }
204 |
205 | public function getRoute(int $id)
206 | {
207 | $json = '{"response": 1}';
208 | return $this->format($json);
209 | }
210 |
211 | public function getRouteAsGPX(int $id)
212 | {
213 | $gpx = '';
214 | return $gpx;
215 | }
216 |
217 | public function getRouteAsTCX(int $id)
218 | {
219 | $tcx = '';
220 | return $tcx;
221 | }
222 |
223 | public function getSegment(int $id)
224 | {
225 | $json = '{"response": 1}';
226 | return $this->format($json);
227 | }
228 |
229 | public function getSegmentLeaderboard(int $id, ?string $gender = null, ?string $age_group = null, $weight_class = null, $following = null, $club_id = null, $date_range = null, $context_entries = null, $page = null, $per_page = null)
230 | {
231 | $json = '{"response": 1}';
232 | return $this->format($json);
233 | }
234 |
235 | public function getSegmentExplorer(string $bounds, string $activity_type = 'riding', ?int $min_cat = null, ?int $max_cat = null)
236 | {
237 | $json = '{"response": 1}';
238 | return $this->format($json);
239 | }
240 |
241 | public function getSegmentEffort(int $id, ?int $athlete_id = null, ?string $start_date_local = null, ?string $end_date_local = null, ?int $page = null, ?int $per_page = null)
242 | {
243 | $json = '{"response": 1}';
244 | return $this->format($json);
245 | }
246 |
247 | public function getStreamsActivity(int $id, string $types, $resolution = null, string $series_type = 'distance')
248 | {
249 | $json = '{"response": 1}';
250 | return $this->format($json);
251 | }
252 |
253 | public function getStreamsEffort(int $id, string $types, $resolution = null, string $series_type = 'distance')
254 | {
255 | $json = '{"response": 1}';
256 | return $this->format($json);
257 | }
258 |
259 | public function getStreamsSegment(int $id, string $types, $resolution = null, string $series_type = 'distance')
260 | {
261 | $json = '{"response": 1}';
262 | return $this->format($json);
263 | }
264 |
265 | public function getStreamsRoute(int $id)
266 | {
267 | $json = '{"response": 1}';
268 | return $this->format($json);
269 | }
270 |
271 | public function createWebhookSubscription(int $clientId, string $clientSecret, string $callbackUrl, string $verifyToken)
272 | {
273 | $json = '{"id": 123, "callback_url": "' . $callbackUrl . '", "created_at": "2023-01-01T00:00:00Z"}';
274 | return $this->format($json);
275 | }
276 |
277 | public function listWebhookSubscriptions(int $clientId, string $clientSecret)
278 | {
279 | $json = '[{"id": 123, "callback_url": "https://example.com/webhook", "created_at": "2023-01-01T00:00:00Z"}]';
280 | return $this->format($json);
281 | }
282 |
283 | public function deleteWebhookSubscription(int $clientId, string $clientSecret, int $subscriptionId)
284 | {
285 | $json = '{"success": true}';
286 | return $this->format($json);
287 | }
288 |
289 | /**
290 | * @param string $result
291 | */
292 | private function format($result)
293 | {
294 | return json_decode($result, true);
295 | }
296 | }
297 |
--------------------------------------------------------------------------------
/src/Strava/API/Webhook.php:
--------------------------------------------------------------------------------
1 | false,
42 | 'error' => 'Invalid request method. Expected GET.'
43 | ];
44 | }
45 |
46 | if ($hubMode !== 'subscribe') {
47 | return [
48 | 'success' => false,
49 | 'error' => 'Invalid hub_mode. Expected "subscribe".'
50 | ];
51 | }
52 |
53 | if (empty($hubChallenge)) {
54 | return [
55 | 'success' => false,
56 | 'error' => 'Missing hub_challenge parameter.'
57 | ];
58 | }
59 |
60 | if ($hubVerifyToken !== $verifyToken) {
61 | return [
62 | 'success' => false,
63 | 'error' => 'Invalid verify token.'
64 | ];
65 | }
66 |
67 | $result = [
68 | 'success' => true,
69 | 'challenge' => $hubChallenge
70 | ];
71 |
72 | // Auto-respond if requested
73 | if ($autoRespond) {
74 | self::sendChallengeResponse($hubChallenge);
75 | }
76 |
77 | return $result;
78 | }
79 |
80 | /**
81 | * Send challenge response to Strava
82 | *
83 | * @param string $challenge The challenge string from Strava
84 | * @return void
85 | */
86 | public static function sendChallengeResponse(string $challenge): void
87 | {
88 | header('Content-Type: application/json');
89 | http_response_code(200);
90 | echo json_encode(['hub.challenge' => $challenge]);
91 | exit;
92 | }
93 |
94 | /**
95 | * Process incoming webhook event
96 | *
97 | * @param callable|null $eventHandler Optional callback function to handle the event
98 | * @return array Parsed webhook event data
99 | */
100 | public static function processEvent(?callable $eventHandler = null): array
101 | {
102 | $method = $_SERVER['REQUEST_METHOD'] ?? '';
103 |
104 | if ($method !== 'POST') {
105 | return [
106 | 'success' => false,
107 | 'error' => 'Invalid request method. Expected POST.'
108 | ];
109 | }
110 |
111 | $rawBody = file_get_contents('php://input');
112 | if (empty($rawBody)) {
113 | return [
114 | 'success' => false,
115 | 'error' => 'Empty request body.'
116 | ];
117 | }
118 |
119 | $data = json_decode($rawBody, true);
120 | if (json_last_error() !== JSON_ERROR_NONE) {
121 | return [
122 | 'success' => false,
123 | 'error' => 'Invalid JSON: ' . json_last_error_msg()
124 | ];
125 | }
126 |
127 | // Validate required webhook event fields (matching your tested implementation)
128 | if (!isset($data['object_type']) || !isset($data['aspect_type']) || !isset($data['object_id']) || !isset($data['owner_id'])) {
129 | return [
130 | 'success' => false,
131 | 'error' => 'Invalid webhook payload structure. Missing required fields: object_type, aspect_type, object_id, or owner_id.'
132 | ];
133 | }
134 |
135 | // Process the webhook event with custom handler if provided
136 | if ($eventHandler) {
137 | try {
138 | $success = call_user_func($eventHandler, $data);
139 | if (!$success) {
140 | return [
141 | 'success' => false,
142 | 'error' => 'Event processing failed.'
143 | ];
144 | }
145 | } catch (\Exception $e) {
146 | return [
147 | 'success' => false,
148 | 'error' => 'Event processing failed: ' . $e->getMessage()
149 | ];
150 | }
151 | }
152 |
153 | return [
154 | 'success' => true,
155 | 'event' => $data
156 | ];
157 | }
158 |
159 | /**
160 | * Verify webhook event signature (if using signature verification)
161 | *
162 | * @param string $payload The raw request body
163 | * @param string $signature The X-Hub-Signature header value
164 | * @param string $secret Your webhook secret (if configured)
165 | * @return bool True if signature is valid
166 | */
167 | public static function verifySignature(string $payload, string $signature, string $secret): bool
168 | {
169 | if (empty($secret)) {
170 | return true; // No secret configured, skip verification
171 | }
172 |
173 | $expectedSignature = 'sha256=' . hash_hmac('sha256', $payload, $secret);
174 | return hash_equals($expectedSignature, $signature);
175 | }
176 |
177 | /**
178 | * Get webhook event type
179 | *
180 | * @param array $event The parsed webhook event
181 | * @return string The event type (e.g., 'activity.create', 'activity.update')
182 | */
183 | public static function getEventType(array $event): string
184 | {
185 | return $event['object_type'] . '.' . $event['aspect_type'];
186 | }
187 |
188 | /**
189 | * Check if event is for a specific object type
190 | *
191 | * @param array $event The parsed webhook event
192 | * @param string $objectType The object type to check (e.g., 'activity', 'athlete')
193 | * @return bool True if event is for the specified object type
194 | */
195 | public static function isObjectType(array $event, string $objectType): bool
196 | {
197 | return isset($event['object_type']) && $event['object_type'] === $objectType;
198 | }
199 |
200 | /**
201 | * Check if event is a specific aspect type
202 | *
203 | * @param array $event The parsed webhook event
204 | * @param string $aspectType The aspect type to check (e.g., 'create', 'update', 'delete')
205 | * @return bool True if event is the specified aspect type
206 | */
207 | public static function isAspectType(array $event, string $aspectType): bool
208 | {
209 | return isset($event['aspect_type']) && $event['aspect_type'] === $aspectType;
210 | }
211 |
212 | /**
213 | * Handle complete webhook endpoint (both GET and POST requests)
214 | *
215 | * This method provides a complete webhook endpoint handler that can be used
216 | * as the main entry point for your webhook endpoint.
217 | *
218 | * @param string $verifyToken The verify token for subscription validation
219 | * @param callable|null $eventHandler Optional callback function to handle events
220 | * @return void This method will exit after sending response
221 | */
222 | public static function handleWebhookEndpoint(string $verifyToken, ?callable $eventHandler = null): void
223 | {
224 | $method = $_SERVER['REQUEST_METHOD'] ?? '';
225 |
226 | // Set content type based on request method
227 | if ($method === 'GET') {
228 | header('Content-Type: application/json');
229 | } else {
230 | header('Content-Type: text/plain');
231 | }
232 |
233 | // Handle GET requests (webhook verification)
234 | if ($method === 'GET') {
235 | $result = self::handleSubscriptionChallenge($verifyToken, false);
236 |
237 | if ($result['success']) {
238 | // Return the challenge value as JSON as required by Strava
239 | echo json_encode(['hub.challenge' => $result['challenge']]);
240 | exit;
241 | } else {
242 | http_response_code(400);
243 | echo 'Invalid verification request';
244 | exit;
245 | }
246 | }
247 |
248 | // Handle POST requests (webhook events)
249 | if ($method === 'POST') {
250 | $result = self::processEvent($eventHandler);
251 |
252 | if ($result['success']) {
253 | http_response_code(200);
254 | echo 'OK';
255 | exit;
256 | } else {
257 | http_response_code(400);
258 | echo $result['error'];
259 | exit;
260 | }
261 | }
262 |
263 | // Invalid method
264 | http_response_code(405);
265 | echo 'Method not allowed';
266 | exit;
267 | }
268 |
269 | /**
270 | * Generate a random verify token
271 | *
272 | * @param int $length Length of the token (default: 32)
273 | * @return string Random verify token
274 | */
275 | public static function generateVerifyToken(int $length = 32): string
276 | {
277 | if (function_exists('random_bytes')) {
278 | return bin2hex(random_bytes($length / 2));
279 | } elseif (function_exists('openssl_random_pseudo_bytes')) {
280 | return bin2hex(openssl_random_pseudo_bytes($length / 2));
281 | } else {
282 | // Fallback for older PHP versions
283 | $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
284 | $token = '';
285 | for ($i = 0; $i < $length; $i++) {
286 | $token .= $characters[rand(0, strlen($characters) - 1)];
287 | }
288 | return $token;
289 | }
290 | }
291 |
292 | /**
293 | * Check if webhook event is an activity creation event
294 | *
295 | * @param array $event The webhook event data
296 | * @return bool True if this is an activity creation event
297 | */
298 | public static function isActivityCreationEvent(array $event): bool
299 | {
300 | return self::isObjectType($event, 'activity') && self::isAspectType($event, 'create');
301 | }
302 |
303 | /**
304 | * Get athlete ID from webhook event
305 | *
306 | * @param array $event The webhook event data
307 | * @return int|null The athlete ID or null if not found
308 | */
309 | public static function getAthleteId(array $event): ?int
310 | {
311 | return isset($event['owner_id']) ? (int)$event['owner_id'] : null;
312 | }
313 |
314 | /**
315 | * Get object ID from webhook event
316 | *
317 | * @param array $event The webhook event data
318 | * @return int|null The object ID or null if not found
319 | */
320 | public static function getObjectId(array $event): ?int
321 | {
322 | return isset($event['object_id']) ? (int)$event['object_id'] : null;
323 | }
324 |
325 | /**
326 | * Validate webhook event payload structure
327 | *
328 | * @param array $event The webhook event data
329 | * @return array Validation result with 'valid' boolean and 'error' message if invalid
330 | */
331 | public static function validateEventPayload(array $event): array
332 | {
333 | // Check required fields (matching your tested implementation)
334 | $requiredFields = ['object_type', 'aspect_type', 'object_id', 'owner_id'];
335 |
336 | foreach ($requiredFields as $field) {
337 | if (!isset($event[$field])) {
338 | return [
339 | 'valid' => false,
340 | 'error' => "Missing required field: {$field}"
341 | ];
342 | }
343 | }
344 |
345 | // Validate field types
346 | if (!is_string($event['object_type'])) {
347 | return [
348 | 'valid' => false,
349 | 'error' => 'object_type must be a string'
350 | ];
351 | }
352 |
353 | if (!is_string($event['aspect_type'])) {
354 | return [
355 | 'valid' => false,
356 | 'error' => 'aspect_type must be a string'
357 | ];
358 | }
359 |
360 | if (!is_numeric($event['object_id'])) {
361 | return [
362 | 'valid' => false,
363 | 'error' => 'object_id must be numeric'
364 | ];
365 | }
366 |
367 | if (!is_numeric($event['owner_id'])) {
368 | return [
369 | 'valid' => false,
370 | 'error' => 'owner_id must be numeric'
371 | ];
372 | }
373 |
374 | return [
375 | 'valid' => true,
376 | 'error' => null
377 | ];
378 | }
379 | }
380 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | StravaPHP
2 | =========
3 | [](https://github.com/basvandorst/StravaPHP/actions/workflows/php.yml) [](https://coveralls.io/github/basvandorst/StravaPHP?branch=develop)
4 |
5 | **TLDR;** Strava V3 API PHP client with OAuth authentication
6 |
7 | The Strava V3 API is a publicly available interface allowing developers access
8 | to the rich [Strava](https://www.strava.com/) dataset. The interface is stable and currently used by the
9 | Strava mobile applications. However, changes are occasionally made to improve
10 | performance and enhance features. See Strava's [changelog](https://strava.github.io/api/v3/changelog/) for more details.
11 |
12 | In this GitHub repository you can find the PHP implementation of the
13 | Strava V3 API. The current version of StravaPHP combines the V3 API
14 | with a proper OAuth authentication.
15 |
16 | ## Getting started
17 | ### Get your API key
18 | All calls to the Strava API require an access token defining the athlete and
19 | application making the call. Any registered Strava user can obtain an access
20 | token by first creating an application at [https://developers.strava.com](https://developers.strava.com/)
21 |
22 | ### Composer package
23 | Use composer to install this StravaPHP package.
24 |
25 | ```
26 | {
27 | "require": {
28 | "basvandorst/stravaphp": "^2.0.0"
29 | }
30 | }
31 | ```
32 |
33 | ### StravaPHP usage
34 | #### First, authorisation and authentication
35 | ```php
36 | 1234,
45 | 'clientSecret' => 'APP-TOKEN',
46 | 'redirectUri' => 'http://my-app/callback.php'
47 | ];
48 | $oauth = new OAuth($options);
49 |
50 | if (!isset($_GET['code'])) {
51 | print 'Connect';
63 | } else {
64 | $token = $oauth->getAccessToken('authorization_code', [
65 | 'code' => $_GET['code']
66 | ]);
67 | print $token->getToken();
68 | }
69 | } catch(Exception $e) {
70 | print $e->getMessage();
71 | }
72 | ```
73 | #### Then, call your API method!
74 | ```php
75 | 'https://www.strava.com/api/v3/']);
84 | $service = new REST($token->getToken(), $adapter); // Define your user token here.
85 | $client = new Client($service);
86 |
87 | $athlete = $client->getAthlete();
88 | print_r($athlete);
89 |
90 | $activities = $client->getAthleteActivities();
91 | print_r($activities);
92 |
93 | $club = $client->getClub(9729);
94 | print_r($club);
95 | } catch(Exception $e) {
96 | print $e->getMessage();
97 | }
98 | ```
99 |
100 | ## Class documentation
101 |
102 | ### Strava\API\Factory
103 | #### Usage
104 | ```php
105 | use Strava\API\Factory;
106 |
107 | // Configure your app ID, app token and callback uri
108 | $factory = new Factory();
109 | $OAuthClient = $factory->getOAuthClient(1234, 'APP-TOKEN', 'http://my-app/callback.php');
110 | ```
111 | #### Methods
112 | ```php
113 | $factory->getOAuthClient($client_id, $client_secret, $redirect_uri);
114 | $factory->getAPIClient($token);
115 | ```
116 |
117 | ### Strava\API\OAuth
118 | #### Usage
119 | ```php
120 | use Strava\API\OAuth;
121 |
122 | // Parameter information: https://strava.github.io/api/v3/oauth/#get-authorize
123 | $options = [
124 | 'clientId' => 1234,
125 | 'clientSecret' => 'APP-TOKEN',
126 | 'redirectUri' => 'http://my-app/callback.php'
127 | ];
128 | $oauth = new OAuth($options);
129 |
130 | // The OAuth authorization procces (1st; let the user approve, 2nd; token exchange with Strava)
131 | if (!isset($_GET['code'])) {
132 | print 'Connect';
144 | } else {
145 | $token = $oauth->getAccessToken('authorization_code', [
146 | 'code' => $_GET['code']
147 | ]);
148 | print $token->getToken();
149 | }
150 | ```
151 | #### Methods
152 | ```php
153 | $oauth->getAuthorizationUrl($options = []);
154 | $oauth->getAccessToken($grant = 'authorization_code', $params = []);
155 | ```
156 | ### Strava\API\Client
157 | #### Usage
158 | ```php
159 | // REST adapter (We use `Guzzle` in this project)
160 | use GuzzleHttp\Client as GuzzleClient;
161 | use Strava\API\Service\REST;
162 | use Strava\API\Client;
163 |
164 | $adapter = new GuzzleClient(['base_uri' => 'https://www.strava.com/api/v3/']);
165 | // Service to use (Service\Stub is also available for test purposes)
166 | $service = new REST('RECEIVED-TOKEN', $adapter);
167 |
168 | // Receive the athlete!
169 | $client = new Client($service);
170 | $athlete = $client->getAthlete();
171 | print_r($athlete);
172 | ```
173 | #### Methods
174 | ```php
175 | $client->getAthlete($id = null);
176 | $client->getAthleteStats($id);
177 | $client->getAthleteClubs();
178 | $client->getAthleteRoutes($id, $type = null, $after = null, $page = null, $per_page = null);
179 | $client->getAthleteActivities($before = null, $after = null, $page = null, $per_page = null);
180 | $client->getAthleteFriends($id = null, $page = null, $per_page = null);
181 | $client->getAthleteFollowers($id = null, $page = null, $per_page = null);
182 | $client->getAthleteBothFollowing($id, $page = null, $per_page = null);
183 | $client->getAthleteKom($id, $page = null, $per_page = null);
184 | $client->getAthleteZones();
185 | $client->getAthleteStarredSegments($id = null, $page = null, $per_page = null);
186 | $client->updateAthlete($city, $state, $country, $sex, $weight);
187 | $client->getActivityFollowing($before = null, $page = null, $per_page = null);
188 | $client->getActivity($id, $include_all_efforts = null);
189 | $client->getActivityComments($id, $markdown = null, $page = null, $per_page = null);
190 | $client->getActivityKudos($id, $page = null, $per_page = null);
191 | $client->getActivityPhotos($id, $size = 2048, $photo_sources = 'true');
192 | $client->getActivityZones($id);
193 | $client->getActivityLaps($id);
194 | $client->getActivityUploadStatus($id);
195 | $client->createActivity($name, $type, $start_date_local, $elapsed_time, $description = null, $distance = null);
196 | $client->uploadActivity($file, $activity_type = null, $name = null, $description = null, $private = null, $commute = null, $trainer = null, $data_type = null, $external_id = null);
197 | $client->updateActivity($id, $name = null, $type = null, $private = false, $commute = false, $trainer = false, $gear_id = null, $description = null);
198 | $client->deleteActivity($id);
199 | $client->getGear($id);
200 | $client->getClub($id);
201 | $client->getClubMembers($id, $page = null, $per_page = null);
202 | $client->getClubActivities($id, $page = null, $per_page = null);
203 | $client->getRoute($id);
204 | $client->getRouteAsGPX($id);
205 | $client->getRouteAsTCX($id);
206 | $client->getSegment($id);
207 | $client->getSegmentLeaderboard($id, $gender = null, $age_group = null, $weight_class = null, $following = null, $club_id = null, $date_range = null, $page = null, $per_page = null);
208 | $client->getSegmentExplorer($bounds, $activity_type = 'riding', $min_cat = null, $max_cat = null);
209 | $client->getSegmentEffort($id, $athlete_id = null, $start_date_local = null, $end_date_local = null, $page = null, $per_page = null);
210 | $client->getStreamsActivity($id, $types, $resolution = null, $series_type = 'distance');
211 | $client->getStreamsEffort($id, $types, $resolution = null, $series_type = 'distance');
212 | $client->getStreamsSegment($id, $types, $resolution = null, $series_type = 'distance');
213 | $client->getStreamsRoute($id);
214 | $client->createWebhookSubscription($clientId, $clientSecret, $callbackUrl, $verifyToken);
215 | $client->listWebhookSubscriptions($clientId, $clientSecret);
216 | $client->deleteWebhookSubscription($clientId, $clientSecret, $subscriptionId);
217 | ```
218 |
219 | ## Webhook Integration
220 |
221 | StravaPHP now includes comprehensive webhook support for real-time event notifications. This allows you to receive instant notifications when activities are created, updated, or deleted.
222 |
223 | ### Webhook Subscription Management
224 |
225 | ```php
226 | 'https://www.strava.com/api/v3/']);
235 | $service = new REST('YOUR_ACCESS_TOKEN', $adapter);
236 | $client = new Client($service);
237 |
238 | // Your Strava app credentials
239 | $clientId = 12345;
240 | $clientSecret = 'your_client_secret';
241 | $callbackUrl = 'https://yourdomain.com/webhook-endpoint.php';
242 | $verifyToken = 'your_random_verify_token';
243 |
244 | try {
245 | // Create a webhook subscription
246 | $subscription = $client->createWebhookSubscription(
247 | $clientId,
248 | $clientSecret,
249 | $callbackUrl,
250 | $verifyToken
251 | );
252 |
253 | echo "Webhook subscription created: " . $subscription['id'] . "\n";
254 |
255 | // List existing subscriptions
256 | $subscriptions = $client->listWebhookSubscriptions($clientId, $clientSecret);
257 | echo "Active subscriptions: " . count($subscriptions) . "\n";
258 |
259 | // Delete a subscription
260 | $client->deleteWebhookSubscription($clientId, $clientSecret, $subscription['id']);
261 | echo "Subscription deleted\n";
262 |
263 | } catch (Exception $e) {
264 | echo "Error: " . $e->getMessage() . "\n";
265 | }
266 | ```
267 |
268 | ### Webhook Event Handling
269 |
270 | ```php
271 | 'success']);
318 | } else {
319 | // Handle error
320 | http_response_code(400);
321 | echo json_encode(['error' => $eventResult['error']]);
322 | }
323 | ```
324 |
325 | ### Webhook Helper Methods
326 |
327 | The `Webhook` class provides several utility methods:
328 |
329 | ```php
330 | // Get event type (e.g., 'activity.create')
331 | $eventType = Webhook::getEventType($event);
332 |
333 | // Check if event is for specific object type
334 | $isActivity = Webhook::isObjectType($event, 'activity');
335 | $isAthlete = Webhook::isObjectType($event, 'athlete');
336 |
337 | // Check if event is specific aspect type
338 | $isCreate = Webhook::isAspectType($event, 'create');
339 | $isUpdate = Webhook::isAspectType($event, 'update');
340 | $isDelete = Webhook::isAspectType($event, 'delete');
341 |
342 | // Verify webhook signature (if using signature verification)
343 | $isValid = Webhook::verifySignature($payload, $signature, $secret);
344 | ```
345 |
346 | ### Webhook Events
347 |
348 | Strava webhooks support the following event types:
349 |
350 | - **Activity Events:**
351 | - `activity.create` - New activity created
352 | - `activity.update` - Activity updated
353 | - `activity.delete` - Activity deleted
354 |
355 | - **Athlete Events:**
356 | - `athlete.update` - Athlete profile updated
357 |
358 | For more information about webhook events, see the [Strava Webhook Documentation](https://developers.strava.com/docs/webhooks/).
359 |
360 | ## UML diagrams
361 | ### Class diagram
362 | 
363 | ### Sequence diagram
364 | 
365 |
366 | ## About StravaPHP
367 | ### Used libraries
368 | - [Strava API](https://strava.github.io/api/)
369 | - [thephpleague/oauth2-client](https://github.com/thephpleague/oauth2-client/)
370 | - [guzzlehttp/guzzle](https://github.com/guzzle/guzzle)
371 |
372 | ### Development
373 | The StravaPHP library was created by Bas van Dorst, [software engineer](https://www.linkedin.com/in/basvandorst) and cyclist enthusiast.
374 | And of course, special thanks to all [contributors](https://github.com/basvandorst/StravaPHP/graphs/contributors)
375 |
376 | ### Contributing
377 | All issues and pull requests should be filled on the basvandorst/StravaPHP repository.
378 |
379 | ### License
380 | The StravaPHP library is open-source software licensed under MIT license.
381 |
--------------------------------------------------------------------------------
/src/Strava/API/Service/REST.php:
--------------------------------------------------------------------------------
1 | getToken();
46 | }
47 | $this->token = $token;
48 | $this->adapter = $adapter;
49 | $this->responseVerbosity = $responseVerbosity;
50 | }
51 |
52 | protected function getToken()
53 | {
54 | return $this->token;
55 | }
56 |
57 | /**
58 | * Get a request result.
59 | * Returns an array with a response body or and error code => reason.
60 | * @param ResponseInterface|string $response
61 | * @return array|string
62 | */
63 | protected function getResult($response)
64 | {
65 | // Workaround for export methods getRouteAsGPX, getRouteAsTCX:
66 | if (is_string($response)) {
67 | return $response;
68 | }
69 |
70 | $status = $response->getStatusCode();
71 |
72 | $expandedResponse = [];
73 |
74 | $expandedResponse['headers'] = $response->getHeaders();
75 | $expandedResponse['body'] = json_decode($response->getBody(), true);
76 | $expandedResponse['success'] = $status === 200 || $status === 201;
77 | $expandedResponse['status'] = $status;
78 |
79 | return $expandedResponse;
80 | }
81 |
82 | /**
83 | * Get an API request response and handle possible exceptions.
84 | *
85 | * @param string $method
86 | * @param string $path
87 | * @param array $parameters
88 | *
89 | * @return array|mixed|string
90 | * @throws \GuzzleHttp\Exception\GuzzleException|Exception
91 | */
92 | protected function getResponse(string $method, string $path, array $parameters)
93 | {
94 | try {
95 | $response = $this->adapter->request($method, $path, $parameters);
96 | $result = $this->getResult($response);
97 |
98 | if ($this->responseVerbosity === 0 && !is_string($result)) {
99 | return $result["body"];
100 | }
101 |
102 | return $result;
103 | } catch (\Exception $e) {
104 | throw new Exception('[SERVICE] ' . $e->getMessage());
105 | }
106 | }
107 |
108 | public function getAthlete(?int $id = null)
109 | {
110 | $path = 'athlete';
111 | if (isset($id)) {
112 | $path = 'athletes/' . $id;
113 | }
114 | $parameters['query'] = ['access_token' => $this->getToken()];
115 |
116 | return $this->getResponse('GET', $path, $parameters);
117 | }
118 |
119 | public function getAthleteStats(int $id)
120 | {
121 | $path = 'athletes/' . $id . '/stats';
122 | $parameters['query'] = ['access_token' => $this->getToken()];
123 |
124 | return $this->getResponse('GET', $path, $parameters);
125 | }
126 |
127 | public function getAthleteRoutes(int $id, ?string $type = null, ?int $after = null, ?int $page = null, ?int $per_page = null)
128 | {
129 | $path = 'athletes/' . $id . '/routes';
130 | $parameters['query'] = [
131 | 'type' => $type,
132 | 'after' => $after,
133 | 'page' => $page,
134 | 'per_page' => $per_page,
135 | 'access_token' => $this->getToken(),
136 | ];
137 |
138 | return $this->getResponse('GET', $path, $parameters);
139 | }
140 |
141 | public function getAthleteClubs()
142 | {
143 | $path = 'athlete/clubs';
144 | $parameters['query'] = ['access_token' => $this->getToken()];
145 |
146 | return $this->getResponse('GET', $path, $parameters);
147 | }
148 |
149 | public function getAthleteActivities(?string $before = null, ?string $after = null, ?int $page = null, ?int $per_page = null)
150 | {
151 | $path = 'athlete/activities';
152 | $parameters['query'] = [
153 | 'before' => $before,
154 | 'after' => $after,
155 | 'page' => $page,
156 | 'per_page' => $per_page,
157 | 'access_token' => $this->getToken(),
158 | ];
159 |
160 | return $this->getResponse('GET', $path, $parameters);
161 | }
162 |
163 | public function getAthleteFriends(?int $id = null, ?int $page = null, ?int $per_page = null)
164 | {
165 | $path = 'athlete/friends';
166 | if (isset($id)) {
167 | $path = 'athletes/' . $id . '/friends';
168 | }
169 | $parameters['query'] = [
170 | 'page' => $page,
171 | 'per_page' => $per_page,
172 | 'access_token' => $this->getToken(),
173 | ];
174 |
175 | return $this->getResponse('GET', $path, $parameters);
176 | }
177 |
178 | public function getAthleteFollowers(?int $id = null, ?int $page = null, ?int $per_page = null)
179 | {
180 | $path = 'athlete/followers';
181 | if (isset($id)) {
182 | $path = 'athletes/' . $id . '/followers';
183 | }
184 | $parameters['query'] = [
185 | 'page' => $page,
186 | 'per_page' => $per_page,
187 | 'access_token' => $this->getToken(),
188 | ];
189 |
190 | return $this->getResponse('GET', $path, $parameters);
191 | }
192 |
193 | public function getAthleteBothFollowing(int $id, ?int $page = null, ?int $per_page = null)
194 | {
195 | $path = 'athletes/' . $id . '/both-following';
196 | $parameters['query'] = [
197 | 'page' => $page,
198 | 'per_page' => $per_page,
199 | 'access_token' => $this->getToken(),
200 | ];
201 |
202 | return $this->getResponse('GET', $path, $parameters);
203 | }
204 |
205 | public function getAthleteKom(int $id, ?int $page = null, ?int $per_page = null)
206 | {
207 | $path = 'athletes/' . $id . '/koms';
208 | $parameters['query'] = [
209 | 'page' => $page,
210 | 'per_page' => $per_page,
211 | 'access_token' => $this->getToken(),
212 | ];
213 |
214 | return $this->getResponse('GET', $path, $parameters);
215 | }
216 |
217 | public function getAthleteZones()
218 | {
219 | $path = 'athlete/zones';
220 | $parameters['query'] = ['access_token' => $this->getToken()];
221 |
222 | return $this->getResponse('GET', $path, $parameters);
223 | }
224 |
225 | public function getAthleteStarredSegments(?int $id = null, ?int $page = null, ?int $per_page = null)
226 | {
227 | $path = 'segments/starred';
228 | if (isset($id)) {
229 | $path = 'athletes/' . $id . '/segments/starred';
230 | // ...wrong in Strava documentation
231 | }
232 | $parameters['query'] = [
233 | 'page' => $page,
234 | 'per_page' => $per_page,
235 | 'access_token' => $this->getToken(),
236 | ];
237 |
238 | return $this->getResponse('GET', $path, $parameters);
239 | }
240 |
241 | public function updateAthlete(string $city, string $state, string $country, string $sex, float $weight)
242 | {
243 | $path = 'athlete';
244 | $parameters['query'] = [
245 | 'city' => $city,
246 | 'state' => $state,
247 | 'country' => $country,
248 | 'sex' => $sex,
249 | 'weight' => $weight,
250 | 'access_token' => $this->getToken(),
251 | ];
252 |
253 | return $this->getResponse('PUT', $path, $parameters);
254 | }
255 |
256 | public function getActivity(int $id, ?bool $include_all_efforts = null)
257 | {
258 | $path = 'activities/' . $id;
259 | $parameters['query'] = [
260 | 'include_all_efforts' => $include_all_efforts,
261 | 'access_token' => $this->getToken(),
262 | ];
263 |
264 | return $this->getResponse('GET', $path, $parameters);
265 | }
266 |
267 | public function getActivityComments(int $id, ?bool $markdown = null, ?int $page = null, ?int $per_page = null)
268 | {
269 | $path = 'activities/' . $id . '/comments';
270 | $parameters['query'] = [
271 | 'markdown' => $markdown,
272 | 'page' => $page,
273 | 'per_page' => $per_page,
274 | 'access_token' => $this->getToken(),
275 | ];
276 |
277 | return $this->getResponse('GET', $path, $parameters);
278 | }
279 |
280 | public function getActivityKudos(int $id, ?int $page = null, ?int $per_page = null)
281 | {
282 | $path = 'activities/' . $id . '/kudos';
283 | $parameters['query'] = [
284 | 'page' => $page,
285 | 'per_page' => $per_page,
286 | 'access_token' => $this->getToken(),
287 | ];
288 |
289 | return $this->getResponse('GET', $path, $parameters);
290 | }
291 |
292 | public function getActivityPhotos(int $id, int $size = 2048, string $photo_sources = 'true')
293 | {
294 | $path = 'activities/' . $id . '/photos';
295 | $parameters['query'] = [
296 | 'size' => $size,
297 | 'photo_sources' => $photo_sources,
298 | 'access_token' => $this->getToken(),
299 | ];
300 |
301 | return $this->getResponse('GET', $path, $parameters);
302 | }
303 |
304 | public function getActivityZones(int $id)
305 | {
306 | $path = 'activities/' . $id . '/zones';
307 | $parameters['query'] = ['access_token' => $this->getToken()];
308 |
309 | return $this->getResponse('GET', $path, $parameters);
310 | }
311 |
312 | public function getActivityLaps(int $id)
313 | {
314 | $path = 'activities/' . $id . '/laps';
315 | $parameters['query'] = ['access_token' => $this->getToken()];
316 |
317 | return $this->getResponse('GET', $path, $parameters);
318 | }
319 |
320 | public function getActivityUploadStatus(int $id)
321 | {
322 | $path = 'uploads/' . $id;
323 | $parameters['query'] = ['access_token' => $this->getToken()];
324 |
325 | return $this->getResponse('GET', $path, $parameters);
326 | }
327 |
328 | public function createActivity(string $name, string $type, string $start_date_local, int $elapsed_time, ?string $description = null, ?float $distance = null, ?int $private = null, ?int $trainer = null)
329 | {
330 | $path = 'activities';
331 | $parameters['query'] = [
332 | 'name' => $name,
333 | 'type' => $type,
334 | 'start_date_local' => $start_date_local,
335 | 'elapsed_time' => $elapsed_time,
336 | 'description' => $description,
337 | 'distance' => $distance,
338 | 'private' => $private,
339 | 'trainer' => $trainer,
340 | 'access_token' => $this->getToken(),
341 | ];
342 |
343 | return $this->getResponse('POST', $path, $parameters);
344 | }
345 |
346 | public function uploadActivity(string $file, ?string $activity_type = null, ?string $name = null, ?string $description = null, ?int $private = null, ?int $trainer = null, ?int $commute = null, ?string $data_type = null, ?string $external_id = null)
347 | {
348 | $path = 'uploads';
349 | $parameters['query'] = [
350 | 'activity_type' => $activity_type,
351 | 'name' => $name,
352 | 'description' => $description,
353 | 'private' => $private,
354 | 'trainer' => $trainer,
355 | 'commute' => $commute,
356 | 'data_type' => $data_type,
357 | 'external_id' => $external_id,
358 | 'file' => curl_file_create($file),
359 | 'file_hack' => '@' . ltrim($file, '@'),
360 | 'access_token' => $this->getToken(),
361 | ];
362 |
363 | return $this->getResponse('POST', $path, $parameters);
364 | }
365 |
366 | public function updateActivity(int $id, ?string $name = null, ?string $type = null, bool $private = false, bool $commute = false, bool $trainer = false, ?string $gear_id = null, ?string $description = null)
367 | {
368 | $path = 'activities/' . $id;
369 | $parameters['query'] = [
370 | 'name' => $name,
371 | 'type' => $type,
372 | 'private' => $private,
373 | 'commute' => $commute,
374 | 'trainer' => $trainer,
375 | 'gear_id' => $gear_id,
376 | 'description' => $description,
377 | 'access_token' => $this->getToken(),
378 | ];
379 |
380 | return $this->getResponse('PUT', $path, $parameters);
381 | }
382 |
383 | public function deleteActivity(int $id)
384 | {
385 | $path = 'activities/' . $id;
386 | $parameters['query'] = ['access_token' => $this->getToken()];
387 |
388 | return $this->getResponse('DELETE', $path, $parameters);
389 | }
390 |
391 | public function getGear(int $id)
392 | {
393 | $path = 'gear/' . $id;
394 | $parameters['query'] = ['access_token' => $this->getToken()];
395 |
396 | return $this->getResponse('GET', $path, $parameters);
397 | }
398 |
399 | public function getClub(int $id)
400 | {
401 | $path = 'clubs/' . $id;
402 | $parameters['query'] = ['access_token' => $this->getToken()];
403 |
404 | return $this->getResponse('GET', $path, $parameters);
405 | }
406 |
407 | public function getClubMembers(int $id, ?int $page = null, ?int $per_page = null)
408 | {
409 | $path = 'clubs/' . $id . '/members';
410 | $parameters['query'] = [
411 | 'page' => $page,
412 | 'per_page' => $per_page,
413 | 'access_token' => $this->getToken(),
414 | ];
415 |
416 | return $this->getResponse('GET', $path, $parameters);
417 | }
418 |
419 | public function getClubActivities(int $id, ?int $page = null, ?int $per_page = null)
420 | {
421 | $path = 'clubs/' . $id . '/activities';
422 | $parameters['query'] = [
423 | 'page' => $page,
424 | 'per_page' => $per_page,
425 | 'access_token' => $this->getToken(),
426 | ];
427 |
428 | return $this->getResponse('GET', $path, $parameters);
429 | }
430 |
431 | public function getClubAnnouncements(int $id)
432 | {
433 | $path = 'clubs/' . $id . '/announcements';
434 | $parameters['query'] = ['access_token' => $this->getToken()];
435 |
436 | return $this->getResponse('GET', $path, $parameters);
437 | }
438 |
439 | public function getClubGroupEvents(int $id)
440 | {
441 | $path = 'clubs/' . $id . '/group_events';
442 | $parameters['query'] = ['access_token' => $this->getToken()];
443 |
444 | return $this->getResponse('GET', $path, $parameters);
445 | }
446 |
447 | public function joinClub(int $id)
448 | {
449 | $path = 'clubs/' . $id . '/join';
450 | $parameters['query'] = ['access_token' => $this->getToken()];
451 |
452 | return $this->getResponse('POST', $path, $parameters);
453 | }
454 |
455 | public function leaveClub(int $id)
456 | {
457 | $path = 'clubs/' . $id . '/leave';
458 | $parameters['query'] = ['access_token' => $this->getToken()];
459 |
460 | return $this->getResponse('POST', $path, $parameters);
461 | }
462 |
463 | public function getRoute(int $id)
464 | {
465 | $path = 'routes/' . $id;
466 | $parameters['query'] = ['access_token' => $this->getToken()];
467 |
468 | return $this->getResponse('GET', $path, $parameters);
469 | }
470 |
471 | public function getRouteAsGPX(int $id)
472 | {
473 | $path = 'routes/' . $id . '/export_gpx';
474 | $parameters['query'] = ['access_token' => $this->getToken()];
475 |
476 | return $this->getResponse('GET', $path, $parameters);
477 | }
478 |
479 | public function getRouteAsTCX(int $id)
480 | {
481 | $path = 'routes/' . $id . '/export_tcx';
482 | $parameters['query'] = ['access_token' => $this->getToken()];
483 |
484 | return $this->getResponse('GET', $path, $parameters);
485 | }
486 |
487 | public function getSegment(int $id)
488 | {
489 | $path = 'segments/' . $id;
490 | $parameters['query'] = ['access_token' => $this->getToken()];
491 |
492 | return $this->getResponse('GET', $path, $parameters);
493 | }
494 |
495 | public function getSegmentLeaderboard(int $id, ?string $gender = null, ?string $age_group = null, $weight_class = null, $following = null, $club_id = null, $date_range = null, $context_entries = null, $page = null, $per_page = null)
496 | {
497 | $path = 'segments/' . $id . '/leaderboard';
498 | $parameters['query'] = [
499 | 'gender' => $gender,
500 | 'age_group' => $age_group,
501 | 'weight_class' => $weight_class,
502 | 'following' => $following,
503 | 'club_id' => $club_id,
504 | 'date_range' => $date_range,
505 | 'context_entries' => $context_entries,
506 | 'page' => $page,
507 | 'per_page' => $per_page,
508 | 'access_token' => $this->getToken(),
509 | ];
510 |
511 | return $this->getResponse('GET', $path, $parameters);
512 | }
513 |
514 | public function getSegmentExplorer(string $bounds, string $activity_type = 'riding', ?int $min_cat = null, ?int $max_cat = null)
515 | {
516 | $path = 'segments/explore';
517 | $parameters['query'] = [
518 | 'bounds' => $bounds,
519 | 'activity_type' => $activity_type,
520 | 'min_cat' => $min_cat,
521 | 'max_cat' => $max_cat,
522 | 'access_token' => $this->getToken(),
523 | ];
524 |
525 | return $this->getResponse('GET', $path, $parameters);
526 | }
527 |
528 | public function getSegmentEffort(int $id, ?int $athlete_id = null, ?string $start_date_local = null, ?string $end_date_local = null, ?int $page = null, ?int $per_page = null)
529 | {
530 | $path = 'segments/' . $id . '/all_efforts';
531 | $parameters['query'] = [
532 | 'athlete_id' => $athlete_id,
533 | 'start_date_local' => $start_date_local,
534 | 'end_date_local' => $end_date_local,
535 | 'page' => $page,
536 | 'per_page' => $per_page,
537 | 'access_token' => $this->getToken(),
538 | ];
539 |
540 | return $this->getResponse('GET', $path, $parameters);
541 | }
542 |
543 | public function getStreamsActivity(int $id, string $types, $resolution = null, string $series_type = 'distance')
544 | {
545 | $path = 'activities/' . $id . '/streams/' . $types;
546 | $parameters['query'] = [
547 | 'resolution' => $resolution,
548 | 'series_type' => $series_type,
549 | 'access_token' => $this->getToken(),
550 | ];
551 |
552 | return $this->getResponse('GET', $path, $parameters);
553 | }
554 |
555 | public function getStreamsEffort(int $id, string $types, $resolution = null, string $series_type = 'distance')
556 | {
557 | $path = 'segment_efforts/' . $id . '/streams/' . $types;
558 | $parameters['query'] = [
559 | 'resolution' => $resolution,
560 | 'series_type' => $series_type,
561 | 'access_token' => $this->getToken(),
562 | ];
563 |
564 | return $this->getResponse('GET', $path, $parameters);
565 | }
566 |
567 | public function getStreamsSegment(int $id, string $types, $resolution = null, string $series_type = 'distance')
568 | {
569 | $path = 'segments/' . $id . '/streams/' . $types;
570 | $parameters['query'] = [
571 | 'resolution' => $resolution,
572 | 'series_type' => $series_type,
573 | 'access_token' => $this->getToken(),
574 | ];
575 |
576 | return $this->getResponse('GET', $path, $parameters);
577 | }
578 |
579 | public function getStreamsRoute(int $id)
580 | {
581 | $path = 'routes/' . $id . '/streams';
582 | $parameters['query'] = ['access_token' => $this->getToken()];
583 |
584 | return $this->getResponse('GET', $path, $parameters);
585 | }
586 |
587 | public function createWebhookSubscription(int $clientId, string $clientSecret, string $callbackUrl, string $verifyToken)
588 | {
589 | $path = 'push_subscriptions';
590 | $parameters['form_params'] = [
591 | 'client_id' => $clientId,
592 | 'client_secret' => $clientSecret,
593 | 'callback_url' => $callbackUrl,
594 | 'verify_token' => $verifyToken,
595 | ];
596 |
597 | return $this->getResponse('POST', $path, $parameters);
598 | }
599 |
600 | public function listWebhookSubscriptions(int $clientId, string $clientSecret)
601 | {
602 | $path = 'push_subscriptions';
603 | $parameters['query'] = [
604 | 'client_id' => $clientId,
605 | 'client_secret' => $clientSecret,
606 | ];
607 |
608 | return $this->getResponse('GET', $path, $parameters);
609 | }
610 |
611 | public function deleteWebhookSubscription(int $clientId, string $clientSecret, int $subscriptionId)
612 | {
613 | $path = 'push_subscriptions/' . $subscriptionId;
614 | $parameters['form_params'] = [
615 | 'client_id' => $clientId,
616 | 'client_secret' => $clientSecret,
617 | ];
618 |
619 | $result = $this->getResponse('DELETE', $path, $parameters);
620 |
621 | // For DELETE operations that return 204, ensure we return a proper structure
622 | if ($result === null) {
623 | return ['success' => true];
624 | }
625 |
626 | return $result;
627 | }
628 | }
629 |
--------------------------------------------------------------------------------
/src/Strava/API/Client.php:
--------------------------------------------------------------------------------
1 | service = $service;
32 | }
33 |
34 | /**
35 | * Retrieve current athlete
36 | *
37 | * @link https://strava.github.io/api/v3/athlete/#get-details,
38 | * https://strava.github.io/api/v3/athlete/#get-another-details
39 | * @param ?int $id
40 | * @return array
41 | * @throws Exception
42 | */
43 | public function getAthlete(?int $id = null): array
44 | {
45 | try {
46 | return $this->service->getAthlete($id);
47 | } catch (ServiceException $e) {
48 | throw new ClientException('[SERVICE] ' . $e->getMessage());
49 | }
50 | }
51 |
52 | /**
53 | * Retrieve athlete stats
54 | *
55 | * Only available for the authenticated athlete.
56 | *
57 | * @link https://strava.github.io/api/v3/athlete/#stats
58 | * @param int $id
59 | * @return array
60 | * @throws ClientException
61 | */
62 | public function getAthleteStats(int $id): array
63 | {
64 | try {
65 | return $this->service->getAthleteStats($id);
66 | } catch (ServiceException $e) {
67 | throw new ClientException('[SERVICE] ' . $e->getMessage());
68 | }
69 | }
70 |
71 | /**
72 | * Retrieve athlete routes
73 | *
74 | * @link https://strava.github.io/api/v3/routes/#list
75 | * @param int $id
76 | * @param string|null $type
77 | * @param int|null $after
78 | * @param int|null $page
79 | * @param int|null $per_page
80 | * @return array
81 | * @throws Exception
82 | */
83 | public function getAthleteRoutes(int $id, ?string $type = null, ?int $after = null, ?int $page = null, ?int $per_page = null): array
84 | {
85 | try {
86 | return $this->service->getAthleteRoutes($id, $type, $after, $page, $per_page);
87 | } catch (ServiceException $e) {
88 | throw new ClientException('[SERVICE] ' . $e->getMessage());
89 | }
90 | }
91 |
92 | /**
93 | * List athlete clubs
94 | *
95 | * @link https://strava.github.io/api/v3/clubs/#get-athletes
96 | * @return array
97 | * @throws Exception
98 | */
99 | public function getAthleteClubs(): array
100 | {
101 | try {
102 | return $this->service->getAthleteClubs();
103 | } catch (ServiceException $e) {
104 | throw new ClientException('[SERVICE] ' . $e->getMessage());
105 | }
106 | }
107 |
108 | /**
109 | * List athlete activities
110 | *
111 | * @link https://strava.github.io/api/v3/activities/#get-activities
112 | * @param string|null $before
113 | * @param string|null $after
114 | * @param int|null $page
115 | * @param int|null $per_page
116 | * @return array
117 | * @throws Exception
118 | */
119 | public function getAthleteActivities(?string $before = null, ?string $after = null, ?int $page = null, ?int $per_page = null): array
120 | {
121 | try {
122 | return $this->service->getAthleteActivities($before, $after, $page, $per_page);
123 | } catch (ServiceException $e) {
124 | throw new ClientException('[SERVICE] ' . $e->getMessage());
125 | }
126 | }
127 |
128 | /**
129 | * List athlete friends
130 | *
131 | * @link https://strava.github.io/api/v3/follow/#friends
132 | * @param int|null $id
133 | * @param int|null $page
134 | * @param int|null $per_page
135 | * @return array
136 | * @throws Exception
137 | */
138 | public function getAthleteFriends(?int $id = null, ?int $page = null, ?int $per_page = null): array
139 | {
140 | try {
141 | return $this->service->getAthleteFriends($id, $page, $per_page);
142 | } catch (ServiceException $e) {
143 | throw new ClientException('[SERVICE] ' . $e->getMessage());
144 | }
145 | }
146 |
147 | /**
148 | * List athlete followers
149 | *
150 | * @link https://strava.github.io/api/v3/follow/#followers
151 | * @param int|null $id
152 | * @param int|null $page
153 | * @param int|null $per_page
154 | * @return array
155 | * @throws Exception
156 | */
157 | public function getAthleteFollowers(?int $id = null, ?int $page = null, ?int $per_page = null): array
158 | {
159 | try {
160 | return $this->service->getAthleteFollowers($id, $page, $per_page);
161 | } catch (ServiceException $e) {
162 | throw new ClientException('[SERVICE] ' . $e->getMessage());
163 | }
164 | }
165 |
166 | /**
167 | * List both following
168 | *
169 | * @link https://strava.github.io/api/v3/follow/#both
170 | * @param int $id
171 | * @param int|null $page
172 | * @param int|null $per_page
173 | * @return array
174 | * @throws Exception
175 | */
176 | public function getAthleteBothFollowing($id, ?int $page = null, ?int $per_page = null): array
177 | {
178 | try {
179 | return $this->service->getAthleteBothFollowing($id, $page, $per_page);
180 | } catch (ServiceException $e) {
181 | throw new ClientException('[SERVICE] ' . $e->getMessage());
182 | }
183 | }
184 |
185 | /**
186 | * List athlete K/QOMs/CRs
187 | *
188 | * @link https://strava.github.io/api/v3/athlete/#koms
189 | * @param int $id
190 | * @param int|null $page
191 | * @param int|null $per_page
192 | * @return array
193 | * @throws Exception
194 | */
195 | public function getAthleteKom(int $id, ?int $page = null, ?int $per_page = null): array
196 | {
197 | try {
198 | return $this->service->getAthleteKom($id, $page, $per_page);
199 | } catch (ServiceException $e) {
200 | throw new ClientException('[SERVICE] ' . $e->getMessage());
201 | }
202 | }
203 |
204 | /**
205 | * List athlete zones
206 | *
207 | * @link https://strava.github.io/api/v3/athlete/#zones
208 | * @return array
209 | * @throws Exception
210 | */
211 | public function getAthleteZones(): array
212 | {
213 | try {
214 | return $this->service->getAthleteZones();
215 | } catch (ServiceException $e) {
216 | throw new ClientException('[SERVICE] ' . $e->getMessage());
217 | }
218 | }
219 |
220 |
221 | /**
222 | * List starred segment
223 | *
224 | * @link https://strava.github.io/api/v3/segments/#starred
225 | * @param int|null $id
226 | * @param int|null $page
227 | * @param int|null $per_page
228 | * @return array
229 | * @throws Exception
230 | */
231 | public function getAthleteStarredSegments(?int $id = null, ?int $page = null, ?int $per_page = null): array
232 | {
233 | try {
234 | return $this->service->getAthleteStarredSegments($id, $page, $per_page);
235 | } catch (ServiceException $e) {
236 | throw new ClientException('[SERVICE] ' . $e->getMessage());
237 | }
238 | }
239 |
240 | /**
241 | * Update current athlete
242 | *
243 | * @link https://strava.github.io/api/v3/athlete/#update
244 | * @param string $city
245 | * @param string $state
246 | * @param string $country
247 | * @param string $sex
248 | * @param float $weight
249 | * @return array
250 | * @throws Exception
251 | */
252 | public function updateAthlete(string $city, string $state, string $country, string $sex, float $weight): array
253 | {
254 | try {
255 | return $this->service->updateAthlete($city, $state, $country, $sex, $weight);
256 | } catch (ServiceException $e) {
257 | throw new ClientException('[SERVICE] ' . $e->getMessage());
258 | }
259 | }
260 |
261 | /**
262 | * Retrieve an activity
263 | *
264 | * @link https://strava.github.io/api/v3/athlete/#get-details,
265 | * https://strava.github.io/api/v3/athlete/#get-another-details
266 | * @param int $id
267 | * @param boolean|null $include_all_efforts
268 | * @return array
269 | * @throws Exception
270 | */
271 | public function getActivity(int $id, ?bool $include_all_efforts = null): array
272 | {
273 | try {
274 | return $this->service->getActivity($id, $include_all_efforts);
275 | } catch (ServiceException $e) {
276 | throw new ClientException('[SERVICE] ' . $e->getMessage());
277 | }
278 | }
279 |
280 | /**
281 | * List activity comments
282 | *
283 | * @link https://strava.github.io/api/v3/comments/#list
284 | * @param int $id
285 | * @param boolean|null $markdown
286 | * @param int|null $page
287 | * @param int|null $per_page
288 | * @return array
289 | * @throws Exception
290 | */
291 | public function getActivityComments(int $id, ?bool $markdown = null, ?int $page = null, ?int $per_page = null): array
292 | {
293 | try {
294 | return $this->service->getActivityComments($id, $markdown, $page, $per_page);
295 | } catch (ServiceException $e) {
296 | throw new ClientException('[SERVICE] ' . $e->getMessage());
297 | }
298 | }
299 |
300 | /**
301 | * List activity kudoers
302 | *
303 | * @link https://strava.github.io/api/v3/kudos/#list
304 | * @param int $id
305 | * @param int|null $page
306 | * @param int|null $per_page
307 | * @return array
308 | * @throws Exception
309 | */
310 | public function getActivityKudos(int $id, ?int $page = null, ?int $per_page = null): array
311 | {
312 | try {
313 | return $this->service->getActivityKudos($id, $page, $per_page);
314 | } catch (ServiceException $e) {
315 | throw new ClientException('[SERVICE] ' . $e->getMessage());
316 | }
317 | }
318 |
319 | /**
320 | * List activity photos
321 | *
322 | * @link https://strava.github.io/api/v3/photos/#list
323 | * @param int $id
324 | * @param int $size In pixels.
325 | * @param string $photo_sources Must be "true".
326 | * @return array
327 | * @throws Exception
328 | */
329 | public function getActivityPhotos(int $id, int $size = 2048, string $photo_sources = 'true'): array
330 | {
331 | try {
332 | return $this->service->getActivityPhotos($id, $size, $photo_sources);
333 | } catch (ServiceException $e) {
334 | throw new ClientException('[SERVICE] ' . $e->getMessage());
335 | }
336 | }
337 |
338 | /**
339 | * List activity zones
340 | *
341 | * @link https://strava.github.io/api/v3/activities/#zones
342 | * @param int $id
343 | * @return array
344 | * @throws Exception
345 | */
346 | public function getActivityZones(int $id): array
347 | {
348 | try {
349 | return $this->service->getActivityZones($id);
350 | } catch (ServiceException $e) {
351 | throw new ClientException('[SERVICE] ' . $e->getMessage());
352 | }
353 | }
354 |
355 | /**
356 | * List activity laps
357 | *
358 | * @link https://strava.github.io/api/v3/activities/#laps
359 | * @param int $id
360 | * @return array
361 | * @throws Exception
362 | */
363 | public function getActivityLaps(int $id): array
364 | {
365 | try {
366 | return $this->service->getActivityLaps($id);
367 | } catch (ServiceException $e) {
368 | throw new ClientException('[SERVICE] ' . $e->getMessage());
369 | }
370 | }
371 |
372 | /**
373 | * Check upload status
374 | *
375 | * @link https://strava.github.io/api/v3/uploads/#get-status
376 | * @param int $id
377 | * @return array
378 | * @throws Exception
379 | */
380 | public function getActivityUploadStatus(int $id): array
381 | {
382 | try {
383 | return $this->service->getActivityUploadStatus($id);
384 | } catch (ServiceException $e) {
385 | throw new ClientException('[SERVICE] ' . $e->getMessage());
386 | }
387 | }
388 |
389 | /**
390 | * Create an activity
391 | *
392 | * @link https://strava.github.io/api/v3/activities/#create
393 | * @param string $name
394 | * @param string $type
395 | * @param string $start_date_local
396 | * @param int $elapsed_time
397 | * @param string|null $description
398 | * @param float|null $distance
399 | * @param int|null $private
400 | * @param int|null $trainer
401 | * @return array
402 | * @throws Exception
403 | */
404 | public function createActivity(string $name, string $type, string $start_date_local, int $elapsed_time, ?string $description = null, ?float $distance = null, ?int $private = null, ?int $trainer = null): array
405 | {
406 | try {
407 | return $this->service->createActivity($name, $type, $start_date_local, $elapsed_time, $description, $distance, $private, $trainer);
408 | } catch (ServiceException $e) {
409 | throw new ClientException('[SERVICE] ' . $e->getMessage());
410 | }
411 | }
412 |
413 | /**
414 | * Upload an activity
415 | *
416 | * @link https://strava.github.io/api/v3/uploads/#post-file
417 | * @param string $file Path to file
418 | * @param string|null $activity_type
419 | * @param string|null $name
420 | * @param string|null $description
421 | * @param int|null $private
422 | * @param int|null $trainer
423 | * @param int|null $commute
424 | * @param string|null $data_type
425 | * @param string|null $external_id
426 | * @return array
427 | * @throws Exception
428 | */
429 | public function uploadActivity(string $file, ?string $activity_type = null, ?string $name = null, ?string $description = null, ?int $private = null, ?int $trainer = null, ?int $commute = null, ?string $data_type = null, ?string $external_id = null): array
430 | {
431 | try {
432 | return $this->service->uploadActivity($file, $activity_type, $name, $description, $private, $trainer, $commute, $data_type, $external_id);
433 | } catch (ServiceException $e) {
434 | throw new ClientException('[SERVICE] ' . $e->getMessage());
435 | }
436 | }
437 |
438 | /**
439 | * Update an activity
440 | *
441 | * @link https://strava.github.io/api/v3/activities/#put-updates
442 | * @param int $id
443 | * @param string|null $name
444 | * @param string|null $type
445 | * @param boolean $private
446 | * @param boolean $commute
447 | * @param boolean $trainer
448 | * @param string|null $gear_id
449 | * @param string|null $description
450 | * @return array
451 | * @throws Exception
452 | */
453 | public function updateActivity(int $id, ?string $name = null, ?string $type = null, bool $private = false, bool $commute = false, bool $trainer = false, ?string $gear_id = null, ?string $description = null): array
454 | {
455 | try {
456 | return $this->service->updateActivity($id, $name, $type, $private, $commute, $trainer, $gear_id, $description);
457 | } catch (ServiceException $e) {
458 | throw new ClientException('[SERVICE] ' . $e->getMessage());
459 | }
460 | }
461 |
462 | /**
463 | * Delete an activity
464 | *
465 | * @link https://strava.github.io/api/v3/activities/#delete
466 | * @param int $id
467 | * @return array
468 | * @throws Exception
469 | */
470 | public function deleteActivity(int $id): array
471 | {
472 | try {
473 | return $this->service->deleteActivity($id);
474 | } catch (ServiceException $e) {
475 | throw new ClientException('[SERVICE] ' . $e->getMessage());
476 | }
477 | }
478 |
479 | /**
480 | * Retrieve gear
481 | *
482 | * @link https://strava.github.io/api/v3/gear/
483 | * @param int $id
484 | * @return array
485 | * @throws Exception
486 | */
487 | public function getGear(int $id): array
488 | {
489 | try {
490 | return $this->service->getGear($id);
491 | } catch (ServiceException $e) {
492 | throw new ClientException('[SERVICE] ' . $e->getMessage());
493 | }
494 | }
495 |
496 | /**
497 | * Retrieve a club
498 | *
499 | * @link https://strava.github.io/api/v3/clubs/#get-details
500 | * @param int $id
501 | * @return array
502 | * @throws Exception
503 | */
504 | public function getClub(int $id): array
505 | {
506 | try {
507 | return $this->service->getClub($id);
508 | } catch (ServiceException $e) {
509 | throw new ClientException('[SERVICE] ' . $e->getMessage());
510 | }
511 | }
512 |
513 | /**
514 | * List club members
515 | *
516 | * @link https://strava.github.io/api/v3/clubs/#get-members
517 | * @param int $id
518 | * @param int|null $page
519 | * @param int|null $per_page
520 | * @return array
521 | * @throws Exception
522 | */
523 | public function getClubMembers(int $id, ?int $page = null, ?int $per_page = null): array
524 | {
525 | try {
526 | return $this->service->getClubMembers($id, $page, $per_page);
527 | } catch (ServiceException $e) {
528 | throw new ClientException('[SERVICE] ' . $e->getMessage());
529 | }
530 | }
531 |
532 | /**
533 | * List club activities
534 | *
535 | * @link https://strava.github.io/api/v3/clubs/#get-activities
536 | * @param int $id
537 | * @param int|null $page
538 | * @param int|null $per_page
539 | * @return array
540 | * @throws Exception
541 | */
542 | public function getClubActivities(int $id, ?int $page = null, ?int $per_page = null): array
543 | {
544 | try {
545 | return $this->service->getClubActivities($id, $page, $per_page);
546 | } catch (ServiceException $e) {
547 | throw new ClientException('[SERVICE] ' . $e->getMessage());
548 | }
549 | }
550 |
551 | /**
552 | * List club announcements
553 | *
554 | * @link https://strava.github.io/api/v3/clubs/#get-announcements
555 | * @param int $id
556 | * @return array
557 | * @throws Exception
558 | */
559 | public function getClubAnnouncements(int $id): array
560 | {
561 | try {
562 | return $this->service->getClubAnnouncements($id);
563 | } catch (ServiceException $e) {
564 | throw new ClientException('[SERVICE] ' . $e->getMessage());
565 | }
566 | }
567 |
568 | /**
569 | * List club group events
570 | *
571 | * @link https://strava.github.io/api/v3/clubs/#get-group-events
572 | * @param int $id
573 | * @return array
574 | * @throws Exception
575 | */
576 | public function getClubGroupEvents(int $id): array
577 | {
578 | try {
579 | return $this->service->getClubGroupEvents($id);
580 | } catch (ServiceException $e) {
581 | throw new ClientException('[SERVICE] ' . $e->getMessage());
582 | }
583 | }
584 |
585 | /**
586 | * Join a club
587 | *
588 | * @link https://strava.github.io/api/v3/clubs/#join
589 | * @param int $id
590 | * @return array
591 | * @throws Exception
592 | */
593 | public function joinClub(int $id): array
594 | {
595 | try {
596 | return $this->service->joinClub($id);
597 | } catch (ServiceException $e) {
598 | throw new ClientException('[SERVICE] ' . $e->getMessage());
599 | }
600 | }
601 |
602 | /**
603 | * Leave a club
604 | *
605 | * @link https://strava.github.io/api/v3/clubs/#leave
606 | * @param int $id
607 | * @return array
608 | * @throws Exception
609 | */
610 | public function leaveClub(int $id): array
611 | {
612 | try {
613 | return $this->service->leaveClub($id);
614 | } catch (ServiceException $e) {
615 | throw new ClientException('[SERVICE] ' . $e->getMessage());
616 | }
617 | }
618 |
619 | /**
620 | * Get route details
621 | *
622 | * @link https://strava.github.io/api/v3/routes/#list
623 | * @param int $id
624 | * @return array
625 | * @throws Exception
626 | */
627 | public function getRoute(int $id): array
628 | {
629 | try {
630 | return $this->service->getRoute($id);
631 | } catch (ServiceException $e) {
632 | throw new ClientException('[SERVICE] ' . $e->getMessage());
633 | }
634 | }
635 |
636 | /**
637 | * Get route as GPX.
638 | *
639 | * @link https://developers.strava.com/docs/reference/#api-Routes-getRouteAsGPX
640 | * @param int $id
641 | * @return string
642 | * @throws Exception
643 | */
644 | public function getRouteAsGPX(int $id): string
645 | {
646 | try {
647 | return $this->service->getRouteAsGPX($id);
648 | } catch (ServiceException $e) {
649 | throw new ClientException('[SERVICE] ' . $e->getMessage());
650 | }
651 | }
652 |
653 | /**
654 | * Get route as TCX.
655 | *
656 | * @link https://developers.strava.com/docs/reference/#api-Routes-getRouteAsTCX
657 | * @param int $id
658 | * @return string
659 | * @throws Exception
660 | */
661 | public function getRouteAsTCX(int $id): string
662 | {
663 | try {
664 | return $this->service->getRouteAsTCX($id);
665 | } catch (ServiceException $e) {
666 | throw new ClientException('[SERVICE] ' . $e->getMessage());
667 | }
668 | }
669 |
670 | /**
671 | * Retrieve a segment
672 | *
673 | * @link https://strava.github.io/api/v3/segments/#retrieve
674 | * @param int $id
675 | * @return array
676 | * @throws Exception
677 | */
678 | public function getSegment(int $id): array
679 | {
680 | try {
681 | return $this->service->getSegment($id);
682 | } catch (ServiceException $e) {
683 | throw new ClientException('[SERVICE] ' . $e->getMessage());
684 | }
685 | }
686 |
687 | /**
688 | * Segment leaderboards
689 | *
690 | * @link https://strava.github.io/api/v3/segments/#leaderboard
691 | * @param int $id
692 | * @param string|null $gender
693 | * @param string|null $age_group
694 | * @param string|null $weight_class
695 | * @param boolean|null $following
696 | * @param int|null $club_id
697 | * @param string|null $date_range
698 | * @param int|null $context_entries
699 | * @param int|null $page
700 | * @param int|null $per_page
701 | * @return array
702 | * @throws Exception
703 | */
704 | public function getSegmentLeaderboard(int $id, ?string $gender = null, ?string $age_group = null, ?string $weight_class = null, ?bool $following = null, ?int $club_id = null, ?string $date_range = null, ?int $context_entries = null, ?int $page = null, ?int $per_page = null): array
705 | {
706 | try {
707 | return $this->service->getSegmentLeaderboard($id, $gender, $age_group, $weight_class, $following, $club_id, $date_range, $context_entries, $page, $per_page);
708 | } catch (ServiceException $e) {
709 | throw new ClientException('[SERVICE] ' . $e->getMessage());
710 | }
711 | }
712 |
713 | /**
714 | * Segment explorer
715 | *
716 | * @link https://strava.github.io/api/v3/segments/#explore
717 | * @param string $bounds
718 | * @param string $activity_type
719 | * @param int|null $min_cat
720 | * @param int|null $max_cat
721 | * @return array
722 | * @throws Exception
723 | */
724 | public function getSegmentExplorer(string $bounds, string $activity_type = 'riding', ?int $min_cat = null, ?int $max_cat = null): array
725 | {
726 | try {
727 | return $this->service->getSegmentExplorer($bounds, $activity_type, $min_cat, $max_cat);
728 | } catch (ServiceException $e) {
729 | throw new ClientException('[SERVICE] ' . $e->getMessage());
730 | }
731 | }
732 |
733 | /**
734 | * List efforts filtered by athlete and/or a date range
735 | *
736 | * @link https://strava.github.io/api/v3/segments/#efforts
737 | * @param int $id
738 | * @param int|null $athlete_id
739 | * @param string|null $start_date_local
740 | * @param string|null $end_date_local
741 | * @param int|null $page
742 | * @param int|null $per_page
743 | * @return array
744 | * @throws Exception
745 | */
746 | public function getSegmentEffort(int $id, ?int $athlete_id = null, ?string $start_date_local = null, ?string $end_date_local = null, ?int $page = null, ?int $per_page = null): array
747 | {
748 | try {
749 | return $this->service->getSegmentEffort($id, $athlete_id, $start_date_local, $end_date_local, $page, $per_page);
750 | } catch (ServiceException $e) {
751 | throw new ClientException('[SERVICE] ' . $e->getMessage());
752 | }
753 | }
754 |
755 | /**
756 | * Retrieve activity streams
757 | *
758 | * @link https://strava.github.io/api/v3/streams/#activity
759 | * @param int $id
760 | * @param string $types
761 | * @param string|null $resolution
762 | * @param string $series_type
763 | * @return array
764 | * @throws Exception
765 | */
766 | public function getStreamsActivity(int $id, string $types, ?string $resolution = null, string $series_type = 'distance'): array
767 | {
768 | try {
769 | return $this->service->getStreamsActivity($id, $types, $resolution, $series_type);
770 | } catch (ServiceException $e) {
771 | throw new ClientException('[SERVICE] ' . $e->getMessage());
772 | }
773 | }
774 |
775 | /**
776 | * Retrieve effort streams
777 | *
778 | * @link https://strava.github.io/api/v3/streams/#effort
779 | * @param int $id
780 | * @param string $types
781 | * @param ?string $resolution
782 | * @param string $series_type
783 | * @return array
784 | * @throws Exception
785 | */
786 | public function getStreamsEffort(int $id, string $types, ?string $resolution = null, string $series_type = 'distance'): array
787 | {
788 | try {
789 | return $this->service->getStreamsEffort($id, $types, $resolution, $series_type);
790 | } catch (ServiceException $e) {
791 | throw new ClientException('[SERVICE] ' . $e->getMessage());
792 | }
793 | }
794 |
795 | /**
796 | * Retrieve segment streams
797 | * @link https://strava.github.io/api/v3/streams/#segment
798 | * @param int $id
799 | * @param string $types
800 | * @param ?string $resolution
801 | * @param string $series_type
802 | * @return array
803 | * @throws Exception
804 | */
805 | public function getStreamsSegment(int $id, string $types, ?string $resolution = null, string $series_type = 'distance'): array
806 | {
807 | try {
808 | return $this->service->getStreamsSegment($id, $types, $resolution, $series_type);
809 | } catch (ServiceException $e) {
810 | throw new ClientException('[SERVICE] ' . $e->getMessage());
811 | }
812 | }
813 |
814 | /**
815 | * Retrieve route streams
816 | *
817 | * @link https://strava.github.io/api/v3/streams/#routes
818 | * @param int $id
819 | * @return array
820 | * @throws Exception
821 | */
822 | public function getStreamsRoute(int $id): array
823 | {
824 | try {
825 | return $this->service->getStreamsRoute($id);
826 | } catch (ServiceException $e) {
827 | throw new ClientException('[SERVICE] ' . $e->getMessage());
828 | }
829 | }
830 |
831 | /**
832 | * Create a webhook subscription
833 | *
834 | * @link https://developers.strava.com/docs/webhooks/#create-a-subscription
835 | * @param int $clientId
836 | * @param string $clientSecret
837 | * @param string $callbackUrl
838 | * @param string $verifyToken
839 | * @return array
840 | * @throws Exception
841 | */
842 | public function createWebhookSubscription(int $clientId, string $clientSecret, string $callbackUrl, string $verifyToken): array
843 | {
844 | try {
845 | return $this->service->createWebhookSubscription($clientId, $clientSecret, $callbackUrl, $verifyToken);
846 | } catch (ServiceException $e) {
847 | throw new ClientException('[SERVICE] ' . $e->getMessage());
848 | }
849 | }
850 |
851 | /**
852 | * List webhook subscriptions
853 | *
854 | * @link https://developers.strava.com/docs/webhooks/#list-subscriptions
855 | * @param int $clientId
856 | * @param string $clientSecret
857 | * @return array
858 | * @throws Exception
859 | */
860 | public function listWebhookSubscriptions(int $clientId, string $clientSecret): array
861 | {
862 | try {
863 | return $this->service->listWebhookSubscriptions($clientId, $clientSecret);
864 | } catch (ServiceException $e) {
865 | throw new ClientException('[SERVICE] ' . $e->getMessage());
866 | }
867 | }
868 |
869 | /**
870 | * Delete a webhook subscription
871 | *
872 | * @link https://developers.strava.com/docs/webhooks/#delete-a-subscription
873 | * @param int $clientId
874 | * @param string $clientSecret
875 | * @param int $subscriptionId
876 | * @return array
877 | * @throws Exception
878 | */
879 | public function deleteWebhookSubscription(int $clientId, string $clientSecret, int $subscriptionId): array
880 | {
881 | try {
882 | return $this->service->deleteWebhookSubscription($clientId, $clientSecret, $subscriptionId);
883 | } catch (ServiceException $e) {
884 | throw new ClientException('[SERVICE] ' . $e->getMessage());
885 | }
886 | }
887 | }
888 |
--------------------------------------------------------------------------------
/tests/Strava/API/ClientTest.php:
--------------------------------------------------------------------------------
1 | getMockBuilder('Strava\API\Service\Stub')
18 | ->disableOriginalConstructor()
19 | ->getMock();
20 | return $serviceMock;
21 | }
22 |
23 | public function testGetAthlete()
24 | {
25 | $serviceMock = $this->getServiceMock();
26 | $serviceMock->expects($this->once())->method('getAthlete')
27 | ->will($this->returnValue(['id' => 1234, 'name' => 'Test Athlete']));
28 |
29 | $client = new Strava\API\Client($serviceMock);
30 | $output = $client->getAthlete(1234);
31 |
32 | $this->assertEquals(['id' => 1234, 'name' => 'Test Athlete'], $output);
33 | }
34 |
35 | public function testGetAthleteException()
36 | {
37 | $this->expectException('Strava\API\Exception');
38 |
39 | $serviceMock = $this->getServiceMock();
40 | $serviceMock->expects($this->once())->method('getAthlete')
41 | ->will($this->throwException(new ServiceException));
42 |
43 | $client = new Strava\API\Client($serviceMock);
44 | $client->getAthlete(1234);
45 | }
46 |
47 | public function testGetAthleteStats()
48 | {
49 | $serviceMock = $this->getServiceMock();
50 | $serviceMock->expects($this->once())->method('getAthleteStats')
51 | ->will($this->returnValue(['id' => 1234, 'data' => 'test']));
52 |
53 | $client = new Strava\API\Client($serviceMock);
54 | $output = $client->getAthleteStats(1234);
55 |
56 | $this->assertEquals(['id' => 1234, 'data' => 'test'], $output);
57 | }
58 |
59 | public function testGetAthleteRoutes()
60 | {
61 | $serviceMock = $this->getServiceMock();
62 | $serviceMock->expects($this->once())->method('getAthleteRoutes')
63 | ->will($this->returnValue(['id' => 1234, 'data' => 'test']));
64 |
65 | $client = new Strava\API\Client($serviceMock);
66 | $output = $client->getAthleteRoutes(1234);
67 |
68 | $this->assertEquals(['id' => 1234, 'data' => 'test'], $output);
69 | }
70 |
71 | public function testGetAthleteClubs()
72 | {
73 | $serviceMock = $this->getServiceMock();
74 | $serviceMock->expects($this->once())->method('getAthleteClubs')
75 | ->will($this->returnValue(['id' => 1234, 'data' => 'test']));
76 |
77 | $client = new Strava\API\Client($serviceMock);
78 | $output = $client->getAthleteClubs();
79 |
80 | $this->assertEquals(['id' => 1234, 'data' => 'test'], $output);
81 | }
82 |
83 | public function testGetAthleteClubsException()
84 | {
85 | $this->expectException('Strava\API\Exception');
86 |
87 | $serviceMock = $this->getServiceMock();
88 | $serviceMock->expects($this->once())->method('getAthleteClubs')
89 | ->will($this->throwException(new ServiceException));
90 |
91 | $client = new Strava\API\Client($serviceMock);
92 | $client->getAthleteClubs();
93 | }
94 |
95 | public function testGetAthleteActivities()
96 | {
97 | $serviceMock = $this->getServiceMock();
98 | $serviceMock->expects($this->once())->method('getAthleteActivities')
99 | ->will($this->returnValue(['id' => 1234, 'data' => 'test']));
100 |
101 | $client = new Strava\API\Client($serviceMock);
102 | $output = $client->getAthleteActivities();
103 |
104 | $this->assertEquals(['id' => 1234, 'data' => 'test'], $output);
105 | }
106 |
107 | public function testGetAthleteActivitiesException()
108 | {
109 | $this->expectException('Strava\API\Exception');
110 |
111 | $serviceMock = $this->getServiceMock();
112 | $serviceMock->expects($this->once())->method('getAthleteActivities')
113 | ->will($this->throwException(new ServiceException));
114 |
115 | $client = new Strava\API\Client($serviceMock);
116 | $client->getAthleteActivities();
117 | }
118 |
119 | public function testGetAthleteFriends()
120 | {
121 | $serviceMock = $this->getServiceMock();
122 | $serviceMock->expects($this->once())->method('getAthleteFriends')
123 | ->will($this->returnValue(['id' => 1234, 'data' => 'test']));
124 |
125 | $client = new Strava\API\Client($serviceMock);
126 | $output = $client->getAthleteFriends();
127 |
128 | $this->assertEquals(['id' => 1234, 'data' => 'test'], $output);
129 | }
130 |
131 | public function testGetAthleteFriendsException()
132 | {
133 | $this->expectException('Strava\API\Exception');
134 |
135 | $serviceMock = $this->getServiceMock();
136 | $serviceMock->expects($this->once())->method('getAthleteFriends')
137 | ->will($this->throwException(new ServiceException));
138 |
139 | $client = new Strava\API\Client($serviceMock);
140 | $client->getAthleteFriends();
141 | }
142 |
143 | public function testGetAthleteFollowers()
144 | {
145 | $serviceMock = $this->getServiceMock();
146 | $serviceMock->expects($this->once())->method('getAthleteFollowers')
147 | ->will($this->returnValue(['id' => 1234, 'data' => 'test']));
148 |
149 | $client = new Strava\API\Client($serviceMock);
150 | $output = $client->getAthleteFollowers();
151 |
152 | $this->assertEquals(['id' => 1234, 'data' => 'test'], $output);
153 | }
154 |
155 | public function testGetAthleteFollowersException()
156 | {
157 | $this->expectException('Strava\API\Exception');
158 |
159 | $serviceMock = $this->getServiceMock();
160 | $serviceMock->expects($this->once())->method('getAthleteFollowers')
161 | ->will($this->throwException(new ServiceException));
162 |
163 | $client = new Strava\API\Client($serviceMock);
164 | $client->getAthleteFollowers();
165 | }
166 |
167 | public function testGetAthleteBothFollowing()
168 | {
169 | $serviceMock = $this->getServiceMock();
170 | $serviceMock->expects($this->once())->method('getAthleteBothFollowing')
171 | ->will($this->returnValue(['id' => 1234, 'data' => 'test']));
172 |
173 | $client = new Strava\API\Client($serviceMock);
174 | $output = $client->getAthleteBothFollowing(1234);
175 |
176 | $this->assertEquals(['id' => 1234, 'data' => 'test'], $output);
177 | }
178 |
179 | public function testGetAthleteBothFollowingException()
180 | {
181 | $this->expectException('Strava\API\Exception');
182 |
183 | $serviceMock = $this->getServiceMock();
184 | $serviceMock->expects($this->once())->method('getAthleteBothFollowing')
185 | ->will($this->throwException(new ServiceException));
186 |
187 | $client = new Strava\API\Client($serviceMock);
188 | $client->getAthleteBothFollowing(1234);
189 | }
190 |
191 | public function testGetAthleteKom()
192 | {
193 | $serviceMock = $this->getServiceMock();
194 | $serviceMock->expects($this->once())->method('getAthleteKom')
195 | ->will($this->returnValue(['id' => 1234, 'data' => 'test']));
196 |
197 | $client = new Strava\API\Client($serviceMock);
198 | $output = $client->getAthleteKom(1234);
199 |
200 | $this->assertEquals(['id' => 1234, 'data' => 'test'], $output);
201 | }
202 |
203 | public function testGetAthleteKomException()
204 | {
205 | $this->expectException('Strava\API\Exception');
206 |
207 | $serviceMock = $this->getServiceMock();
208 | $serviceMock->expects($this->once())->method('getAthleteKom')
209 | ->will($this->throwException(new ServiceException));
210 |
211 | $client = new Strava\API\Client($serviceMock);
212 | $client->getAthleteKom(1234);
213 | }
214 |
215 |
216 | public function testGetAthleteZones()
217 | {
218 | $serviceMock = $this->getServiceMock();
219 | $serviceMock->expects($this->once())->method('getAthleteZones')
220 | ->will($this->returnValue(['id' => 1234, 'data' => 'test']));
221 |
222 | $client = new Strava\API\Client($serviceMock);
223 | $output = $client->getAthleteZones();
224 |
225 | $this->assertEquals(['id' => 1234, 'data' => 'test'], $output);
226 | }
227 |
228 | public function testGetAthleteZonesException()
229 | {
230 | $this->expectException('Strava\API\Exception');
231 |
232 | $serviceMock = $this->getServiceMock();
233 | $serviceMock->expects($this->once())->method('getAthleteZones')
234 | ->will($this->throwException(new ServiceException));
235 |
236 | $client = new Strava\API\Client($serviceMock);
237 | $client->getAthleteZones();
238 | }
239 |
240 | public function testGetAthleteStarredSegments()
241 | {
242 | $serviceMock = $this->getServiceMock();
243 | $serviceMock->expects($this->once())->method('getAthleteStarredSegments')
244 | ->will($this->returnValue(['id' => 1234, 'data' => 'test']));
245 |
246 | $client = new Strava\API\Client($serviceMock);
247 | $output = $client->getAthleteStarredSegments();
248 |
249 | $this->assertEquals(['id' => 1234, 'data' => 'test'], $output);
250 | }
251 |
252 | public function testGetAthleteStarredSegmentsException()
253 | {
254 | $this->expectException('Strava\API\Exception');
255 |
256 | $serviceMock = $this->getServiceMock();
257 | $serviceMock->expects($this->once())->method('getAthleteStarredSegments')
258 | ->will($this->throwException(new ServiceException));
259 |
260 | $client = new Strava\API\Client($serviceMock);
261 | $client->getAthleteStarredSegments();
262 | }
263 |
264 | public function testUpdateAthlete()
265 | {
266 | $serviceMock = $this->getServiceMock();
267 | $serviceMock->expects($this->once())->method('updateAthlete')
268 | ->will($this->returnValue(['id' => 1234, 'data' => 'test']));
269 |
270 | $client = new Strava\API\Client($serviceMock);
271 | $output = $client->updateAthlete('Xyz', 'ABC', 'The Netherlands', 'M', 83.00);
272 |
273 | $this->assertEquals(['id' => 1234, 'data' => 'test'], $output);
274 | }
275 |
276 | public function testUpdateAthleteException()
277 | {
278 | $this->expectException('Strava\API\Exception');
279 |
280 | $serviceMock = $this->getServiceMock();
281 | $serviceMock->expects($this->once())->method('updateAthlete')
282 | ->will($this->throwException(new ServiceException));
283 |
284 | $client = new Strava\API\Client($serviceMock);
285 | $client->updateAthlete('Xyz', 'ABC', 'The Netherlands', 'M', 83.00);
286 | }
287 |
288 | public function testGetActivity()
289 | {
290 | $serviceMock = $this->getServiceMock();
291 | $serviceMock->expects($this->once())->method('getActivity')
292 | ->will($this->returnValue(['id' => 1234, 'data' => 'test']));
293 |
294 | $client = new Strava\API\Client($serviceMock);
295 | $output = $client->getActivity(1234);
296 |
297 | $this->assertEquals(['id' => 1234, 'data' => 'test'], $output);
298 | }
299 |
300 | public function testGetActivityException()
301 | {
302 | $this->expectException('Strava\API\Exception');
303 |
304 | $serviceMock = $this->getServiceMock();
305 | $serviceMock->expects($this->once())->method('getActivity')
306 | ->will($this->throwException(new ServiceException));
307 |
308 | $client = new Strava\API\Client($serviceMock);
309 | $client->getActivity(1234);
310 | }
311 |
312 | public function testGetActivityComments()
313 | {
314 | $serviceMock = $this->getServiceMock();
315 | $serviceMock->expects($this->once())->method('getActivityComments')
316 | ->will($this->returnValue(['id' => 1234, 'data' => 'test']));
317 |
318 | $client = new Strava\API\Client($serviceMock);
319 | $output = $client->getActivityComments(1234);
320 |
321 | $this->assertEquals(['id' => 1234, 'data' => 'test'], $output);
322 | }
323 |
324 | public function testGetActivityCommentsException()
325 | {
326 | $this->expectException('Strava\API\Exception');
327 |
328 | $serviceMock = $this->getServiceMock();
329 | $serviceMock->expects($this->once())->method('getActivityComments')
330 | ->will($this->throwException(new ServiceException));
331 |
332 | $client = new Strava\API\Client($serviceMock);
333 | $client->getActivityComments(1234);
334 | }
335 |
336 | public function testGetActivityKudos()
337 | {
338 | $serviceMock = $this->getServiceMock();
339 | $serviceMock->expects($this->once())->method('getActivityKudos')
340 | ->will($this->returnValue(['id' => 1234, 'data' => 'test']));
341 |
342 | $client = new Strava\API\Client($serviceMock);
343 | $output = $client->getActivityKudos(1234);
344 |
345 | $this->assertEquals(['id' => 1234, 'data' => 'test'], $output);
346 | }
347 |
348 | public function testGetActivityKudosException()
349 | {
350 | $this->expectException('Strava\API\Exception');
351 |
352 | $serviceMock = $this->getServiceMock();
353 | $serviceMock->expects($this->once())->method('getActivityKudos')
354 | ->will($this->throwException(new ServiceException));
355 |
356 | $client = new Strava\API\Client($serviceMock);
357 | $client->getActivityKudos(1234);
358 | }
359 |
360 | public function testGetActivityPhotos()
361 | {
362 | $serviceMock = $this->getServiceMock();
363 | $serviceMock->expects($this->once())->method('getActivityPhotos')
364 | ->will($this->returnValue(['id' => 1234, 'data' => 'test']));
365 |
366 | $client = new Strava\API\Client($serviceMock);
367 | $output = $client->getActivityPhotos(1234);
368 |
369 | $this->assertEquals(['id' => 1234, 'data' => 'test'], $output);
370 | }
371 |
372 | public function testGetActivityPhotosException()
373 | {
374 | $this->expectException('Strava\API\Exception');
375 |
376 | $serviceMock = $this->getServiceMock();
377 | $serviceMock->expects($this->once())->method('getActivityPhotos')
378 | ->will($this->throwException(new ServiceException));
379 |
380 | $client = new Strava\API\Client($serviceMock);
381 | $client->getActivityPhotos(1234);
382 | }
383 |
384 | public function testGetActivityZones()
385 | {
386 | $serviceMock = $this->getServiceMock();
387 | $serviceMock->expects($this->once())->method('getActivityZones')
388 | ->will($this->returnValue(['id' => 1234, 'data' => 'test']));
389 |
390 | $client = new Strava\API\Client($serviceMock);
391 | $output = $client->getActivityZones(1234);
392 |
393 | $this->assertEquals(['id' => 1234, 'data' => 'test'], $output);
394 | }
395 |
396 | public function testGetActivityZonesException()
397 | {
398 | $this->expectException('Strava\API\Exception');
399 |
400 | $serviceMock = $this->getServiceMock();
401 | $serviceMock->expects($this->once())->method('getActivityZones')
402 | ->will($this->throwException(new ServiceException));
403 |
404 | $client = new Strava\API\Client($serviceMock);
405 | $client->getActivityZones(1234);
406 | }
407 |
408 | public function testGetActivityLaps()
409 | {
410 | $serviceMock = $this->getServiceMock();
411 | $serviceMock->expects($this->once())->method('getActivityLaps')
412 | ->will($this->returnValue(['id' => 1234, 'data' => 'test']));
413 |
414 | $client = new Strava\API\Client($serviceMock);
415 | $output = $client->getActivityLaps(1234);
416 |
417 | $this->assertEquals(['id' => 1234, 'data' => 'test'], $output);
418 | }
419 |
420 | public function testGetActivityLapsException()
421 | {
422 | $this->expectException('Strava\API\Exception');
423 |
424 | $serviceMock = $this->getServiceMock();
425 | $serviceMock->expects($this->once())->method('getActivityLaps')
426 | ->will($this->throwException(new ServiceException));
427 |
428 | $client = new Strava\API\Client($serviceMock);
429 | $client->getActivityLaps(1234);
430 | }
431 |
432 | public function testGetActivityUploadStatus()
433 | {
434 | $serviceMock = $this->getServiceMock();
435 | $serviceMock->expects($this->once())->method('getActivityUploadStatus')
436 | ->will($this->returnValue(['id' => 1234, 'data' => 'test']));
437 |
438 | $client = new Strava\API\Client($serviceMock);
439 | $output = $client->getActivityUploadStatus(1234);
440 |
441 | $this->assertEquals(['id' => 1234, 'data' => 'test'], $output);
442 | }
443 |
444 | public function testGetActivityUploadStatusException()
445 | {
446 | $this->expectException('Strava\API\Exception');
447 |
448 | $serviceMock = $this->getServiceMock();
449 | $serviceMock->expects($this->once())->method('getActivityUploadStatus')
450 | ->will($this->throwException(new ServiceException));
451 |
452 | $client = new Strava\API\Client($serviceMock);
453 | $client->getActivityUploadStatus(1234);
454 | }
455 |
456 | public function testCreateActivity()
457 | {
458 | $serviceMock = $this->getServiceMock();
459 | $serviceMock->expects($this->once())->method('createActivity')
460 | ->will($this->returnValue(['id' => 1234, 'data' => 'test']));
461 |
462 | $client = new Strava\API\Client($serviceMock);
463 | $output = $client->createActivity('cycling ride', 'cycling', '20140101', 100);
464 |
465 | $this->assertEquals(['id' => 1234, 'data' => 'test'], $output);
466 | }
467 |
468 | public function testCreateActivityException()
469 | {
470 | $this->expectException('Strava\API\Exception');
471 |
472 | $serviceMock = $this->getServiceMock();
473 | $serviceMock->expects($this->once())->method('createActivity')
474 | ->will($this->throwException(new ServiceException));
475 |
476 | $client = new Strava\API\Client($serviceMock);
477 | $client->createActivity('cycling ride', 'cycling', '20140101', 100);
478 | }
479 |
480 | public function testUploadActivity()
481 | {
482 | $serviceMock = $this->getServiceMock();
483 | $serviceMock->expects($this->once())->method('uploadActivity')
484 | ->will($this->returnValue(['id' => 1234, 'data' => 'test']));
485 |
486 | $client = new Strava\API\Client($serviceMock);
487 | $output = $client->uploadActivity("abc23487fsdfds");
488 |
489 | $this->assertEquals(['id' => 1234, 'data' => 'test'], $output);
490 | }
491 |
492 | public function testUploadActivityException()
493 | {
494 | $this->expectException('Strava\API\Exception');
495 |
496 | $serviceMock = $this->getServiceMock();
497 | $serviceMock->expects($this->once())->method('uploadActivity')
498 | ->will($this->throwException(new ServiceException));
499 |
500 | $client = new Strava\API\Client($serviceMock);
501 | $client->uploadActivity("abc23487fsdfds");
502 | }
503 |
504 | public function testUpdateActivity()
505 | {
506 | $serviceMock = $this->getServiceMock();
507 | $serviceMock->expects($this->once())->method('updateActivity')
508 | ->will($this->returnValue(['id' => 1234, 'data' => 'test']));
509 |
510 | $client = new Strava\API\Client($serviceMock);
511 | $output = $client->updateActivity(123);
512 |
513 | $this->assertEquals(['id' => 1234, 'data' => 'test'], $output);
514 | }
515 |
516 | public function testUpdateActivityException()
517 | {
518 | $this->expectException('Strava\API\Exception');
519 |
520 | $serviceMock = $this->getServiceMock();
521 | $serviceMock->expects($this->once())->method('updateActivity')
522 | ->will($this->throwException(new ServiceException));
523 |
524 | $client = new Strava\API\Client($serviceMock);
525 | $client->updateActivity(123);
526 | }
527 |
528 | public function testDeleteActivity()
529 | {
530 | $serviceMock = $this->getServiceMock();
531 | $serviceMock->expects($this->once())->method('deleteActivity')
532 | ->will($this->returnValue(['id' => 1234, 'data' => 'test']));
533 |
534 | $client = new Strava\API\Client($serviceMock);
535 | $output = $client->deleteActivity(1234);
536 |
537 | $this->assertEquals(['id' => 1234, 'data' => 'test'], $output);
538 | }
539 |
540 | public function testDeleteActivityException()
541 | {
542 | $this->expectException('Strava\API\Exception');
543 |
544 | $serviceMock = $this->getServiceMock();
545 | $serviceMock->expects($this->once())->method('deleteActivity')
546 | ->will($this->throwException(new ServiceException));
547 |
548 | $client = new Strava\API\Client($serviceMock);
549 | $client->deleteActivity(1234);
550 | }
551 |
552 | public function testGetGear()
553 | {
554 | $serviceMock = $this->getServiceMock();
555 | $serviceMock->expects($this->once())->method('getGear')
556 | ->will($this->returnValue(['id' => 1234, 'data' => 'test']));
557 |
558 | $client = new Strava\API\Client($serviceMock);
559 | $output = $client->getGear(1234);
560 |
561 | $this->assertEquals(['id' => 1234, 'data' => 'test'], $output);
562 | }
563 |
564 | public function testGetGearException()
565 | {
566 | $this->expectException('Strava\API\Exception');
567 |
568 | $serviceMock = $this->getServiceMock();
569 | $serviceMock->expects($this->once())->method('getGear')
570 | ->will($this->throwException(new ServiceException));
571 |
572 | $client = new Strava\API\Client($serviceMock);
573 | $client->getGear(1234);
574 | }
575 |
576 | public function testGetClub()
577 | {
578 | $serviceMock = $this->getServiceMock();
579 | $serviceMock->expects($this->once())->method('getClub')
580 | ->will($this->returnValue(['id' => 1234, 'data' => 'test']));
581 |
582 | $client = new Strava\API\Client($serviceMock);
583 | $output = $client->getClub(1234);
584 |
585 | $this->assertEquals(['id' => 1234, 'data' => 'test'], $output);
586 | }
587 |
588 | public function testGetClubException()
589 | {
590 | $this->expectException('Strava\API\Exception');
591 |
592 | $serviceMock = $this->getServiceMock();
593 | $serviceMock->expects($this->once())->method('getClub')
594 | ->will($this->throwException(new ServiceException));
595 |
596 | $client = new Strava\API\Client($serviceMock);
597 | $client->getClub(1234);
598 | }
599 |
600 | public function testGetClubMembers()
601 | {
602 | $serviceMock = $this->getServiceMock();
603 | $serviceMock->expects($this->once())->method('getClubMembers')
604 | ->will($this->returnValue(['id' => 1234, 'data' => 'test']));
605 |
606 | $client = new Strava\API\Client($serviceMock);
607 | $output = $client->getClubMembers(1234);
608 |
609 | $this->assertEquals(['id' => 1234, 'data' => 'test'], $output);
610 | }
611 |
612 | public function testGetClubMembersException()
613 | {
614 | $this->expectException('Strava\API\Exception');
615 |
616 | $serviceMock = $this->getServiceMock();
617 | $serviceMock->expects($this->once())->method('getClubMembers')
618 | ->will($this->throwException(new ServiceException));
619 |
620 | $client = new Strava\API\Client($serviceMock);
621 | $client->getClubMembers(1234);
622 | }
623 |
624 | public function testGetClubActivities()
625 | {
626 | $serviceMock = $this->getServiceMock();
627 | $serviceMock->expects($this->once())->method('getClubActivities')
628 | ->will($this->returnValue(['id' => 1234, 'data' => 'test']));
629 |
630 | $client = new Strava\API\Client($serviceMock);
631 | $output = $client->getClubActivities(1234);
632 |
633 | $this->assertEquals(['id' => 1234, 'data' => 'test'], $output);
634 | }
635 |
636 | public function testGetClubActivitiesException()
637 | {
638 | $this->expectException('Strava\API\Exception');
639 |
640 | $serviceMock = $this->getServiceMock();
641 | $serviceMock->expects($this->once())->method('getClubActivities')
642 | ->will($this->throwException(new ServiceException));
643 |
644 | $client = new Strava\API\Client($serviceMock);
645 | $client->getClubActivities(1234);
646 | }
647 |
648 | public function testGetClubAnnouncements()
649 | {
650 | $serviceMock = $this->getServiceMock();
651 | $serviceMock->expects($this->once())->method('getClubAnnouncements')
652 | ->will($this->returnValue(['id' => 1234, 'data' => 'test']));
653 |
654 | $client = new Strava\API\Client($serviceMock);
655 | $output = $client->getClubAnnouncements(1234);
656 |
657 | $this->assertEquals(['id' => 1234, 'data' => 'test'], $output);
658 | }
659 |
660 | public function testGetClubAnnouncementsException()
661 | {
662 | $this->expectException('Strava\API\Exception');
663 |
664 | $serviceMock = $this->getServiceMock();
665 | $serviceMock->expects($this->once())->method('getClubAnnouncements')
666 | ->will($this->throwException(new ServiceException));
667 |
668 | $client = new Strava\API\Client($serviceMock);
669 | $client->getClubAnnouncements(1234);
670 | }
671 |
672 | public function testGetClubGroupEvents()
673 | {
674 | $serviceMock = $this->getServiceMock();
675 | $serviceMock->expects($this->once())->method('getClubGroupEvents')
676 | ->will($this->returnValue(['id' => 1234, 'data' => 'test']));
677 |
678 | $client = new Strava\API\Client($serviceMock);
679 | $output = $client->getClubGroupEvents(1234);
680 |
681 | $this->assertEquals(['id' => 1234, 'data' => 'test'], $output);
682 | }
683 |
684 | public function testGetClubGroupEventsException()
685 | {
686 | $this->expectException('Strava\API\Exception');
687 |
688 | $serviceMock = $this->getServiceMock();
689 | $serviceMock->expects($this->once())->method('getClubGroupEvents')
690 | ->will($this->throwException(new ServiceException));
691 |
692 | $client = new Strava\API\Client($serviceMock);
693 | $client->getClubGroupEvents(1234);
694 | }
695 |
696 | public function testJoinClub()
697 | {
698 | $serviceMock = $this->getServiceMock();
699 | $serviceMock->expects($this->once())->method('joinClub')
700 | ->will($this->returnValue(['id' => 1234, 'data' => 'test']));
701 |
702 | $client = new Strava\API\Client($serviceMock);
703 | $output = $client->joinClub(1234);
704 |
705 | $this->assertEquals(['id' => 1234, 'data' => 'test'], $output);
706 | }
707 |
708 | public function testJoinClubException()
709 | {
710 | $this->expectException('Strava\API\Exception');
711 |
712 | $serviceMock = $this->getServiceMock();
713 | $serviceMock->expects($this->once())->method('joinClub')
714 | ->will($this->throwException(new ServiceException));
715 |
716 | $client = new Strava\API\Client($serviceMock);
717 | $client->joinClub(1234);
718 | }
719 |
720 | public function testLeaveClub()
721 | {
722 | $serviceMock = $this->getServiceMock();
723 | $serviceMock->expects($this->once())->method('leaveClub')
724 | ->will($this->returnValue(['id' => 1234, 'data' => 'test']));
725 |
726 | $client = new Strava\API\Client($serviceMock);
727 | $output = $client->leaveClub(1234);
728 |
729 | $this->assertEquals(['id' => 1234, 'data' => 'test'], $output);
730 | }
731 |
732 | public function testLeaveClubException()
733 | {
734 | $this->expectException('Strava\API\Exception');
735 |
736 | $serviceMock = $this->getServiceMock();
737 | $serviceMock->expects($this->once())->method('leaveClub')
738 | ->will($this->throwException(new ServiceException));
739 |
740 | $client = new Strava\API\Client($serviceMock);
741 | $client->leaveClub(1234);
742 | }
743 |
744 | public function testGetRoute()
745 | {
746 | $serviceMock = $this->getServiceMock();
747 | $serviceMock->expects($this->once())->method('getRoute')
748 | ->will($this->returnValue(['id' => 1234, 'data' => 'test']));
749 |
750 | $client = new Strava\API\Client($serviceMock);
751 | $output = $client->getRoute(1234);
752 |
753 | $this->assertEquals(['id' => 1234, 'data' => 'test'], $output);
754 | }
755 |
756 | public function testGetRouteException()
757 | {
758 | $this->expectException('Strava\API\Exception');
759 |
760 | $serviceMock = $this->getServiceMock();
761 | $serviceMock->expects($this->once())->method('getRoute')
762 | ->will($this->throwException(new ServiceException));
763 |
764 | $client = new Strava\API\Client($serviceMock);
765 | $client->getRoute(1234);
766 | }
767 |
768 | public function testGetSegment()
769 | {
770 | $serviceMock = $this->getServiceMock();
771 | $serviceMock->expects($this->once())->method('getSegment')
772 | ->will($this->returnValue(['id' => 1234, 'data' => 'test']));
773 |
774 | $client = new Strava\API\Client($serviceMock);
775 | $output = $client->getSegment(1234);
776 |
777 | $this->assertEquals(['id' => 1234, 'data' => 'test'], $output);
778 | }
779 |
780 | public function testGetSegmentException()
781 | {
782 | $this->expectException('Strava\API\Exception');
783 |
784 | $serviceMock = $this->getServiceMock();
785 | $serviceMock->expects($this->once())->method('getSegment')
786 | ->will($this->throwException(new ServiceException));
787 |
788 | $client = new Strava\API\Client($serviceMock);
789 | $client->getSegment(1234);
790 | }
791 |
792 | public function testGetSegmentLeaderboard()
793 | {
794 | $serviceMock = $this->getServiceMock();
795 | $serviceMock->expects($this->once())->method('getSegmentLeaderboard')
796 | ->will($this->returnValue(['id' => 1234, 'data' => 'test']));
797 |
798 | $client = new Strava\API\Client($serviceMock);
799 | $output = $client->getSegmentLeaderboard(1234);
800 |
801 | $this->assertEquals(['id' => 1234, 'data' => 'test'], $output);
802 | }
803 |
804 | public function testGetSegmentLeaderboardException()
805 | {
806 | $this->expectException('Strava\API\Exception');
807 |
808 | $serviceMock = $this->getServiceMock();
809 | $serviceMock->expects($this->once())->method('getSegmentLeaderboard')
810 | ->will($this->throwException(new ServiceException));
811 |
812 | $client = new Strava\API\Client($serviceMock);
813 | $client->getSegmentLeaderboard(1234);
814 | }
815 |
816 | public function testGetSegmentExplorer()
817 | {
818 | $serviceMock = $this->getServiceMock();
819 | $serviceMock->expects($this->once())->method('getSegmentExplorer')
820 | ->will($this->returnValue(['id' => 1234, 'data' => 'test']));
821 |
822 | $client = new Strava\API\Client($serviceMock);
823 | $output = $client->getSegmentExplorer("lng.lat");
824 |
825 | $this->assertEquals(['id' => 1234, 'data' => 'test'], $output);
826 | }
827 |
828 | public function testGetSegmentExplorerException()
829 | {
830 | $this->expectException('Strava\API\Exception');
831 |
832 | $serviceMock = $this->getServiceMock();
833 | $serviceMock->expects($this->once())->method('getSegmentExplorer')
834 | ->will($this->throwException(new ServiceException));
835 |
836 | $client = new Strava\API\Client($serviceMock);
837 | $client->getSegmentExplorer("lng.lat");
838 | }
839 |
840 | public function testGetSegmentEffort()
841 | {
842 | $serviceMock = $this->getServiceMock();
843 | $serviceMock->expects($this->once())->method('getSegmentEffort')
844 | ->will($this->returnValue(['id' => 1234, 'data' => 'test']));
845 |
846 | $client = new Strava\API\Client($serviceMock);
847 | $output = $client->getSegmentEffort(1234);
848 |
849 | $this->assertEquals(['id' => 1234, 'data' => 'test'], $output);
850 | }
851 |
852 | public function testGetSegmentEffortException()
853 | {
854 | $this->expectException('Strava\API\Exception');
855 |
856 | $serviceMock = $this->getServiceMock();
857 | $serviceMock->expects($this->once())->method('getSegmentEffort')
858 | ->will($this->throwException(new ServiceException));
859 |
860 | $client = new Strava\API\Client($serviceMock);
861 | $client->getSegmentEffort(1234);
862 | }
863 |
864 | public function testGetStreamsActivity()
865 | {
866 | $serviceMock = $this->getServiceMock();
867 | $serviceMock->expects($this->once())->method('getStreamsActivity')
868 | ->will($this->returnValue(['id' => 1234, 'data' => 'test']));
869 |
870 | $client = new Strava\API\Client($serviceMock);
871 | $output = $client->getStreamsActivity(1234, 'abc');
872 |
873 | $this->assertEquals(['id' => 1234, 'data' => 'test'], $output);
874 | }
875 |
876 | public function testGetStreamsActivityException()
877 | {
878 | $this->expectException('Strava\API\Exception');
879 |
880 | $serviceMock = $this->getServiceMock();
881 | $serviceMock->expects($this->once())->method('getStreamsActivity')
882 | ->will($this->throwException(new ServiceException));
883 |
884 | $client = new Strava\API\Client($serviceMock);
885 | $client->getStreamsActivity(1234, 'abc');
886 | }
887 |
888 | public function testGetStreamsEffort()
889 | {
890 | $serviceMock = $this->getServiceMock();
891 | $serviceMock->expects($this->once())->method('getStreamsEffort')
892 | ->will($this->returnValue(['id' => 1234, 'data' => 'test']));
893 |
894 | $client = new Strava\API\Client($serviceMock);
895 | $output = $client->getStreamsEffort(1234, 'abc');
896 |
897 | $this->assertEquals(['id' => 1234, 'data' => 'test'], $output);
898 | }
899 |
900 | public function testGetStreamsEffortException()
901 | {
902 | $this->expectException('Strava\API\Exception');
903 |
904 | $serviceMock = $this->getServiceMock();
905 | $serviceMock->expects($this->once())->method('getStreamsEffort')
906 | ->will($this->throwException(new ServiceException));
907 |
908 | $client = new Strava\API\Client($serviceMock);
909 | $client->getStreamsEffort(1234, 'abc');
910 | }
911 |
912 | public function testGetStreamsSegment()
913 | {
914 | $serviceMock = $this->getServiceMock();
915 | $serviceMock->expects($this->once())->method('getStreamsSegment')
916 | ->will($this->returnValue(['id' => 1234, 'data' => 'test']));
917 |
918 | $client = new Strava\API\Client($serviceMock);
919 | $output = $client->getStreamsSegment(1234, 'abc');
920 |
921 | $this->assertEquals(['id' => 1234, 'data' => 'test'], $output);
922 | }
923 |
924 | public function testGetStreamsSegmentException()
925 | {
926 | $this->expectException('Strava\API\Exception');
927 |
928 | $serviceMock = $this->getServiceMock();
929 | $serviceMock->expects($this->once())->method('getStreamsSegment')
930 | ->will($this->throwException(new ServiceException));
931 |
932 | $client = new Strava\API\Client($serviceMock);
933 | $client->getStreamsSegment(1234, 'abc');
934 | }
935 |
936 | public function testGetStreamsRoute()
937 | {
938 | $serviceMock = $this->getServiceMock();
939 | $serviceMock->expects($this->once())->method('getStreamsRoute')
940 | ->will($this->returnValue(['id' => 1234, 'data' => 'test']));
941 |
942 | $client = new Strava\API\Client($serviceMock);
943 | $output = $client->getStreamsRoute(1234);
944 |
945 | $this->assertEquals(['id' => 1234, 'data' => 'test'], $output);
946 | }
947 |
948 | public function testGetStreamsRouteException()
949 | {
950 | $this->expectException('Strava\API\Exception');
951 |
952 | $serviceMock = $this->getServiceMock();
953 | $serviceMock->expects($this->once())->method('getStreamsRoute')
954 | ->will($this->throwException(new ServiceException));
955 |
956 | $client = new Strava\API\Client($serviceMock);
957 | $client->getStreamsRoute(1234);
958 | }
959 |
960 | public function testCreateWebhookSubscription()
961 | {
962 | $serviceMock = $this->getServiceMock();
963 | $serviceMock->expects($this->once())->method('createWebhookSubscription')
964 | ->with(12345, 'secret', 'https://example.com/webhook', 'verify_token')
965 | ->will($this->returnValue(['id' => 123, 'callback_url' => 'https://example.com/webhook']));
966 |
967 | $client = new Strava\API\Client($serviceMock);
968 | $output = $client->createWebhookSubscription(12345, 'secret', 'https://example.com/webhook', 'verify_token');
969 |
970 | $this->assertEquals(['id' => 123, 'callback_url' => 'https://example.com/webhook'], $output);
971 | }
972 |
973 | public function testCreateWebhookSubscriptionException()
974 | {
975 | $this->expectException('Strava\API\Exception');
976 |
977 | $serviceMock = $this->getServiceMock();
978 | $serviceMock->expects($this->once())->method('createWebhookSubscription')
979 | ->will($this->throwException(new ServiceException));
980 |
981 | $client = new Strava\API\Client($serviceMock);
982 | $client->createWebhookSubscription(12345, 'secret', 'https://example.com/webhook', 'verify_token');
983 | }
984 |
985 | public function testListWebhookSubscriptions()
986 | {
987 | $serviceMock = $this->getServiceMock();
988 | $serviceMock->expects($this->once())->method('listWebhookSubscriptions')
989 | ->with(12345, 'secret')
990 | ->will($this->returnValue([['id' => 123, 'callback_url' => 'https://example.com/webhook']]));
991 |
992 | $client = new Strava\API\Client($serviceMock);
993 | $output = $client->listWebhookSubscriptions(12345, 'secret');
994 |
995 | $this->assertEquals([['id' => 123, 'callback_url' => 'https://example.com/webhook']], $output);
996 | }
997 |
998 | public function testListWebhookSubscriptionsException()
999 | {
1000 | $this->expectException('Strava\API\Exception');
1001 |
1002 | $serviceMock = $this->getServiceMock();
1003 | $serviceMock->expects($this->once())->method('listWebhookSubscriptions')
1004 | ->will($this->throwException(new ServiceException));
1005 |
1006 | $client = new Strava\API\Client($serviceMock);
1007 | $client->listWebhookSubscriptions(12345, 'secret');
1008 | }
1009 |
1010 | public function testDeleteWebhookSubscription()
1011 | {
1012 | $serviceMock = $this->getServiceMock();
1013 | $serviceMock->expects($this->once())->method('deleteWebhookSubscription')
1014 | ->with(12345, 'secret', 123)
1015 | ->will($this->returnValue(['success' => true]));
1016 |
1017 | $client = new Strava\API\Client($serviceMock);
1018 | $output = $client->deleteWebhookSubscription(12345, 'secret', 123);
1019 |
1020 | $this->assertEquals(['success' => true], $output);
1021 | }
1022 |
1023 | public function testDeleteWebhookSubscriptionException()
1024 | {
1025 | $this->expectException('Strava\API\Exception');
1026 |
1027 | $serviceMock = $this->getServiceMock();
1028 | $serviceMock->expects($this->once())->method('deleteWebhookSubscription')
1029 | ->will($this->throwException(new ServiceException));
1030 |
1031 | $client = new Strava\API\Client($serviceMock);
1032 | $client->deleteWebhookSubscription(12345, 'secret', 123);
1033 | }
1034 |
1035 | }
1036 |
--------------------------------------------------------------------------------