Skip to content

Commit b07feed

Browse files
authored
Merge pull request #9 from trms/add-save-and-delete-to-models
add save and delete to persisted models
2 parents a376092 + a9aa505 commit b07feed

File tree

6 files changed

+179
-14
lines changed

6 files changed

+179
-14
lines changed

README.md

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,17 @@ This package should be installed with composer and requires PHP 7+
1515
```bash
1616
composer install trms/carousel
1717
```
18-
## Instructions
19-
[Basic Useage Examples](#basic-useage-examples)
18+
## [Examples](#basic-useage-examples)
2019

21-
## Servers and Requests
20+
## [Servers & Requests](#servers-and-requests)
2221
[The Server Instance](#api)
2322

2423
[Model Requests](#modelrequest)
2524

2625
[File Upload Requests](#fileuploadrequest)
2726

2827
[Bulletin Order Requests](#bulletinorderrequest)
29-
## Models
28+
## [Carousel Models](#models)
3029
[Templates](#template)
3130

3231
[Bulletins](#bulletin)
@@ -41,6 +40,8 @@ composer install trms/carousel
4140

4241
[Bulletin Sorting](#bulletin-sorting)
4342

43+
## [Thrown Exceptions](#exceptions)
44+
4445
## Basic Useage Examples
4546

4647
### Creating a server instance
@@ -152,15 +153,18 @@ Bulletin order requests are used to get the Group/Bulletin order for a given Zon
152153
|constructor|associative array|Request Object|Pass this an associative array of values to filter the request with. (ie:['ZoneID'=>'5'])|
153154

154155
## Models
155-
156+
|Method|Parameters|Returns|Description|
157+
|------|----------|-------|-----------|
158+
|constructor|associative array|self|Constructor for the class, properties passed to it will be used to define the Model.|
159+
|save|none|none|This is a convenience method for saving previously persisted models. For newly instantiated models this function will throw a `CarouselModelException`. Use the API's `save` method to save new models.|
160+
|delete|none|none|This is a convenience method for deleting previously persisted models. For newly instantiated models this function will throw a `CarouselModelException`.|
156161
### Bulletin
157162
`TRMS\Carousel\Models\Bulletin`
158163

159164
A Bulletin is a piece of content displayed in Carousel. The closest analogy would be a slide in a power point deck.
160165
#### Methods
161166
|Method|Parameters|Returns|Description|
162167
|------|----------|-------|-----------|
163-
|constructor|associative array|Zone Object|Constructor for the class, properties passed to it will be used to define the Bulletin.|
164168
|fromTemplate (static)|Template Object|Bulletin Object|Create a new unsaved bulletin from a template.|
165169
|resolvePartial|none|none|Resolves partial bulletins by getting them by id from the server. See the property `PartialBulletin` for more information. This function is called when trying to save partial bulletins.|
166170
|**Relationships**|
@@ -224,7 +228,6 @@ A template is the starting point for a standard Bulletin and is comprised of a b
224228
#### Methods
225229
|Method|Parameters|Returns|Description|
226230
|------|----------|-------|-----------|
227-
|constructor|associative array|Zone Object|Constructor for the class, properties passed to it will be used to define the Template.|
228231
|setBackground|Media Object|self - chainable|Sets the background Media to be used in this model|
229232
|getBackground|none|Media Object|Gets the related background Media model|
230233
|addBlock|Block Object|self - chainable|Add a Block relationship to the model|
@@ -252,7 +255,6 @@ A group is a container for Bulletins that allows for easier viewing sorting and
252255
#### Methods
253256
|Method|Parameters|Returns|Description|
254257
|------|----------|-------|-----------|
255-
|constructor|associative array|Group Object|Constructor for the class, properties passed to it will be used to define the Group.|
256258
|setZone|Zone Object|self - chainable|Sets the Zone to be used in this model|
257259
|getZone|none|Zone Object|Gets the related Zone model|
258260

@@ -270,7 +272,6 @@ Media represents audio, video images and backgrounds to be used in Bulletins and
270272
#### Methods
271273
|Method|Parameters|Returns|Description|
272274
|------|----------|-------|-----------|
273-
|constructor|associative array|Media Object|Constructor for the class, properties passed to it will be used to define the Media.|
274275
|setUser|User Object|self - chainable|Sets the User to be used in this model|
275276
|getUser|none|User Object|Gets the related User model|
276277
|addTag|Tag Object|self - chainable|Add a Tag relationship to the model.|
@@ -296,7 +297,6 @@ A Zone is an area of real estate on screen where bulletins are displayed. The s
296297
#### Methods
297298
|Method|Parameters|Returns|Description|
298299
|------|----------|-------|-----------|
299-
|constructor|associative array|Zone Object|Constructor for the class, properties passed to it will be used to define the Zone.|
300300
|addTag|ZoneTag Object|self - chainable|Add a Tag relationship to the model|
301301
|removeTag|ZoneTag Object|self - chainable|Remove a Tag relationship from the model|
302302
#### Properties
@@ -326,9 +326,6 @@ Tags are metadata that can be added to the associated model. They are used for
326326
### ZoneTag
327327
`TRMS\Carousel\Models\ZoneTag`
328328
#### Methods
329-
|Method|Parameters|Returns|Description|
330-
|------|----------|-------|-----------|
331-
|constructor|associative array|BulletinTag Object|Constructor for the class, properties passed to it will be used to define the Tag.|
332329
#### Properties
333330
|Property|type|Description|
334331
|--------|----|-----------|
@@ -356,3 +353,11 @@ This represents a Group and the order of its Bulletins. The order of the `Bulle
356353
|--------|----|-----------|
357354
|id|string|This is set by the server and not editable.|
358355
|Bulletins|array|An ordered array of Bulletin ids. Their order represents the order of Bulletins in the Group.|
356+
357+
358+
## Exceptions
359+
You can expect the following exceptions to be thrown if things go off the rails with the server, or if you attepmpt to do things that are unsupported or not allowed.
360+
361+
`TRMS\Carousel\Exceptions\CarouselAPIException`
362+
`TRMS\Carousel\Exceptions\CarouselModelException`
363+
`TRMS\Carousel\Exceptions\CarouselRequestException`

Tests/APITest.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,4 +280,42 @@ function test_the_api_sets_the_blocks_correctly_when_saving_a_bulletin()
280280
$this->assertEquals(2, count($bulletin->Blocks));
281281

282282
}
283+
284+
function test_the_api_gets_set_on_a_carousel_model_when_saving_a_bulletin()
285+
{
286+
$mockResponder = new MockResponder;
287+
$mock = new MockHandler([
288+
new Response(200,[],json_encode(['Blocks'=>[[],[]]])),
289+
]);
290+
$handler = HandlerStack::create($mock);
291+
292+
$server = new API();
293+
$bulletin = new Bulletin();
294+
$server
295+
->addMockHandler($handler)
296+
->connect('server','username','password')
297+
->save($bulletin);
298+
299+
$this->assertInstanceOf(API::class, $bulletin->getApi());
300+
}
301+
302+
function test_a_carousel_model_that_comes_from_the_server_has_the_api_object_on_it()
303+
{
304+
$mockResponder = new MockResponder;
305+
$mock = new MockHandler([
306+
new Response(200,[],$mockResponder->bulletin()),
307+
]);
308+
$handler = HandlerStack::create($mock);
309+
310+
$request = new ModelRequest(Bulletin::class,['id'=>'1']);
311+
$server = new API();
312+
$bulletin = $server
313+
->addMockHandler($handler)
314+
->connect('server','username','password')
315+
->get($request);
316+
317+
$this->assertEquals('server/carouselapi/v1/bulletins/1', (string) $mock->getLastRequest()->getUri());
318+
$this->assertEquals('GET', (string) $mock->getLastRequest()->getMethod());
319+
$this->assertInstanceOf(API::class, $bulletin->getApi());
320+
}
283321
}

Tests/CarouselModelTest.php

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
<?php
2+
3+
use TRMS\Carousel\Models\Bulletin;
4+
use TRMS\Carousel\Server\API;
5+
use TRMS\Carousel\Exceptions\CarouselModelException;
6+
7+
use GuzzleHttp\Handler\MockHandler;
8+
use GuzzleHttp\HandlerStack;
9+
use GuzzleHttp\Psr7\Response;
10+
use GuzzleHttp\Psr7\Request;
11+
use GuzzleHttp\Exception\RequestException;
12+
13+
class CarouselModelTest extends PHPUnit_Framework_TestCase
14+
{
15+
function test_a_persisted_model_has_a_save_function_that_uses_the_api_it_was_created_with()
16+
{
17+
$apiMock = \Mockery::mock(API::class);
18+
$apiMock->shouldReceive('save')
19+
->once()
20+
->andReturn(new Bulletin(['id'=>'1']));
21+
22+
$bulletin = new Bulletin(['id'=>'1'],$apiMock);
23+
24+
$bulletin->save();
25+
26+
\Mockery::close();
27+
}
28+
29+
function test_calling_save_on_a_model_without_an_api_will_throw_a_carousel_model_exception()
30+
{
31+
$bulletin = new Bulletin(['id'=>'1']);
32+
33+
try{
34+
$bulletin->save();
35+
} catch(CarouselModelException $e){
36+
return;
37+
}
38+
39+
$this->fail('the exception was not thrown');
40+
}
41+
42+
function test_calling_save_on_a_non_persisted_model_will_throw_a_carousel_model_exception()
43+
{
44+
$apiMock = \Mockery::mock(API::class);
45+
$apiMock->shouldNotReceive('save');
46+
47+
$bulletin = new Bulletin([],$apiMock);
48+
49+
try{
50+
$bulletin->save();
51+
} catch(CarouselModelException $e){
52+
\Mockery::close();
53+
return;
54+
}
55+
56+
$this->fail('the exception was not thrown');
57+
58+
}
59+
60+
function test_a_persisted_model_has_a_delete_function_that_uses_the_api_it_was_created_with()
61+
{
62+
$apiMock = \Mockery::mock(API::class);
63+
$apiMock->shouldReceive('delete')
64+
->once()
65+
->andReturn(new Bulletin(['id'=>'1']));
66+
67+
$bulletin = new Bulletin(['id'=>'1'],$apiMock);
68+
69+
$bulletin->delete();
70+
71+
\Mockery::close();
72+
}
73+
74+
function test_calling_delete_on_a_model_without_an_api_will_throw_a_carousel_model_exception()
75+
{
76+
$bulletin = new Bulletin(['id'=>'1']);
77+
78+
try{
79+
$bulletin->delete();
80+
} catch(CarouselModelException $e){
81+
return;
82+
}
83+
84+
$this->fail('the exception was not thrown');
85+
}
86+
87+
function test_calling_delete_on_a_non_persisted_model_will_throw_a_carousel_model_exception()
88+
{
89+
$apiMock = \Mockery::mock(API::class);
90+
$apiMock->shouldNotReceive('delete');
91+
92+
$bulletin = new Bulletin([],$apiMock);
93+
94+
try{
95+
$bulletin->delete();
96+
} catch(CarouselModelException $e){
97+
\Mockery::close();
98+
return;
99+
}
100+
101+
$this->fail('the exception was not thrown');
102+
103+
}
104+
}

src/Models/CarouselModel.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,22 @@ public function setProps(Array $props)
2828
}
2929
}
3030

31+
public function save()
32+
{
33+
if(!$this->api || !$this->id){
34+
throw new CarouselModelException("You must use the API's save() method to save new models");
35+
}
36+
$this->api->save($this);
37+
}
38+
39+
public function delete()
40+
{
41+
if(!$this->api || !$this->id){
42+
throw new CarouselModelException("why would you try to delete a model that has never been persisted?");
43+
}
44+
$this->api->delete($this);
45+
}
46+
3147
public function getSaveMethod(){
3248
if(isset($this->id)){
3349
return "put";

src/Models/SaveableInterface.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,6 @@
33
interface SaveableInterface {
44
public function getSaveEndpoint();
55
public function getSaveMethod();
6+
public function save();
7+
public function delete();
68
}

src/Server/API.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ public function save(CarouselModel $model)
8989
];
9090
$request = new APIRequest($this->client, $this->handler, $options);
9191
$response = $request->$method($endpoint, json_encode($model->toArray()));
92-
92+
$model->setApi($this);
9393
$model->setProps($response);
9494
return $model;
9595
}

0 commit comments

Comments
 (0)