Skip to content

Commit dc539ee

Browse files
authored
Merge pull request #102 from utopia-php/feat-v2
Framework V2
2 parents ad6f7e6 + ee4fc6d commit dc539ee

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

88 files changed

+2299
-1135
lines changed

.github/workflows/test.yml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,16 @@ jobs:
1313
- name: Setup PHP
1414
uses: shivammathur/setup-php@v2
1515
with:
16-
php-version: '8.0'
16+
php-version: '8.1'
1717

1818
- name: Setup Docker
1919
run: docker-compose up -d --build
2020

2121
- name: Wait for Server to be ready
2222
run: sleep 10
2323

24-
- name: Run Tests
25-
run: docker compose exec web vendor/bin/phpunit --configuration phpunit.xml
24+
- name: Run FPM Tests
25+
run: docker compose exec fpm vendor/bin/phpunit --configuration phpunit.xml
26+
27+
- name: Run Swoole Tests
28+
run: docker compose exec swoole vendor/bin/phpunit --configuration phpunit.xml

CONTRIBUTING.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@ $ git push origin [name_of_your_new_branch]
6464
8. After approval, merge your PR
6565
9. GitHub will automatically delete the branch after the merge is done. (they can still be restored).
6666

67+
### Testing
68+
69+
- `docker-compose up -d`
70+
- `docker-compose exec web vendor/bin/phpunit --configuration phpunit.xml`
71+
- `docker-compose exec web vendor/bin/psalm --show-info=true`
72+
6773
## Introducing New Features
6874

6975
We would 💖 you to contribute to Framework, but we would also like to make sure Framework is as great as possible and loyal to its vision and mission statement 🙏.
File renamed without changes.

Dockerfile.swoole

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
FROM composer:2.0 AS step0
2+
3+
4+
ARG TESTING=true
5+
6+
ENV TESTING=$TESTING
7+
8+
WORKDIR /usr/local/src/
9+
10+
COPY composer.* /usr/local/src/
11+
12+
RUN composer install --ignore-platform-reqs --optimize-autoloader \
13+
--no-plugins --no-scripts --prefer-dist \
14+
`if [ "$TESTING" != "true" ]; then echo "--no-dev"; fi`
15+
16+
FROM appwrite/base:0.4.3 as final
17+
LABEL maintainer="team@appwrite.io"
18+
19+
WORKDIR /usr/src/code
20+
21+
COPY ./src /usr/src/code/src
22+
COPY ./tests /usr/src/code/tests
23+
COPY ./phpunit.xml /usr/src/code/phpunit.xml
24+
COPY ./phpbench.json /usr/src/code/phpbench.json
25+
COPY --from=step0 /usr/local/src/vendor /usr/src/code/vendor
26+
27+
EXPOSE 80
28+
29+
CMD ["php", "tests/e2e/server-swoole.php"]

README.md

Lines changed: 189 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
Utopia Framework is a PHP MVC based framework with minimal must-have features for professional, simple, advanced and secure web development. This library is maintained by the [Appwrite team](https://appwrite.io).
1010

11-
Utopia Framework is dependency free. Any extra features such as authentication, caching will be available as standalone models in order to keep the framework core as clean, light and easy to learn.
11+
Utopia Framework is dependency-free. Any extra features, such as authentication or caching, will be available as standalone models in order to keep the framework core clean, light, and easy to learn.
1212

1313
## Getting Started
1414

@@ -17,19 +17,21 @@ Install using composer:
1717
composer require utopia-php/framework
1818
```
1919

20-
Init your first application:
20+
Init your first application in `src/server.php`:
21+
2122
```php
22-
require_once __DIR__ . '/../../vendor/autoload.php';
23+
require_once __DIR__.'/../vendor/autoload.php';
2324

24-
use Utopia\App;
25-
use Utopia\Request;
26-
use Utopia\Response;
25+
use Utopia\Http\Http;
26+
use Utopia\Http\Request;
27+
use Utopia\Http\Response;
28+
use Utopia\Http\Adapter\FPM\Server;
2729

28-
App::get('/hello-world') // Define Route
30+
Http::get('/hello-world') // Define Route
2931
->inject('request')
3032
->inject('response')
3133
->action(
32-
function($request, $response) {
34+
function(Request $request, Response $response) {
3335
$response
3436
->addHeader('Cache-Control', 'no-cache, no-store, must-revalidate')
3537
->addHeader('Expires', '0')
@@ -38,90 +40,222 @@ App::get('/hello-world') // Define Route
3840
}
3941
);
4042

41-
App::setMode(App::MODE_TYPE_PRODUCTION); // Define Mode
43+
Http::setMode(Http::MODE_TYPE_PRODUCTION);
44+
45+
$http = new Http(new Server(), 'America/New_York');
46+
$http->start();
47+
```
4248

43-
$app = new App('America/New_York');
44-
$request = new Request();
45-
$response = new Response();
49+
Run HTTP server:
4650

47-
$app->run($request, $response);
51+
```bash
52+
php -S localhost:8000 src/server2.php
4853
```
4954

50-
### Hooks
55+
Send HTTP request:
56+
57+
```bash
58+
curl http://localhost:8000/hello-world
59+
```
60+
61+
### Server Adapters
62+
63+
The library supports server adapters to be able to run on any PHP setup. For instance, you could use the FPM server or the Swoole server.
64+
65+
#### Use PHP FPM server
66+
67+
```php
68+
use Utopia\Http\Http;
69+
use Utopia\Http\Response;
70+
use Utopia\Http\Adapter\FPM\Server;
71+
72+
Http::get('/')
73+
->inject('response')
74+
->action(
75+
function(Response $response) {
76+
$response->send('Hello from PHP FPM');
77+
}
78+
);
5179

52-
There are three types of hooks, init hooks, shutdown hooks and error hooks. Init hooks are executed before the route action is executed. Shutdown hook is executed after route action is executed before application shuts down. Finally error hooks are executed whenever there's an error in the application lifecycle. You can provide multiple hooks for each stage. If you do not assign groups to the hook, by default the hook will be executed for every route.
80+
$http = new Http(new Server(), 'America/New_York');
81+
$http->start();
82+
```
83+
84+
> When using PHP FPM, you can use the command `php -S localhost:80 src/server.php` to run the HTTP server locally
85+
86+
#### Using Swoole server
5387

5488
```php
55-
require_once __DIR__ . '/../../vendor/autoload.php';
89+
use Utopia\Http\Http;
90+
use Utopia\Http\Request;
91+
use Utopia\Http\Response;
92+
use Utopia\Http\Adapter\Swoole\Server;
93+
94+
Http::get('/')
95+
->inject('request')
96+
->inject('response')
97+
->action(
98+
function(Request $request, Response $response) {
99+
$response->send('Hello from Swoole');
100+
}
101+
);
102+
103+
$http = new Http(new Server('0.0.0.0', '80'), 'America/New_York');
104+
$http->start();
105+
```
106+
107+
> When using Swoole, you can use the command `php src/server.php` to run the HTTP server locally, but you need Swoole installed. For setup with Docker, check out our [example application](/example)
108+
109+
### Parameters
110+
111+
Parameters are used to receive input into endpoint action from the HTTP request. Parameters could be defined as URL parameters or in a body with a structure such as JSON.
112+
113+
Every parameter must have a validator defined. Validators are simple classes that verify the input and ensure the security of inputs. You can define your own validators or use some of [built-in validators](/src/Http/Validator).
114+
115+
Define an endpoint with params:
116+
117+
```php
118+
Http::get('/')
119+
->param('name', 'World', new Text(256), 'Name to greet. Optional, max length 256.', true)
120+
->inject('response')
121+
->action(function(string $name, Response $response) {
122+
$response->send('Hello ' . $name);
123+
});
124+
```
125+
126+
Send HTTP requests to ensure the parameter works:
127+
128+
```bash
129+
curl http://localhost:8000/hello-world
130+
curl http://localhost:8000/hello-world?name=Utopia
131+
curl http://localhost:8000/hello-world?name=Appwrite
132+
```
133+
134+
It's always recommended to use params instead of getting params or body directly from the request resource. If you do that intentionally, always make sure to run validation right after fetching such a raw input.
135+
136+
### Hooks
137+
138+
There are three types of hooks:
56139

57-
use Utopia\App;
58-
use Utopia\Request;
59-
use Utopia\Response;
140+
- **Init hooks** are executed before the route action is executed
141+
- **Shutdown hooks** are executed after route action is finished, but before application shuts down
142+
- **Error hooks** are executed whenever there's an error in the application lifecycle.
60143

61-
App::init()
144+
You can provide multiple hooks for each stage. If you do not assign groups to the hook, by default, the hook will be executed for every route. If a group is defined on a hook, it will only run during the lifecycle of a request with the same group name on the action.
145+
146+
```php
147+
Http::init()
148+
->inject('request')
149+
->action(function(Request $request) {
150+
\var_dump("Recieved: " . $request->getMethod() . ' ' . $request->getURI());
151+
});
152+
153+
Http::shutdown()
62154
->inject('response')
63-
->action(function($response) {
64-
$response->addHeader('content-type', 'application/json');
155+
->action(function(Response $response) {
156+
\var_dump('Responding with status code: ' . $response->getStatusCode());
65157
});
66158

67-
App::error()
159+
Http::error()
68160
->inject('error')
69161
->inject('response')
70-
->action(function($error, $response) {
162+
->action(function(\Throwable $error, Response $response) {
71163
$response
72164
->setStatusCode(500)
73165
->send('Error occurred ' . $error);
74166
});
167+
```
75168

76-
App::get('/hello-world') // Define Route
77-
->inject('request')
169+
Hooks are designed to be actions that run during the lifecycle of requests. Hooks should include functional logic. Hooks are not designed to prepare dependencies or context for the request. For such a use case, you should use resources.
170+
171+
### Groups
172+
173+
Groups allow you to define common behavior for multiple endpoints.
174+
175+
You can start by defining a group on an endpoint. Keep in mind you can also define multiple groups on a single endpoint.
176+
177+
```php
178+
Http::get('/v1/health')
179+
->groups(['api', 'public'])
78180
->inject('response')
79181
->action(
80-
function($request, $response) {
81-
$response
82-
->addHeader('Cache-Control', 'no-cache, no-store, must-revalidate')
83-
->addHeader('Expires', '0')
84-
->addHeader('Pragma', 'no-cache')
85-
->json(['Hello' => 'World']);
182+
function(Response $response) {
183+
$response->send('OK');
86184
}
87185
);
186+
```
88187

89-
App::setMode(App::MODE_TYPE_PRODUCTION); // Define Mode
188+
Now you can define hooks that would apply only to specific groups. Remember, hooks can also be assigned to multiple groups.
90189

91-
$app = new App('America/New_York');
92-
$request = new Request();
93-
$response = new Response();
190+
```php
191+
Http::init()
192+
->groups(['api'])
193+
->inject('request')
194+
->inject('response')
195+
->action(function(Request $request, Response $response) {
196+
$apiKey = $request->getHeader('x-api-key', '');
94197

95-
$app->run($request, $response);
198+
if(empty($apiKey)) {
199+
$response
200+
->setStatusCode(Response::STATUS_CODE_UNAUTHORIZED)
201+
->send('API key missing.');
202+
}
203+
});
96204
```
97205

206+
Groups are designed to be actions that run during the lifecycle of requests to endpoints that have some logic in common. Groups allow you to prevent code duplication and are designed to be defined anywhere in your source code to allow flexibility.
207+
208+
### Resources
209+
210+
Resources allow you to prepare dependencies for requests such as database connection or the user who sent the request. A new instance of a resource is created for every request.
211+
212+
Define a resource:
213+
214+
```php
215+
Http::setResource('timing', function() {
216+
return \microtime(true);
217+
});
218+
```
219+
220+
Inject resource into endpoint action:
221+
222+
```php
223+
Http::get('/')
224+
->inject('timing')
225+
->inject('response')
226+
->action(function(float $timing, Response $response) {
227+
$response->send('Request Unix timestamp: ' . \strval($timing));
228+
});
229+
```
230+
231+
Inject resource into a hook:
232+
233+
```php
234+
Http::shutdown()
235+
->inject('timing')
236+
->action(function(float $timing) {
237+
$difference = \microtime(true) - $timing;
238+
\var_dump("Request took: " . $difference . " seconds");
239+
});
240+
```
241+
242+
In advanced scenarios, resources can also be injected into other resources or endpoint parameters.
243+
244+
Resources are designed to prepare dependencies or context for the request. Resources are not meant to do functional logic or return callbacks. For such a use case, you should use hooks.
245+
246+
To learn more about Framework architecture and features, check out more in-depth [Getting started guide](/docs/Getting-Starting-Guide.md).
247+
98248
## System Requirements
99249

100250
Utopia Framework requires PHP 8.0 or later. We recommend using the latest PHP version whenever possible.
101251

102252
## More from Utopia
103253

104-
Our ecosystem support other thin PHP projects aiming to extend the core PHP Utopia framework.
254+
Our ecosystem supports other thin PHP projects aiming to extend the core PHP Utopia framework.
105255

106256
Each project is focused on solving a single, very simple problem and you can use composer to include any of them in your next project.
107257

108-
Library | Description
109-
--- | ---
110-
**[Utopia AB](https://github.com/utopia-php/ab)** | Simple PHP library for managing AB testing on the server side.
111-
**[Utopia Abuse](https://github.com/utopia-php/abuse)** | Simple PHP library for rate limiting usage of different features in your app or API.
112-
**[Utopia Analytics](https://github.com/utopia-php/analytics)** | Simple PHP library to send information about events or pageviews to Google Analytics.
113-
**[Utopia Audit](https://github.com/utopia-php/audit)** | Simple PHP library for audit logging users actions and system events
114-
**[Utopia Cache](https://github.com/utopia-php/cache)** | Simple PHP library for managing cache with different storage adapters.
115-
**[Utopia CLI](https://github.com/utopia-php/cli)** | Simple PHP library for for building simple command line tools.
116-
**[Utopia Config](https://github.com/utopia-php/config)** | Simple PHP library for managing your app configuration.
117-
**[Utopia Database](https://github.com/utopia-php/database)** | Simple PHP library for managing application persistency. It supports multiple database adapters.
118-
**[Utopia Domains](https://github.com/utopia-php/domains)** | Simple PHP library for parsing domain names.
119-
**[Utopia Image](https://github.com/utopia-php/image)** | Simple PHP library for creating common image manipulations that is easy to use.
120-
**[Utopia Locale](https://github.com/utopia-php/locale)** | Simple PHP library for adding support to multiple locales in your app or API.
121-
**[Utopia Preloader](https://github.com/utopia-php/preloader)** | Simple PHP library for managing PHP preloading configuration.
122-
**[Utopia Registry](https://github.com/utopia-php/registry)** | Simple PHP library for dependency injection and lazy loading of objects or resources.
123-
**[Utopia System](https://github.com/utopia-php/system)** | Simple PHP library for obtaining information about the host's system.
124-
**[Utopia Storage](https://github.com/utopia-php/storage)** | Simple and lite PHP library for managing application storage. It supports multiple storage adapters.
258+
You can find all libraries in [GitHub Utopia organization](https://github.com/utopia-php).
125259

126260
## Contributing
127261

@@ -133,12 +267,6 @@ You can refer to the [Contributing Guide](https://github.com/utopia-php/framewor
133267

134268
For security issues, please email security@appwrite.io instead of posting a public issue in GitHub.
135269

136-
### Testing
137-
138-
- `docker-compose up -d`
139-
- `docker-compose exec web vendor/bin/phpunit --configuration phpunit.xml`
140-
- `docker-compose exec web vendor/bin/psalm --show-info=true`
141-
142270
## Copyright and license
143271

144272
The MIT License (MIT) [http://www.opensource.org/licenses/mit-license.php](http://www.opensource.org/licenses/mit-license.php)

0 commit comments

Comments
 (0)