Skip to content

Commit

Permalink
Feature/improvements (#10)
Browse files Browse the repository at this point in the history
* Experimental Branch

* Added some underlying scaffolding

* Added binary to composer file

* Improved error handling

Handles missing arguments better

* Fixed a bug in the RegExpValidator

Expected to return boolean, but returned int|false from preg_match. Corrected the issue and added a test around it.

* Ensured strict types are respected in validators

Validators now correctly respecting strict types, added supporting tests and reordered min/max parameters for float and int.

* Added the ability to clear the route cache

Support for clearing the route cache
Added documentation for:
- Using the streetlamp binary
- NGINX Setup

* Linux line endings

Fixed the line endings

* Fix line endings

* Fixing PHP CS issues

* Fixing formatting issue
  • Loading branch information
willitscale authored Jan 29, 2024
1 parent 131cbdc commit e272aad
Show file tree
Hide file tree
Showing 40 changed files with 1,403 additions and 413 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,9 @@ We could have also applied the `#[Path('/hello')]` to the `RouteController` and
- [Validators](docs/VALIDATORS.MD)
- [Caching](docs/CACHING.MD)
- [Configuration](docs/CONFIGURATION.MD)
- [Setup](docs/SETUP.MD)
- [Testing](docs/TESTING.MD)
- [Error Codes](docs/ERROR_CODES.MD)
- [Commands](docs/COMMANDS.MD)
- [Performance](docs/PERFORMANCE.MD)
- [TODO](docs/TODO.MD)
5 changes: 4 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,8 @@
"platform": {
"php": "8.2.0"
}
}
},
"bin": [
"streetlamp"
]
}
69 changes: 69 additions & 0 deletions docs/COMMANDS.MD
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Commands

Streetlamp is accompanied by a binary application which allows you to perform basic streetlamp commands.

## Available commands

The commands available are the following formats:

### Init Docker

Init docker will scaffold a simple docker compose infrastructure for you app to build and run locally.

#### Command

```bash
vendor/bin/streetlamp init docker
```

### Routes List

Routes list simply provides you with a list of all possible routes and which classes and functions they map to.
It takes two optional parameters of:
- `APPLICATION_PATH` which is the root directory of your application.
- `COMPOSER_FILE` an alternative composer file for your application.

#### Command

```bash
vendor/bin/streetlamp routes list <APPLICATION_PATH> <COMPOSER_FILE>
```

#### Example

Run using the TestApp in the Streetlamp tests.

```bash
root@4e192099443e:/app# ./streetlamp routes list tests tests/TestApp/composer.test.json
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Method | Path | Accepts | Class | Function |
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| GET | /cache/(?<cacheId>[^/]+) | | willitscale\StreetlampTests\TestApp\Controllers\CacheTestController | simpleGetWithCacheRule |
| GET | /cache/parameter/(?<cacheId>[^/]+) | | willitscale\StreetlampTests\TestApp\Controllers\CacheTestController | simpleGetWithParameterCacheRule |
| POST | /json/array | | willitscale\StreetlampTests\TestApp\Controllers\JsonTestController | mapJsonArray |
| POST | /json/nested | | willitscale\StreetlampTests\TestApp\Controllers\JsonTestController | mapNestedJsonArray |
| GET | / | | willitscale\StreetlampTests\TestApp\Controllers\TestController | simpleGet |
| GET | /json | application/json | willitscale\StreetlampTests\TestApp\Controllers\TestController | simpleGetThatAcceptsJsonOnly |
| POST | / | | willitscale\StreetlampTests\TestApp\Controllers\TestController | simplePost |
| PUT | /(?<test>[^/]+) | | willitscale\StreetlampTests\TestApp\Controllers\TestController | simplePut |
| DELETE | / | | willitscale\StreetlampTests\TestApp\Controllers\TestController | simpleDelete |
| PATCH | / | | willitscale\StreetlampTests\TestApp\Controllers\TestController | simplePatch |
| GET | /validator/(?<validatorId>[^/]+) | | willitscale\StreetlampTests\TestApp\Controllers\ValidatorTestController | simpleGetWithPathParameterAndValidator |
| POST | /validator/validation | | willitscale\StreetlampTests\TestApp\Controllers\ValidatorTestController | validateSingleInput |
| POST | /validator/validations | | willitscale\StreetlampTests\TestApp\Controllers\ValidatorTestController | validateMultipleInputs |
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
```

### Routes Cache Clear

A way to clear the routes cache which may persist between code changes.
It takes two optional parameters of:
- `APPLICATION_PATH` which is the root directory of your application.
- `COMPOSER_FILE` an alternative composer file for your application.

#### Command

```bash
vendor/bin/streetlamp routes cache clear <OPTIONAL_PATH> <OPTIONAL_COMPOSER_FILE>
```

246 changes: 123 additions & 123 deletions docs/DATA_MAPPING.MD
Original file line number Diff line number Diff line change
@@ -1,123 +1,123 @@

# Data Mapping

Streetlamp supports object mapping with the help of the `DataBindingObjectInterface`.
You can either use pre-existing data bindings which are currently limited to JSON, or alternatively create your own.
Again, as with most parts of Streetlamp, the data mapping has fully supported extensibility to fit your needs.
As JSON is the most commonly used format for data exchange, there's an included set of libraries to allow you to map data in both directions.

## Route Definition

When defining a data binding in your route, you simply need to bind the input to that particular route.
Similarly, if you want to return an object you just need to set it as the data in the `ResponseBuilder`.

## Signatures

```php
#[JsonObject]
#[JsonIgnore]
#[JsonProperty(bool $required = true, ?string $alias = null)]
#[JsonArray(string $className, bool $required = true, ?string $alias = null)]
```

## Example

### Controller

```php
#[RouteController]
#[Path('/person')]
class Person
{
#[Method(HttpMethod::POST)]
#[Accepts(MediaType::APPLICATION_JSON)]
public function createPerson(
#[BodyParameter] PersonModel $personModel
): ResponseBuilder
{
return (new ResponseBuilder())
->setData($personModel)
->setHttpStatusCode(HttpStatusCode::HTTP_OK)
->setContentType(MediaType::APPLICATION_JSON);
}
}

```

### Model

```php
#[JsonObject]
class PersonModel
{
#[JsonProperty(true)]
#[AlphabeticValidator]
private string $name;

#[JsonProperty]
private AgeModel $data;

public function __construct(
#[JsonProperty(true)]
#[JsonIgnore]
private string $email
) {}

}
```

As shown in the above example you can use the annotation `JsonProperty` at both member and constructor levels.

### cURL

```sh
curl --request POST \
--location 'http://localhost/person' \
--header 'Content-Type: application/json' \
--data-raw '{
"name": "test",
"email": "[email protected]",
"data": {
"age": 60
}
}'
```

## Mapping Arrays

In addition to mapping objects directly to variables, you can also map arrays of objects too.
This is done using the `JsonArray` attribute which can be applied to input parameters and properties of a `JsonObject`.

### Controller

```php
#[Method(HttpMethod::POST)]
#[Path('/array')]
public function mapJsonArray(
#[BodyParameter]
#[JsonArray(DataType::class)] array $dataTypes
): ResponseBuilder {
return (new ResponseBuilder())
->setData($dataTypes)
->setContentType(MediaType::APPLICATION_JSON)
->setHttpStatusCode(HttpStatusCode::HTTP_OK);
}
```

The `JsonArray` object defined must be a `JsonObject` and each object will apply the validation rules where applicable too.

### Model

```php
#[JsonObject]
readonly class NestedDataType
{
public function __construct(
#[JsonArray(DataType::class, true)] public array $dataTypeArray,
#[JsonProperty(true)] public array $nativeArray
) {
}
}
```

Only one of either the `JsonArray` or `JsonProperty` can be applied to a property with the `JsonArray` taking priority.

# Data Mapping

Streetlamp supports object mapping with the help of the `DataBindingObjectInterface`.
You can either use pre-existing data bindings which are currently limited to JSON, or alternatively create your own.
Again, as with most parts of Streetlamp, the data mapping has fully supported extensibility to fit your needs.
As JSON is the most commonly used format for data exchange, there's an included set of libraries to allow you to map data in both directions.

## Route Definition

When defining a data binding in your route, you simply need to bind the input to that particular route.
Similarly, if you want to return an object you just need to set it as the data in the `ResponseBuilder`.

## Signatures

```php
#[JsonObject]
#[JsonIgnore]
#[JsonProperty(bool $required = true, ?string $alias = null)]
#[JsonArray(string $className, bool $required = true, ?string $alias = null)]
```

## Example

### Controller

```php
#[RouteController]
#[Path('/person')]
class Person
{
#[Method(HttpMethod::POST)]
#[Accepts(MediaType::APPLICATION_JSON)]
public function createPerson(
#[BodyParameter] PersonModel $personModel
): ResponseBuilder
{
return (new ResponseBuilder())
->setData($personModel)
->setHttpStatusCode(HttpStatusCode::HTTP_OK)
->setContentType(MediaType::APPLICATION_JSON);
}
}

```

### Model

```php
#[JsonObject]
class PersonModel
{
#[JsonProperty(true)]
#[AlphabeticValidator]
private string $name;

#[JsonProperty]
private AgeModel $data;

public function __construct(
#[JsonProperty(true)]
#[JsonIgnore]
private string $email
) {}

}
```

As shown in the above example you can use the annotation `JsonProperty` at both member and constructor levels.

### cURL

```sh
curl --request POST \
--location 'http://localhost/person' \
--header 'Content-Type: application/json' \
--data-raw '{
"name": "test",
"email": "[email protected]",
"data": {
"age": 60
}
}'
```

## Mapping Arrays

In addition to mapping objects directly to variables, you can also map arrays of objects too.
This is done using the `JsonArray` attribute which can be applied to input parameters and properties of a `JsonObject`.

### Controller

```php
#[Method(HttpMethod::POST)]
#[Path('/array')]
public function mapJsonArray(
#[BodyParameter]
#[JsonArray(DataType::class)] array $dataTypes
): ResponseBuilder {
return (new ResponseBuilder())
->setData($dataTypes)
->setContentType(MediaType::APPLICATION_JSON)
->setHttpStatusCode(HttpStatusCode::HTTP_OK);
}
```

The `JsonArray` object defined must be a `JsonObject` and each object will apply the validation rules where applicable too.

### Model

```php
#[JsonObject]
readonly class NestedDataType
{
public function __construct(
#[JsonArray(DataType::class, true)] public array $dataTypeArray,
#[JsonProperty(true)] public array $nativeArray
) {
}
}
```

Only one of either the `JsonArray` or `JsonProperty` can be applied to a property with the `JsonArray` taking priority.
8 changes: 8 additions & 0 deletions docs/SETUP.MD
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Setup

This section provides guides on how to setup Streetlamp with various HTTP servers.

| HTTP Server | Description |
|---------------------------------|-------------------------------------------|
| [Apache](Setup/APACHE_SETUP.MD) | TODO |
| [Nginx](Setup/NGINX_SETUP.MD) | How to setup Streetlamp with Nginx vHosts |
3 changes: 3 additions & 0 deletions docs/Setup/APACHE_SETUP.MD
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Apache Setup

TODO
Loading

0 comments on commit e272aad

Please sign in to comment.