|
| 1 | +# About this project |
| 2 | + |
| 3 | +This is pretty raw library which is aimed to provide full HTTP client mock for `stripe-php` library in order to |
| 4 | +perform tests without actually sending HTTP requests to Stripe. |
| 5 | + |
| 6 | +At the moment this library covers a small part of `stripe-php` functionality but there is a hope that one day |
| 7 | +it will be developed enough to cover everything `stripe-php` provides. |
| 8 | + |
| 9 | +The main idea behind this library is to provide stateful "server" which remembers of what he was asked before. |
| 10 | +The state is not saved between lifecycles but within a single lifecycle the state is preserved. This is the |
| 11 | +main difference from [the official Stripe's server mock](https://github.com/stripe/stripe-mock). |
| 12 | +Another reason for this library to exist is to avoid having a separate component of you application written |
| 13 | +in a different programming language and thus requiring to have another container with it (or environment |
| 14 | +configuration in container-less case). |
| 15 | + |
| 16 | +# Taking a part in this project |
| 17 | + |
| 18 | +The task "to cover all the functionality of `stripe-php` library" is really huge. It's possible to achieve it, |
| 19 | +but it requires a huge efforts (as huge as the task is) and is financially senseless in order to be implemented |
| 20 | +by a group of programmers while working on the main project. |
| 21 | + |
| 22 | +Therefore, it is **highly** appreciated to take part in this project for anyone interested in any of thees ways: |
| 23 | +- You have an idea on how to improve this project, or you see that something is wrong? Don't hesitate opening |
| 24 | +an issue. |
| 25 | +- You have time and will to add/improve functionality or fix a bug? Your pull requests would be **extremely** |
| 26 | +valuable |
| 27 | + |
| 28 | +# Installation |
| 29 | + |
| 30 | +Nothing special here, just use composer to install the package and that's it. |
| 31 | + |
| 32 | +# Usage |
| 33 | + |
| 34 | +Usage is as simple as two lines of code in bootstrap script of your PHPUnit configuration: |
| 35 | + |
| 36 | +>Readdle\StripeHttpClientMock\HttpClient::$apiKey = "your_api_key_goes_here"; |
| 37 | +> |
| 38 | +>Stripe\ApiRequestor\ApiRequestor::setHttpClient(new Readdle\StripeHttpClientMock\HttpClient()); |
| 39 | +
|
| 40 | +That's it, now you have your instance of `stripe-php`'s HTTP client mocked, and it will "communicate" with a |
| 41 | +piece of code instead of performing real HTTP requests. |
| 42 | + |
| 43 | +# Overall structure |
| 44 | + |
| 45 | +### Files |
| 46 | + |
| 47 | +`Collection.php` - representation of collection of entities |
| 48 | + |
| 49 | +`EntityManager.php` - manager, which is responsible for creating/updating/deleting/listing entities, also performs |
| 50 | +search and paging functions |
| 51 | + |
| 52 | +`HttpClient.php` - it's obvious from its name, HTTP client which substitutes `stripe-php`'s curl-based client |
| 53 | + |
| 54 | +### Directories |
| 55 | + |
| 56 | +`Entity` - implemented entities, each entity **must** extend AbstractEntity class |
| 57 | + |
| 58 | +`Error` - erroneous responses, each error **must** extend AbstractError class |
| 59 | + |
| 60 | +`Success` - success responses, which doesn't contain entity in it, but an information about an action |
| 61 | +and its result, **must** implement `ResponseInterface` |
| 62 | + |
| 63 | +# Entity structure |
| 64 | + |
| 65 | +### Props |
| 66 | + |
| 67 | +Each entity **must** have at least `$props` property filled in with all the fields this entity has (the list of fields |
| 68 | +for each entity could be found in [Stripe's documentation](https://stripe.com/docs/api)). |
| 69 | + |
| 70 | +### Prefix |
| 71 | + |
| 72 | +In most cases an entity will override method `prefix()` in order to have the correct prefix in newly generated IDs. |
| 73 | + |
| 74 | +--- |
| 75 | + |
| 76 | +The following is optional and should be applied in cases when it is needed, however to have **all** the functionality |
| 77 | +covered it's better to follow these instructions where it's applicable. |
| 78 | + |
| 79 | +--- |
| 80 | + |
| 81 | +### Creation of an entity |
| 82 | + |
| 83 | +If the creation of an entity requires any additional actions, you can override `create()` method and do something |
| 84 | +prior/after the creation happens. Usually it's useful for creating related entities. |
| 85 | + |
| 86 | +### Expandable properties |
| 87 | + |
| 88 | +Entity may have property `$expandableProps` filled with the fields which could be expanded (they are marked |
| 89 | +as "expandable" in the documentation). By default, if a field is listed in this array and request contains |
| 90 | +`expand` parameter which requires this field to be expanded, an entity will try to expand this field automatically. |
| 91 | +The field name will be used as sub-entity name (class) and its value will be used as an ID. This is a recursive |
| 92 | +action, so in case when `expand` parameter requires expanding of a field in the expanded field, it will be passed |
| 93 | +to subsequent entity and will be expanded in the same way. |
| 94 | + |
| 95 | +In case when the logic of expanding the field is more complex, you can override `howToExpand()` method and |
| 96 | +implement specific piece of logic for the entity there. Please, don't forget to call parent method for cases |
| 97 | +when your implementation is not covering the case. |
| 98 | + |
| 99 | +### Sub-actions |
| 100 | + |
| 101 | +Entity may have property `$subActions` filled with all the available sub-actions. Sub-action is an action performed on |
| 102 | +an entity which is not following (due to impossibility) the REST concept. For example: |
| 103 | +> POST /v1/payment_methods/:id/attach |
| 104 | +> |
| 105 | +> POST /v1/payment_methods/:id/detach |
| 106 | +
|
| 107 | +These are not actions of creating/updating/deleting, but performing additional action on the exact entity. |
| 108 | + |
| 109 | +`$subActions` is an associative array where the key is an action (what is stated in the request) and the value is |
| 110 | +a name of a method, which is responsible for performing this action. This method should return an implementation |
| 111 | +of `ResponseInterface` and it will be returned as an "API response" to the `stripe-php` client. |
| 112 | + |
| 113 | +In case when this functionality can't fulfil an entity's behaviour, you can override `subAction()` method and implement |
| 114 | +custom logic for that entity. Don't forget to call parent method in order to cover regular cases. |
| 115 | + |
| 116 | +### Sub-entities |
| 117 | + |
| 118 | +Entity may have property `$subEntities` filled with entity names of its sub-entities. Sub-entity is an entity |
| 119 | +which is accessed through the main entity, take a look at these examples: |
| 120 | +> POST /v1/customers/:id/tax_ids |
| 121 | +> |
| 122 | +> GET /v1/customers/:id/tax_ids/:id |
| 123 | +> |
| 124 | +> DELETE /v1/customers/:id/tax_ids/:id |
| 125 | +> |
| 126 | +> GET /v1/customers/:id/tax_ids |
| 127 | +> |
| 128 | +Despite the fact that these requests are performed (following the REST concept) on the `customer` entity, actually |
| 129 | +all of them are performed on the `tax_id` entity of the customer with the specified ID. So, the library transforms |
| 130 | +all these actions in a way like they are performed (in this particular example) on the `tax_id` entity, but using |
| 131 | +`customer`'s ID as a filter (or a value for the appropriate field in case when the `tax_id` entity is being created). |
| 132 | + |
| 133 | +### Uncovered requests |
| 134 | + |
| 135 | +It is possible (and even likely) that there are some specific requests which are not covered by this library. |
| 136 | +If the requested URL differs from a regular one (performing an action on an entity, performing a sub-action on an |
| 137 | +entity or performing an action on sub-entity), you can override `parseUrlTail()` method of the appropriate entity and |
| 138 | +add logic which parses this specific request. But it's most likely that the library won't be able to deal with |
| 139 | +this result, so there are two preferred ways of sorting it out: |
| 140 | +- open an issue and ask for the functionality that the library lacks with detailed description of how to implement it |
| 141 | +- improve the library and create a pull request with code which covers this specific case |
| 142 | + |
| 143 | +Both options would be **highly** appreciated and the reaction will follow as soon as it possible. |
0 commit comments