├── .gitignore ├── changelog.md ├── composer.json ├── license.md ├── phpunit.xml ├── readme.md ├── src ├── Cache.php ├── Exceptions │ ├── InvalidArgumentException.php │ └── UnauthorizedRequestMethodException.php ├── Flarum.php ├── Fluent.php ├── Models │ ├── Discussion.php │ └── Model.php ├── Resource │ ├── Collection.php │ ├── Item.php │ └── Resource.php ├── Response │ └── Factory.php └── Traits │ ├── HasRelationships.php │ └── UsesCache.php └── tests ├── TestCase.php └── Unit └── DiscussionTest.php /.gitignore: -------------------------------------------------------------------------------- 1 | composer.lock 2 | vendor/ -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | # Changelog flagrow/flarum-php-client 2 | 3 | ### 0.2.0-beta.2 4 | 5 | - Allowing easier retrieval on resource items. 6 | - Fixed issue with keys on relationships. 7 | 8 | ### 0.2.0-beta.1 9 | 10 | - Completely rewritten. 11 | - Implemented Fluent building of REST queries. 12 | 13 | ### 0.1.2 14 | 15 | - generic patch method 16 | - patch method for changing user group added (issue #7) 17 | 18 | ### 0.1.1 19 | 20 | - made the client more generic, added a load and create method that can handle any type 21 | 22 | ### 0.1.0 23 | 24 | - basic guzzle implementation 25 | - load discussion without authorization 26 | - create tag with authorization (to assist in an issue asked on Gitter by @rodenastyle) -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "flagrow/flarum-api-client", 3 | "description": "Standalone package for calling the API of a Flarum installation.", 4 | "keywords": ["api", "flarum", "flagrow"], 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Daniël Klabbers", 9 | "email": "daniel+flarum@klabbers.email", 10 | "homepage": "http://hyn.io" 11 | } 12 | ], 13 | "support": { 14 | "issues": "https://github.com/flagrow/flarum-api-client/issues", 15 | "source": "https://github.com/flagrow/flarum-api-client" 16 | }, 17 | "require": { 18 | "php": "^7.1", 19 | "guzzlehttp/guzzle": "^6.1.1", 20 | "illuminate/support": "^5.3", 21 | "illuminate/cache": "^5.3" 22 | }, 23 | "require-dev": { 24 | "phpunit/phpunit": "^6.0" 25 | }, 26 | "extra": { 27 | "branch-alias": { 28 | "dev-master": "0.2.x-dev" 29 | } 30 | }, 31 | "autoload": { 32 | "psr-4": { 33 | "Flagrow\\Flarum\\Api\\": "src/" 34 | } 35 | }, 36 | "autoload-dev": { 37 | "psr-4": { 38 | "Flagrow\\Flarum\\Api\\Tests\\": "tests" 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /license.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Flagrow 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. -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | ./tests/unit/ 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # flarum-api-client by ![flagrow logo](https://avatars0.githubusercontent.com/u/16413865?v=3&s=15) [flagrow](https://discuss.flarum.org/d/1832-flagrow-extension-developer-group) 2 | 3 | [![Latest Stable Version](https://poser.pugx.org/flagrow/flarum-api-client/v/stable)](https://packagist.org/packages/flagrow/flarum-api-client) [![Gitter](https://badges.gitter.im/flagrow/flarum-api-client.svg)](https://gitter.im/flagrow/chat) 4 | 5 | This is a generic PHP API client for use in any project. You can simply include this package as a dependency to your project to use it. 6 | 7 | ### installation 8 | 9 | ```bash 10 | composer require flagrow/flarum-api-client 11 | ``` 12 | 13 | ### configuration 14 | 15 | In order to start working with the client you might need a Flarum master key: 16 | 17 | 1. Generate a 40 character random, unguessable string, this is the Token needed for this package. 18 | 2. Manually add it to the `api_keys` table using phpmyadmin/adminer or another solution. 19 | 20 | The master key is required to access non-public discussions and running actions otherwise reserved for 21 | Flarum administrators. 22 | 23 | ### examples 24 | 25 | A basic example: 26 | 27 | ```php 28 | discussions()->request(); 38 | // Read a specific discussion. 39 | $discussion = $api->discussions()->id(1)->request(); 40 | // Read the first page of users. 41 | $users = $api->users()->request(); 42 | ``` 43 | 44 | An authorized example: 45 | 46 | ```php 47 | $api = Flarum('http://example.com', ['token' => '; userId=1']); 48 | ``` 49 | 50 | > The userId refers to a user that has admin permissions or the user you want to run actions for. Appending the userId setting to the token only works for Master keys. 51 | 52 | ### links 53 | 54 | - [on github](https://github.com/flagrow/flarum-api-client) 55 | - [on packagist](http://packagist.com/packages/flagrow/flarum-api-client) 56 | - [issues](https://github.com/flagrow/flarum-api-client/issues) 57 | - [changelog](https://github.com/flagrow/flarum-api-client/changelog.md) 58 | 59 | > Flagrow is a collaboration of Flarum extension developers to provide quality, maintained extensions. -------------------------------------------------------------------------------- /src/Cache.php: -------------------------------------------------------------------------------- 1 | store = $store; 37 | } 38 | 39 | /** 40 | * @param string $type 41 | * @return Cache 42 | */ 43 | public function setActive(string $type): Cache 44 | { 45 | $this->active = $type; 46 | 47 | return $this; 48 | } 49 | 50 | /** 51 | * @return Store 52 | */ 53 | public function getActive(): Store 54 | { 55 | return $this->active; 56 | } 57 | 58 | /** 59 | * @param string|null $store 60 | * @return Store 61 | */ 62 | public function getStore(string $store = null): Store 63 | { 64 | $store = $store ?? $this->active; 65 | 66 | if (!array_key_exists($store, $this->stores)) { 67 | $this->stores[$store] = clone $this->store; 68 | } 69 | 70 | return $this->stores[$store]; 71 | } 72 | 73 | /** 74 | * @param int $id 75 | * @param Item $item 76 | * @param string|null $type 77 | * @return Cache 78 | */ 79 | public function set(int $id, Item $item, string $type = null): Cache 80 | { 81 | $this->getStore($type)->put($id, $item, $this->duration); 82 | 83 | return $this; 84 | } 85 | 86 | /** 87 | * @param int $id 88 | * @param null $default 89 | * @param string|null $type 90 | * @return mixed 91 | */ 92 | public function get(int $id, $default = null, string $type = null) 93 | { 94 | $value = $this->getStore($type)->get($id); 95 | 96 | return $value ?: $default; 97 | } 98 | 99 | /** 100 | * @param string|null $type 101 | * @return mixed 102 | */ 103 | public function all(string $type = null) 104 | { 105 | return $this->getStore($type)->all(); 106 | } 107 | } -------------------------------------------------------------------------------- /src/Exceptions/InvalidArgumentException.php: -------------------------------------------------------------------------------- 1 | rest = new Guzzle([ 53 | 'base_uri' => "$host/api/", 54 | 'headers' => $this->requestHeaders($authorization) 55 | ]); 56 | 57 | $this->fluent = new Fluent($this); 58 | 59 | static::$cache = new Cache(new ArrayStore); 60 | } 61 | 62 | public static function getCache(): Cache 63 | { 64 | return self::$cache; 65 | } 66 | 67 | public function request() 68 | { 69 | $method = $this->fluent->getMethod(); 70 | 71 | /** @var ResponseInterface $response */ 72 | try { 73 | $response = $this->rest->{$method}((string)$this->fluent, $this->getVariablesForMethod()); 74 | } finally { 75 | // Reset the fluent builder for a new request. 76 | $this->fluent->reset(); 77 | } 78 | 79 | if ($response->getStatusCode() >= 200 && $response->getStatusCode() < 300) { 80 | return Factory::build($response); 81 | } 82 | } 83 | 84 | protected function requestHeaders(array $authorization = []) 85 | { 86 | $headers = [ 87 | 'Accept' => 'application/vnd.api+json, application/json', 88 | 'User-Agent' => 'Flagrow Api Client' 89 | ]; 90 | 91 | $token = Arr::get($authorization, 'token'); 92 | 93 | if ($token) { 94 | $this->authorized = true; 95 | Arr::set($headers, 'Authorization', "Token $token"); 96 | } 97 | 98 | return $headers; 99 | } 100 | 101 | function __call($name, $arguments) 102 | { 103 | return call_user_func_array([$this->fluent, $name], $arguments); 104 | } 105 | 106 | protected function getVariablesForMethod(): array 107 | { 108 | $variables = $this->fluent->getVariables(); 109 | 110 | if (empty($variables)) { 111 | return []; 112 | } 113 | 114 | switch ($this->fluent->getMethod()) { 115 | case 'get': 116 | return $variables; 117 | break; 118 | default: 119 | return [ 120 | 'json' => ['data' => $variables] 121 | ]; 122 | } 123 | } 124 | 125 | public function getFluent(): Fluent 126 | { 127 | return $this->fluent; 128 | } 129 | 130 | public function getRest(): Guzzle 131 | { 132 | return $this->rest; 133 | } 134 | 135 | public function setStrict(bool $strict): Flarum 136 | { 137 | $this->strict = $strict; 138 | return $this; 139 | } 140 | 141 | public function isStrict(): bool 142 | { 143 | return $this->strict; 144 | } 145 | 146 | public function isAuthorized(): bool 147 | { 148 | return $this->authorized; 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /src/Fluent.php: -------------------------------------------------------------------------------- 1 | flarum = $flarum; 86 | } 87 | 88 | public function reset() 89 | { 90 | $this->segments = []; 91 | $this->includes = []; 92 | $this->query = []; 93 | $this->variables = []; 94 | $this->method = 'get'; 95 | 96 | return $this; 97 | } 98 | 99 | protected function handleType(string $type, $id): Fluent 100 | { 101 | $this->segments[] = $type; 102 | 103 | if ($id) { 104 | $this->segments[] = $id; 105 | } 106 | 107 | return $this; 108 | } 109 | 110 | public function setPath(string $path): Fluent 111 | { 112 | $this->segments = [$path]; 113 | 114 | return $this; 115 | } 116 | 117 | /** 118 | * @param string $method 119 | * @return Fluent 120 | * @throws UnauthorizedRequestMethodException 121 | */ 122 | public function setMethod(string $method): Fluent 123 | { 124 | $this->method = strtolower($method); 125 | 126 | if ( 127 | $this->flarum->isStrict() && 128 | !$this->flarum->isAuthorized() && 129 | in_array($this->method, $this->methodsRequiringAuthorization)) { 130 | throw new UnauthorizedRequestMethodException($this->method); 131 | } 132 | 133 | return $this; 134 | } 135 | 136 | public function setVariables(array $variables = []) 137 | { 138 | if (isset($variables['relationships'])) { 139 | foreach ($variables['relationships'] as $relation => $relationship) { 140 | if (! array_get($relationship, 'data')) { 141 | unset($variables['relationships'][$relation]); 142 | $variables['relationships'][$relation]['data'] = $relationship; 143 | } 144 | } 145 | } 146 | 147 | if (count($variables) === 1 && is_array($variables[0])) { 148 | $this->variables = $variables[0]; 149 | } else { 150 | $this->variables = $variables; 151 | } 152 | 153 | return $this; 154 | } 155 | 156 | public function getMethod(): string 157 | { 158 | return $this->method; 159 | } 160 | 161 | public function getVariables(): array 162 | { 163 | return $this->variables; 164 | } 165 | 166 | protected function handlePagination(string $type, $value) 167 | { 168 | $this->query[$type] = $value; 169 | 170 | return $this; 171 | } 172 | 173 | public function id(int $id): Fluent 174 | { 175 | $this->segments[] = $id; 176 | 177 | return $this; 178 | } 179 | 180 | public function include(string $include): Fluent 181 | { 182 | $this->includes[] = $include; 183 | 184 | return $this; 185 | } 186 | 187 | public function offset(int $number): Fluent 188 | { 189 | return $this->handlePagination('page[offset]', $number); 190 | } 191 | 192 | /** 193 | * {@inheritdoc} 194 | */ 195 | function __toString() 196 | { 197 | $path = implode('/', $this->segments); 198 | 199 | if ($this->includes || $this->query) { 200 | $path .= '?'; 201 | } 202 | 203 | if ($this->includes) { 204 | $path .= sprintf( 205 | 'include=%s&', 206 | implode(',', $this->includes) 207 | ); 208 | } 209 | 210 | if ($this->query) { 211 | $path .= http_build_query($this->query); 212 | } 213 | 214 | return $path; 215 | } 216 | 217 | /** 218 | * @param $name 219 | * @param $arguments 220 | * @return Fluent 221 | */ 222 | function __call($name, $arguments) 223 | { 224 | if (in_array($name, $this->methods)) { 225 | if (!empty($arguments)) { 226 | $this->setVariables($arguments); 227 | } 228 | return $this->setMethod($name, $arguments); 229 | } 230 | 231 | if (count($arguments) <= 1 && in_array($name, $this->types)) { 232 | return $this->handleType($name, $arguments[0] ?? null); 233 | } 234 | 235 | if (in_array($name, $this->pagination) && count($arguments) === 1) { 236 | return call_user_func_array([$this, 'handlePagination'], array_prepend($arguments, $name)); 237 | } 238 | 239 | if (method_exists($this->flarum, $name)) { 240 | return call_user_func_array([$this->flarum, $name], $arguments); 241 | } 242 | } 243 | } 244 | -------------------------------------------------------------------------------- /src/Models/Discussion.php: -------------------------------------------------------------------------------- 1 | id = Arr::pluck($attributes, 'id'); 31 | } 32 | 33 | $this->attributes = $attributes; 34 | } 35 | 36 | public static function fromResource(Item $item) 37 | { 38 | $class = sprintf("%s\\%s", __NAMESPACE__, Str::camel(Str::singular($item->type))); 39 | 40 | if (class_exists($class)) { 41 | $response = new $class($item->attributes); 42 | 43 | if ($item->id) { 44 | $response->id = $item->id; 45 | } 46 | 47 | return $response; 48 | } 49 | 50 | throw new InvalidArgumentException("Resource type {$item->type} could not be migrated to Model"); 51 | } 52 | 53 | /** 54 | * @param Flarum $dispatcher 55 | */ 56 | public static function setDispatcher(Flarum $dispatcher) 57 | { 58 | self::$dispatcher = $dispatcher; 59 | } 60 | 61 | /** 62 | * @return Flarum 63 | */ 64 | public static function getDispatcher(): Flarum 65 | { 66 | return self::$dispatcher; 67 | } 68 | 69 | /** 70 | * Resource type. 71 | * 72 | * @return string 73 | */ 74 | public function type(): string 75 | { 76 | return Str::plural(Str::lower( 77 | Str::replaceFirst(__NAMESPACE__ . '\\', '', static::class) 78 | )); 79 | } 80 | 81 | /** 82 | * Generated resource item. 83 | * 84 | * @return Item 85 | */ 86 | public function item(): Item 87 | { 88 | return new Item([ 89 | 'type' => $this->type(), 90 | 'attributes' => $this->attributes 91 | ]); 92 | } 93 | 94 | /** 95 | * @return array 96 | */ 97 | public function attributes(): array 98 | { 99 | return $this->attributes; 100 | } 101 | 102 | /** 103 | * @param Model $relation 104 | */ 105 | public function addRelation($relation) 106 | { 107 | 108 | } 109 | 110 | /** 111 | * @return Fluent 112 | */ 113 | public function baseRequest(): Fluent 114 | { 115 | // Set resource type. 116 | $dispatch = call_user_func_array([ 117 | static::$dispatcher, 118 | $this->type() 119 | ], []); 120 | 121 | // Set resource Id. 122 | if ($this->id) { 123 | $dispatch->id($this->id); 124 | } 125 | 126 | return $dispatch; 127 | } 128 | 129 | /** 130 | * @return mixed 131 | */ 132 | public function delete() 133 | { 134 | if (!$this->id) { 135 | throw new InvalidArgumentException("Resource doesn't exist."); 136 | } 137 | 138 | return $this->baseRequest()->delete()->request(); 139 | } 140 | 141 | /** 142 | * Creates or updates a resource. 143 | * 144 | * @return mixed 145 | */ 146 | public function save() 147 | { 148 | return $this->baseRequest() 149 | // Set method and variables. 150 | ->post( 151 | $this->item()->toArray() 152 | ) 153 | // Send request. 154 | ->request(); 155 | } 156 | 157 | /** 158 | * {@inheritdoc} 159 | */ 160 | function __set($name, $value) 161 | { 162 | if ($name === 'id') { 163 | $this->id = $value; 164 | } else { 165 | $this->attributes[$name] = $value; 166 | } 167 | } 168 | 169 | /** 170 | * {@inheritdoc} 171 | */ 172 | function __get($name) 173 | { 174 | return Arr::get($this->attributes, $name); 175 | } 176 | } -------------------------------------------------------------------------------- /src/Resource/Collection.php: -------------------------------------------------------------------------------- 1 | items[$item->id] = $item; 23 | } 24 | } 25 | 26 | /** 27 | * @return Collection 28 | */ 29 | public function cache() 30 | { 31 | foreach ($this->items as $id => $item) { 32 | $item->cache(); 33 | } 34 | 35 | return $this; 36 | } 37 | 38 | /** 39 | * @return Collect 40 | */ 41 | public function collect(): Collect 42 | { 43 | return collect($this->items)->keyBy('id'); 44 | } 45 | 46 | /** 47 | * @param string $by 48 | * @param int|null $amount 49 | * @return Collect 50 | */ 51 | public function latest(string $by = 'created_at', int $amount = null): Collect 52 | { 53 | $set = $this->collect()->sortBy($by); 54 | 55 | if ($amount) { 56 | $set = $set->splice(0, $amount); 57 | } 58 | 59 | return $set; 60 | } 61 | } -------------------------------------------------------------------------------- /src/Resource/Item.php: -------------------------------------------------------------------------------- 1 | id = (int) Arr::get($item, 'id'); 30 | $this->type = Arr::get($item, 'type'); 31 | $this->attributes = Arr::get($item, 'attributes', []); 32 | 33 | $this->relations(Arr::get($item, 'relationships', [])); 34 | } 35 | 36 | /** 37 | * {@inheritdoc} 38 | */ 39 | function __get($name) 40 | { 41 | if (Arr::has($this->attributes, $name)) { 42 | return Arr::get($this->attributes, $name); 43 | } 44 | 45 | if (Arr::has($this->relationships, $name)) { 46 | return Arr::get($this->relationships, $name); 47 | } 48 | } 49 | 50 | public function toArray() 51 | { 52 | return [ 53 | 'id' => $this->id, 54 | 'type' => $this->type, 55 | 'attributes' => $this->attributes, 56 | 'relationships' => $this->relationships 57 | ]; 58 | } 59 | } -------------------------------------------------------------------------------- /src/Resource/Resource.php: -------------------------------------------------------------------------------- 1 | getStatusCode() === 204) { 15 | return true; 16 | } 17 | 18 | $body = $response->getBody()->getContents(); 19 | 20 | if (empty($body)) { 21 | return null; 22 | } 23 | 24 | $json = json_decode($body, true); 25 | 26 | $data = Arr::get($json, 'data'); 27 | $included = Arr::get($json, 'included', []); 28 | 29 | // Sets included values to global store. 30 | if (!empty($included)) { 31 | (new Collection($included))->cache(); 32 | } 33 | 34 | // Collection, paginated 35 | if ($data && !array_key_exists('type', $data)) { 36 | return (new Collection($data))->cache(); 37 | } 38 | 39 | return (new Item($data))->cache(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Traits/HasRelationships.php: -------------------------------------------------------------------------------- 1 | $relation) { 24 | $data = Arr::get($relation, 'data'); 25 | 26 | // Single item. 27 | if (Arr::get($data, 'type')) { 28 | $this->relationships[$attribute] = $this->parseRelationshipItem( 29 | Arr::get($data, 'type'), 30 | Arr::get($data, 'id') 31 | ); 32 | } else { 33 | $this->relationships[$attribute] = []; 34 | 35 | foreach ($data as $item) { 36 | $id = (int) Arr::get($item, 'id'); 37 | $this->relationships[$attribute][$id] = $this->parseRelationshipItem( 38 | Arr::get($item, 'type'), 39 | $id 40 | ); 41 | } 42 | } 43 | } 44 | } 45 | 46 | /** 47 | * @param string $type 48 | * @param int $id 49 | * @return Item|null 50 | */ 51 | protected function parseRelationshipItem(string $type, int $id) 52 | { 53 | return Flarum::getCache()->get($id, null, $type); 54 | } 55 | } -------------------------------------------------------------------------------- /src/Traits/UsesCache.php: -------------------------------------------------------------------------------- 1 | set($this->id, $this, $this->type); 16 | 17 | return $this; 18 | } 19 | } -------------------------------------------------------------------------------- /tests/TestCase.php: -------------------------------------------------------------------------------- 1 | flarum = new Flarum( 22 | getenv('FLARUM_HOST') ?? 'https://discuss.flarum.org', 23 | $token ? compact('token') : [] 24 | ); 25 | 26 | Model::setDispatcher($this->flarum); 27 | } 28 | } -------------------------------------------------------------------------------- /tests/Unit/DiscussionTest.php: -------------------------------------------------------------------------------- 1 | flarum->discussions()->request(); 21 | 22 | $this->assertTrue($collection instanceof Collection); 23 | 24 | $this->assertGreaterThan(0, $collection->collect()->count()); 25 | 26 | return $collection; 27 | } 28 | 29 | /** 30 | * @test 31 | * @depends frontpage 32 | * @param Collection $collection 33 | */ 34 | public function discussion(Collection $collection) 35 | { 36 | /** @var Item $discussion */ 37 | $discussion = $collection->collect()->first(); 38 | 39 | /** @var Item $item */ 40 | $item = $this->flarum->discussions()->id($discussion->id)->request(); 41 | 42 | $this->assertEquals($discussion->id, $item->id, 'Requesting an existing discussion retrieves an incorrect result.'); 43 | $this->assertEquals($discussion->type, $item->type, 'Requesting an existing discussion retrieves an incorrect resource type.'); 44 | 45 | $cached = Flarum::getCache()->get($discussion->id, null, $discussion->type); 46 | 47 | $this->assertNotNull($cached, 'Discussion was not automatically persisted to global store.'); 48 | $this->assertEquals($discussion->id, $cached->id, 'The wrong discussion was stored into cache.'); 49 | 50 | $this->assertNotNull($discussion->title); 51 | $this->assertNotNull($discussion->slug); 52 | 53 | $this->assertNotNull($discussion->tags, 'The relation tags should be set on a discussion.'); 54 | 55 | $this->assertNotNull($discussion->startPost, 'A discussion has a start post.'); 56 | } 57 | 58 | /** 59 | * @test 60 | */ 61 | public function createsDiscussions() 62 | { 63 | if (! $this->flarum->isAuthorized()) { 64 | $this->markTestSkipped('No authentication set.'); 65 | } 66 | 67 | $discussion = new Discussion([ 68 | 'title' => 'Foo', 69 | 'content' => 'Some testing content' 70 | ]); 71 | 72 | $resource = $discussion->save(); 73 | 74 | $this->assertInstanceOf(Item::class, $resource); 75 | 76 | $this->assertEquals($discussion->title, $resource->title); 77 | $this->assertNotEmpty($resource->startPost); 78 | $this->assertEquals($discussion->content, $resource->startPost->content); 79 | 80 | return $resource; 81 | } 82 | 83 | /** 84 | * @test 85 | * @depends createsDiscussions 86 | * @param Item $resource 87 | */ 88 | public function deletesDiscussions(Item $resource) 89 | { 90 | if (! $this->flarum->isAuthorized()) { 91 | $this->markTestSkipped('No authentication set.'); 92 | } 93 | 94 | $discussion = Discussion::fromResource($resource); 95 | $model = Model::fromResource($resource); 96 | 97 | // Resolve the same instance. 98 | $this->assertEquals($discussion, $model); 99 | 100 | // See if we can delete things. 101 | $this->assertTrue($discussion->delete()); 102 | } 103 | } --------------------------------------------------------------------------------