MVC.xml

Sebastian Kurfuerst, 2011-08-26 10:27

Download (44.5 kB)

 
1
<?xml version="1.0" encoding="UTF-8"?>
2
<chapter version="5.0" xml:id="flow3.mvcframework"
3
         xmlns="http://docbook.org/ns/docbook"
4
         xmlns:ns52="http://www.w3.org/1998/Math/MathML"
5
         xmlns:ns5="http://www.w3.org/1999/xlink"
6
         xmlns:ns4="http://www.w3.org/2000/svg"
7
         xmlns:ns3="http://www.w3.org/1999/xhtml"
8
         xmlns:ns="http://docbook.org/ns/docbook">
9
  <title>MVC Framework</title>
10

    
11
  <section xml:id="flow3.mvcframework.introduction">
12
    <title>Introduction</title>
13

    
14
    <section>
15
      <title>Model-View-Controller</title>
16

    
17
      <para>In the design of FLOW3's architecture we have taken great care to
18
      separate concerns and assign each part of the framework with
19
      well-defined tasks. The separation of concerns is an important principle
20
      of good software design and its most prominent representative probably
21
      is the Model-View-Controller pattern. MVC separates the business logic
22
      from the presentation by splitting up user interaction into three
23
      roles:</para>
24

    
25
      <itemizedlist>
26
        <listitem>
27
          <para>The <emphasis>model</emphasis> is an object which contains
28
          data and business logic of a certain domain. It doesn't contain any
29
          information about the presentation of that data, but rather defines
30
          the behaviour. In the FLOW3 project we prefer a special kind of
31
          model, the <link
32
          ns5:href="http://martinfowler.com/eaaCatalog/domainModel.html">Domain
33
          Model</link>.</para>
34
        </listitem>
35

    
36
        <listitem>
37
          <para>The <emphasis>view</emphasis> represents the display of the
38
          model on the web or another output channel. Views only display data,
39
          they don't build or modify it.</para>
40
        </listitem>
41

    
42
        <listitem>
43
          <para>The <emphasis>controller</emphasis> reacts on user input,
44
          selects and manipulates the model as accordingly, selects a view and
45
          passes it the prepared model for rendering.</para>
46
        </listitem>
47
      </itemizedlist>
48

    
49
      <para>This diagram outlines the collaboration between model, view and
50
      controller:</para>
51

    
52
      <figure>
53
        <title>Model-View-Controller Pattern</title>
54

    
55
        <mediaobject>
56
          <imageobject>
57
            <imagedata contentdepth="100%"
58
                       fileref="MVC_ModelViewController.png"
59
                       scalefit="1" width="100%"/>
60
          </imageobject>
61
        </mediaobject>
62
      </figure>
63
    </section>
64

    
65
    <section>
66
      <title>Other Patterns Used</title>
67

    
68
      <para>Design Patterns (and MVC is one of them) are not only great for
69
      solving reoccuring design problems in a structured manner - they also
70
      help you communicating software designs. The following patterns play an
71
      important role in FLOW3's MVC mechanism and might give you a better idea
72
      of the overall design:</para>
73

    
74
      <itemizedlist>
75
        <listitem>
76
          <para>Incoming requests are handled by a Request Handler which takes
77
          the role of a <link ns5:href="???">Front Controller</link>.</para>
78
        </listitem>
79

    
80
        <listitem>
81
          <para><link ns5:href="???">Template View</link> is the most commonly
82
          used pattern for views, but <link ns5:href="???">Transform
83
          Views</link> and <link ns5:href="???">Two-Step Views</link> are
84
          equally supported.</para>
85
        </listitem>
86

    
87
        <listitem>
88
          <para>The preferred type of model is the <link ns5:href="???">Domain
89
          Model</link>.</para>
90
        </listitem>
91
      </itemizedlist>
92
    </section>
93

    
94
    <section>
95
      <title>Hello World!</title>
96

    
97
      <para>Let's start with an example before we go into greater detail of
98
      request handling and the internals of the MVC framework. The minimal
99
      approach is to create an Action Controller which just returns
100
      <quote>Hello World!</quote>. To begin with, we need to create some
101
      directories which contain the code of our FLOW3 package and eventually
102
      the controller class:</para>
103

    
104
      <literallayout>Packages/
105
  Demo/
106
    Classes/
107
      Controller/
108
        StandardController.php</literallayout>
109

    
110
      <para>The StandardController class looks as simple as this (leaving out
111
      the very recommended comments):</para>
112

    
113
      <example>
114
        <title>Hello World! controller</title>
115

    
116
        <programlisting language="php">namespace TYPO3\Demo\Controller;
117

    
118
class StandardController extends \TYPO3\FLOW3\MVC\Controller\ActionController {
119
        public function indexAction() {
120
                return 'Hello World!';
121
        }
122
}</programlisting>
123
      </example>
124

    
125
      <para>Provided that the document root of your local server points to
126
      FLOW3's <filename>Web/</filename> directory, you will get the following
127
      output when calling the URI <uri>http://localhost/demo/</uri>:</para>
128

    
129
      <screen>Hello World!</screen>
130

    
131
      <para>Great, that was easy - but didn't we say that it's the view's
132
      responsibility to take care of the presentation? Let's create a simple
133
      PHP-based view for that purpose:</para>
134

    
135
      <literallayout>Packages/
136
  Demo/
137
    Classes/
138
      Controller/
139
        StandardController.php
140
      View/
141
        Standard/
142
          Index.php</literallayout>
143

    
144
      <para>The view's code is equally trivial:</para>
145

    
146
      <example>
147
        <title>Hello World! view</title>
148

    
149
        <programlisting language="php">namespace TYPO3\Demo\View\Standard;
150

    
151
class Index extends \TYPO3\FLOW3\MVC\View\AbstractView {
152
        public function render() {
153
                return 'Hello World from your view!';
154
        }
155
}</programlisting>
156
      </example>
157

    
158
      <para>Finally our action controller needs a little tweak to return the
159
      rendered view instead of shouting <quote>Hello World!</quote>
160
      itself:</para>
161

    
162
      <example>
163
        <title>Improved Hello World! controller</title>
164

    
165
        <programlisting language="php">namespace TYPO3\Demo\Controller;
166

    
167
class StandardController extends \TYPO3\FLOW3\MVC\Controller\ActionController {
168
        public function indexAction() {
169
                return $this-&gt;view-&gt;render();
170
        }
171
}</programlisting>
172
      </example>
173

    
174
      <para>Some notes about the view: Although a view class written in PHP is
175
      the most basic way to implement a view, it is not the most common way
176
      you'll take. In practice you'll want to use <package>Fluid</package>,
177
      FLOW3's powerful templating engine which allows you to write views in
178
      plain HTML and still have all the power like loops and
179
      conditions.</para>
180
    </section>
181

    
182
    <section>
183
      <title>Recommended File Structure</title>
184

    
185
      <para>As you have seen in the hello world example, conventions for the
186
      directory layout simplify your development a lot. There's no need to
187
      register controllers, actions or views if you follow our recommended
188
      file structure. These are the rules:</para>
189

    
190
      <itemizedlist>
191
        <listitem>
192
          <para><emphasis>Controllers</emphasis> are located in their own
193
          directory <filename>Controller</filename> just below the
194
          <filename>Classes</filename> directory of your package. They can
195
          have arbitrary names while the
196
          <classname>StandardController</classname> has a special meaning: If
197
          the package was specified in the request but no controller, the
198
          <classname>StandardController</classname> will be used.</para>
199
        </listitem>
200

    
201
        <listitem>
202
          <para><emphasis>View</emphasis> classes are situated below a
203
          <filename>View</filename> directory. The classname of the view is a
204
          combination of the name of the controller and the name of the
205
          action.</para>
206
        </listitem>
207
      </itemizedlist>
208

    
209
      <para>This sample directory layout demonstrates the above rules:</para>
210

    
211
      <example>
212
        <title>Sample file structure</title>
213

    
214
        <literallayout>Packages/
215
  Demo/
216
    Classes/
217
      Controller/
218
        StandardController.php
219
        CustomerController.php
220
        OrderController.php
221
      View/
222
        Standard/
223
          Index.php
224
        Customer/
225
          Index.php
226
          List.php
227
          Details.php
228
        Order/
229
          List.php</literallayout>
230
      </example>
231

    
232
      <para>Adhering to these conventions has the advantage that the classname
233
      of the view for example is resolved automatically. However it is
234
      possible (and not really difficult) to deviate from this layout and have
235
      a completely different structure.</para>
236
    </section>
237

    
238
    <section>
239
      <title>From the URI to the view</title>
240

    
241
      <caution>
242
        <para>For the example URIs we assume that the web root directory of
243
        your local server points to FLOW3's <filename>public/</filename>
244
        directory. If that's not the case you have to extend the URI
245
        accordingly.</para>
246
      </caution>
247

    
248
      <para>FLOW3 provides a standard way of resolving the URI to your
249
      MVC-Objects.</para>
250

    
251
      <para>Say, you want to see the list of customers (based on the
252
      file-structure-example above). The URI to get the list would be:
253
      <uri>http://localhost/demo/customer/list.html</uri> or just
254
      <uri>http://localhost/demo/customer/list</uri>.</para>
255

    
256
      <para>This URI will be resolved into the package-name
257
      (<emphasis>Demo</emphasis>), controller-name
258
      (<emphasis>Customer</emphasis>), action-name(<emphasis>list</emphasis>)
259
      and format-name (<emphasis>html</emphasis> - which is the default
260
      format).</para>
261

    
262
      <para>Depending on that, the controller
263
      <classname>\TYPO3\Demo\Controller\CustomerController</classname> (pattern:
264
      '<code>TYPO3\@package\Controller\@controllerController'</code>) and its
265
      method <methodname>listAction()</methodname> will be used. The
266
      corresponding view is <classname>\TYPO3\Demo\View\CustomerList</classname>
267
      (Pattern:
268
      <code>'TYPO3\@package\View\@controller@action@format'</code>).</para>
269

    
270
      <para>By looking at the view pattern you easily see that it's fairly
271
      easily to address a view which renders a different format, for example
272
      XML. All you need to do is creating a class called
273
      <classname>\TYPO3\Demo\View\Customer\ListXML</classname>. To see the output
274
      of this new view, just use the URI
275
      <uri>http://localhost/demo/customer/list.xml</uri>.</para>
276
    </section>
277
  </section>
278

    
279
  <section xml:id="flow3.mvcframework.requestresponse">
280
    <title>Request and Response</title>
281

    
282
    <para>No matter if a FLOW3 application runs in a web context or is
283
    launched from the command line, the basic workflow is always the same: The
284
    user request is analyzed and forwarded to an appropriate controller which
285
    decides on which actions to take and finally returns a response which is
286
    handed over to the user. This section highlights the flow and the
287
    collaborators in the request-response machinery.</para>
288

    
289
    <section>
290
      <title>Request Processing Overview</title>
291

    
292
      <para>A sequence diagram is worth a thousand words said my grandma, so
293
      let's take a look at the standard request-response workflow in
294
      FLOW3:</para>
295

    
296
      <figure>
297
        <title>Example of a Web Request-Response Workflow</title>
298

    
299
        <mediaobject>
300
          <imageobject>
301
            <imagedata contentdepth="100%"
302
                       fileref="MVC_RequestResponseWorkflow.png"
303
                       scalefit="1" width="100%"/>
304
          </imageobject>
305
        </mediaobject>
306
      </figure>
307

    
308
      <para>As you see, there are a lot of parts of the framework involved for
309
      answering a request - and the diagram doesn't even consider caching or
310
      forwarding of requests. But we didn't create this structure just for the
311
      fun of it - each object plays an important role as you'll see in the
312
      next sections.</para>
313
    </section>
314

    
315
    <section>
316
      <title>Request Handler</title>
317

    
318
      <para>The request handler takes the important task to handle and respond
319
      to a request. There exists exactly one request handler for each request
320
      type. By default web and command line requests are supported, but more
321
      specialized request handlers can be developed, too.</para>
322

    
323
      <para>Before one of the request handlers comes to play, the framework
324
      needs to determine which of them is the most suitable for the current
325
      request. The request handler resolver asks all of the registered request
326
      handlers to rate on a scale how well they can handle the current raw
327
      request. The resolver then chooses the request handler with the most
328
      points and passes over the control.</para>
329

    
330
      <para>Custom request handlers for special purposes just need to
331
      implement the
332
      <interfacename>\TYPO3\FLOW3\MVC\RequestHandlerInterface</interfacename>.
333
      All classes implementing that interface are automatically registered and
334
      will be considered while resolving a suitable request handler.</para>
335
    </section>
336

    
337
    <section>
338
      <title>Request Builder</title>
339

    
340
      <para>When a request handler receives a raw request, it needs to build a
341
      request object which can be passed to the dispatcher and later to the
342
      controller. The request building delegated to a request builder which
343
      can build the required request type (ie. web, CLI etc.).</para>
344

    
345
      <para>The building process mainly consists of</para>
346

    
347
      <procedure>
348
        <step>
349
          <para>create a new request object</para>
350
        </step>
351

    
352
        <step>
353
          <para>set some request-type specific parameters (like the request
354
          URI for a web request)</para>
355
        </step>
356

    
357
        <step>
358
          <para>determine and set the responsible controller, action and
359
          action arguments</para>
360
        </step>
361
      </procedure>
362

    
363
      <para>Especially the last step is important and requires some more or
364
      less complex routing in case of web requests.</para>
365
    </section>
366

    
367
    <section>
368
      <title>Request Dispatcher</title>
369

    
370
      <para>The final task of the MVC framework consists in dispatching the
371
      request to the controller specified in the request object. Dispatching
372
      means that the request and response object is passed to the controller
373
      specified in the request object and after the controller did its job,
374
      control is returned to the request handler which eventually sends the
375
      response.</para>
376

    
377
      <para>The dispatch method itself is a loop which tries to invoke a
378
      controller until a flag in the request object indicates that the request
379
      has been dispatched. In most cases this loop has only one cycle: the
380
      action method specified in the request is called and the action
381
      controller automatically sets the <varname>dispatched</varname> flag
382
      which leads to exiting the dispatch loop. However, when the controller
383
      wants to forward or redirect the request to another controller or
384
      action, the respective information is written to the request object and
385
      the <varname>dispatched</varname> flag remains unset. Therefore the
386
      dispatcher calls the next controller which hopefully can finally process
387
      the request and exits the dispatch loop.</para>
388

    
389
      <para>The dispatcher comes with a safeguard which assures that the
390
      dispatching process does not end up in an endless loop.</para>
391
    </section>
392

    
393
    <section>
394
      <title>Request Types</title>
395

    
396
      <para>FLOW3 supports the most important request types out of the box.
397
      Additional request types can easily be implemented by implementing the
398
      <interfacename>\TYPO3\FLOW3\MVC\RequestInterface</interfacename> or
399
      extending the <classname>\TYPO3\FLOW3\MVC\Request</classname> class and
400
      registering a request handling which can handle the new request type
401
      (and takes care of building the request object). Here are the request
402
      types which come with the default FLOW3 distribution:</para>
403

    
404
      <section>
405
        <title>Web Request / Response</title>
406

    
407
        <para>Web requests are the most common request types. Additional to
408
        the common request functionality, this request type delivers
409
        information about the request method, request URI and the base
410
        URI.</para>
411
      </section>
412

    
413
      <section>
414
        <title>CLI Request / Response</title>
415

    
416
        <para>Requests from the command line are recognized by the used SAPI
417
        (Server Application Programming Interface).</para>
418
      </section>
419
    </section>
420
  </section>
421

    
422
  <section xml:id="flow3.mvcframework.controller">
423
    <title>Controller</title>
424

    
425
    <para>The main responsibility of a controller is to process a request and
426
    deliver a meaningful response. The
427
    <interfacename>\TYPO3\FLOW3\MVC\Controller\ControllerInterface</interfacename>
428
    therefore only contains two methods:</para>
429

    
430
    <programlisting language="php">/**
431
 * Checks if the current request type is supported by the controller.
432
 *
433
 * @param \TYPO3\FLOW3\MVC\RequestInterface $request The current request
434
 * @return boolean TRUE if this request type is supported, otherwise FALSE
435
 */
436
public function canProcessRequest(\TYPO3\FLOW3\MVC\RequestInterface $request);
437

    
438
/**
439
 * Processes a general request. The result can be returned by altering the given response.
440
 *
441
 * @param \TYPO3\FLOW3\MVC\RequestInterface $request The request object
442
 * @param \TYPO3\FLOW3\MVC\ResponseInterface $response The response, modified by the controller
443
 * @return void
444
 * @throws \TYPO3\FLOW3\MVC\Exception\UnsupportedRequestTypeException if the controller doesn't support the current request type
445
 */
446
public function processRequest(\TYPO3\FLOW3\MVC\RequestInterface $request, \TYPO3\FLOW3\MVC\ResponseInterface $response);
447
</programlisting>
448

    
449
    <para>However, only few applications will implement the whole request
450
    processing logic themselves. Most of the time you'll be extending the
451
    Action Controller.</para>
452

    
453
    <section>
454
      <title>Action Controller</title>
455

    
456
      <para>The
457
      <classname>\TYPO3\FLOW3\MVC\Controller\ActionController</classname>
458
      processes a request by calling action methods. Actions are the
459
      foundation of your application's workflow and logic. Which action is
460
      called is usually determined by the URI as you have already seen in the
461
      short hello world example.</para>
462

    
463
      <section>
464
        <title>Initialization Methods</title>
465

    
466
        <para>Before an action method is called, the view, validation and
467
        arguments are initialized. The following methods can be extended or
468
        overloaded to hook into this initialization process:</para>
469

    
470
        <itemizedlist>
471
          <listitem>
472
            <para><methodname>initializeView()</methodname> is called in order
473
            to resolve, set and initialize a view which matches the current
474
            action.</para>
475
          </listitem>
476

    
477
          <listitem>
478
            <para><methodname>initializeAction()</methodname> is called after
479
            the view has been initialized and the automatic registration of
480
            arguments is done. At that point, the argument's values are still
481
            empty and have not been validated.</para>
482
          </listitem>
483

    
484
          <listitem>
485
            <para><methodname>initializeFooAction()</methodname> where
486
            <methodname>Foo</methodname> is the name of the action, is called
487
            only before an action of that name is called.</para>
488
          </listitem>
489
        </itemizedlist>
490

    
491
        <para>Action arguments are usually registered automatically (see
492
        below). If you wish to register additional arguments manually, you may
493
        do that in one of the <methodname>initialize*Action()</methodname>
494
        methods.</para>
495
      </section>
496

    
497
      <section>
498
        <title>Configuration</title>
499

    
500
        <para>The settings of the package containing your controller are
501
        automatically injected into the action controller and can be accessed
502
        through the <varname>$this-&gt;settings</varname> variable. Please
503
        note that this variable contains all settings of the package as an
504
        array, not only settings specific to your controller.</para>
505

    
506
        <para>You should not modify the settings array because any information
507
        you'd add would be lost anyway and is invisible to other parts of your
508
        application.</para>
509
      </section>
510

    
511
      <section>
512
        <title>Supported Request Types</title>
513

    
514
        <para>The action controller generally supports any kind of request,
515
        which means that theoretically you need only one controller for web
516
        and CLI requests. In practice you might want to structure your
517
        application so that a controller is responsable for only one request
518
        type. If that is the case, you can define the supported request types
519
        by setting the <property>supportedRequestTypes</property> property of
520
        your class:</para>
521

    
522
        <example>
523
          <title>Defining the supported request types</title>
524

    
525
          <programlisting language="php">/**
526
 * My web-specific controller
527
 */
528
class StandardController extends \TYPO3\FLOW3\MVC\Controller\ActionController {
529

    
530
   /**
531
    * @var array
532
    */
533
   protected $supportedRequestTypes = array('TYPO3\FLOW3\MVC\Web\Request');
534

    
535
</programlisting>
536
        </example>
537
      </section>
538

    
539
      <section>
540
        <title>Arguments</title>
541

    
542
        <para>An action usually needs some more information about what it's
543
        supposed to do. This information comes in form of GET or POST
544
        arguments in case of a web request or via command line options if
545
        we're dealing with a CLI request. Because there are even more ways to
546
        pass information to an action and because this information needs
547
        special care to assure a secure application, these arguments are
548
        abstracted by FLOW3 in form of controller arguments.</para>
549

    
550
        <para>The basic rule in FLOW3 is: an action method only gets those
551
        arguments it asked for which have always values which are allowed for
552
        the declared data type. Therefore arguments need to be registered and
553
        it is not possible to access PHP's superglobals
554
        <varname>$_GET</varname> and <varname>$_POST</varname>
555
        directly.</para>
556

    
557
        <para>Fortunately argument registration is very easy in FLOW3. It's
558
        just a matter declaring the arguments in your action method
559
        signature:</para>
560

    
561
        <example>
562
          <title>Declaring arguments in an action method</title>
563

    
564
          <programlisting language="php">/**
565
 * An example action method
566
 *
567
 * @param string $emailAddress Some email address
568
 * @param string $streetName Some street name
569
 * @param \TYPO3\Foo\Model\Customer $customer A customer object
570
 * @return void
571
 */
572
public function exampleAction($emailAddress, $streetName, \TYPO3\Foo\Model\Customer $customer) {
573

    
574
}
575
</programlisting>
576
        </example>
577

    
578
        <para>FLOW3 will automatically register the arguments
579
        <parameter>$emailAddress</parameter>,
580
        <parameter>$streetName</parameter> and
581
        <parameter>$customer</parameter>. Their expected data types are
582
        <classname>Text</classname>, <classname>Text</classname> and
583
        <classname>\TYPO3\Foo\customer</classname> respectively.</para>
584

    
585
        <para>In essence this means that if you send a GET parameter
586
        <parameter>emailAddress</parameter> with your request, it will end up
587
        in <parameter>$emailAddress</parameter> if it is a valid
588
        <classname>Text</classname> (which means: no HTML, no JavaScript, no
589
        danger). Even the <parameter>$customer</parameter> argument will
590
        contain a real <classname>Customer</classname> object if enough
591
        information has been sent with the request.</para>
592
      </section>
593

    
594
      <section>
595
        <title>Argument Validation</title>
596

    
597
        <para>All arguments passed to the action methods will automatically
598
        validated through their base validation rules defined in the
599
        respective models. Additional validation rules can be defined by using
600
        the <varname>@validate</varname> annotation. The syntax is similar to
601
        a regular <varname>@validate</varname> declaration with the addition
602
        that the argument name must be specified:</para>
603

    
604
        <example>
605
          <title>Additional validation rules in an action method</title>
606

    
607
          <programlisting language="php">/**
608
 * An example action method
609
 *
610
 * @param string $emailAddress Some email address
611
 * @param string $streetName Some street name
612
 * @param \TYPO3\Foo\Model\Customer $customer A customer object
613
 * @return void
614
 * @validate $emailAddress EmailAddress
615
 * @validate $streeName Alphanumeric, StringLength(minimum = 5, maximum = 100)
616
 * @validate $customer TYPO3\Foo\Validator\PlatinumCustomerValidator
617
 */
618
public function exampleAction($emailAddress, $streetName, \TYPO3\Foo\Model\Customer $customer) {
619

    
620
}
621
</programlisting>
622
        </example>
623

    
624
        <para>In a few situations it is necessary to disable validation for a
625
        single argument, for example if an object needs to passed between
626
        actions while it is beeing edited and therefore is knowingly in an
627
        incomplete state. In these cases validation can be swtiched off
628
        through the <literal>@dontvalidate</literal> annotation:</para>
629

    
630
        <programlisting language="php">/**
631
 * An example edit action method
632
 *
633
 * @param \TYPO3\Foo\Model\Customer $customer A customer object
634
 * @return void
635
 * @dontvalidate $customer
636
 */
637
public function editAction(\TYPO3\Foo\Model\Customer $customer) {
638

    
639
}</programlisting>
640
      </section>
641

    
642
      <section>
643
        <title>Action Methods</title>
644

    
645
        <para>$this-&gt;indexActionMethodName</para>
646

    
647
        <para/>
648
      </section>
649
    </section>
650

    
651
    <section>
652
      <title>Other Controllers</title>
653

    
654
      <section>
655
        <title>Abstract Controller</title>
656

    
657
        <para/>
658
      </section>
659

    
660
      <section>
661
        <title>Request Handling Controller</title>
662

    
663
        <para/>
664
      </section>
665

    
666
      <section>
667
        <title>Standard Controller</title>
668

    
669
        <para/>
670
      </section>
671

    
672
      <section>
673
        <title>Not Found Controller</title>
674

    
675
        <para>The
676
        <classname>TYPO3\FLOW3\MVC\Controller\NotFoundController</classname> is
677
        used whenever no other controller could be resolved which would match
678
        the current request. It displays a generic "404 Page Not Found"
679
        message.</para>
680

    
681
        <para>It is possible to define your own custom controller which is
682
        used in these cases. Just specify the object name in the FLOW3
683
        settings.</para>
684
      </section>
685
    </section>
686
  </section>
687

    
688
  <section xml:id="flow3.mvcframework.view">
689
    <title>View</title>
690

    
691
    <para/>
692

    
693
    <section>
694
      <title>Template View</title>
695

    
696
      <para/>
697
    </section>
698

    
699
    <section>
700
      <title>Special Views</title>
701

    
702
      <section>
703
        <title>Standard View</title>
704

    
705
        <para/>
706
      </section>
707

    
708
      <section>
709
        <title>Empty View</title>
710

    
711
        <para/>
712
      </section>
713
    </section>
714
  </section>
715

    
716
  <section xml:id="flow3.mvcframework.helpers">
717
    <title>Helpers</title>
718

    
719
    <para/>
720
  </section>
721

    
722
  <section xml:id="flow3.mvcframework.model">
723
    <title>Model</title>
724

    
725
    <para/>
726
  </section>
727

    
728
  <section xml:id="flow3.mvcframework.routing">
729
    <title>Routing</title>
730

    
731
    <para>As explained in the beginning of this chapter, in FLOW3 the
732
    dispatcher passes the request to a controller which then calls the
733
    respective action. But how to tell, what controller of what package is the
734
    right one for the current request? This is were the routing framework
735
    comes into play.</para>
736

    
737
    <section>
738
      <title>Router</title>
739

    
740
      <para>The request builder asks the router for the correct package,
741
      controller and action. For this it passes the current request path to
742
      the routers <methodname>match</methodname> method. The router then
743
      iterates through all configured routes and invokes their
744
      <methodname>matches</methodname> method. The first route that matches,
745
      determines which action will be called with what parameters.</para>
746

    
747
      <para>The same works for the opposite direction: If a link is generated
748
      the router calls the <methodname>resolve</methodname> method of all
749
      routes until one route can return the correct URI for the specified
750
      arguments.</para>
751

    
752
      <para><note>
753
          <para>If no matching route can be found, the
754
          <methodname>indexAction</methodname> of the
755
          <classname>StandardController</classname> of the
756
          <package>FLOW3</package> package is called.</para>
757
        </note></para>
758
    </section>
759

    
760
    <section>
761
      <title>Route</title>
762

    
763
      <para>A route describes the way from your browser to the controller -
764
      and back.</para>
765

    
766
      <para>With the <emphasis>URI pattern</emphasis> you can define how a
767
      route is represented in the browsers address bar. By setting
768
      <emphasis>defaults</emphasis> you can specify package, controller and
769
      action that should apply when a request matches the route. Besides you
770
      can set arbitrary default values that will be available in your
771
      controller. They are called <emphasis>defaults</emphasis> because you
772
      can overwrite them by so called <emphasis>dynamic route
773
      parts</emphasis>.</para>
774

    
775
      <para>But let's start with an easy example:<example>
776
          <title>Simple route - Routes.yaml</title>
777

    
778
          <programlisting language="yaml">--
779
  name: 'Homepage'
780
  uriPattern: ''
781
  defaults:
782
    '@package': Demo</programlisting>
783
        </example><note>
784
          <para>name is optional, but it's recommended to set a name for all
785
          routes to make debugging easier.</para>
786
        </note></para>
787

    
788
      <para>If you insert these lines at the beginning of the file
789
      <filename>Configurations/Routes.yaml</filename>, the
790
      <methodname>indexAction</methodname> of the
791
      <classname>StandardController</classname> in your
792
      <package>Demo</package> package will be called when you open up the
793
      homepage of your FLOW3 installation
794
      (<uri>http://localhost/).</uri></para>
795

    
796
      <para><note>
797
          <para>You don't have to specify action and controller in this
798
          example as the <methodname>indexAction</methodname> of the
799
          <classname>StandardController</classname> is always called by
800
          default.</para>
801
        </note></para>
802

    
803
      <section>
804
        <title>URI pattern</title>
805

    
806
        <para>The URI pattern defines the appearance of the URI. In a simple
807
        setup the pattern only consists of <emphasis>static route
808
        parts</emphasis> and is equal to the actual URI (without protocol and
809
        host).</para>
810

    
811
        <para>In order to reduce the amount of routes that have to be created,
812
        you are allowed to insert markers, so called <emphasis>dynamic route
813
        parts</emphasis>, that will be repaced by the routing framework. You
814
        can even mark route parts <emphasis>optional</emphasis>.</para>
815

    
816
        <para>But first things first.</para>
817

    
818
        <section>
819
          <title>Static route parts</title>
820

    
821
          <para>A static route part is really simple - it will be mapped
822
          one-to-one to the resulting URI without transformation.</para>
823

    
824
          <para>Let's create a route that calls the listAction of the
825
          CustomerController when browsing to
826
          <uri>http://localhost/my/demo</uri>:<example>
827
              <title>Simple route with static route parts -
828
              Configuration/Routes.yaml</title>
829

    
830
              <para><programlisting language="yaml">--
831
  name: 'Static demo route'
832
  uriPattern: 'my/demo'
833
  defaults:
834
    '@package':    Demo
835
    '@controller': Customer
836
    '@action':     list</programlisting></para>
837
            </example></para>
838
        </section>
839

    
840
        <section>
841
          <title>Dynamic route parts</title>
842

    
843
          <para>Dynamic route parts are enclosed in curly brackets and define
844
          parts of the URI that are not fixed.</para>
845

    
846
          <para>Let's add some dynamics to the previous example:<example>
847
              <title>Simple route with static and dynamic route parts -
848
              Configuration/Routes.yaml</title>
849

    
850
              <para><programlisting language="yaml">--
851
  name: 'Dynamic demo route'
852
  uriPattern: 'my/demo/{@action}'
853
  defaults:
854
    '@package':    Demo
855
    '@controller': Customer</programlisting></para>
856
            </example>Now <uri>http://localhost/my/demo/list</uri> calls the
857
          <methodname>listAction</methodname> just like in the previous
858
          example.</para>
859

    
860
          <para>With <uri>http://localhost/my/demo/index</uri> you'd invoke
861
          the <methodname>indexAction</methodname> and so on.</para>
862

    
863
          <para><note>
864
              <para>It's not allowed to have successive dynamic route parts in
865
              the URI pattern because it wouldn't be possible to determine the
866
              end of the first dynamic route part then.</para>
867
            </note></para>
868

    
869
          <para>The @-prefix should reveal that action has a special meaning
870
          here. Other predefined keys are @package, @subpackage, @controller
871
          and @format. But you can use dynamic route parts to set any kind of
872
          arguments:<example>
873
              <title>dynamic parameters - Configuration/Routes.yaml</title>
874

    
875
              <programlisting language="yaml">--
876
  name: 'Dynamic demo route'
877
  uriPattern: 'clients/{sortOrder}.{@format}'
878
  defaults:
879
    '@package':    Demo
880
    '@controller': Customer
881
    '@action':     list</programlisting>
882
            </example></para>
883

    
884
          <para>Browsing to <uri>http://localhost/clients/descending.xml</uri>
885
          would call the <methodname>listAction</methodname> in your
886
          <classname>Customer</classname> controller and the request argument
887
          "sortOrder" had the value of "descending".</para>
888

    
889
          <para>By default, dynamic route parts match anything apart from
890
          empty strings. If you have more specialized requirements you can
891
          create your custom route part handlers.</para>
892
        </section>
893

    
894
        <section>
895
          <title>Route part handler</title>
896

    
897
          <para>Route part handlers are classes that implement
898
          <interfacename>TYPO3\FLOW3\MVC\Web\Routing\DynamicRoutePartInterface</interfacename>.
899
          But for most cases it will be sufficient to extend
900
          <classname>TYPO3\FLOW3\MVC\Web\Routing\DynamicRoutePart</classname> and
901
          overwrite the methods <methodname>matchValue</methodname> and
902
          <methodname>resolveValue</methodname>.</para>
903

    
904
          <para>Let's have a look at the (very simple) route part handler of
905
          the blog example:<example>
906
              <title>BlogRoutePartHandler.php</title>
907

    
908
              <programlisting language="php">class BlogRoutePartHandler extends \TYPO3\FLOW3\MVC\Web\Routing\DynamicRoutePart {
909

    
910
        /**
911
         * While matching, converts the blog title into an identifer array
912
         *
913
         * @param string $value value to match, the blog title
914
         * @return boolean TRUE if value could be matched successfully, otherwise FALSE.
915
         */
916
        protected function matchValue($value) {
917
                if ($value === NULL || $value === '') return FALSE;
918
                $this-&gt;value = array('__identity' =&gt; array('name' =&gt; $value));
919
                return TRUE;
920
        }
921

    
922
        /**
923
         * Resolves the name of the blog
924
         *
925
         * @param \TYPO3\Blog\Domain\Model\Blog $value The Blog object
926
         * @return boolean TRUE if the name of the blog could be resolved and stored in $this-&gt;value, otherwise FALSE.
927
         */
928
        protected function resolveValue($value) {
929
                if (!$value instanceof \TYPO3\Blog\Domain\Model\Blog) return FALSE;
930
                $this-&gt;value = $value-&gt;getName();
931
                return TRUE;
932
        }
933
}</programlisting>
934
            </example></para>
935

    
936
          <para>The corresponding route might look like this:<example>
937
              <title>Route with route part handlers -
938
              Configuration/Routes.yaml</title>
939

    
940
              <programlisting language="yaml">--
941
  name: 'Blog route'
942
  uriPattern: 'blogs/{blog}/{@action}'
943
  defaults:
944
    '@package':    Blog
945
    '@controller': Blog
946
  routeParts:
947
    blog:
948
      handler: TYPO3\Blog\RoutePartHandlers\BlogRoutePartHandler</programlisting>
949
            </example></para>
950

    
951
          <para>Have a look at the blog example for a working setup.</para>
952
        </section>
953

    
954
        <section>
955
          <title>Optional route parts</title>
956

    
957
          <para>By putting one or more route parts in round brackets you mark
958
          them optional. The following route matches
959
          <uri>http://localhost/my/demo/ </uri>and
960
          <uri>http://localhost/my/demo/list.html</uri>.</para>
961

    
962
          <example>
963
            <title>Route with optional route parts -
964
            Configuration/Routes.yaml</title>
965

    
966
            <para><programlisting language="yaml">--
967
  name: 'Dynamic demo route'
968
  uriPattern: 'my/demo(/{@action}.html)'
969
  defaults:
970
    '@package':    'Demo'
971
    '@controller': 'Customer'
972
    '@action':     'list'</programlisting></para>
973
          </example>
974

    
975
          <note>
976
            <para><uri>http://localhost/my/demo/list</uri> won't match here,
977
            because either all optional parts have to match - or none.</para>
978
          </note>
979

    
980
          <note>
981
            <para>You have to define default values for all optional dynamic
982
            route parts.</para>
983
          </note>
984
        </section>
985

    
986
        <section>
987
          <title>Case sensitivity</title>
988

    
989
          <para>By Default the case is not changed when creating URIs. The
990
          following example with a username of "Kasper" will result in
991
          <uri>http://localhost/Users/Kasper</uri><example>
992
              <title>Route with default case handling</title>
993

    
994
              <para><programlisting language="yaml">--
995
  uriPattern: 'Users/{username}'
996
  defaults:
997
    @package:    'Demo'
998
    @controller: 'Customer'
999
    @action:     'show'</programlisting></para>
1000
            </example></para>
1001

    
1002
          <para>You can change this behavior for routes and/or dynamic route
1003
          parts:<example>
1004
              <title>Route with customised case handling</title>
1005

    
1006
              <para><programlisting language="yaml">--
1007
  uriPattern: 'Users/{username}'
1008
  defaults:
1009
    @package:    'Demo'
1010
    @controller: 'Customer'
1011
    @action:     'show'
1012
  toLowerCase: true
1013
  routeParts:
1014
    username:
1015
      toLowerCase: false</programlisting></para>
1016
            </example>This will change the default behavior for this route and
1017
          reset it for the username route part. Given the same username of
1018
          "Kasper" the resulting URI will now be
1019
          <uri>http://localhost/users/Kasper</uri> (note the lower case "u" in
1020
          "users").</para>
1021

    
1022
          <note>
1023
            <para>The predefined route parts @package, @subpackage,
1024
            @controller, @action and @format are an exception, they're always
1025
            lower cased!</para>
1026
          </note>
1027

    
1028
          <para>Matching of incoming URIs is always done case insensitive. So
1029
          both "Users/Kasper" and "users/Kasper" will match, and the value of
1030
          the dynamic part will never be changed. If you want to handle data
1031
          coming in through dynamic route parts case-insensitive, you need to
1032
          handle that in your own code.</para>
1033
        </section>
1034
      </section>
1035
    </section>
1036

    
1037
    <section>
1038
      <title>Subroutes</title>
1039

    
1040
      <para>For security reasons and to avoid confusion, only routes
1041
      configured in your global configuration folder are active. But FLOW3
1042
      supports what we call subroutes enabling you to provide custom routes
1043
      with your package and reference them in the global routing setup.</para>
1044

    
1045
      <para>Imagine following routes in the <filename>Routes.yaml</filename>
1046
      file inside your demo package:<example>
1047
          <title>Demo Subroutes - Demo/Configuration/Routes.yaml</title>
1048

    
1049
          <programlisting language="yaml">--
1050
  name: 'Customer routes'
1051
  uriPattern: '/clients/{@action}'
1052
  defaults:
1053
    '@controller': Customer
1054

    
1055
--
1056
  name: 'Standard routes'
1057
  uriPattern: '/{@action}'
1058
  defaults:
1059
    '@controller': Standard
1060

    
1061
--
1062
  name: 'Fallback'
1063
  uriPattern: ''
1064
  defaults:
1065
    '@controller': Standard
1066
    '@action':     index</programlisting>
1067
        </example></para>
1068

    
1069
      <para>And in your global <filename>Routes.yaml</filename>:<example>
1070
          <title>Referencing subroutes - Configuration/Routes.yaml</title>
1071

    
1072
          <programlisting language="yaml">--
1073
  name: 'Demo subroutes'
1074
  uriPattern: 'demo&lt;DemoSubroutes&gt;(.{@format})'
1075
  defaults:
1076
    '@package': Demo
1077
    '@format':  html
1078
  subRoutes:
1079
    DemoSubroutes:
1080
      package: Demo</programlisting>
1081
        </example></para>
1082

    
1083
      <para>As you can see, you can reference subroutes by putting parts of
1084
      the URI pattern in angle brackets (like &lt;subRoutes&gt;). With the
1085
      subRoutes setting you specify where to load the subroutes from.</para>
1086

    
1087
      <para>Internally the ConfigurationManager merges toghether the main
1088
      route with its subroutes:<example>
1089
          <title>Composite routes</title>
1090

    
1091
          <programlisting language="yaml">--
1092
  name: 'Demo subroutes :: Customer routes'
1093
  uriPattern: 'demo/clients/{@action}(.{@format})'
1094
  defaults:
1095
    '@package': Demo
1096
    '@format':  html
1097
    '@controller': Customer
1098

    
1099
--
1100
  name: 'Demo subroutes :: Standard routes'
1101
  uriPattern: 'demo/{@action}(.{@format})'
1102
  defaults:
1103
    '@package': Demo
1104
    '@format':  html
1105
    '@controller': Standard
1106

    
1107
--
1108
  name: 'Demo subroutes :: Fallback'
1109
  uriPattern: 'demo(.{@format})'
1110
  defaults:
1111
    '@package': Demo
1112
    '@format':  html
1113
    '@controller': Standard
1114
    '@action':     index</programlisting>
1115

    
1116
          <para>You can even reference multiple subroutes from one route -
1117
          that will create one route for all possible combinations.</para>
1118
        </example></para>
1119
    </section>
1120
  </section>
1121

    
1122
  <section xml:id="flow3.mvcframework.clirequests">
1123
    <title>CLI request handling</title>
1124

    
1125
    <para>FLOW3's CLI request handling offers a comfortable and flexible way
1126
    of calling code from the command line:</para>
1127

    
1128
    <para><command>php index.php [<replaceable>command</replaceable>]
1129
    [<replaceable>options</replaceable>] [--]
1130
    [<replaceable>arguments</replaceable>]</command></para>
1131

    
1132
    <para><replaceable>command</replaceable>,
1133
    <replaceable>options</replaceable> and
1134
    <replaceable>arguments</replaceable> are optional, with varying results.
1135
    The command structure follows what is commonly accpeted on unixoid systems
1136
    for CLI programs:<variablelist>
1137
        <varlistentry>
1138
          <term>command</term>
1139

    
1140
          <listitem>
1141
            <para>If not given, the default controller of the FLOW3 package is
1142
            used and it's index action is called. While this is an allowed
1143
            call, it hardly makes sense (other than checking if FLOW basically
1144
            works). If command is given then it is defined as
1145
            <emphasis><replaceable>package</replaceable>
1146
            [[<replaceable>sub1..N</replaceable>]
1147
            <replaceable>controller</replaceable>
1148
            <replaceable>action</replaceable>]</emphasis></para>
1149

    
1150
            <para>First part is always the package. If only the package is
1151
            given, it's StandardController's index action is called.</para>
1152

    
1153
            <para>If at least three command parts are given, the last two
1154
            sepcify controller and action. Anything in between specifys a sub
1155
            package structure.<example>
1156
                <title>Some FLOW3 CLI command specifications</title>
1157

    
1158
                <para><literal>testing cli run</literal> would call the "run"
1159
                action of the "cli" controller in the "Testing" package</para>
1160

    
1161
                <para><literal>typo3cr admin setup foo</literal> would call
1162
                the "setup" controller's "foo" action in the subpackage
1163
                "admin" of the package "TYPO3CR"</para>
1164
              </example></para>
1165
          </listitem>
1166
        </varlistentry>
1167

    
1168
        <varlistentry>
1169
          <term>options</term>
1170

    
1171
          <listitem>
1172
            <para>Options are either short- or long-style. The first option
1173
            detected ends collecting command parts. Here are some
1174
            examples:<example>
1175
                <title>Giving options to FLOW3 CLI requests</title>
1176

    
1177
                <para><literal>-o -f=value --a-long-option --with-spaces="is
1178
                possible" --input file1 -o=file2 --event-this =
1179
                works</literal></para>
1180
              </example></para>
1181
          </listitem>
1182
        </varlistentry>
1183

    
1184
        <varlistentry>
1185
          <term>arguments</term>
1186

    
1187
          <listitem>
1188
            <para>Arguments can follow and will be available to the called
1189
            controller in the request object. To distinguish between
1190
            <replaceable>command</replaceable> and
1191
            <replaceable>arguments</replaceable> in cases where no
1192
            <replaceable>options</replaceable> are given the seperator
1193
            <literal>--</literal> must be used.</para>
1194
          </listitem>
1195
        </varlistentry>
1196
      </variablelist></para>
1197
  </section>
1198
</chapter>