Popcorn
The Popcorn PHP Micro-Framework is a lightweight REST micro-framework that's built
on top of the Pop PHP Framework core components. With it, you can rapidly wire together
the routes and configuration needed for your REST-based web application, while leveraging
the pre-existing features and functionality of the Pop PHP Framework. It provides a simple
layer on top of the main Pop\Application
object that allows you to wire up routes and
enforce their access based on the request method. By default, it ships with popphp/popphp
,
popphp/pop-http
, popphp/pop-session
and popphp/pop-view
components.
Basic Use
In a simple index.php
file, you can define the routes you want to allow in your application.
In this example, closures are used as the controllers. The wildcard route *
can serve as a
"catch-all" to handle routes that are not found or not allowed.
use Popcorn\Pop;
$app = new Pop();
// Home page: GET http://localhost/
$app->get('/', function() {
echo 'Hello World!';
});
// Say hello page: GET http://localhost/hello/world
$app->get('/hello/:name', function($name) {
echo 'Hello ' . ucfirst($name) . '!';
});
// Wildcard route to handle errors
$app->get('*', function() {
header('HTTP/1.1 404 Not Found');
echo 'Page Not Found.';
});
The above example defines two GET
routes and wildcard to handle failures.
We can define a POST
route like in this example below:
// Post auth route: POST http://localhost/auth
$app->post('/auth', function() {
if ($_SERVER['HTTP_AUTHORIZATION'] == 'my-token') {
echo 'Auth successful';
} else {
echo 'Auth failed';
}
});
$app->run();
curl -X POST --header "Authorization: bad-token" http://localhost:8000/auth
Auth failed
curl -X POST --header "Authorization: my-token" http://localhost:8000/auth
Auth successful
Advanced Use
In a more advanced example, we can take advantage of more of an MVC-style of wiring up an application
using the core components of Pop PHP with Popcorn. Let's look at a controller
class MyApp\Controller\IndexController
like this:
namespace MyApp\Controller;
use Pop\Controller\AbstractController;
use Pop\Http\Server\Request;
use Pop\Http\Server\Response;
use Pop\View\View;
class IndexController extends AbstractController
{
protected Request $request;
protected Response $response;
protected string $viewPath;
public function __construct(
Request $request = new Request(), Response $response = new Response()
)
{
$this->request = $request;
$this->response = $response;
$this->viewPath = __DIR__ . '/../view/';
}
public function index(): void
{
$view = new View($this->viewPath . '/index.phtml');
$view->title = 'Hello';
$this->response->setBody($view->render());
$this->response->send();
}
public function hello($name): void
{
$view = new View($this->viewPath . '/index.phtml');
$view->title = 'Hello ' . $name;
$view->name = $name;
$this->response->setBody($view->render());
$this->response->send();
}
public function error(): void
{
$view = new View($this->viewPath . '/error.phtml');
$view->title = 'Error';
$this->response->setBody($view->render());
$this->response->send(404);
}
}
and two view scripts, index.phtml
and error.phtml
, respectively:
<!DOCTYPE html>
<!-- index.phtml //-->
<html>
<head>
<title><?=$title; ?></title>
</head>
<body>
<h1><?=$title; ?></h1>
<?php if (isset($name)): ?>
<p>Your name is <?=$name; ?></p>
<?php endif; ?>
</body>
</html>
<!DOCTYPE html>
<!-- error.phtml //-->
<html>
<head>
<title><?=$title; ?></title>
</head>
<body>
<h1 style="color: #f00;"><?=$title; ?></h1>
<p>Sorry, that page was not found.</p>
</body>
</html>
Then we can set the app like this:
use Popcorn\Pop;
$app = new Pop();
$app->get('/', [
'controller' => 'MyApp\Controller\IndexController',
'action' => 'index',
'default' => true
]);
$app->get('/hello/:name', [
'controller' => 'MyApp\Controller\IndexController',
'action' => 'hello'
]);
$app->run();
The default
parameter sets the controller as the default controller to handle routes that aren't found. Typically, there is a default action in the controller, such as an error
method, to handle this.
Routes
As in the above examples, you can use the API to define routes directly:
get($route, $controller)
head($route, $controller)
post($route, $controller)
put($route, $controller)
delete($route, $controller)
trace($route, $controller)
options($route, $controller)
connect($route, $controller)
patch($route, $controller)
Or, you can use the standard Pop\Application
route configuration array
for Popcorn
by nesting the routes inside another array level, with the
array keys being the defined method:
// Routes configuration
$config = [
'routes' => [
'get' => [
'/users' => [
'controller' => 'MyApp\Http\Controller\UsersController',
'action' => 'index'
]
],
'post' => [
'/users' => [
'controller' => 'MyApp\Http\Controller\UsersController',
'action' => 'create'
]
],
'patch' => [
'/users/:id' => [
'controller' => 'MyApp\Http\Controller\UsersController',
'action' => 'update'
]
],
'delete' => [
'/users/:id' => [
'controller' => 'MyApp\Http\Controller\UsersController',
'action' => 'delete'
]
]
]
];
$app = new Pop($config);
Custom Methods
If your web server allows the configuration of custom HTTP methods, Popcorn supports that and allows you to register custom HTTP methods with the application.
use Popcorn\Pop;
$app = new Pop();
$app->addCustomMethod('PURGE')
->addCustomMethod('COPY');
$app->purge('/image/:id', function($id){
// Do something with the PURGE method on the image URL
});
$app->copy('/image/:id', function($id){
// Do something with the COPY method on the image URL
});
$app->run();
Then you can submit requests with your custom HTTP methods like this:
curl -X PURGE http://localhost/image/1
curl -X COPY http://localhost/image/1
API
Here is an overview of the available API within the Popcorn\Pop
class:
get($route, $controller)
- Set a GET routehead($route, $controller)
- Set a HEAD routepost($route, $controller)
- Set a POST routeput($route, $controller)
- Set a PUT routedelete($route, $controller)
- Set a DELETE routetrace($route, $controller)
- Set a TRACE routeoptions($route, $controller)
- Set an OPTIONS routeconnect($route, $controller)
- Set a CONNECT routepatch($route, $controller)
- Set a PATCH routesetRoute($method, $route, $controller)
- Set a specific routesetRoutes($methods, $route, $controller)
- Set a specific route and apply to multiple methods at onceaddToAll($route, $controller)
- Set a specific route to all methods at onceany($route, $controller)
- Set a specific route to all methods at once (alias to 'addToAll')addCustomMethod($customMethod)
- Add a custom methodhasCustomMethod($customMethod)
- Check if the object has a custom method
The setRoutes()
method allows you to set a specific route and
apply it to multiple methods all at once, like this:
use Popcorn\Pop;
$app = new Pop();
$app->setRoutes('get,post', '/login', [
'controller' => 'MyApp\Controller\IndexController',
'action' => 'login'
]);
$app->run();
In the above example, the route /login
could display the login form on
GET
, and then accept the login form submission on POST
.