├── .styleci.yml
├── src
├── Exceptions
│ ├── TokenException.php
│ ├── ConfigException.php
│ ├── OperationException.php
│ ├── RequestException.php
│ ├── ClientException.php
│ └── ResponseException.php
├── Operations
│ ├── Unfollow.php
│ ├── Common
│ │ ├── HasName.php
│ │ ├── SerializesJson.php
│ │ └── HasParameters.php
│ ├── SubOperation.php
│ ├── Operation.php
│ ├── Reblog.php
│ ├── Follow.php
│ ├── CommentOptions.php
│ ├── Vote.php
│ ├── CustomJson.php
│ └── Comment.php
├── Contracts
│ └── Operations
│ │ └── Operation.php
├── Client
│ ├── Response.php
│ ├── Broadcaster.php
│ └── Client.php
├── Config
│ └── Config.php
├── Auth
│ ├── Token.php
│ └── Manager.php
├── Http
│ ├── HasHttpResponse.php
│ └── Client.php
└── Transactions
│ └── Transaction.php
├── .gitignore
├── .travis.yml
├── docs
├── css
│ └── extra.css
├── index.md
├── 01-configuration.md
├── 02-authentication.md
├── img
│ └── sc-logo.svg
└── 03-operations.md
├── tests
├── TestCase.php
├── Resources
│ └── stub-transaction.json
├── Operations
│ ├── OperationTest.php
│ ├── ReblogTest.php
│ ├── Common
│ │ ├── HasNameTraitTest.php
│ │ ├── SerializesJsonTest.php
│ │ └── HasParametersTraitTest.php
│ ├── VoteTest.php
│ ├── CommentOptionsTest.php
│ ├── FollowTest.php
│ └── CommentTest.php
├── Auth
│ ├── TokenTest.php
│ └── ManagerTest.php
├── Config
│ └── ConfigTest.php
├── Client
│ ├── ResponseTest.php
│ ├── ClientTest.php
│ └── BroadcasterTest.php
├── Http
│ ├── HasHttpResponseTest.php
│ └── ClientTest.php
├── Transactions
│ └── TransactionTest.php
└── Exceptions
│ └── ResponseExceptionTest.php
├── readme.md
├── mkdocs.yml
├── LICENSE
├── composer.json
└── phpunit.xml.dist
/.styleci.yml:
--------------------------------------------------------------------------------
1 | preset: recommended
2 |
3 | risky: false
4 |
5 | finder:
6 | name:
7 | - "*.php"
8 | path:
9 | - "src"
--------------------------------------------------------------------------------
/src/Exceptions/TokenException.php:
--------------------------------------------------------------------------------
1 | name = $name;
27 |
28 | return $this;
29 | }
30 |
31 | /**
32 | * Operation name getter.
33 | *
34 | * @return null|string
35 | */
36 | public function getName() : ?string
37 | {
38 | return $this->name;
39 | }
40 | }
--------------------------------------------------------------------------------
/tests/Resources/stub-transaction.json:
--------------------------------------------------------------------------------
1 | {
2 | "ref_block_num": 99999,
3 | "ref_block_prefix": 4094062943,
4 | "expired": true,
5 | "expiration": "2018-03-17T23:41:12",
6 | "operations": [
7 | [
8 | "vote",
9 | {
10 | "voter": "sparkesy43",
11 | "author": "gameon",
12 | "permlink": "nba-challenge-winner-s-for-03-15-2018-game-1-or-congratulations",
13 | "weight": 10000
14 | }
15 | ]
16 | ],
17 | "extensions": [],
18 | "signatures": [
19 | "20756ad9e9b45b9e6a2b9e6f3cd7b0d1c46c636e554cbcee307070cb81eb60fc353da3687ff7d50fb53013dc82b3687784a98de6286c3aa8011fe870dc3a35e6e8"
20 | ],
21 | "id": "4b1d2f863b6e4b133ceb61e75c00534f95ebdd03",
22 | "block_num": 0,
23 | "trx_num": 0
24 | }
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # SteemConnect V2 SDK for PHP.
2 |
3 | [](https://travis-ci.org/hernandev/sc2-sdk-php)
4 | [](https://codecov.io/gh/hernandev/sc2-sdk-php)
5 | [](https://packagist.org/packages/hernandev/sc2-sdk-php)
6 | [](https://packagist.org/packages/hernandev/sc2-sdk-php)
7 |
8 | Easily integrate STEEM blockchain into your PHP applications, though [SteemConnect](https://steemconnect.com).
9 |
10 | ## Documentation
11 |
12 | The complete documentation for this library can be read at:
13 | [https://hernandev.github.io/sc2-sdk-php](https://hernandev.github.io/sc2-sdk-php).
14 |
15 |
--------------------------------------------------------------------------------
/mkdocs.yml:
--------------------------------------------------------------------------------
1 | site_name: SteemConnect SDK for PHP
2 | theme:
3 | name: 'material'
4 | logo: 'img/sc-logo.svg'
5 | font:
6 | text: 'Roboto'
7 | code: 'Roboto Mono'
8 | repo_name: 'hernandev/sc2-sdk-php'
9 | repo_url: 'https://github.com/hernandev/sc2-sdk-php'
10 |
11 | extra_css:
12 | - 'css/extra.css'
13 | extra:
14 | social:
15 | - type: 'github'
16 | link: 'https://github.com/hernandev'
17 | - type: 'twitter'
18 | link: 'https://twitter.com/_hernandev'
19 | - type: 'linkedin'
20 | link: 'https://linkedin.com/in/hernandev'
21 | # Extensions
22 | markdown_extensions:
23 | - admonition
24 | - codehilite:
25 | linenums: true
26 | guess_lang: true
27 | - toc:
28 | permalink: true
29 | pages:
30 | - Home: index.md
31 | - Configuration: 01-configuration.md
32 | - Authentication: 02-authentication.md
33 | - Operations: 03-operations.md
34 |
--------------------------------------------------------------------------------
/tests/Operations/OperationTest.php:
--------------------------------------------------------------------------------
1 | 'bar']);
21 |
22 | // assert the parameters were correctly set.
23 | $this->assertEquals($operation->getParameters(), ['foo' => 'bar']);
24 |
25 | // assert the magic getters will retrieve parameters.
26 | $this->assertEquals('bar', $operation->foo);
27 | // assert the magic getters will retrieve class attributes as well.
28 | $this->assertEquals('foo', $operation->name);
29 | }
30 | }
--------------------------------------------------------------------------------
/src/Client/Response.php:
--------------------------------------------------------------------------------
1 | responseBody || !is_array($this->responseBody)) {
27 | // then just return null cause there's no transaction to parse.
28 | return null;
29 | }
30 |
31 | // otherwise, factories a transaction from the response body itself and return.
32 | return Transaction::factory($this->responseBody);
33 | }
34 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Diego Hernandes
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.
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hernandev/sc2-sdk-php",
3 | "description": "PHP SDK for SteemConnect V2",
4 | "type": "library",
5 | "keywords": ["steem", "steemconnect", "steem-connect", "sc2", "sdk"],
6 | "license": "MIT",
7 | "authors": [
8 | {
9 | "name": "Diego Hernandes",
10 | "email": "diego@hernandev.com"
11 | }
12 | ],
13 | "minimum-stability": "stable",
14 | "autoload": {
15 | "psr-4": {
16 | "SteemConnect\\": "src/"
17 | }
18 | },
19 | "autoload-dev": {
20 | "psr-4": {
21 | "SteemConnect\\": "tests/"
22 | }
23 | },
24 | "require": {
25 | "league/oauth2-client": "^2.3",
26 | "php": ">=7.1.0",
27 | "ext-curl": "*",
28 | "ext-json": "*",
29 | "illuminate/support": "^5.6",
30 | "symfony/http-foundation": "^4.0",
31 | "guzzlehttp/guzzle": "^6.3",
32 | "hernandev/oauth2-sc2": "^0.10.1",
33 | "nesbot/carbon": "^1.23"
34 | },
35 | "require-dev": {
36 | "phpunit/phpunit": "^7.0",
37 | "mockery/mockery": "^1.0",
38 | "symfony/var-dumper": "^4.0"
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
20 |
22 |
23 |
24 |
25 | ./tests/
26 |
27 |
28 |
29 |
30 | ./src
31 |
32 | ./vendor
33 | ./tests
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/tests/Operations/ReblogTest.php:
--------------------------------------------------------------------------------
1 | account('testing-reblog-account');
25 | $this->assertEquals('testing-reblog-account', $reblog->account);
26 |
27 | // assert set and get.
28 | $reblog->author('testing-author');
29 | $this->assertEquals('testing-author', $reblog->author);
30 |
31 | // assert set and get.
32 | $reblog->permLink('some-post');
33 | $this->assertEquals('some-post', $reblog->permlink);
34 |
35 | // empty instance.
36 | $reblog = new Reblog();
37 |
38 | // test reblog method.
39 | $reblog->reblog('test-author', 'test-permlink');
40 | $this->assertEquals('test-author', $reblog->author);
41 | $this->assertEquals('test-permlink', $reblog->permlink);
42 | }
43 | }
--------------------------------------------------------------------------------
/tests/Operations/Common/HasNameTraitTest.php:
--------------------------------------------------------------------------------
1 | getDumbInstance();
41 |
42 | // assert both getter and setter exists.
43 | $this->assertTrue(method_exists($dumb, 'getName'));
44 | $this->assertTrue(method_exists($dumb, 'setName'));
45 |
46 | // assert no default name exists.
47 | $this->assertNull($dumb->getName());
48 |
49 | // call the setter and hold it's return.
50 | $setReturn = $dumb->setName('foo');
51 |
52 | // assert the fluent return.
53 | $this->assertSame($dumb, $setReturn);
54 |
55 | // now assert the actual content was correctly set.
56 | $this->assertEquals('foo', $dumb->getName());
57 | }
58 | }
--------------------------------------------------------------------------------
/src/Operations/SubOperation.php:
--------------------------------------------------------------------------------
1 | setName($name);
37 |
38 | // set sub operation parameters.
39 | $this->setParameters($parameters);
40 | }
41 |
42 | /**
43 | * Magic getter for operations.
44 | *
45 | * @param $name
46 | *
47 | * @return array|null|Operation|SubOperation|string
48 | */
49 | public function __get($name)
50 | {
51 | if (property_exists($this, $name)) {
52 | return $this->{$name};
53 | }
54 |
55 | return $this->getParameter($name);
56 | }
57 | }
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | # SteemConnect PHP SDK
2 |
3 | This is the documentation for **[SteemConnect](https://steemconnect.com) [PHP SDK](https://github.com/hernandev/sc2-php-sdk)**, which is available at **[https://github.com/hernandev/sc2-sdk-php](https://github.com/hernandev/sc2-sdk-php)**.
4 |
5 | ## How to Read the Code Examples.
6 |
7 | This documentation was built with several code examples.
8 |
9 | For code highlighting and easy to understand reasons, any PHP code will start with a `app = $app;
37 |
38 | return $this;
39 | }
40 |
41 | /**
42 | * Returns the current application name configured.
43 | *
44 | * @return null|string
45 | */
46 | public function getApp() : ?string
47 | {
48 | return $this->app;
49 | }
50 |
51 | /**
52 | * Set the community using the SDK.
53 | *
54 | * @param string|null $community
55 | *
56 | * @return self
57 | */
58 | public function setCommunity(string $community = null) : self
59 | {
60 | $this->community = $community;
61 |
62 | return $this;
63 | }
64 |
65 | /**
66 | * Returns the community using the SDK.
67 | *
68 | * @return null|string
69 | */
70 | public function getCommunity() : ?string
71 | {
72 | return $this->community;
73 | }
74 | }
--------------------------------------------------------------------------------
/src/Operations/Operation.php:
--------------------------------------------------------------------------------
1 | name = $name;
45 | // set parameters directly, because of fluent interfaces.
46 | $this->parameters = $parameters;
47 | }
48 |
49 | /**
50 | * Magic getter for operations.
51 | *
52 | * @param $name
53 | *
54 | * @return array|null|Operation|SubOperation|string
55 | */
56 | public function __get($name)
57 | {
58 | if (property_exists($this, $name)) {
59 | return $this->{$name};
60 | }
61 |
62 | return $this->getParameter($name);
63 | }
64 | }
--------------------------------------------------------------------------------
/src/Auth/Token.php:
--------------------------------------------------------------------------------
1 | jsonSerialize();
68 | }
69 | }
--------------------------------------------------------------------------------
/src/Exceptions/ResponseException.php:
--------------------------------------------------------------------------------
1 | setHttpResponse($response);
29 |
30 | // parse the message and status code, then call parent constructor.
31 | parent::__construct($this->parseResponseMessage(), $this->responseStatusCode, $previous);
32 | }
33 |
34 | /**
35 | * Parses the error response message into a single string for the exception.
36 | *
37 | * @return string
38 | */
39 | protected function parseResponseMessage() : string
40 | {
41 | // if the response is a json string.
42 | if ($this->responseIsJson()) {
43 | // collect the array body keys.
44 | $body = collect($this->responseBody);
45 |
46 | // parse the error name.
47 | $error = $body->get('error', null);
48 | // parse the error message, defaulting to HTTP.
49 | $message = $body->get('error_description', $this->responseStatusMessage);
50 |
51 | // return the formatted error message.
52 | return $error ? "{$error}: {$message}" : $message;
53 | }
54 |
55 | // in case the body is a string, just not an array / json.
56 | // return just the status message otherwise.
57 | return is_string($this->responseBody) ? strip_tags($this->responseBody) : $this->responseStatusMessage;
58 | }
59 | }
--------------------------------------------------------------------------------
/tests/Operations/VoteTest.php:
--------------------------------------------------------------------------------
1 | voter('some-voter');
24 | $this->assertEquals('some-voter', $vote->voter);
25 |
26 | // assert set and get.
27 | $vote->account('some-voter-account');
28 | $this->assertEquals('some-voter-account', $vote->voter);
29 |
30 | // assert set and get.
31 | $vote->author('author');
32 | $this->assertEquals('author', $vote->author);
33 |
34 | // assert set and get.
35 | $vote->permLink('some-post');
36 | $this->assertEquals('some-post', $vote->permlink);
37 |
38 | // assert set and get.
39 | $vote->on('user', 'post-link');
40 | $this->assertEquals('user', $vote->author);
41 | $this->assertEquals('post-link', $vote->permlink);
42 |
43 | // weight tests.
44 | $vote->weight(1);
45 | $this->assertEquals(10000, $vote->weight);
46 |
47 | // normal units
48 | $vote->weight(10000);
49 | $this->assertEquals(10000, $vote->weight);
50 |
51 | // percent alias.
52 | $vote->percent(0.5);
53 | $this->assertEquals(5000, $vote->weight);
54 |
55 | // test positive value on downvote.
56 | $vote->downVote(0.5);
57 | $this->assertEquals(-5000, $vote->weight);
58 |
59 | // test negative value on downvote.
60 | $vote->downVote(-5000);
61 | $this->assertEquals(-5000, $vote->weight);
62 |
63 | // test upvote.
64 | $vote->upVote(-5000);
65 | $this->assertEquals(5000, $vote->weight);
66 |
67 | // test upvote.
68 | $vote->upVote(0.7);
69 | $this->assertEquals(7000, $vote->weight);
70 | }
71 | }
--------------------------------------------------------------------------------
/src/Operations/Reblog.php:
--------------------------------------------------------------------------------
1 | getId()) {
34 | $this->setId('follow');
35 | }
36 | }
37 |
38 | /**
39 | * Set the follower name.
40 | *
41 | * @param string $account
42 | *
43 | * @return self
44 | */
45 | public function account(string $account) : self
46 | {
47 | $this->setRequiredPostingAuths([$account]);
48 |
49 | $this->getSubOperation()->setParameter('account', $account);
50 |
51 | return $this;
52 | }
53 |
54 | /**
55 | * Set the follower name.
56 | *
57 | * @param string $author
58 | *
59 | * @return self
60 | */
61 | public function author(string $author) : self
62 | {
63 | $this->getSubOperation()->setParameter('author', $author);
64 |
65 | return $this;
66 | }
67 |
68 | /**
69 | * Set the follower name.
70 | *
71 | * @param string $permLink
72 | *
73 | * @return self
74 | */
75 | public function permLink(string $permLink) : self
76 | {
77 | $this->getSubOperation()->setParameter('permlink', $permLink);
78 |
79 | return $this;
80 | }
81 |
82 | /**
83 | * Set the original author username.
84 | *
85 | * @param string $author
86 | * @param string $permLink
87 | *
88 | * @return self
89 | */
90 | public function reblog(string $author, string $permLink) : self
91 | {
92 | return $this->author($author)->permLink($permLink);
93 | }
94 | }
--------------------------------------------------------------------------------
/tests/Operations/CommentOptionsTest.php:
--------------------------------------------------------------------------------
1 | author('foo-user');
24 | $comment->permLink('foo-permlink');
25 |
26 | // start the comment options.
27 | $commentOptions = new CommentOptions();
28 |
29 | // set the comment operation pair.
30 | $commentOptions->of($comment);
31 |
32 | // assert the author and permlink were set from the comment.
33 | $this->assertEquals('foo-user', $commentOptions->author);
34 | $this->assertEquals('foo-permlink', $commentOptions->permlink);
35 | }
36 |
37 | /**
38 | * Test the setting of another options.
39 | */
40 | public function test_options_setters()
41 | {
42 | // start a comment.
43 | $comment = new Comment();
44 |
45 | // set the comment author and permlink.
46 | $comment->author('foo-user');
47 | $comment->permLink('foo-permlink');
48 |
49 | // start the comment options.
50 | $commentOptions = new CommentOptions();
51 |
52 | // disable curation.
53 | $commentOptions->allowCurationRewards(false);
54 | // assert it was set as false.
55 | $this->assertFalse($commentOptions->allow_curation_rewards);
56 |
57 | // disable votes.
58 | $commentOptions->allowVotes(false);
59 | // assert it was set as false.
60 | $this->assertFalse($commentOptions->allow_votes);
61 |
62 | // set the max accepted payout.
63 | $commentOptions->maxAcceptedPayout(10);
64 | // assert the value formatting.
65 | $this->assertEquals('10.000 SBD', $commentOptions->max_accepted_payout);
66 |
67 | // set the SBD percent.
68 | $commentOptions->percentSteemDollars(9000);
69 | // assert the correct value.
70 | $this->assertEquals(9000, $commentOptions->percent_steem_dollars);
71 | }
72 | }
--------------------------------------------------------------------------------
/src/Operations/Common/SerializesJson.php:
--------------------------------------------------------------------------------
1 | parameters;
31 |
32 | // collect and loop on json parameters.
33 | collect($this->jsonParameters)->each(function ($parameter) use (&$parameters) {
34 | // get the current value.
35 | $value = Arr::get($parameters, $parameter);
36 |
37 | // if the current value is indeed an array...
38 | if (is_array($value)) {
39 | // rewrite it's value with the JSON serialized version.
40 | Arr::set($parameters, $parameter, utf8_encode(json_encode($value)));
41 | }
42 |
43 | // set the array as json string.
44 | if (is_object($value) && method_exists($value, 'toArray')) {
45 | Arr::set($parameters, $parameter, utf8_encode(json_encode($value->toArray())));
46 | }
47 |
48 | // set the value as it is, if string.
49 | if (is_string($value)) {
50 | Arr::set($parameters, $parameter, utf8_encode($value));
51 | }
52 | });
53 |
54 | // return the parameters.
55 | return $parameters;
56 | }
57 |
58 | /**
59 | * Array representation of the operation.
60 | *
61 | * @return array
62 | */
63 | public function toArray()
64 | {
65 | // only call the getName if the method exists.
66 | if (method_exists($this, 'getName')) {
67 | return [ $this->getName(), $this->serializeJsonParameters() ];
68 | }
69 |
70 | // return the raw serialization method otherwise.
71 | return $this->serializeJsonParameters();
72 | }
73 |
74 | /**
75 | * JSON serialization method.
76 | *
77 | * {@inheritdoc}
78 | */
79 | public function jsonSerialize()
80 | {
81 | return $this->toArray();
82 | }
83 | }
--------------------------------------------------------------------------------
/src/Auth/Manager.php:
--------------------------------------------------------------------------------
1 | config = $config;
50 |
51 | // setup provider.
52 | $this->provider = $provider;
53 |
54 | // set the access token on the manager instance.
55 | $this->accessToken = $token;
56 | }
57 |
58 | /**
59 | * Returns the provider authorization URL.
60 | *
61 | * @param array $options Additional options for the URL building.
62 | *
63 | * @return string
64 | */
65 | public function getAuthorizationUrl(array $options = []): string
66 | {
67 | return $this->provider->getAuthorizationUrl($options);
68 | }
69 |
70 | /**
71 | * Parses the OAuth2 callback/return code and exchange for an access token.
72 | *
73 | * @param string|null $code
74 | *
75 | * @return Token
76 | */
77 | public function parseReturn(string $code = null)
78 | {
79 | try {
80 | // get the original token object.
81 | $oAuthToken = $this->provider->parseReturn($code);
82 | } catch (\Exception $e) {
83 | // throw token exception if return parsing could not be successful.
84 | throw new TokenException('Error while exchanging access code with access token.');
85 | }
86 |
87 |
88 | // return a new SDK token object.
89 | $this->accessToken = new Token($oAuthToken->jsonSerialize());
90 |
91 | // return the access token parsed from response.
92 | return $this->accessToken;
93 | }
94 | }
--------------------------------------------------------------------------------
/src/Operations/Follow.php:
--------------------------------------------------------------------------------
1 | getId()) {
34 | $this->setId('follow');
35 | }
36 | }
37 |
38 | /**
39 | * Alias for the follower account.
40 | *
41 | * @param string $account
42 | *
43 | * @return Follow
44 | */
45 | public function account(string $account): self
46 | {
47 | return $this->follower($account);
48 | }
49 |
50 |
51 | /**
52 | * Set the follower name.
53 | *
54 | * @param string $follower
55 | *
56 | * @return self
57 | */
58 | public function follower(string $follower) : self
59 | {
60 | $this->setRequiredPostingAuths([$follower]);
61 |
62 | $this->getSubOperation()->setParameter('follower', $follower);
63 |
64 | return $this;
65 | }
66 |
67 | /**
68 | * Set the user that will be followed.
69 | *
70 | * @param string $account
71 | * @param bool $following
72 | *
73 | * @return self
74 | */
75 | public function following(string $account, bool $following = true) : self
76 | {
77 | // set the account to follow or unfollow.
78 | $this->getSubOperation()->setParameter('following', $account);
79 |
80 | // determine the what section based on the following flag,
81 | $what = $following ? ['blog'] : [];
82 |
83 | // set the what parameter.
84 | $this->getSubOperation()->setParameter('what', $what);
85 |
86 | // return it.
87 | return $this;
88 | }
89 |
90 | /**
91 | * Alias for follow.
92 | *
93 | * @param string $account
94 | *
95 | * @return self
96 | */
97 | public function follow(string $account) : self
98 | {
99 | return $this->following($account, true);
100 | }
101 |
102 | /**
103 | * Alias for unfollow.
104 | *
105 | * @param string $account
106 | *
107 | * @return self
108 | */
109 | public function unfollow(string $account) : self
110 | {
111 | return $this->following($account, false);
112 | }
113 | }
--------------------------------------------------------------------------------
/tests/Auth/TokenTest.php:
--------------------------------------------------------------------------------
1 | validToken = [
29 | 'username' => 'foo-username',
30 | 'access_token' => 'jwt.dummy.token',
31 | 'refresh_token' => 'jwt.dummy.refresh',
32 | 'expires' => Carbon::now()->addDays(1)->timestamp,
33 | 'resource_owner_id' => 'foo-username',
34 | ];
35 | }
36 |
37 | /**
38 | * Token parsing.
39 | */
40 | public function test_token_parsing()
41 | {
42 | $token = Token::fromArray($this->validToken);
43 |
44 | $this->assertInstanceOf(Token::class, $token);
45 | }
46 |
47 | /**
48 | * Empty token.
49 | */
50 | public function test_empty_token_parsing_exception()
51 | {
52 | try {
53 | Token::fromArray([]);
54 | } catch (\Exception $e) {
55 | $this->assertInstanceOf(TokenException::class, $e);
56 | }
57 | }
58 |
59 | /**
60 | * Token JSON serialization tests.
61 | */
62 | public function test_json_serialization()
63 | {
64 | $originalJson = json_encode($this->validToken);
65 |
66 | $token = Token::fromArray($this->validToken);
67 |
68 | $this->assertEquals($originalJson, json_encode($token->jsonSerialize()));
69 |
70 | $this->assertEquals($originalJson, json_encode($token->toArray()));
71 | }
72 |
73 | /**
74 | * Token JSON string parsing tests.
75 | */
76 | public function test_token_parsing_from_json_string()
77 | {
78 | $jsonString = json_encode($this->validToken);
79 |
80 | $token = Token::fromJsonString($jsonString);
81 |
82 | $this->assertInstanceOf(Token::class, $token);
83 | }
84 |
85 | /**
86 | * Invalid token parsing tests.
87 | */
88 | public function test_token_parsing_from_json_string_with_invalid_data()
89 | {
90 | $jsonString = json_encode(['foo' => 'bar']);
91 |
92 | try {
93 | $token = Token::fromJsonString($jsonString);
94 | } catch (\Exception $e) {
95 | $this->assertInstanceOf(TokenException::class, $e);
96 | }
97 |
98 | $jsonString = '{';
99 |
100 | try {
101 | $token = Token::fromJsonString($jsonString);
102 | } catch (\Exception $e) {
103 | $this->assertInstanceOf(TokenException::class, $e);
104 | }
105 | }
106 | }
--------------------------------------------------------------------------------
/src/Http/HasHttpResponse.php:
--------------------------------------------------------------------------------
1 | responseInstance;
50 | }
51 |
52 | /**
53 | * Configure the http response on the current resource.
54 | *
55 | * @param ResponseInterface $response
56 | */
57 | public function setHttpResponse(ResponseInterface $response)
58 | {
59 | // assign the http response instance itself.
60 | $this->responseInstance = $response;
61 |
62 | // assign the http response status code.
63 | $this->responseStatusCode = $response->getStatusCode();
64 |
65 | // assign the http response status message.
66 | $this->responseStatusMessage = $response->getReasonPhrase();
67 |
68 | // assign the http response headers.
69 | $this->responseHeaders = collect($response->getHeaders());
70 |
71 | // assign the parsed http response body.
72 | $this->responseBody = $this->decodeResponseBody($response->getBody());
73 |
74 | }
75 |
76 | /**
77 | * Decode the response body, parsing to array when json.
78 | *
79 | * @param StreamInterface $body
80 | *
81 | * @return mixed|string
82 | */
83 | protected function decodeResponseBody(StreamInterface $body)
84 | {
85 | if ($this->responseIsJson()) {
86 | return json_decode((string) $body, true);
87 | } else {
88 | return (string) $body;
89 | }
90 | }
91 |
92 | /**
93 | * Detect the response as being a json response or not.
94 | *
95 | * @return bool
96 | */
97 | protected function responseIsJson() : bool
98 | {
99 | $type = json_encode($this->responseHeaders->get('Content-Type'));
100 |
101 | return Str::contains($type, 'json');
102 | }
103 | }
--------------------------------------------------------------------------------
/tests/Operations/Common/SerializesJsonTest.php:
--------------------------------------------------------------------------------
1 | jsonParameters = ['foo', 'bar', 'baz'];
23 | }
24 | }
25 |
26 | /**
27 | * Class SerializesJsonTest.
28 | *
29 | * Tests for the SerializesJson trait.
30 | */
31 | class SerializesJsonTest extends TestCase implements \JsonSerializable
32 | {
33 | // enable both traits.
34 | use HasParameters;
35 | use SerializesJson;
36 |
37 | /**
38 | * Test serialization (using the test class itself.)
39 | */
40 | public function test_json_serialize_calls_array_transform()
41 | {
42 | // custom set name.
43 | $this->setName('foo');
44 |
45 | // some fake data for testing.
46 | $fakeData = [ 'bar' => 'baz', 'obj' => collect(['a']) ];
47 |
48 | // set some parameters
49 | $this->parameters = $fakeData;
50 |
51 | // set the name of the json parameters key.
52 | $this->jsonParameters = 'foo';
53 |
54 | // expected result array format.
55 | $expectedArray = [
56 | 'foo', $fakeData,
57 | ];
58 |
59 | // encode the data.
60 | $expectedJson = json_encode($expectedArray);
61 |
62 | // encoded result
63 | $json = json_encode($this->toArray());
64 |
65 | // assert both json versions are the same.
66 | $this->assertEquals($expectedJson, $json);
67 |
68 | // assert the array transformation.
69 | $this->assertEquals($expectedArray, $this->toArray());
70 | }
71 |
72 | /**
73 | * Test for operations / instances that don't have name setters and getter.
74 | */
75 | public function test_nameless_serialization()
76 | {
77 | // start a dump class instance.
78 | $dumb = new DumbJsonClass();
79 |
80 | // set some parameters.
81 | $parameters = [
82 | 'foo' => 'bar',
83 | 'bar' => collect(['baz']),
84 | 'baz' => ['a', 'b', 'c']
85 | ];
86 |
87 | // create a json version, with external json encoding.
88 | $parametersJson = json_encode([
89 | 'foo' => 'bar',
90 | 'bar' => json_encode(collect(['baz'])),
91 | 'baz' => json_encode(['a', 'b', 'c'])
92 | ]);
93 |
94 | // set the parameters on the dump implementation.
95 | $dumb->setParameters($parameters);
96 |
97 | // finally call the json encode on the dump implementation.
98 | $jsonSerialized = json_encode($dumb);
99 |
100 | // assert the parameters match after serialization.
101 | $this->assertEquals($parametersJson, $jsonSerialized);
102 | }
103 | }
--------------------------------------------------------------------------------
/src/Operations/CommentOptions.php:
--------------------------------------------------------------------------------
1 | parameters, $parameters));
35 | }
36 |
37 | /**
38 | * Set author and permlink from a comment instance.
39 | *
40 | * @param Comment $comment
41 | *
42 | * @return self
43 | */
44 | public function of(Comment $comment) : self
45 | {
46 | return $this->author($comment->author)->permLink($comment->permlink);
47 | }
48 |
49 | /**
50 | * Author parameter setter.
51 | *
52 | * @param string $author
53 | *
54 | * @return $this
55 | */
56 | public function author(string $author) : self
57 | {
58 | return $this->setParameter('author', $author);
59 | }
60 |
61 | /**
62 | * PermLink parameter setter.
63 | *
64 | * @param string $permLink
65 | *
66 | * @return $this
67 | */
68 | public function permLink(string $permLink) : self
69 | {
70 | return $this->setParameter('permlink', $permLink);
71 | }
72 |
73 | /**
74 | * Set the max payout for the comment.
75 | *
76 | * @param float $maxPayout
77 | *
78 | * @return self
79 | */
80 | public function maxAcceptedPayout(float $maxPayout) : self
81 | {
82 | // format the number with 3 decimal digits.
83 | $max = number_format($maxPayout, 3, '.', '');
84 |
85 | return $this->setParameter('max_accepted_payout', "{$max} SBD");
86 | }
87 |
88 | /**
89 | * @param $value
90 | *
91 | * @return self
92 | */
93 | public function percentSteemDollars($value) : self
94 | {
95 | return $this->setParameter('percent_steem_dollars', $value);
96 | }
97 |
98 | /**
99 | * @param bool $allowVotes
100 | *
101 | * @return self
102 | */
103 | public function allowVotes(bool $allowVotes = true) : self
104 | {
105 | return $this->setParameter('allow_votes', $allowVotes);
106 | }
107 |
108 | /**
109 | * @param bool $allowCuration
110 | *
111 | * @return self
112 | */
113 | public function allowCurationRewards(bool $allowCuration = true) : self
114 | {
115 | return $this->setParameter('allow_curation_rewards', $allowCuration);
116 | }
117 | }
--------------------------------------------------------------------------------
/tests/Config/ConfigTest.php:
--------------------------------------------------------------------------------
1 | clientId, $this->clientSecret);
23 | }
24 |
25 | /**
26 | * Test the construction and the inheritance of the config instance.
27 | */
28 | public function test_construction()
29 | {
30 | // generate a local instance of the config class.
31 | // passing the default client and secret for testing.
32 | $config = new Config($this->clientId, $this->clientSecret);
33 |
34 | // assert the client id and secret were set correctly.
35 | $this->assertEquals($config->getClientId(), $this->clientId);
36 | $this->assertEquals($config->getClientSecret(), $this->clientSecret);
37 |
38 | // assert the instance if actually the SDK config.
39 | $this->assertInstanceOf(Config::class, $config);
40 | // assert the config class inherits the OAuth config class.
41 | $this->assertInstanceOf(OAuthConfig::class, $config);
42 | }
43 |
44 | /**
45 | * Test the default application name on the SDK.
46 | */
47 | public function test_default_app_name()
48 | {
49 | // get a default config instance from factory.
50 | $config = $this->factoryConfig();
51 |
52 | // assert the default application name.
53 | $this->assertEquals('sc2-php-sdk/1.0', $config->getApp());
54 | }
55 |
56 | /**
57 | * Test the customizations on the application name/version.
58 | */
59 | public function test_customization_of_app_name()
60 | {
61 | // factory a default configuration instance.
62 | $config = $this->factoryConfig();
63 |
64 | // customize the application name.
65 | $setReturn = $config->setApp('testing/0.10.0');
66 |
67 | // assert fluent return.
68 | $this->assertSame($config, $setReturn);
69 |
70 | // assert the customized application name was actually set on the instance
71 | $this->assertEquals('testing/0.10.0', $config->getApp());
72 | }
73 |
74 | /**
75 | * Test the default community on the configuration.
76 | */
77 | public function test_default_community_is_empty()
78 | {
79 | // factory config.
80 | $config = $this->factoryConfig();
81 |
82 | // the default community should be null.
83 | $this->assertNull($config->getCommunity());
84 | }
85 |
86 | /**
87 | * Test the custom community setting.
88 | */
89 | public function test_customization_of_community()
90 | {
91 | // factory config.
92 | $config = $this->factoryConfig();
93 |
94 | // customize the community.
95 | $setReturn = $config->setCommunity('some-community');
96 |
97 | // assert the return is fluent.
98 | $this->assertSame($config, $setReturn);
99 |
100 | // the default community should be null.
101 | $this->assertEquals('some-community', $config->getCommunity());
102 | }
103 | }
--------------------------------------------------------------------------------
/src/Operations/Vote.php:
--------------------------------------------------------------------------------
1 | parameters, $parameters));
26 | }
27 |
28 | /**
29 | * Voter/account parameter setter.
30 | *
31 | * @param string $voter
32 | *
33 | * @return self
34 | */
35 | public function voter(string $voter) : self
36 | {
37 | return $this->setParameter('voter', $voter);
38 | }
39 |
40 | /**
41 | * Alias for the voter setter.
42 | *
43 | * @param string $account
44 | *
45 | * @return self
46 | */
47 | public function account(string $account) : self
48 | {
49 | return $this->voter($account);
50 | }
51 |
52 | /**
53 | * Author parameter setter.
54 | *
55 | * @param string $author
56 | *
57 | * @return self
58 | */
59 | public function author(string $author) : self
60 | {
61 | return $this->setParameter('author', $author);
62 | }
63 |
64 | /**
65 | * PermLink parameter setter.
66 | *
67 | * @param string $permLink
68 | *
69 | * @return self
70 | */
71 | public function permLink(string $permLink) : self
72 | {
73 | return $this->setParameter('permlink', $permLink);
74 | }
75 |
76 | /**
77 | * Simple vote author & permlink alias.
78 | *
79 | * @param string $author
80 | * @param string $permlink
81 | *
82 | * @return self
83 | */
84 | public function on(string $author, string $permlink) : self
85 | {
86 | return $this->author($author)->permLink($permlink);
87 | }
88 |
89 | /**
90 | * Up vote alias.
91 | *
92 | * @param int|float $weight
93 | *
94 | * @return self
95 | */
96 | public function upVote($weight = 1) : self
97 | {
98 | return $this->weight(abs($weight));
99 | }
100 |
101 | /**
102 | * Down vote alias.
103 | *
104 | * @param int|float $weight
105 | *
106 | * @return self
107 | */
108 | public function downVote($weight = -1) : self
109 | {
110 | return $this->weight(abs($weight) * -1);
111 | }
112 |
113 | /**
114 | * Weight parameter setter.
115 | *
116 | * Notice: This value should be a float between 0 and 1 if integers are disabled in configuration.
117 | *
118 | * @param float|int $weight For integers usage, pass 7500 for 75%, for decimal, pass 0.75 for 75%.
119 | *
120 | * @return self
121 | */
122 | public function weight($weight) : self
123 | {
124 | // detect decimal vs big integer for vote weight.
125 | if (abs($weight) > 0 && abs($weight) <= 1) {
126 | $realWeight = $weight * 10000;
127 | } else {
128 | $realWeight = $weight;
129 | }
130 |
131 | return $this->setParameter('weight', $realWeight);
132 | }
133 |
134 | /**
135 | * Alias for weight setter.
136 | *
137 | * @param $percent
138 | *
139 | * @return self
140 | */
141 | public function percent($percent) : self
142 | {
143 | return $this->weight($percent);
144 | }
145 | }
--------------------------------------------------------------------------------
/tests/Auth/ManagerTest.php:
--------------------------------------------------------------------------------
1 | mockProvider();
55 | // mock the authorization method to a given return.
56 | $provider->shouldReceive('getAuthorizationUrl')->andReturn('https://foo.bar/authorization');
57 |
58 | // start a manager instance.
59 | $manager = new Manager($this->mockConfig(), $provider);
60 |
61 | // assert the url building matches.
62 | $this->assertEquals($manager->getAuthorizationUrl(), 'https://foo.bar/authorization');
63 | }
64 |
65 | /**
66 | * Test token parsing from callback.
67 | */
68 | public function test_parsing_return()
69 | {
70 | // start a mock oauth provider.
71 | $provider = $this->mockProvider();
72 |
73 | // mock an access token.
74 | $mockToken = $this->mockAccessToken();
75 |
76 | // mock the JSON serialization.
77 | $mockToken->shouldReceive('jsonSerialize')->andReturn([ "access_token" => "foo"]);
78 |
79 | // mock the parse return method.
80 | $provider->shouldReceive('parseReturn')->andReturn($mockToken);
81 |
82 | // start a manager instance.
83 | $manager = new Manager($this->mockConfig(), $provider);
84 |
85 | // parse the return from oauth.
86 | $token = $manager->parseReturn();
87 |
88 | // assert the token was returned properly.
89 | $this->assertEquals("foo", $token->getToken());
90 | }
91 |
92 | /**
93 | * Test the custom exception throw from parse error (token exception).
94 | */
95 | public function test_parsing_return_error_custom_exception()
96 | {
97 | // start a mock oauth provider.
98 | $provider = $this->mockProvider();
99 |
100 | // the provider should throw an exception when the
101 | // parse return method is called.
102 | $provider->shouldReceive('parseReturn')->andReturnUsing(function () {
103 | throw new \Exception();
104 | });
105 |
106 | // start a manager instance.
107 | $manager = new Manager($this->mockConfig(), $provider);
108 |
109 | // try the parse.
110 | try {
111 | // this will throw an exception.
112 | $manager->parseReturn();
113 | } catch (\Exception $e) {
114 | // the exception must be of the TokenException type.
115 | $this->assertInstanceOf(TokenException::class, $e);
116 | }
117 | }
118 | }
--------------------------------------------------------------------------------
/src/Operations/Common/HasParameters.php:
--------------------------------------------------------------------------------
1 | parameters = array_merge($this->parameters, $parameters);
33 | } else {
34 | $this->parameters = $parameters;
35 | }
36 |
37 | return $this;
38 | }
39 |
40 | /**
41 | * Get the parameters array as they are.
42 | *
43 | * @return array
44 | */
45 | public function getParameters() : array
46 | {
47 | return $this->parameters;
48 | }
49 |
50 | /**
51 | * Fluent parameters setter.
52 | *
53 | * @param string $key
54 | * @param null $value
55 | *
56 | * @return $this
57 | */
58 | public function setParameter(string $key, $value = null) : self
59 | {
60 | // set a parameter value.
61 | Arr::set($this->parameters, $key, $value);
62 |
63 | // fluent return.
64 | return $this;
65 | }
66 |
67 | /**
68 | * Parameters getter.
69 | *
70 | * @param string $key
71 | *
72 | * @return null|string|array|Operation|SubOperation
73 | */
74 | public function getParameter(string $key)
75 | {
76 | return Arr::get($this->parameters, $key);
77 | }
78 |
79 | /**
80 | * Set a inner parameter.
81 | *
82 | * @param string $parameter
83 | * @param string $innerParameter
84 | * @param null $value
85 | *
86 | * @return self
87 | */
88 | public function setInnerParameter(string $parameter, string $innerParameter, $value = null) : self
89 | {
90 | Arr::set($this->parameters, "{$parameter}.{$innerParameter}", $value);
91 |
92 | return $this;
93 | }
94 |
95 | /**
96 | * Retrieve a inner parameter key.
97 | *
98 | * @param string $parameter
99 | * @param string $innerParameter
100 | *
101 | * @return mixed
102 | */
103 | public function getInnerParameter(string $parameter, string $innerParameter)
104 | {
105 | return Arr::get($this->parameters, "{$parameter}.{$innerParameter}");
106 | }
107 |
108 | /**
109 | * Unset a previously set parameter.
110 | *
111 | * @param string $key Parameter to remove.
112 | *
113 | * @return bool
114 | */
115 | public function forgetParameter(string $key)
116 | {
117 | // forget the element on the parameters array.
118 | Arr::forget($this->parameters, $key);
119 |
120 | // return true if the parameter no longer exists.
121 | return !Arr::has($this->parameters, $key);
122 | }
123 |
124 | /**
125 | * Unset a previously set inner parameter.
126 | *
127 | * @param string $parameter Parameter key to remove.
128 | * @param string $innerParameter Inner parameter key to remove.
129 | *
130 | * @return bool
131 | */
132 | public function forgetInnerParameter(string $parameter, string $innerParameter)
133 | {
134 | // forget the element on the parameters array.
135 | Arr::forget($this->parameters, "{$parameter}.{$innerParameter}");
136 |
137 | // return the parameter key existence, to indicate operation success or failure.
138 | return !Arr::has($this->parameters, "{$parameter}.{$innerParameter}");
139 | }
140 | }
--------------------------------------------------------------------------------
/docs/01-configuration.md:
--------------------------------------------------------------------------------
1 | # Configuration
2 |
3 | Before heading into SDK usage, we need to configure it, with credentials, return url and scopes.
4 |
5 | ## Configuration Class.
6 |
7 | To start, we are going to create an instance of **`SteemConnect\Config\Config`**.
8 |
9 | ``` php
10 | setReturnUrl('https://your-steem-app/auth/callback');
37 | ```
38 |
39 | !!! note
40 | The URL being used on configuration must match the one configured on SteemConnect dashboard, otherwise the authorization flow will fail.
41 |
42 | ### Scopes.
43 |
44 | Other required configuration are which scopes your application requires.
45 |
46 | On the OAuth flow, a scope could be translated to which permissions your users will grant you.
47 |
48 | There are several scopes available. The list of scopes presented here may change with time, so, an up-to-date reference can fe found at **[SteemConnect wiki](https://github.com/steemit/steemconnect/wiki/OAuth-2#scopes)**.
49 |
50 | | Scope | Description
51 | | - | -
52 | | **login** | Verify Steem identity
53 | | **offline** | Allow long-lived token
54 | | **vote** | Upvote, downvote or unvote a post or comment
55 | | **comment** | Publish or edit a post or a comment
56 | | **comment_delete** | Delete a post or a comment
57 | | **comment_options** | Add options for a post or comment
58 | | **custom_json** | Follow, unfollow, ignore, reblog or any custom_json operation
59 | | **claim_reward_balance** | Claim reward for user
60 |
61 | !!! note
62 | If your application only needs to verify the user identity, the required scope **`login`** does not persist changes on the user account, so be sure to remember the user session to avoid the authorization dialog in every visit.
63 |
64 | To configure the scopes your application will require, just call the `setScopes` method on the config object, passing those scopes as an array:
65 |
66 | ``` php
67 | setScopes([
73 | 'login',
74 | 'vote',
75 | 'comment'
76 | ]);
77 |
78 | ```
79 |
80 | ### Application and Community Name.
81 |
82 | An optional but interesting feature, is to configure both the application and community names. Those are used to indicate
83 | what application was used to make the post, and some frontend will display that information.
84 |
85 | If you don't know what I'm talking about, here is an example:
86 |
87 | 
88 |
89 | The syntax for application name, as of right now, is **`lowercase-app-name/version`**, here's an example:
90 |
91 | ``` php
92 | setApp('coolapp/2.4');
98 | ```
99 |
100 | The same way, it's possible to set the community name:
101 |
102 | ``` php
103 | setCommunity('CoolApp');
109 | ```
110 |
111 | ### Custom SteemConnect Servers.
112 |
113 | If for some reason, you are using a custom install of SteemConnect (a development install, for example), you may
114 | change the base URL so all calls will use that domain.
115 |
116 | ``` php
117 | setBaseUrl('https://my-custom-steemconnect.com');
123 |
124 | ```
--------------------------------------------------------------------------------
/tests/Operations/FollowTest.php:
--------------------------------------------------------------------------------
1 | account('some-account');
25 | $this->assertEquals('some-account', $follow->follower);
26 |
27 | // set and test.
28 | $follow->follower('follower-account');
29 | $this->assertEquals('follower-account', $follow->follower);
30 |
31 | // set and test.
32 | $follow->following('following', true);
33 | $this->assertEquals('following', $follow->following);
34 | $this->assertEquals(['blog'], $follow->what);
35 |
36 | // set and test.
37 | $follow->following('following', false);
38 | $this->assertEquals('following', $follow->following);
39 | $this->assertEquals([], $follow->what);
40 |
41 | // reset the follow instance.
42 | $follow = new Follow();
43 |
44 | // follow alias test.
45 | $follow->follow('others');
46 | $this->assertEquals('others', $follow->following);
47 | $this->assertEquals(['blog'], $follow->what);
48 |
49 | // unfollow alias test.
50 | $follow->unfollow('others');
51 | $this->assertEquals('others', $follow->following);
52 | $this->assertEquals([], $follow->what);
53 |
54 | $follow->following('other', true);
55 | }
56 |
57 | /**
58 | * Test the getter on a sub operation property.
59 | */
60 | public function test_defined_sub_operation_property()
61 | {
62 | // start a follow operation.
63 | $follow = new Follow();
64 |
65 | // use the magic setter against a already defined property.
66 | $this->assertNotNull($follow->getSubOperation()->parameters);
67 | }
68 |
69 | /**
70 | * Required auths and posting auths testing.
71 | */
72 | public function test_required_auths()
73 | {
74 | // start a follow operation.
75 | $follow = new Follow();
76 |
77 | // required auths getter / setter tests.
78 | $this->assertEquals([], $follow->getRequiredAuths());
79 | $this->assertEquals([], $follow->getRequiredPostingAuths());
80 |
81 | // custom the auths.
82 | $follow->setRequiredAuths(['a', 'b']);
83 | $follow->setRequiredPostingAuths(['c', 'd']);
84 |
85 | // required auths getter tests.
86 | $this->assertEquals(['a', 'b'], $follow->getRequiredAuths());
87 | $this->assertEquals(['c', 'd'], $follow->getRequiredPostingAuths());
88 | }
89 |
90 | /**
91 | * Sub operation testing.
92 | */
93 | public function test_sub_operations()
94 | {
95 | // start a follow operation.
96 | $follow = new Follow();
97 |
98 | // get the sub operation (currently empty);
99 | $subOperation = $follow->getSubOperation();
100 | // set a given parameter/
101 | $subOperation->setParameter('foo', 'bar');
102 |
103 | // set the sub operation back.
104 | $follow->setSubOperation($subOperation);
105 |
106 | // call the magic getter to extract the value.
107 | $this->assertEquals('bar', $follow->foo);
108 | }
109 |
110 | /**
111 | * Test direct parameters getter.
112 | */
113 | public function test_magic_getter_against_local_property()
114 | {
115 | // start a follow operation.
116 | $follow = new Follow();
117 |
118 | // test the getter and it's value.
119 | $this->assertEquals('follow', $follow->customOperation);
120 | }
121 |
122 | /**
123 | * Assert parsing JSON string on the constructor.
124 | */
125 | public function test_json_string_parsing_on_constructor()
126 | {
127 | // dummy operation data.
128 | $operation = [
129 | 'json' => json_encode(['foo' => 'bar'])
130 | ];
131 |
132 | // start a follow instance, passing some data.
133 | $follow = new Follow($operation);
134 |
135 | // assert the value.
136 | $this->assertEquals('bar', $follow->foo);
137 | }
138 | }
--------------------------------------------------------------------------------
/src/Operations/CustomJson.php:
--------------------------------------------------------------------------------
1 | [],
30 | 'required_posting_auths' => [],
31 | ];
32 |
33 | /**
34 | * @var string List of parameters to treat as JSON.
35 | */
36 | protected $jsonParameters = 'json';
37 |
38 | /**
39 | * Vote operation constructor.
40 | *
41 | * @param array $parameters
42 | */
43 | public function __construct(array $parameters = [])
44 | {
45 | // extract json string from custom_json.
46 | $json = array_get($parameters, $this->jsonParameters);
47 |
48 | // if there's a json sub operation data to be parsed.
49 | if ($json && Str::startsWith($json, '{')) {
50 | // decode it's data.
51 | $subOperationParameters = json_decode($json, true);
52 | // overwrite with a sub operation instance.
53 | Arr::set($parameters, $this->jsonParameters, new SubOperation($this->customOperation, $subOperationParameters));
54 | } else {
55 | Arr::set($parameters, $this->jsonParameters, new SubOperation($this->customOperation));
56 | }
57 |
58 | // cal parent constructor.
59 | parent::__construct('custom_json', array_merge($this->parameters, $parameters));
60 | }
61 |
62 | /**
63 | * Set the required auths for the custom json operation.
64 | *
65 | * @param array $requiredAuths
66 | *
67 | * @return self
68 | */
69 | public function setRequiredAuths(array $requiredAuths = []) : self
70 | {
71 | return $this->setParameter('required_auths', $requiredAuths);
72 | }
73 |
74 | /**
75 | * Returns the configured required auths for the operation.
76 | *
77 | * @return array
78 | */
79 | public function getRequiredAuths() : array
80 | {
81 | return $this->getParameter('required_auths');
82 | }
83 |
84 | /**
85 | * Set the required posting auths for the custom json operation.
86 | *
87 | * @param array $requiredPostingAuths
88 | *
89 | * @return self
90 | */
91 | public function setRequiredPostingAuths(array $requiredPostingAuths = []) : self
92 | {
93 | return $this->setParameter('required_posting_auths', $requiredPostingAuths);
94 | }
95 |
96 | /**
97 | * Returns the configured required posting auths for the operation.
98 | *
99 | * @return array
100 | */
101 | public function getRequiredPostingAuths() : array
102 | {
103 | return $this->getParameter('required_posting_auths');
104 | }
105 |
106 | /**
107 | * Set the custom json operation id.
108 | *
109 | * @param string $id
110 | *
111 | * @return self
112 | */
113 | public function setId(string $id) : self
114 | {
115 | return $this->setParameter('id', $id);
116 | }
117 |
118 | /**
119 | * Returns the custom json operation id.
120 | *
121 | * @return null|string
122 | */
123 | public function getId() : ? string
124 | {
125 | return $this->getParameter('id');
126 | }
127 |
128 | /**
129 | * Get the sub operation instance, if any.
130 | *
131 | * @return null|SubOperation
132 | */
133 | public function getSubOperation() : ?SubOperation
134 | {
135 | return $this->getParameter($this->jsonParameters);
136 | }
137 |
138 | /**
139 | * Set the sub operation directly on the json attribute.
140 | *
141 | * @param SubOperation $subOperation
142 | *
143 | * @return self
144 | */
145 | public function setSubOperation(SubOperation $subOperation) : self
146 | {
147 | $this->setParameter($this->jsonParameters, $subOperation);
148 |
149 | return $this;
150 | }
151 |
152 | /**
153 | * {@inheritdoc}
154 | */
155 | public function __get($name)
156 | {
157 | $value = parent::__get($name);
158 |
159 | if ($value) {
160 | return $value;
161 | }
162 |
163 | return $this->getSubOperation()->{$name};
164 | }
165 | }
--------------------------------------------------------------------------------
/src/Client/Broadcaster.php:
--------------------------------------------------------------------------------
1 | config = $config;
47 |
48 | // assign token instance.
49 | $this->token = $token;
50 |
51 | // assign http client instance.
52 | $this->httpClient = $httpClient;
53 | }
54 |
55 | /**
56 | * Get the current configuration instance on the broadcaster.
57 | *
58 | * @return Config
59 | */
60 | public function getConfig(): Config
61 | {
62 | return $this->config;
63 | }
64 |
65 | /**
66 | * Customize the configuration on the broadcaster instance.
67 | *
68 | * @param Config $config
69 | *
70 | * @return self
71 | */
72 | public function setConfig(Config $config): self
73 | {
74 | $this->config = $config;
75 |
76 | return $this;
77 | }
78 |
79 | /**
80 | * Get the current access token instance on the broadcaster.
81 | *
82 | * @return Token
83 | */
84 | public function getToken(): Token
85 | {
86 | return $this->token;
87 | }
88 |
89 | /**
90 | * Customize the access token on the broadcaster.
91 | *
92 | * @param Token $token
93 | *
94 | * @return self
95 | */
96 | public function setToken(Token $token): self
97 | {
98 | $this->token = $token;
99 |
100 | return $this;
101 | }
102 |
103 | /**
104 | * Get the current HttpClient instance on the broadcaster.
105 | *
106 | * @return HttpClient
107 | */
108 | public function getHttpClient(): HttpClient
109 | {
110 | return $this->httpClient;
111 | }
112 |
113 | /**
114 | * Customize the HttpClient instance on the broadcaster.
115 | *
116 | * @param HttpClient $httpClient
117 | *
118 | * @return self
119 | */
120 | public function setHttpClient(HttpClient $httpClient): self
121 | {
122 | $this->httpClient = $httpClient;
123 |
124 | return $this;
125 | }
126 |
127 | /**
128 | * Broadcasts an Operation through SteemConnect V2.
129 | *
130 | * @param array $operations List of operations to broadcast, usually, just one.
131 | *
132 | * @throws \Exception
133 | *
134 | * @return Response
135 | */
136 | public function broadcast($operations)
137 | {
138 | // collect the operations list to broadcast.
139 | $operationsList = collect($operations)->toArray();
140 |
141 | try {
142 | // call SteemConnect passing a list of operations to broadcast.
143 | $httpResponse = $this->getHttpClient()
144 | ->call('POST', 'api/broadcast', [
145 | 'operations' => $operationsList
146 | ]);
147 |
148 | // creates a client response instance.
149 | $response = new Response();
150 | // set the http response on the client response object.
151 | $response->setHttpResponse($httpResponse);
152 |
153 | // finally returns the response object.
154 | return $response;
155 |
156 | } catch (BadResponseException $e) {
157 | // throw a custom response exception otherwise.
158 | throw new ResponseException($e->getResponse());
159 | } catch (HttpClientException $e) {
160 | // throw a client exception, passing the previous one.
161 | throw new ClientException("Error broadcasting the operation", 0, $e);
162 | }
163 | }
164 | }
--------------------------------------------------------------------------------
/src/Http/Client.php:
--------------------------------------------------------------------------------
1 | config = $config;
44 |
45 | // access token.
46 | $this->accessToken = $token;
47 |
48 | // get the http client (default one at constructor time.)
49 | $this->httpClient = $httpClient ? $httpClient : $this->getHttpClient();
50 | }
51 |
52 | /**
53 | * Replaces the configuration object.
54 | *
55 | * @param Config $config Config instance to replace on the client.
56 | *
57 | * @return $this
58 | */
59 | public function setConfig(Config $config) : self
60 | {
61 | $this->config = $config;
62 |
63 | return $this;
64 | }
65 |
66 | /**
67 | * Retrieves the current configuration object.
68 | *
69 | * @return Config Configuration instance.
70 | */
71 | public function getConfig() : ?Config
72 | {
73 | return $this->config;
74 | }
75 |
76 | /**
77 | * Custom Access Token setter.
78 | *
79 | * @param Token $token
80 | *
81 | * @return Client
82 | */
83 | public function setAccessToken(Token $token) : self
84 | {
85 | $this->accessToken = $token;
86 |
87 | return $this;
88 | }
89 |
90 | /**
91 | * Access Token getter.
92 | *
93 | * @return null|Token
94 | */
95 | public function getAccessToken() : ?Token
96 | {
97 | return $this->accessToken;
98 | }
99 |
100 | /**
101 | * HttpClient instance.
102 | *
103 | * @param HttpClientInterface $httpClient
104 | */
105 | public function setHttpClient(HttpClientInterface $httpClient)
106 | {
107 | $this->httpClient = $httpClient;
108 | }
109 |
110 | /**
111 | * Returns the custom or factories a new HttpClient for the API client.
112 | *
113 | * @return HttpClientInterface
114 | */
115 | public function getHttpClient() : HttpClientInterface
116 | {
117 | // returns a new HTTP client, if none is set on the client instance.
118 | return $this->httpClient ? $this->httpClient : new HttpClient();
119 | }
120 |
121 | /**
122 | * Returns a list of default HTTP headers to include in every request
123 | *
124 | * @return array
125 | */
126 | protected function defaultHeaders()
127 | {
128 | return [
129 | // accepted types of response.
130 | 'Accept' => 'application/json',
131 | // current request content type.
132 | 'Content-Type' => 'application/json',
133 | // authorization (OAuth token) header.
134 | 'Authorization' => "Bearer {$this->accessToken->getToken()}",
135 | ];
136 | }
137 |
138 | /**
139 | * Execute a HTTP request.
140 | *
141 | * @param string $method HTTP method to call (most of the time, it's post.)
142 | * @param string $uri HTTP request URI.
143 | * @param array|null $body HTTP request body.
144 | *
145 | * @return mixed|\Psr\Http\Message\ResponseInterface
146 | *
147 | * @throws \GuzzleHttp\Exception\GuzzleException
148 | */
149 | public function call(string $method, string $uri, array $body = null)
150 | {
151 | $request = new Request($method, $this->config->buildUrl($uri), $this->defaultHeaders(), $body ? json_encode($body) : null);
152 |
153 | $response = $this->httpClient->send($request);
154 |
155 | return $response;
156 | }
157 | }
--------------------------------------------------------------------------------
/tests/Client/ResponseTest.php:
--------------------------------------------------------------------------------
1 | transactionJson = file_get_contents(__DIR__.'/../Resources/stub-transaction.json');
42 |
43 | // decode the json stub transaction into array.
44 | $this->transactionData = json_decode($this->transactionJson, true);
45 | }
46 |
47 | /**
48 | * Mock a valid transaction http response.
49 | *
50 | * @return Mockery\MockInterface|ResponseInterface
51 | */
52 | protected function mockHttpResponse()
53 | {
54 | // mock a response.
55 | $response = Mockery::mock(ResponseInterface::class);
56 |
57 | // status codes and reason phrase.
58 | $response->shouldReceive('getStatusCode')->andReturn(200);
59 | $response->shouldReceive('getReasonPhrase')->andReturn('OK');
60 |
61 | // json headers.
62 | $response->shouldReceive('getHeaders')->andReturn(['Content-Type' => 'application/json']);
63 |
64 | // transaction json body.
65 | $body = Mockery::mock(StreamInterface::class);
66 | $body->shouldReceive('__toString')->andReturn($this->transactionJson);
67 |
68 | // response body stream.
69 | $response->shouldReceive('getBody')->andReturn($body);
70 |
71 | // response return.
72 | return $response;
73 | }
74 |
75 | /**
76 | * Mock a invalid, empty http response.
77 | *
78 | * @return Mockery\MockInterface|ResponseInterface
79 | */
80 | protected function mockEmptyHttpResponse()
81 | {
82 | // mock a response.
83 | $response = Mockery::mock(ResponseInterface::class);
84 |
85 | // status codes and reason phrase.
86 | $response->shouldReceive('getStatusCode')->andReturn(200);
87 | $response->shouldReceive('getReasonPhrase')->andReturn('OK');
88 |
89 | // json headers.
90 | $response->shouldReceive('getHeaders')->andReturn(['Content-Type' => 'application/json']);
91 |
92 | // transaction json body.
93 | $body = Mockery::mock(StreamInterface::class);
94 | $body->shouldReceive('__toString')->andReturn("");
95 |
96 | // response body stream.
97 | $response->shouldReceive('getBody')->andReturn($body);
98 |
99 | // response return.
100 | return $response;
101 | }
102 |
103 | /**
104 | * Parse the transaction from the response.
105 | */
106 | public function test_parsing_into_transaction()
107 | {
108 | // get the mock http response.
109 | $httpResponse = $this->mockHttpResponse();
110 |
111 | // start a new response instance.
112 | $response = new Response();
113 |
114 | // set the http response on the response instance.
115 | $response->setHttpResponse($httpResponse);
116 |
117 | // get the transaction from the http response.
118 | $transaction = $response->getTransaction();
119 |
120 | // assert the transaction instance was returned.
121 | $this->assertInstanceOf(Transaction::class, $transaction);
122 | }
123 |
124 | /**
125 | * Test invalid responses.
126 | */
127 | public function test_parsing_invalid_responses()
128 | {
129 | // get the mock http response.
130 | $httpResponse = $this->mockEmptyHttpResponse();
131 |
132 | // start a new response instance.
133 | $response = new Response();
134 |
135 | // set the http response on the response instance.
136 | $response->setHttpResponse($httpResponse);
137 |
138 | // get the transaction from the http response.
139 | // this return should be null.
140 | $transaction = $response->getTransaction();
141 |
142 | // assert the return was null.
143 | $this->assertNull($transaction);
144 | }
145 | }
--------------------------------------------------------------------------------
/tests/Operations/Common/HasParametersTraitTest.php:
--------------------------------------------------------------------------------
1 | assertEquals(0, count($this->getParameters()));
24 |
25 | // assert the parameter does not previously exists.
26 | // meaning, it must return null.
27 | $this->assertNull($this->getParameter('foo'));
28 |
29 | // set a given parameter
30 | $setReturn = $this->setParameter('foo', 'bar');
31 |
32 | // assert the fluent return.
33 | $this->assertSame($this, $setReturn);
34 |
35 | // assert the parameter was correctly set.
36 | $this->assertEquals('bar', $this->getParameter('foo'));
37 | }
38 |
39 | /**
40 | * Test batch setters and getters of parameters.
41 | */
42 | public function test_batch_parameter_setter_and_getter()
43 | {
44 | // assert the number of parameters starts as zero.
45 | $this->assertEquals(0, count($this->getParameters()));
46 |
47 | // set a given number of parameters (2).
48 | $setReturn = $this->setParameters([
49 | 'foo' => 'bar',
50 | 'bar' => 'baz',
51 | ]);
52 |
53 | // assert the fluent return.
54 | $this->assertSame($this, $setReturn);
55 |
56 | // assert that now there are two parameters.
57 | $this->assertEquals(2, count($this->getParameters()));
58 |
59 | // assert the parameters are the ones previously set.
60 | $this->assertEquals([
61 | 'foo' => 'bar',
62 | 'bar' => 'baz',
63 | ], $this->getParameters());
64 | }
65 |
66 | /**
67 | * Test batch parameter setter, with the merge option.
68 | */
69 | public function test_batch_parameter_merge()
70 | {
71 | // set an initial parameter
72 | $this->setParameter('foo', 'bar');
73 |
74 | // set additional parameters, this time merging.
75 | $this->setParameters(['bar' => 'baz'], true);
76 |
77 | // assert the parameters are the ones previously set.
78 | $this->assertEquals([
79 | 'foo' => 'bar',
80 | 'bar' => 'baz',
81 | ], $this->getParameters());
82 | }
83 |
84 | /**
85 | * Test for forgetting a given parameter by key.
86 | */
87 | public function test_parameter_forget()
88 | {
89 | // set a given parameter.
90 | $this->setParameter('foo', 'bar');
91 |
92 | // assert it was set on the first place.
93 | $this->assertEquals('bar', $this->getParameter('foo'));
94 |
95 | // forget the parameter previously set.
96 | $forgetReturn = $this->forgetParameter('foo');
97 |
98 | // since the parameter was removed, true should be returned.
99 | $this->assertTrue($forgetReturn);
100 |
101 | // after removal, the return should be now null.
102 | $this->assertEquals(null, $this->getParameter('foo'));
103 | }
104 |
105 | /**
106 | * Test the inner parameter (used for nested parameter setting / getting).
107 | */
108 | public function test_inner_parameter_getter_and_setter()
109 | {
110 | // get a inner value
111 | $innerBar = $this->getInnerParameter('foo', 'bar');
112 |
113 | // assert the return is null, even when when the parent does not exists.
114 | $this->assertNull($innerBar);
115 |
116 | // set a inner parameter, on a non existing key.
117 | $innerSetReturn = $this->setInnerParameter('foo', 'bar', 'baz');
118 |
119 | // assert the fluent return from setter.
120 | $this->assertSame($this, $innerSetReturn);
121 |
122 | // get a inner value
123 | $innerBar = $this->getInnerParameter('foo', 'bar');
124 |
125 | // assert the value was set and get be retrieved just fine.
126 | $this->assertEquals('baz', $innerBar);
127 | }
128 |
129 | /**
130 | * Test a inner parameter forget.
131 | */
132 | public function test_inner_parameter_forget()
133 | {
134 | // set a inner parameter.
135 | $this->setInnerParameter('foo', 'bar', 'baz');
136 |
137 | // forget the inner parameter.
138 | $forgetInnerReturn = $this->forgetInnerParameter('foo', 'bar');
139 |
140 | // forget should return true case the forget key no longer exists.
141 | $this->assertTrue($forgetInnerReturn);
142 |
143 | // assert the value is now null.
144 | $this->assertNull($this->getInnerParameter('foo', 'bar'));
145 | }
146 | }
--------------------------------------------------------------------------------
/tests/Operations/CommentTest.php:
--------------------------------------------------------------------------------
1 | title($title);
31 |
32 | // assert a permlink was generated.
33 | $this->assertEquals($permLink, $comment->permlink);
34 | }
35 |
36 | /**
37 | * Test permlink is preserved when present and title is set.
38 | */
39 | public function test_permlink_is_preserved()
40 | {
41 | // start comment.
42 | $comment = new Comment();
43 |
44 | // set a custom permlink.
45 | $comment->permLink('some-custom-permlink');
46 |
47 | // set comment title.
48 | $comment->title('foo bar, baz');
49 |
50 | // now assert the title did not replaced the initial permlink.
51 | $this->assertEquals('some-custom-permlink', $comment->permlink);
52 | }
53 |
54 | /**
55 | * Test reply settings.
56 | */
57 | public function test_reply_setters()
58 | {
59 | // start a comment.
60 | $comment = new Comment();
61 |
62 | // call the reply alias.
63 | $comment->reply('some-user', 'post-permlink');
64 |
65 | // assert the parent author and permlink.
66 | $this->assertEquals('some-user', $comment->parent_author);
67 | $this->assertEquals('post-permlink', $comment->parent_permlink);
68 |
69 | // start another comment.
70 | $comment = new Comment();
71 |
72 | // parent author setter.
73 | $comment->parentAuthor('another-user');
74 | $this->assertEquals('another-user', $comment->parent_author);
75 |
76 | // parent permlink setter.
77 | $comment->parentPermLink('another-post-permlink');
78 | $this->assertEquals('another-post-permlink', $comment->parent_permlink);
79 | }
80 |
81 | /**
82 | * Test author and category.
83 | */
84 | public function test_author_and_category()
85 | {
86 | // start a comment.
87 | $comment = new Comment();
88 |
89 | // call the category alias.
90 | $comment->category('cool-topic');
91 |
92 | // assert the parent permlink.
93 | $this->assertEquals('cool-topic', $comment->parent_permlink);
94 | // parent author should start as empty string.
95 | $this->assertEquals('', $comment->parent_author);
96 |
97 | // set the author.
98 | $comment->author('the-author');
99 | // assert it's value.
100 | $this->assertEquals('the-author', $comment->author);
101 | }
102 |
103 | /**
104 | * Test tags.
105 | */
106 | public function test_tags()
107 | {
108 | // start a comment.
109 | $comment = new Comment();
110 |
111 | // set the tags on the comment.
112 | $comment->tags(['foo', 'bar', 'baz']);
113 |
114 | // assert the json meta value was set.
115 | $this->assertEquals(['foo', 'bar', 'baz'], $comment->tags);
116 | }
117 |
118 | /**
119 | * Customize application and community on a given comment.
120 | */
121 | public function test_app_and_community()
122 | {
123 | // start a comment.
124 | $comment = new Comment();
125 |
126 | // set the app name.
127 | $comment->app('foobar/9.0');
128 |
129 | // set community.
130 | $comment->community('steemdev');
131 |
132 | // assert the json meta value was set.
133 | $this->assertEquals('foobar/9.0', $comment->app);
134 |
135 | // assert the json meta value was set.
136 | $this->assertEquals('steemdev', $comment->community);
137 | }
138 |
139 | /**
140 | * Test direct setting json metadata.
141 | */
142 | public function test_direct_json_meta_parsing()
143 | {
144 | // start a comment
145 | $comment = new Comment();
146 |
147 | // set the json metadata.
148 | $comment->jsonMetadata(['foo' => 'bar', 'tags' => ['a', 'b']]);
149 |
150 | // assert the tags set from the direct array passing.
151 | $this->assertEquals(['a', 'b'], $comment->tags);
152 | }
153 |
154 | /**
155 | * Tests related to comment content (body).
156 | */
157 | public function test_body_set_and_parsing()
158 | {
159 | // start the comment.
160 | $comment = new Comment();
161 |
162 | // post body
163 | $comment->body('this is a body ok?');
164 |
165 | // assert a slug was generated for the permlink from the content body.
166 | $this->assertEquals('this-is-a-body-ok', $comment->permlink);
167 | }
168 | }
--------------------------------------------------------------------------------
/docs/02-authentication.md:
--------------------------------------------------------------------------------
1 | # Authentication
2 |
3 | This library wraps all authentication functionality built on **[oauth2-sc2](https://github.com/hernandev/oauth2-sc2)**, if you are using the SDK, there's no need for separate authentication configuration, since all logic is wrapped on the SDK.
4 |
5 | ## Before Authentication.
6 |
7 | Before we head into the actual authentication, we must have a SDK client instance.
8 |
9 | The class that handle all SDK features is **`SteemConnect\Client\Client`** and for the examples on this section, we will create one instance and name the variable **`$sdk`**:
10 |
11 | Also, we are assuming, you have the **`$config`** variable from the configuration section available.
12 |
13 | ``` php
14 | auth()->getAuthorizationUrl();
52 | ```
53 |
54 | Now, you can actually redirect the user to that URL. Be free to use any method you want.
55 |
56 | ``` php
57 | auth()->parseReturn();
96 | ```
97 |
98 | The token returned on the callback / return page is an instance of **`SteemConnect\Auth\Token`**, which we will discuss on the next section.
99 |
100 | ## Storing and Using Access Tokens.
101 |
102 | Each access token is specific to a given user. Meaning when you need to the access token every time you need to broadcast an operation
103 | to the Steem blockchain.
104 |
105 | Since the tokens as an instance of **`SteemConnect\Auth\Token`**, it's easy to serialize and factory it's instance:
106 |
107 | ### Serialization for Storage:
108 |
109 | When you have a **`Token`** instance, and you need to store it, you can transform the token into a JSON string by doing:
110 |
111 | ``` php
112 | setToken($token);
150 | ```
--------------------------------------------------------------------------------
/tests/Http/HasHttpResponseTest.php:
--------------------------------------------------------------------------------
1 | shouldReceive('__toString')->andReturn('{"foo": "bar"}');
31 |
32 | // return the mock stream.
33 | return $stream;
34 | }
35 |
36 | /**
37 | * Mock a Stream with Text/HTML contents.
38 | *
39 | * @return Mockery\MockInterface|StreamInterface
40 | */
41 | protected function makeTextStreamMock()
42 | {
43 | // create a stream mock.
44 | $stream= Mockery::mock(StreamInterface::class);
45 | // return some html when serialized.
46 | $stream->shouldReceive('__toString')->andReturn('
foo - bar
');
47 |
48 | // return the mock stream.
49 | return $stream;
50 | }
51 |
52 | /**
53 | * Generic response mock factory.
54 | *
55 | * @param int $statusCode
56 | * @param string $reasonPhrase
57 | *
58 | * @return Mockery\MockInterface|ResponseInterface
59 | */
60 | protected function makeResponseMock(int $statusCode = 200, string $reasonPhrase = 'Ok.')
61 | {
62 | // get a new mock response.
63 | $response = Mockery::mock(ResponseInterface::class);
64 |
65 | // set both status code and status reason (phrase) on the mock.
66 | $response->shouldReceive('getStatusCode')->andReturn($statusCode);
67 | $response->shouldReceive('getReasonPhrase')->andReturn($reasonPhrase);
68 |
69 | // return the mock response.
70 | return $response;
71 | }
72 |
73 | /**
74 | * Mock a normal (200) response.
75 | *
76 | * @return Mockery\MockInterface|ResponseInterface
77 | */
78 | protected function getNormalJsonResponse()
79 | {
80 | // start a mock with code 200.
81 | $response = $this->makeResponseMock(200, 'Ok');
82 |
83 | // the response headers should match a JSON response headers.
84 | $response->shouldReceive('getHeaders')->andReturn([
85 | 'Content-Type' => 'application/json'
86 | ]);
87 |
88 | // and the body should return a Stream with JSON contents.
89 | $response->shouldReceive('getBody')->andReturn($this->makeJsonStreamMock());
90 |
91 | // return the mock response.
92 | return $response;
93 | }
94 |
95 | /**
96 | * Mock a normal (200) response.
97 | *
98 | * @return Mockery\MockInterface|ResponseInterface
99 | */
100 | protected function getNormalNonJsonResponse()
101 | {
102 | // start a mock with code 200.
103 | $response = $this->makeResponseMock(200, 'Ok');
104 |
105 | // instead of JSON, the headers should be anything else, in this case, HTML.
106 | $response->shouldReceive('getHeaders')->andReturn([
107 | 'Content-Type' => 'text/html'
108 | ]);
109 |
110 | // the body stream should also return anything but JSON, in this case, some HTML tags.
111 | $response->shouldReceive('getBody')->andReturn($this->makeTextStreamMock());
112 |
113 | // return the mock response.
114 | return $response;
115 | }
116 |
117 | /**
118 | * Test JSON response parsing.
119 | */
120 | public function test_json_detection()
121 | {
122 | // set the HTTP response.
123 | $this->setHttpResponse($this->getNormalJsonResponse());
124 | // assert the response is JSON (JSON detection).
125 | $this->assertTrue($this->responseIsJson());
126 | }
127 |
128 | /**
129 | * Test NON-JSON (text/html and other) responses parsing.
130 | */
131 | public function test_text_detection()
132 | {
133 | // set a non-json response/
134 | $this->setHttpResponse($this->getNormalNonJsonResponse());
135 |
136 | // assert the response is not JSON.
137 | $this->assertFalse($this->responseIsJson());
138 | }
139 |
140 | /**
141 | * Tests for the internal http response getters and setters.
142 | */
143 | public function test_http_response_getter_and_setter()
144 | {
145 | // assert the initial response content is empty
146 | $this->assertNull($this->getHttpResponse());
147 |
148 | // get a response mock.
149 | $mockHttpResponse = $this->getNormalJsonResponse();
150 |
151 | // set the mock http response.
152 | $this->setHttpResponse($mockHttpResponse);
153 |
154 | // assert the set was ok, by comparing the local instance with getter instance.
155 | $this->assertSame($mockHttpResponse, $this->getHttpResponse());
156 | }
157 | }
--------------------------------------------------------------------------------
/tests/Transactions/TransactionTest.php:
--------------------------------------------------------------------------------
1 | transactionJson = file_get_contents(__DIR__.'/../Resources/stub-transaction.json');
46 |
47 | // decode the json stub transaction into array.
48 | $this->transactionData = json_decode($this->transactionJson, true);
49 |
50 | // make sure the transaction data is sorted by key.
51 | ksort($this->transactionData);
52 |
53 | // factory the transaction instance from the data.
54 | $this->transaction = Transaction::factory($this->transactionData);
55 | }
56 |
57 | /**
58 | * Test the transaction data parsing and it's serialization.
59 | */
60 | public function test_transaction_getters()
61 | {
62 | // start a transaction instance with the stub data.
63 | $transaction = Transaction::factory($this->transactionData);
64 |
65 | // test transaction id.
66 | $this->assertEquals($this->transactionData['id'], $transaction->getId());
67 |
68 | // test block number.
69 | $this->assertEquals($this->transactionData['block_num'], $transaction->getBlockNumber());
70 |
71 | // test transaction number.
72 | $this->assertEquals($this->transactionData['trx_num'], $transaction->getTransactionNumber());
73 |
74 | // test expiration status.
75 | $this->assertEquals($this->transactionData['expired'], $transaction->getExpired());
76 |
77 | // ensure the expiration is a carbon instance.
78 | $this->assertInstanceOf(Carbon::class, $transaction->getExpiration());
79 |
80 | // format the expiration for testing.
81 | $formattedExpiration = $transaction->getExpiration()->format('Y-m-d\TH:i:s');
82 | // test if the expiration matches (after formatting).
83 | $this->assertEquals($this->transactionData['expiration'], $formattedExpiration);
84 |
85 | // test reference block number.
86 | $this->assertEquals($this->transactionData['ref_block_num'], $transaction->getReferenceBlockNumber());
87 |
88 | // test reference block prefix.
89 | $this->assertEquals($this->transactionData['ref_block_prefix'], $transaction->getReferenceBlockPrefix());
90 |
91 | // test the operations are a collection.
92 | $this->assertInstanceOf(Collection::class, $transaction->getOperations());
93 | // test the operations (as array).
94 | $this->assertEquals($this->transactionData['operations'], $transaction->getOperations()->toArray());
95 |
96 | // test signatures are a collection.
97 | $this->assertInstanceOf(Collection::class, $transaction->getSignatures());
98 | // test the signatures (as array).
99 | $this->assertEquals($this->transactionData['signatures'], $transaction->getSignatures()->toArray());
100 |
101 | // test extensions are a collection.
102 | $this->assertInstanceOf(Collection::class, $transaction->getExtensions());
103 | // test the extensions (as array).
104 | $this->assertEquals($this->transactionData['extensions'], $transaction->getExtensions()->toArray());
105 |
106 | // parse the transaction back to json.
107 | $parsedJson = json_encode($transaction->toArray());
108 | $originalJson = json_encode([ 'result' => $this->transactionData ]);
109 |
110 | // assert the transaction have the same content after parsed.
111 | $this->assertEquals($parsedJson, $originalJson);
112 | }
113 |
114 | /**
115 | * Test parsing of transaction when errors happens.
116 | */
117 | public function test_parsing_errors_no_matching_name()
118 | {
119 | // copy the transaction data to a local array.
120 | $data = $this->transactionData;
121 |
122 | // rename the operation to a custom name.
123 | $data['operations'][0][0] = 'some-other-name';
124 |
125 | // factory the transaction.
126 | $transaction = Transaction::factory($data);
127 |
128 | // try getting the operations.
129 | $this->assertInstanceOf(Collection::class, $transaction->getOperations());
130 | }
131 |
132 | /**
133 | * Test parsing of transaction when errors happens.
134 | */
135 | public function test_parsing_errors_no_name_present()
136 | {
137 | // copy the transaction data to a local array.
138 | $data = $this->transactionData;
139 |
140 | // rename the operation to a custom name.
141 | $data['operations'][0][0] = null;
142 |
143 | // factory the transaction.
144 | $transaction = Transaction::factory($data);
145 |
146 | // try getting the operations.
147 | $this->assertInstanceOf(Collection::class, $transaction->getOperations());
148 | }
149 | }
--------------------------------------------------------------------------------
/tests/Http/ClientTest.php:
--------------------------------------------------------------------------------
1 | mockConfiguration());
69 |
70 | // start an empty guzzle http client.
71 | $customGuzzle = new GuzzleClient();
72 |
73 | // set the client.
74 | $client->setHttpClient($customGuzzle);
75 |
76 | // assert the instances are the same.
77 | $this->assertSame($customGuzzle, $client->getHttpClient());
78 | }
79 |
80 | /**
81 | * Test the customization of the configuration instance on the Http client.
82 | */
83 | public function test_custom_configuration()
84 | {
85 | // creates a client instance with default config.
86 | $client = new Client($this->mockConfiguration());
87 |
88 | // get the default config, for later comparison.
89 | $defaultConfig = $client->getConfig();
90 |
91 | // creates a new config, to customize on the client.
92 | $config = new Config('foo', 'bar');
93 |
94 | // set the new config instance.
95 | $client->setConfig($config);
96 |
97 | // assert the config instance is the customized one.
98 | $this->assertSame($client->getConfig(), $config);
99 |
100 | // assert the default configuration is not the one on the client instance anymore.
101 | $this->assertNotSame($client->getConfig(), $defaultConfig);
102 | }
103 |
104 | /**
105 | * Test customization of the access token on the client instance.
106 | */
107 | public function test_custom_access_token()
108 | {
109 | // creates a new client instance.
110 | $client = new Client($this->mockConfiguration());
111 |
112 | // get a token mock.
113 | $token = $this->mockAccessToken();
114 |
115 | // customize the access token on the client with the mock
116 | $setReturn = $client->setAccessToken($token);
117 |
118 | // assert the fluent return.
119 | $this->assertSame($client, $setReturn);
120 |
121 | // assert the custom token was set on the client instance.
122 | $this->assertSame($client->getAccessToken(), $token);
123 | }
124 |
125 | /**
126 | * Test all constructor customizations.
127 | */
128 | public function test_constructor_with_optional_parameters()
129 | {
130 | // get a config mock.
131 | $config = $this->mockConfiguration();
132 | // get an access token mock.
133 | $token = $this->mockAccessToken();
134 | // get an internal http mock (guzzle)
135 | $internalHttpClient = $this->mockInternalHttpClient();
136 |
137 | // create a new client instance, using custom token and internal http client.
138 | $client = new Client($config, $token, $internalHttpClient);
139 |
140 | // assert the configuration instance.
141 | $this->assertSame($config, $client->getConfig());
142 |
143 | // assert the same access token instance.
144 | $this->assertSame($token, $client->getAccessToken());
145 |
146 | // assert the same http client.
147 | $this->assertSame($internalHttpClient, $client->getHttpClient());
148 | }
149 |
150 | /**
151 | * Simple test on the actual HTTP call.
152 | *
153 | * @throws
154 | */
155 | public function test_headers_and_http_call()
156 | {
157 | // mock the configuration.
158 | $config = $this->mockConfiguration();
159 |
160 | // the configuration must receive the build url method.
161 | $config->shouldReceive('buildUrl')->withArgs(['foo'])->andReturn('http://foo.bar/foo');
162 |
163 | // mock the access token.
164 | $token = $this->mockAccessToken();
165 |
166 | $token->shouldReceive('getToken')->andReturn('bar');
167 |
168 | // mock the internal client.
169 | $internalClient = $this->mockInternalHttpClient();
170 |
171 | $internalClient->shouldReceive('send')->andReturn(Mockery::mock(ResponseInterface::class));
172 |
173 | // creates a client with the customized mocks
174 | $client = new Client($config, $token, $internalClient);
175 |
176 | // make a call.
177 | $response = $client->call('POST', 'foo');
178 |
179 | // assert a response was returned.
180 | $this->assertInstanceOf(ResponseInterface::class, $response);
181 | }
182 | }
--------------------------------------------------------------------------------
/docs/img/sc-logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
80 |
--------------------------------------------------------------------------------
/src/Operations/Comment.php:
--------------------------------------------------------------------------------
1 | '',
30 | 'parent_permlink' => null,
31 | 'json_metadata' => [],
32 | ];
33 |
34 | /**
35 | * @var array List of parameters that must be treated as JSON.
36 | */
37 | protected $jsonParameters = [
38 | 'json_metadata'
39 | ];
40 |
41 | /**
42 | * Comment Operation constructor.
43 | *
44 | * @param array $parameters Parse parameters directly from constructor.
45 | */
46 | public function __construct(array $parameters = [])
47 | {
48 | // call parent constructor.
49 | parent::__construct('comment', array_merge($this->parameters, $parameters));
50 |
51 | }
52 |
53 | /**
54 | * Parent Author parameter setter.
55 | *
56 | * @param string $parentAuthor
57 | *
58 | * @return $this
59 | */
60 | public function parentAuthor(string $parentAuthor) : self
61 | {
62 | return $this->setParameter('parent_author', $parentAuthor);
63 | }
64 |
65 | /**
66 | * Parent PermLink parameter setter.
67 | *
68 | * @param string $parentPermLink
69 | *
70 | * @return $this
71 | */
72 | public function parentPermLink(string $parentPermLink) : self
73 | {
74 | return $this->setParameter('parent_permlink', $parentPermLink);
75 | }
76 |
77 | /**
78 | * Reply to post or comment.
79 | *
80 | * @param string $author
81 | * @param string $permLink
82 | *
83 | * @return self
84 | */
85 | public function reply(string $author, string $permLink) : self
86 | {
87 | return $this->parentAuthor($author)->parentPermLink($permLink);
88 | }
89 |
90 | /**
91 | * Author parameter setter.
92 | *
93 | * @param string $author
94 | *
95 | * @return $this
96 | */
97 | public function author(string $author) : self
98 | {
99 | return $this->setParameter('author', $author);
100 | }
101 |
102 | /**
103 | * PermLink parameter setter.
104 | *
105 | * @param string $permLink
106 | *
107 | * @return $this
108 | */
109 | public function permLink(string $permLink) : self
110 | {
111 | return $this->setParameter('permlink', $permLink);
112 | }
113 |
114 | /**
115 | * Title parameter setter.
116 | *
117 | * @param string $title
118 | *
119 | * @return $this
120 | */
121 | public function title(string $title) : self
122 | {
123 | if (!$this->getParameter('permlink')) {
124 | $this->setParameter('permlink', Str::slug($title));
125 | }
126 |
127 | return $this->setParameter('title', $title);
128 | }
129 |
130 | /**
131 | * Body parameter setter.
132 | *
133 | * @param string $body
134 | *
135 | * @return $this
136 | */
137 | public function body(string $body) : self
138 | {
139 | $randomTitle = Str::limit($body, 150);
140 |
141 | if (!$this->getParameter('title')) {
142 | $this->title($randomTitle);
143 | }
144 |
145 | return $this->setParameter('body', $body);
146 | }
147 |
148 | /**
149 | * Category on posts == parent_permlink.
150 | *
151 | * So this is an alias, the category functionality does not exactly exists.
152 | *
153 | * @param string|null $category
154 | *
155 | * @return self
156 | */
157 | public function category(string $category = null) :self
158 | {
159 | return $this->parentPermLink($category);
160 | }
161 |
162 | /**
163 | * Set the tags metadata.
164 | *
165 | * @param array $tags List of tags to add.
166 | *
167 | * @return self
168 | */
169 | public function tags(array $tags) : self
170 | {
171 | return $this->setParameter('json_metadata.tags', $tags);
172 | }
173 |
174 |
175 | /**
176 | * Set the community name.
177 | *
178 | * @param string|null $community
179 | *
180 | * @return Comment
181 | */
182 | public function community(string $community = null) : self
183 | {
184 | return $this->setParameter('json_metadata.community', $community);
185 | }
186 |
187 | /**
188 | * Set the application name.
189 | *
190 | * @param string $app
191 | *
192 | * @return self
193 | */
194 | public function app(string $app) : self
195 | {
196 | return $this->setParameter('json_metadata.app', $app);
197 | }
198 |
199 | /**
200 | * Metadata parameter setter.
201 | *
202 | * @param string|array $jsonMetadata
203 | *
204 | * @return $this
205 | */
206 | public function jsonMetadata($jsonMetadata) : self
207 | {
208 | // convert into array, if json.
209 | $metadata = is_string($jsonMetadata) ? json_decode($jsonMetadata, true) : $jsonMetadata;
210 |
211 | // set the json metadata as string or array
212 | return $this->setParameter('json_metadata', $metadata);
213 | }
214 |
215 | /**
216 | * Custom getter implementation.
217 | *
218 | * @param $name
219 | * @return array|mixed|null|Operation|SubOperation|string
220 | */
221 | public function __get($name)
222 | {
223 | $defaultGetValue = parent::__get($name);
224 |
225 | if ($defaultGetValue) {
226 | return $defaultGetValue;
227 | }
228 |
229 | return collect((array) $this->getParameter('json_metadata'))->get($name);
230 | }
231 | }
--------------------------------------------------------------------------------
/tests/Exceptions/ResponseExceptionTest.php:
--------------------------------------------------------------------------------
1 | foo