Skip to content

Commit 5b9c21e

Browse files
authored
Merge pull request #4 from php-api-clients/feature-profile
Profile resource
2 parents 61a1491 + dd20223 commit 5b9c21e

17 files changed

+788
-7
lines changed

examples/emoji.php

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
return [
4+
'😈 ',
5+
'👾 ',
6+
'🤖 ',
7+
'🦄 ',
8+
'🐯 ',
9+
'🦁 ',
10+
'🐆 ',
11+
'🐅 ',
12+
'🐃 ',
13+
'🐦 ',
14+
'🦎 ',
15+
'🐲 ',
16+
'🐉 ',
17+
'🦋 ',
18+
'🐞 ',
19+
'🕷 ',
20+
'🕸 ',
21+
'🍀 ',
22+
'🍔 ',
23+
'🥞 ',
24+
'🌭 ',
25+
'🍕 ',
26+
'🍺 ',
27+
'🍻 ',
28+
'🥃',
29+
'🌍',
30+
'🌎',
31+
'🌏',
32+
'🌐',
33+
'🗺',
34+
'🏔',
35+
'',
36+
'🌋',
37+
'',
38+
'🌪',
39+
'🌀',
40+
'🌈',
41+
'',
42+
'',
43+
'',
44+
'🔥',
45+
'🎃',
46+
'🎮',
47+
'🔊',
48+
'🎵',
49+
'🎶',
50+
];

examples/profile-async.php

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
use ApiClients\Client\Twitter\AsyncClient;
4+
use ApiClients\Client\Twitter\Resource\ProfileInterface;
5+
use React\EventLoop\Factory;
6+
use function ApiClients\Foundation\resource_pretty_print;
7+
8+
require dirname(__DIR__) . DIRECTORY_SEPARATOR . 'vendor/autoload.php';
9+
$config = require 'resolve_config.php';
10+
11+
$loop = Factory::create();
12+
$client = (new AsyncClient(
13+
$config['consumer']['key'],
14+
$config['consumer']['secret'],
15+
$loop
16+
))->withAccessToken(
17+
$config['access_token']['token'],
18+
$config['access_token']['secret']
19+
)->profile()->done(function (ProfileInterface $profile) {
20+
resource_pretty_print($profile);
21+
});
22+
23+
$loop->run();
+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
use ApiClients\Client\Twitter\AsyncClient;
4+
use ApiClients\Client\Twitter\Resource\ProfileInterface;
5+
use React\EventLoop\Factory;
6+
use function ApiClients\Foundation\resource_pretty_print;
7+
8+
if (!isset($argv[1])) {
9+
echo 'This example requires you to pass a username for example \'php profile-update-name-async.php "Cees-Jan %s Kiewiet"\'.', PHP_EOL;
10+
echo 'The %s in there will be replaced with a random emoji.', PHP_EOL;
11+
exit(255);
12+
}
13+
14+
require dirname(__DIR__) . DIRECTORY_SEPARATOR . 'vendor/autoload.php';
15+
$config = require 'resolve_config.php';
16+
$emojis = require 'emoji.php';
17+
18+
$loop = Factory::create();
19+
$client = (new AsyncClient(
20+
$config['consumer']['key'],
21+
$config['consumer']['secret'],
22+
$loop
23+
))->withAccessToken(
24+
$config['access_token']['token'],
25+
$config['access_token']['secret']
26+
)->profile()->then(function (ProfileInterface $profile) use ($argv, $emojis) {
27+
echo 'Fetched profile', PHP_EOL;
28+
resource_pretty_print($profile);
29+
echo 'Setting new name', PHP_EOL;
30+
$profile = $profile->withName(sprintf(
31+
$argv[1],
32+
$emojis[random_int(0, count($emojis) - 1)]
33+
));
34+
resource_pretty_print($profile);
35+
36+
echo 'Updating profile', PHP_EOL;
37+
return $profile->putProfile();
38+
})->done(function (ProfileInterface $profile) {
39+
echo 'Profile updated', PHP_EOL;
40+
resource_pretty_print($profile);
41+
});
42+
43+
$loop->run();

examples/profile-update-name.php

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
use ApiClients\Client\Twitter\Client;
4+
use function ApiClients\Foundation\resource_pretty_print;
5+
6+
if (!isset($argv[1])) {
7+
echo 'This example requires you to pass a username for example \'php profile-update-name-async.php "Cees-Jan %s Kiewiet"\'.', PHP_EOL;
8+
echo 'The %s in there will be replaced with a random emoji.', PHP_EOL;
9+
exit(255);
10+
}
11+
12+
require dirname(__DIR__) . DIRECTORY_SEPARATOR . 'vendor/autoload.php';
13+
$config = require 'resolve_config.php';
14+
$emojis = require 'emoji.php';
15+
16+
$profile = (new Client(
17+
$config['consumer']['key'],
18+
$config['consumer']['secret']
19+
))->withAccessToken(
20+
$config['access_token']['token'],
21+
$config['access_token']['secret']
22+
)->profile();
23+
24+
echo 'Fetched profile', PHP_EOL;
25+
resource_pretty_print($profile);
26+
echo 'Setting new name', PHP_EOL;
27+
$profile = $profile->withName(sprintf(
28+
$argv[1],
29+
$emojis[random_int(0, count($emojis) - 1)]
30+
));
31+
resource_pretty_print($profile);
32+
33+
echo 'Updating profile', PHP_EOL;
34+
$profile = $profile->putProfile();
35+
echo 'Profile updated', PHP_EOL;
36+
resource_pretty_print($profile);

examples/profile.php

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
use ApiClients\Client\Twitter\Client;
4+
use function ApiClients\Foundation\resource_pretty_print;
5+
6+
require dirname(__DIR__) . DIRECTORY_SEPARATOR . 'vendor/autoload.php';
7+
$config = require 'resolve_config.php';
8+
9+
$client = (new Client(
10+
$config['consumer']['key'],
11+
$config['consumer']['secret']
12+
))->withAccessToken(
13+
$config['access_token']['token'],
14+
$config['access_token']['secret']
15+
);
16+
17+
resource_pretty_print($client->profile());

src/AsyncClient.php

+22
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,24 @@ final class AsyncClient implements AsyncClientInterface
4141
*/
4242
protected $client;
4343

44+
/**
45+
* @var array
46+
*/
47+
protected $options;
48+
4449
/**
4550
* @var AsyncStreamingClient
4651
*/
4752
protected $streamingClient;
4853

54+
/**
55+
* AsyncClient constructor.
56+
* @param string $consumerKey
57+
* @param string $consumerSecret
58+
* @param LoopInterface $loop
59+
* @param array $options
60+
* @param Client|null $client
61+
*/
4962
public function __construct(
5063
string $consumerKey,
5164
string $consumerSecret,
@@ -112,6 +125,15 @@ public function getCommandBus(): CommandBusInterface
112125
return $this->client->getFromContainer(CommandBusInterface::class);
113126
}
114127

128+
public function profile(): PromiseInterface
129+
{
130+
return $this->client->handle(new RequestCommand(
131+
new Request('GET', 'account/verify_credentials.json')
132+
))->then(function (ResponseInterface $response) {
133+
return resolve($this->client->handle(new HydrateCommand('Profile', $response->getBody()->getJson())));
134+
});
135+
}
136+
115137
public function user(string $user): PromiseInterface
116138
{
117139
return $this->client->handle(new RequestCommand(

src/Client.php

+88-7
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,34 @@
22

33
namespace ApiClients\Client\Twitter;
44

5+
use ApiClients\Client\Twitter\Resource\Async\Profile;
6+
use ApiClients\Client\Twitter\Resource\ProfileInterface;
57
use ApiClients\Client\Twitter\Resource\TweetInterface;
68
use ApiClients\Client\Twitter\Resource\UserInterface;
9+
use ApiClients\Foundation\Client as FoundationClient;
10+
use ApiClients\Foundation\Factory;
11+
use ApiClients\Foundation\Hydrator\CommandBus\Command\BuildSyncFromAsyncCommand;
12+
use ApiClients\Foundation\Oauth1\Middleware\Oauth1Middleware;
13+
use ApiClients\Foundation\Oauth1\Options as Oauth1Options;
14+
use ApiClients\Foundation\Options;
15+
use ApiClients\Foundation\Transport\Options as TransportOptions;
16+
use ApiClients\Tools\Psr7\Oauth1\Definition;
717
use React\EventLoop\Factory as LoopFactory;
818
use React\EventLoop\LoopInterface;
919
use function Clue\React\Block\await;
1020

1121
final class Client implements ClientInterface
1222
{
23+
/**
24+
* @var string
25+
*/
26+
private $consumerKey;
27+
28+
/**
29+
* @var string
30+
*/
31+
private $consumerSecret;
32+
1333
/**
1434
* @var LoopInterface
1535
*/
@@ -18,32 +38,83 @@ final class Client implements ClientInterface
1838
/**
1939
* @var AsyncClient
2040
*/
41+
protected $asyncClient;
42+
43+
/**
44+
* @var FoundationClient
45+
*/
2146
protected $client;
2247

2348
/**
2449
* @var StreamingClient
2550
*/
2651
protected $streamingClient;
2752

53+
/**
54+
* @var array
55+
*/
56+
protected $options;
57+
2858
public function __construct(
2959
string $consumerKey,
3060
string $consumerSecret
3161
) {
62+
$this->consumerKey = $consumerKey;
63+
$this->consumerSecret = $consumerSecret;
3264
$this->loop = LoopFactory::create();
33-
$this->client = new AsyncClient($consumerKey, $consumerSecret, $this->loop);
65+
66+
$this->options = ApiSettings::getOptions(
67+
$consumerKey,
68+
$consumerSecret,
69+
'Sync'
70+
);
71+
72+
$this->client = Factory::create($this->loop, $this->options);
73+
74+
$this->asyncClient = new AsyncClient($consumerKey, $consumerSecret, $this->loop, [], $this->client);
3475
}
3576

3677
public function withAccessToken(string $accessToken, string $accessTokenSecret): Client
3778
{
79+
$options = $this->options;
80+
// @codingStandardsIgnoreStart
81+
$options[Options::TRANSPORT_OPTIONS][TransportOptions::DEFAULT_REQUEST_OPTIONS][Oauth1Middleware::class][Oauth1Options::ACCESS_TOKEN] = new Definition\AccessToken($accessToken);
82+
$options[Options::TRANSPORT_OPTIONS][TransportOptions::DEFAULT_REQUEST_OPTIONS][Oauth1Middleware::class][Oauth1Options::TOKEN_SECRET] = new Definition\TokenSecret($accessTokenSecret);
83+
// @codingStandardsIgnoreEnd
84+
3885
$clone = clone $this;
39-
$clone->client = $this->client->withAccessToken($accessToken, $accessTokenSecret);
86+
$clone->client = Factory::create($this->loop, $options);
87+
$clone->asyncClient = (new AsyncClient(
88+
$this->consumerKey,
89+
$this->consumerSecret,
90+
$this->loop,
91+
[],
92+
$this->client
93+
))->withAccessToken($accessToken, $accessTokenSecret);
4094
return $clone;
4195
}
4296

4397
public function withOutAccessToken(): Client
4498
{
99+
$options = $this->options;
100+
// @codingStandardsIgnoreStart
101+
if (isset($options[Options::TRANSPORT_OPTIONS][TransportOptions::DEFAULT_REQUEST_OPTIONS][Oauth1Middleware::class][Oauth1Options::ACCESS_TOKEN])) {
102+
unset($options[Options::TRANSPORT_OPTIONS][TransportOptions::DEFAULT_REQUEST_OPTIONS][Oauth1Middleware::class][Oauth1Options::ACCESS_TOKEN]);
103+
}
104+
if (isset($options[Options::TRANSPORT_OPTIONS][TransportOptions::DEFAULT_REQUEST_OPTIONS][Oauth1Middleware::class][Oauth1Options::TOKEN_SECRET])) {
105+
unset($options[Options::TRANSPORT_OPTIONS][TransportOptions::DEFAULT_REQUEST_OPTIONS][Oauth1Middleware::class][Oauth1Options::TOKEN_SECRET]);
106+
}
107+
// @codingStandardsIgnoreEnd
108+
45109
$clone = clone $this;
46-
$clone->client = $this->client->withOutAccessToken();
110+
$clone->client = Factory::create($this->loop, $options);
111+
$clone->asyncClient = (new AsyncClient(
112+
$this->consumerKey,
113+
$this->consumerSecret,
114+
$this->loop,
115+
[],
116+
$this->client
117+
));
47118
return $clone;
48119
}
49120

@@ -52,8 +123,8 @@ public function stream(): StreamingClient
52123
if (!($this->streamingClient instanceof StreamingClient)) {
53124
$this->streamingClient = new StreamingClient(
54125
$this->loop,
55-
$this->client->getCommandBus(),
56-
$this->client->stream()
126+
$this->asyncClient->getCommandBus(),
127+
$this->asyncClient->stream()
57128
);
58129
}
59130

@@ -63,15 +134,25 @@ public function stream(): StreamingClient
63134
public function tweet(string $tweet): TweetInterface
64135
{
65136
return await(
66-
$this->client->tweet($tweet),
137+
$this->asyncClient->tweet($tweet),
138+
$this->loop
139+
);
140+
}
141+
142+
public function profile(): ProfileInterface
143+
{
144+
return await(
145+
$this->asyncClient->profile()->then(function (Profile $profile) {
146+
return $this->client->handle(new BuildSyncFromAsyncCommand(ProfileInterface::HYDRATE_CLASS, $profile));
147+
}),
67148
$this->loop
68149
);
69150
}
70151

71152
public function user(string $tweet): UserInterface
72153
{
73154
return await(
74-
$this->client->user($tweet),
155+
$this->asyncClient->user($tweet),
75156
$this->loop
76157
);
77158
}

src/Resource/Async/EmptyProfile.php

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace ApiClients\Client\Twitter\Resource\Async;
4+
5+
use ApiClients\Client\Twitter\Resource\EmptyProfile as BaseEmptyProfile;
6+
7+
class EmptyProfile extends BaseEmptyProfile
8+
{
9+
}

0 commit comments

Comments
 (0)