In this document, we will see how to create a controller. You will also learn more about what makes a controller.
Note: if you are using Mouf, Splash comes with a controller creation wizard (a nice user interface).
In Splash, a controller is a class that contains a number of Actions. Actions are methods that can be directly accessed from the browser.
There are several ways to declare a method to be an action. The most common ways are:
This is the preferred way of declaring an action:
<?php
namespace Test\Controllers;
use TheCodingMachine\Splash\Annotations\URL;
use Psr\Http\Message\ResponseInterface;
class MyController {
/**
* My first action.
*
* @URL("/path/to/my/action")
* @param string $var1
* @param string $var2
*/
public function myUrl(string $var1, string $var2): ResponseInterface {
$str = "<html><head></head>";
$str .= "<body>";
$str .= "var1 value is ".htmlentities($var1)." and var2 value is ".htmlentities($var2);
$str .= "</body>";
return new HtmlResponse($str);
}
}
Note: this class must be auto-loadable by Composer. Be sure to put the class in the correct repository according to your composer.json autoload
section.
The @URL annotation points to the web path the action is bound to.
The action takes 2 parameters: $var1
and $var2
. This means that the page needs both parameters passed
either in GET or POST.
In order to test this, we must first create an instance of the controller in your container. How you do this really depends on the container you are using. See the installation section for more information.
Finally, we must also register this controller in Splash. How this is done essentially depends on your Splash installation.
if you are using Splash service provider, you need to put in your container an entry named 'thecodingmachine.splash.controllers' that is an array of controller identifiers. The way to do this depends on the container you are using, but might be something similar to:
$container->set('thecodingmachine.splash.controllers', [
'myController',
'myOtherController',
]);
Now, let's test our code.
By browsing to http://localhost/{my_app}/path/to/my/action?var1=42&var2=24
, we should see the message displayed!
Troubleshooting: If for some reason, your controller is not detected, you can try to purge your cache.
Done? Then let's move on!
We might decide that an action should always be called via GET, or via POST (or PUT or DELETE if you want to provide REST services). Splash makes that very easy to handle. You can just add a @Get or @Post annotation (or @Put or @Delete). Here is a sample:
<?php
namespace Test\Controllers;
use TheCodingMachine\Splash\Annotations\URL;
use TheCodingMachine\Splash\Annotations\Get;
use TheCodingMachine\Splash\Annotations\Post;
/**
* This is a sample user controller.
*
*/
class UserController {
/**
* Viewing the user is performed by a @Get.
*
* @URL("/user")
* @Get
* @param string $id
*/
public function viewUser(string $id): ResponseInterface {
return new HtmlResponse("Here, we might put the form for user ".htmlentities($id));
}
/**
* Modifying the user is performed by a @Post.
*
* @URL("/user")
* @Post
* @param string $id
* @param string $name
* @param string $email
*/
public function editUser(string $id, string $name, string $email): ResponseInterface {
return new HtmlResponse("Here, we might put the code to change the user object.");
}
}
In the example above (a sample controller to view/modify users), the "/user" URL is bound to 2 different methods based in the HTTP method used to access this URL.
You can put parameters in the URLs and fetch them very easily:
<?php
/**
* This is a sample user controller.
*
*/
class UserController {
/**
* Viewing the user is performed by a @Get.
*
* @URL("/user/{id}/view")
* @Get
* @param string $id
*/
public function viewUser(string $id): ResponseInterface {
return new HtmlResponse("Here, we might put the form for user ".htmlentities($id));
}
}
?>
Do you see the @URL annotation? The {id} part is a placeholder that will be replaced by any value found in the URL. So for instance, if you access http://[server]/[appname]/user/42/view, the $id parameter will be filled with "42".
As you probably already guessed, you must return a PSR-7 Response object. Splash comes bundled with Zend Diactoros
Therefore, you can write things like:
<?php
use TheCodingMachine\Splash\Annotations\URL;
use Zend\Diactoros\Response\HtmlResponse;
use Zend\Diactoros\Response\JsonResponse;
class MyController {
/**
* Returning a Response object
*
* @URL("/myurl1")
*/
public function test1(): ResponseInterface {
return new HtmlResponse('Hello World', 200, array('content-type' => 'text/html'));
}
/**
* Returning a JSON response
*
* @URL("/myjsonurl")
*/
public function testJson(): ResponseInterface {
return new JsonResponse({ "status" => "ok", "message" => "Hello world!" });
}
}
?>
Typically, in Mouf, you will want to output a template object. You can easily output templates (or any object
implementing the HtmlElementInterface
using the HtmlResponse
object:
<?php
use TheCodingMachine\Splash\Annotations\URL;
use TheCodingMachine\Splash\HtmlResponse;
class MyController {
/**
* @var HtmlElementInterface
*/
private $template;
...
/**
* Returning a Response object
*
* @URL("/test_template")
*/
public function test1(): ResponseInterface {
// do stuff
return new HtmlResponse($this->template);
}
}
Uploaded files are also directly available from the signature of the method:
HTML:
<input type="file" name="avatar" />
PHP:
<?php
use TheCodingMachine\Splash\Annotations\URL;
use Psr\Http\Message\UploadedFileInterface;
class MyController {
...
/**
* Uploads a file
*
* @URL("/upload")
*/
public function uploadLogo(UploadedFileInterface $logo): ResponseInterface {
$logo->moveTo(__DIR__.'/uploads/logo.png');
// ...
}
}
The $logo
object injected implements the PSR-7 UploadedFileInterface
The @Action parameter can replace the @URL parameter. You simply put a @Action annotation in your method. The URLs to access a @Action method are always:
http://[server-url]/[webapp-path]/[controller-instance-name]/[action-name]
Here is a sample:
<?php
use TheCodingMachine\Splash\Annotations\Action;
/**
* This is my test controller.
*
*/
class MyController {
/**
* My first action.
*
* @Action
* @param string $var1
* @param string $var2
*/
public function my_action(string $var1, string $var2): ResponseInterface {
return new HtmlResponse("Hello!");
}
}
?>
The my_action method is a Splash action. You know this because there is a @Action annotation in the PHPDoc comment of the method.
Now, we can access the example page using this URL:
http://[server-url]/[webapp-path]/my_controller/my_action?var1=42&var2=toto
Sometimes, when using @Action annotations, we might want to have a URL that is a bit shorter than /my_webapp/my_controller/my_action. Splash supports a special method called "index". If no action is provided in the URL, the index method will be called instead.
<?php
/**
* This is my test controller.
*/
class MyController extends Controller {
/**
* The action called if no action is provided in the URL.
*
* @Action
*/
public function index(): ResponseInterface {
return new HtmlResponse("This is the index");
}
}
?>
The test page can be accessed using the URL:
http://[server-url]/[webapp-path]/my_controller/.
Wanna learn more? Have a look at the Mouf controller cration wizard
Found a typo? Something is wrong in this documentation? Just fork and edit it!