[Pkg-owncloud-commits] [owncloud-doc] 46/270: finish controllers
David Prévot
taffit at moszumanska.debian.org
Thu Jul 31 03:52:59 UTC 2014
This is an automated email from the git hooks/post-receive script.
taffit pushed a commit to branch master
in repository owncloud-doc.
commit 57b6a93afed858c6305d752cd716619d76c50182
Author: Bernhard Posselt <dev at bernhard-posselt.com>
Date: Thu May 8 02:17:55 2014 +0200
finish controllers
---
developer_manual/app/controllers.rst | 301 ++++++++++++++++++++++++++++++++++-
1 file changed, 295 insertions(+), 6 deletions(-)
diff --git a/developer_manual/app/controllers.rst b/developer_manual/app/controllers.rst
index afd632f..df5470a 100644
--- a/developer_manual/app/controllers.rst
+++ b/developer_manual/app/controllers.rst
@@ -185,32 +185,321 @@ It is possible to pass JSON using a POST, PUT or PATCH request. To do that the *
}
-Headers, files, cookies and session information
------------------------------------------------
+Headers, files, cookies and environment variables
+-------------------------------------------------
+Headers, files, cookies and environment variables can be accessed directly from the request object. Every controller depends on the app name and the request object and sets both on protected attributes:
+
+.. code-block:: php
+
+ <?php
+ namespace OCA\MyApp\Controller;
+
+ use \OCP\AppFramework\Controller;
+ use \OCP\IRequest;
+
+ class PageController extends Controller {
+
+ public function __construct($appName, IRequest $request) {
+ parent::__construct($appName, $request);
+ }
+
+
+ public function someMethod() {
+
+ $type = $this->request->getHeader('Content-Type'); // $_SERVER['HTTP_CONTENT_TYPE']
+ $cookie = $this->request->getCookie('myCookie'); // $_COOKIES['myCookie']
+ $file = $this->request->getUploadedFile('myfile'); // $_FILES['myfile']
+ $env = $this->request->getEnv('SOME_VAR'); // $_ENV['SOME_VAR']
+
+ // access the app name
+ $name = $this->appName;
+ }
+
+ }
+
+Why should those values be accessed from the request object and not from the global array like $_FILES? Simple: `because it's bad practice <http://c2.com/cgi/wiki?GlobalVariablesAreBad>`_
Responses
=========
+Similar to how every controller receives a request object, every controller method has to to return a Response. This can be in the form of a Response subclass or in the form of a value that can be handled by a registered responder.
JSON
----
+Returning JSON is simple, just pass an array to a JSONResponse:
+
+.. code-block:: php
+
+ <?php
+ namespace OCA\MyApp\Controller;
+
+ use \OCP\AppFramework\Controller;
+ use \OCP\AppFramework\Http\JSONResponse;
+
+ class PageController extends Controller {
+
+ public function returnJSON() {
+ $params = array('test' => 'hi');
+ return new JSONResponse($params);
+ }
+
+ }
+
+Because returning JSON is such an incredibly common task, theres even a shorter way how to do this:
+
+.. code-block:: php
+
+ <?php
+ namespace OCA\MyApp\Controller;
+
+ use \OCP\AppFramework\Controller;
+
+ class PageController extends Controller {
+
+ public function returnJSON() {
+ return array('test' => 'hi');
+ }
+
+ }
+
+Why does this work? That's because the dispatcher sees that the controller did not return a subclass of a Response and asks the controller to turn the value into a Response. That's where responders come in.
+
+Responders
+----------
+Responders are short functions that take a value and return a response. They are used to return different kinds of responses based on a **format** parameter. Think of an API that is able to return both XML and JSON depending on if you call the URL with::
+
+ ?format=xml
+
+or::
+
+ ?format=json
+
+The appropriate responder is being chosen by the following criteria:
+
+* First the dispatcher checks the Request if theres a **format** parameter, e.g. ?format=xml or /index.php/apps/myapp/authors.{format}
+* If there is none, look at the **Accept** header, take the first mimetype, cut off the application/ and take that. In the following example the format would be *xml*::
+
+ Accept: application/xml, application/json
+
+* If there is no Accept header or the responder does not exist, format defaults to **json**.
+
+
+By default there is only a responder for JSON but more can be added easily:
+
+.. code-block:: php
+
+ <?php
+ namespace OCA\MyApp\Controller;
+
+ use \OCP\AppFramework\Controller;
+
+ class PageController extends Controller {
+
+ public function returnHi() {
+
+ // XMLResponse has to be implemented
+ $this->registerResponder('xml', function($value) {
+ return new XMLResponse($value);
+ });
+
+ return array('test' => 'hi');
+ }
+
+ }
+
+.. note:: The above example would only return XML if the **format** parameter was *xml*. If you want to return an XMLResponse in any case, extend the Response class and return a new instance of it from the controller method instead.
+
+Serializers
+-----------
+If responders are used it is sometimes useful to add another step before the returned value is being run through a responder. An example for that would be that all methods should wrap the returned value inside an array. First create a seperate serializer class that implements IResponseSerializer:
+
+.. code-block:: php
+
+ <?php
+
+ namespace \OCA\MyApp\Http;
+
+ use \OCP\AppFramework\Http\IResponseSerializer;
+
+
+ class WrapInArraySerializer implements IResponseSerializer {
+
+ public function serialize($value) {
+ $result = array('values' => array());
+
+ if(is_array($value)) {
+ $result['values'] = $value;
+ } else {
+ $result['values'] = array($value);
+ }
+
+ return $result;
+ }
+
+ }
+
+The serializer can now be registered inside the controller:
+
+.. code-block:: php
+
+ <?php
+ namespace OCA\MyApp\Controller;
+
+ use \OCP\AppFramework\Controller;
+
+ use \OCA\MyApp\Http\WrapInArraySerializer;
+
+ class AuthorController extends Controller {
+
+ public function __construct($appName, IRequest $request) {
+ parent::__construct($appName, $request);
+
+ // wrap every response in an array
+ $this->registerSerializer(new WrapInArraySerializer());
+ }
+
+ public function show($id) {
+ return $id;
+ }
+
+ }
Templates
---------
+A :doc:`template <templates>` can be rendered by returning a TemplateResponse. A TemplateResponse takes the following parameters:
+
+* **appName**: tells the template engine in which app the template should be located
+* **templateName**: the name of the template inside the template/ folder without the .php extension
+* **parameters**: optional array parameters that can is available in the template through $_, e.g.::
+
+ array('key' => 'something')
+
+ can be accessed through::
+
+ $_['key']
+
+* **renderAs**: defaults to *user*, tells ownCloud if it should include it in the webinterface, or in case *blank* is passed solely render the template
+
+.. code-block:: php
+
+ <?php
+ namespace OCA\MyApp\Controller;
+
+ use \OCP\AppFramework\Controller;
+ use \OCP\AppFramework\Http\TemplateResponse;
+
+ class PageController extends Controller {
+
+ public function index() {
+ $templateName = 'main'; // will use templates/main.php
+ $parameters = array('key' => 'hi');
+ return new TemplateResponse($this->appName, $templateName, $parameters);
+ }
+
+ }
Redirects
---------
+A redirect can be achieved by returning a RedirectResponse:
+
+.. code-block:: php
+
+ <?php
+ namespace OCA\MyApp\Controller;
+
+ use \OCP\AppFramework\Controller;
+ use \OCP\AppFramework\Http\RedirectResponse;
+
+ class PageController extends Controller {
+
+ public function toGoogle() {
+ return new RedirectResponse('https://google.com');
+ }
+
+ }
Downloads
---------
+A file download can be triggeredby returning a DownloadResponse:
+
+.. code-block:: php
+
+ <?php
+ namespace OCA\MyApp\Controller;
+
+ use \OCP\AppFramework\Controller;
+ use \OCP\AppFramework\Http\DownloadResponse;
+
+ class PageController extends Controller {
+
+ public function downloadXMLFile() {
+ $path = '/some/path/to/file.xml';
+ $contentType = 'application/xml';
+
+ return new DownloadResponse($path, $contentType);
+ }
+
+ }
Creating custom responses
-------------------------
+If no premade Response fits the needed usecase, its possible to extend the Response baseclass and custom Response. The only thing that needs to be implemented is the **render** method which returns the result as string.
+
+Creating a custom XMLResponse class could look like this:
+
+.. code-block:: php
+
+ <?php
+ namespace OCA\MyApp\Http;
+
+ use \OCP\AppFramework\Http\Response;
+
+ class XMLResponse extends Response {
+
+ private $xml;
+
+ public function construct(array $xml) {
+ $this->addHeader('Content-Type', 'application/xml');
+ $this->xml = $xml;
+ }
+
+ public function render() {
+ $root = new SimpleXMLElement('<root/>');
+ array_walk_recursive($this->xml, array ($root, 'addChild'));
+ return $xml->asXML();
+ }
+
+ }
+
+
+Handling errors
+---------------
+Sometimes a request should fail, for instance if an author with id 1 is requested but does not exist. In that case use an appropriate `HTTP error code <https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#4xx_Client_Error>`_ to signal the client that an error occured.
+
+Each response subclass has access to the **setStatus** method which lets you set an HTTP status code. To return a JSONResponse signaling that the author with id 1 has not been found, use the following code:
+
+.. code-block:: php
+
+ <?php
+ namespace OCA\MyApp\Controller;
+
+ use \OCP\AppFramework\Controller;
+ use \OCP\AppFramework\Http;
+ use \OCP\AppFramework\Http\JSONResponse;
+
+ class AuthorController extends Controller {
+
+ public function show($id) {
+ try {
+ // try to get author with $id
+
+ } catch (NotFoundException $ex) {
+ return new JSONResponse()->setStatus(Http::STATUS_NOT_FOUND);
+ }
+ }
+
+ }
-Responders
-----------
-Serializers
------------
Authentication
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-owncloud/owncloud-doc.git
More information about the Pkg-owncloud-commits
mailing list