[ Index ]
 

Code source de Symfony 1.0.0

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/doc/ -> 02-Exploring-Symfony-s-Code.txt (source)

   1  Chapter 2 - Exploring Symfony's Code
   2  ====================================
   3  
   4  At first glance, the code behind a symfony-driven application can seem quite daunting. It consists of many directories and scripts, and the files are a mix of PHP classes, HTML, and even an intermingling of the two. You'll also see references to classes that are otherwise nowhere to be found within the application folder, and the directory depth stretches to six levels. But once you understand the reason behind all of this seeming complexity, you'll suddenly feel like it's so natural that you wouldn't trade the symfony application structure for any other. This chapter explains away that intimidated feeling.
   5  
   6  The MVC Pattern
   7  ---------------
   8  
   9  Symfony is based on the classic web design pattern known as the MVC architecture, which consists of three levels:
  10  
  11    * The model represents the information on which the application operates--its business logic.
  12    * The view renders the model into a web page suitable for interaction with the user.
  13    * The controller responds to user actions and invokes changes on the model or view as appropriate.
  14  
  15  Figure 2-1 illustrates the MVC pattern.
  16  
  17  The MVC architecture separates the business logic (model) and the presentation (view), resulting in greater maintainability. For instance, if your application should run on both standard web browsers and handheld devices, you just need a new view; you can keep the original controller and model. The controller helps to hide the detail of the protocol used for the request (HTTP, console mode, mail, and so on) from the model and the view. And the model abstracts the logic of the data, which makes the view and the action independent of, for instance, the type of database used by the application.
  18  
  19  Figure 2-1 - The MVC pattern
  20  
  21  ![The MVC pattern](/images/book/F0201.png "The MVC pattern")
  22  
  23  ### MVC Layering
  24  
  25  To help you understand MVC's advantages, let's see how to convert a basic PHP application to an MVC-architectured application. A list of posts for a weblog application will be a perfect example.
  26  
  27  #### Flat Programming
  28  
  29  In a flat PHP file, displaying a list of database entries might look like the script presented in Listing 2-1.
  30  
  31  Listing 2-1 - A Flat Script
  32  
  33      [php]
  34      <?php
  35  
  36      // Connecting, selecting database
  37      $link = mysql_connect('localhost', 'myuser', 'mypassword');
  38      mysql_select_db('blog_db', $link);
  39  
  40      // Performing SQL query
  41      $result = mysql_query('SELECT date, title FROM post', $link);
  42  
  43      ?>
  44  
  45      <html>
  46        <head>
  47          <title>List of Posts</title>
  48        </head>
  49        <body>
  50         <h1>List of Posts</h1>
  51         <table>
  52           <tr><th>Date</th><th>Title</th></tr>
  53      <?php
  54      // Printing results in HTML
  55      while ($row = mysql_fetch_array($result, MYSQL_ASSOC))
  56      {
  57      echo "\t<tr>\n";
  58      printf("\t\t<td> %s </td>\n", $row['date']);
  59      printf("\t\t<td> %s </td>\n", $row['title']);
  60      echo "\t</tr>\n";
  61      }
  62      ?>
  63          </table>
  64        </body>
  65      </html>
  66  
  67      <?php
  68  
  69      // Closing connection
  70      mysql_close($link);
  71  
  72      ?>
  73  
  74  That's quick to write, fast to execute, and impossible to maintain. The following are the major problems with this code:
  75  
  76    * There is no error-checking (what if the connection to the database fails?).
  77    * HTML and PHP code are mixed, even interwoven together.
  78    * The code is tied to a MySQL database.
  79  
  80  #### Isolating the Presentation
  81  
  82  The `echo` and `printf` calls in Listing 2-1 make the code difficult to read. Modifying the HTML code to enhance the presentation is a hassle with the current syntax. So the code can be split into two parts. First, the pure PHP code with all the business logic goes in a controller script, as shown in Listing 2-2.
  83  
  84  Listing 2-2 - The Controller Part, in `index.php`
  85  
  86      [php]
  87      <?php
  88  
  89       // Connecting, selecting database
  90       $link = mysql_connect('localhost', 'myuser', 'mypassword');
  91       mysql_select_db('blog_db', $link);
  92  
  93       // Performing SQL query
  94       $result = mysql_query('SELECT date, title FROM post', $link);
  95  
  96       // Filling up the array for the view
  97       $posts = array();
  98       while ($row = mysql_fetch_array($result, MYSQL_ASSOC))
  99       {
 100          $posts[] = $row;
 101       }
 102  
 103       // Closing connection
 104       mysql_close($link);
 105  
 106       // Requiring the view
 107       require('view.php');
 108  
 109       ?>
 110  
 111  The HTML code, containing template-like PHP syntax, is stored in a view script, as shown in Listing 2-3.
 112  
 113  Listing 2-3 - The View Part, in `view.php`
 114  
 115      [php]
 116      <html>
 117        <head>
 118          <title>List of Posts</title>
 119        </head>
 120        <body>
 121          <h1>List of Posts</h1>
 122          <table>
 123            <tr><th>Date</th><th>Title</th></tr>
 124          <?php foreach ($posts as $post): ?>
 125            <tr>
 126              <td><?php echo $post['date'] ?></td>
 127              <td><?php echo $post['title'] ?></td>
 128            </tr>
 129          <?php endforeach; ?>
 130          </table>
 131        </body>
 132      </html>
 133  
 134  A good rule of thumb to determine whether the view is clean enough is that it should contain only a minimum amount of PHP code, in order to be understood by an HTML designer without PHP knowledge. The most common statements in views are echo, if/endif, foreach/endforeach, and that's about all. Also, there should not be PHP code echoing HTML tags.
 135  
 136  All the logic is moved to the controller script, and contains only pure PHP code, with no HTML inside. As a matter of fact, you should imagine that the same controller could be reused for a totally different presentation, perhaps in a PDF file or an XML structure.
 137  
 138  #### Isolating the Data Manipulation
 139  
 140  Most of the controller script code is dedicated to data manipulation. But what if you need the list of posts for another controller, say one that would output an RSS feed of the weblog posts? What if you want to keep all the database queries in one place, to avoid code duplication? What if you decide to change the data model so that the `post` table gets renamed `weblog_post`? What if you want to switch to PostgreSQL instead of MySQL? In order to make all that possible, you need to remove the data-manipulation code from the controller and put it in another script, called the model, as shown in Listing 2-4.
 141  
 142  Listing 2-4 - The Model Part, in `model.php`
 143  
 144      [php]
 145      <?php
 146  
 147      function getAllPosts()
 148      {
 149        // Connecting, selecting database
 150        $link = mysql_connect('localhost', 'myuser', 'mypassword');
 151        mysql_select_db('blog_db', $link);
 152  
 153        // Performing SQL query
 154        $result = mysql_query('SELECT date, title FROM post', $link);
 155  
 156        // Filling up the array
 157        $posts = array();
 158        while ($row = mysql_fetch_array($result, MYSQL_ASSOC))
 159        {
 160           $posts[] = $row;
 161        }
 162  
 163        // Closing connection
 164        mysql_close($link);
 165  
 166        return $posts;
 167      }
 168  
 169      ?>
 170  
 171  The revised controller is presented in Listing 2-5.
 172  
 173  Listing 2-5 - The Controller Part, Revised, in `index.php`
 174  
 175      [php]
 176      <?php
 177  
 178      // Requiring the model
 179      require_once('model.php');
 180  
 181      // Retrieving the list of posts
 182      $posts = getAllPosts();
 183  
 184      // Requiring the view
 185      require('view.php');
 186  
 187      ?>
 188  
 189  The controller becomes easier to read. Its sole task is to get the data from the model and pass it to the view. In more complex applications, the controller also deals with the request, the user session, the authentication, and so on. The use of explicit names for the functions of the model even makes code comments unnecessary in the controller.
 190  
 191  The model script is dedicated to data access and can be organized accordingly. All parameters that don't depend on the data layer (like request parameters) must be given by the controller and not accessed directly by the model. The model functions can be easily reused in another controller.
 192  
 193  ### Layer Separation Beyond MVC
 194  
 195  So the principle of the MVC architecture is to separate the code into three layers, according to its nature. Data logic code is placed within the model, presentation code within the view, and application logic within the controller.
 196  
 197  Other additional design patterns can make the coding experience even easier. The model, view, and controller layers can be further subdivided.
 198  
 199  #### Database Abstraction
 200  
 201  The model layer can be split into a data access layer and a database abstraction layer. That way, data access functions will not use database-dependent query statements, but call some other functions that will do the queries themselves. If you change your database system later, only the database abstraction layer will need updating.
 202  
 203  An example of a MySQL-specific data access layer is presented in Listing 2-6, followed by a sample database abstraction layer in Listing 2-7.
 204  
 205  Listing 2-6 - The Database Abstraction Part of the Model
 206  
 207      [php]
 208      <?php
 209  
 210      function open_connection($host, $user, $password)
 211      {
 212        return mysql_connect($host, $user, $password);
 213      }
 214  
 215      function close_connection($link)
 216      {
 217        mysql_close($link);
 218      }
 219  
 220      function query_database($query, $database, $link)
 221      {
 222        mysql_select_db($database, $link);
 223  
 224        return mysql_query($query, $link);
 225      }
 226  
 227      function fetch_results($result)
 228      {
 229        return mysql_fetch_array($result, MYSQL_ASSOC);
 230      }
 231  
 232  Listing 2-7 - The Data Access Part of the Model
 233  
 234      [php]
 235      function getAllPosts()
 236      {
 237        // Connecting to database
 238        $link = open_connection('localhost', 'myuser', 'mypassword');
 239  
 240        // Performing SQL query
 241        $result = query_database('SELECT date, title FROM post', 'blog_db', $link);
 242  
 243        // Filling up the array
 244        $posts = array();
 245        while ($row = fetch_results($result))
 246        {
 247           $posts[] = $row;
 248        }
 249  
 250        // Closing connection
 251        close_connection($link);
 252  
 253        return $posts;
 254      }
 255  
 256      ?>
 257  
 258  You can check that no database-engine dependent functions can be found in the data access layer, making it database-independent. Additionally, the functions created in the database abstraction layer can be reused for many other model functions that need access to the database.
 259  
 260  >**NOTE**
 261  >The examples in Listings 2-6 and 2-7 are still not very satisfactory, and there is some work left to do to have a full database abstraction (abstracting the SQL code through a database-independent query builder, moving all functions into a class, and so on). But the purpose of this book is not to show you how to write all that code by hand, and you will see in Chapter 8 that symfony natively does all the abstraction very well.
 262  
 263  #### View Elements
 264  
 265  The view layer can also benefit from some code separation. A web page often contains consistent elements throughout an application: the page headers, the graphical layout, the footer, and the global navigation. Only the inner part of the page changes. That's why the view is separated into a layout and a template. The layout is usually global to the application, or to a group of pages. The template only puts in shape the variables made available by the controller. Some logic is needed to make these components work together, and this view logic layer will keep the name view. According to these principles, the view part of Listing 2-3 can be separated into three parts, as shown in Listings 2-8, 2-9, and 2-10.
 266  
 267  Listing 2-8 - The Template Part of the View, in `mytemplate.php`
 268  
 269      [php]
 270      <h1>List of Posts</h1>
 271      <table>
 272      <tr><th>Date</th><th>Title</th></tr>
 273      <?php foreach ($posts as $post): ?>
 274        <tr>
 275          <td><?php echo $post['date'] ?></td>
 276          <td><?php echo $post['title'] ?></td>
 277        </tr>
 278      <?php endforeach; ?>
 279      </table>
 280  
 281  Listing 2-9 - The View Logic Part of the View
 282  
 283      [php]
 284      <?php
 285  
 286      $title = 'List of Posts';
 287      $content = include('mytemplate.php');
 288  
 289      ?>
 290  
 291  Listing 2-10 - The Layout Part of the View
 292  
 293      [php]
 294      <html>
 295        <head>
 296          <title><?php echo $title ?></title>
 297        </head>
 298        <body>
 299          <?php echo $content ?>
 300        </body>
 301      </html>
 302  
 303  #### Action and Front Controller
 304  
 305  The controller doesn't do much in the previous example, but in real web applications, the controller has a lot of work. An important part of this work is common to all the controllers of the application. The common tasks include request handling, security handling, loading the application configuration, and similar chores. This is why the controller is often divided into a front controller, which is unique for the whole application, and actions, which contain only the controller code specific to one page.
 306  
 307  One of the great advantages of a front controller is that it offers a unique entry point to the whole application. If you ever decide to close the access to the application, you will just need to edit the front controller script. In an application without a front controller, each individual controller would need to be turned off.
 308  
 309  #### Object Orientation
 310  
 311  All the previous examples use procedural programming. The OOP capabilities of modern languages make the programming even easier, since objects can encapsulate logic, inherit from one another, and provide clean naming conventions.
 312  
 313  Implementing an MVC architecture in a language that is not object-oriented raises namespace and code-duplication issues, and the overall code is difficult to read.
 314  
 315  Object orientation allows developers to deal with such things as the view object, the controller object, and the model classes, and to transform all the functions in the previous examples into methods. It is a must for MVC architectures.
 316  
 317  >**TIP**
 318  >If you want to learn more about design patterns for web applications in an object-oriented context, read Patterns of Enterprise Application Architecture by Martin Fowler (Addison-Wesley, ISBN: 0-32112-742-0). Code examples in Fowler's book are in Java or C#, but are still quite readable for a PHP developer.
 319  
 320  ### Symfony's MVC Implementation
 321  
 322  Hold on a minute. For a single page listing the posts in a weblog, how many components are required? As illustrated in Figure 2-2, we have the following parts:
 323  
 324    * Model layer
 325      * Database abstraction
 326      * Data access
 327    * View layer
 328      * View
 329      * Template
 330      * Layout
 331    * Controller layer
 332      * Front controller
 333      * Action
 334  
 335  Seven scripts--a whole lot of files to open and to modify each time you create a new page! However, symfony makes things easy. While taking the best of the MVC architecture, symfony implements it in a way that makes application development fast and painless.
 336  
 337  First of all, the front controller and the layout are common to all actions in an application. You can have multiple controllers and layouts, but you need only one of each. The front controller is pure MVC logic component, and you will never need to write a single one, because symfony will generate it for you.
 338  
 339  The other good news is that the classes of the model layer are also generated automatically, based on your data structure. This is the job of the Propel library, which provides class skeletons and code generation. If Propel finds foreign key constraints or date fields, it will provide special accessor and mutator methods that will make data manipulation a piece of cake. And the database abstraction is totally invisible to you, because it is dealt with by another component, called Creole. So if you decide to change your database engine at one moment, you have zero code to rewrite. You just need to change one configuration parameter.
 340  
 341  And the last thing is that the view logic can be easily translated as a simple configuration file, with no programming needed.
 342  
 343  Figure 2-2 - Symfony workflow
 344  
 345  ![Symfony workflow](/images/book/F0202.png "Symfony workflow")
 346  
 347  That means that the list of posts described in our example would require only three files to work in symfony, as shown in Listings 2-11, 2-12, and 2-13.
 348  
 349  Listing 2-11 - `list` Action, in `myproject/apps/myapp/modules/weblog/actions/actions.class.php`
 350  
 351      [php]
 352      <?php
 353      class weblogActions extends sfActions
 354      {
 355        public function executeList()
 356        {
 357          $this->posts = PostPeer::doSelect(new Criteria());
 358        }
 359      }
 360  
 361      ?>
 362  
 363  Listing 2-12 - `list` Template, in `myproject/apps/myapp/modules/weblog/templates/listSuccess.php`
 364  
 365      [php]
 366      <h1>List of Posts</h1>
 367      <table>
 368      <tr><th>Date</th><th>Title</th></tr>
 369      <?php foreach ($posts as $post): ?>
 370        <tr>
 371          <td><?php echo $post->getDate() ?></td>
 372          <td><?php echo $post->getTitle() ?></td>
 373        </tr>
 374      <?php endforeach; ?>
 375      </table>
 376  
 377  Listing 2-13 - `list` View, in `myproject/apps/myapp/modules/weblog/config/view.yml`
 378  
 379      listSuccess:
 380        metas: { title: List of Posts }
 381  
 382  In addition, you will still need to define a layout, as shown in Listing 2-14, but it will be reused many times.
 383  
 384  Listing 2-14 - Layout, in `myproject/apps/myapp/templates/layout.php`
 385  
 386      [php]
 387      <html>
 388        <head>
 389          <?php echo include_title() ?>
 390        </head>
 391        <body>
 392          <?php echo $sf_data->getRaw('sf_content') ?>
 393        </body>
 394      </html>
 395  
 396  And that is really all you need. This is the exact code required to display the very same page as the flat script shown earlier in Listing 2-1. The rest (making all the components work together) is handled by symfony. If you count the lines, you will see that creating the list of posts in an MVC architecture with symfony doesn't require more time or coding than writing a flat file. Nevertheless, it gives you huge advantages, notably clear code organization, reusability, flexibility, and much more fun. And as a bonus, you have XHTML conformance, debug capabilities, easy configuration, database abstraction, smart URL routing, multiple environments, and many more development tools.
 397  
 398  ### Symfony Core Classes
 399  
 400  The MVC implementation in symfony uses several classes that you will meet quite often in this book:
 401  
 402    * `sfController` is the controller class. It decodes the request and hands it to the action.
 403    * `sfRequest` stores all the request elements (parameters, cookies, headers, and so on).
 404    * `sfResponse` contains the response headers and contents. This is the object that will eventually be converted to an HTML response and be sent to the user.
 405    * The context singleton (retrieved by `sfContext::getInstance()`) stores a reference to all the core objects and the current configuration; it is accessible from everywhere.
 406  
 407  You will learn more about these objects in Chapter 6.
 408  
 409  As you can see, all the symfony classes use the `sf` prefix, as do the symfony core variables in the templates. This should avoid name collisions with your own classes and variables, and make the core framework classes sociable and easy to recognize.
 410  
 411  >**NOTE**
 412  >Among the coding standards used in symfony, UpperCamelCase is the standard for class and variable naming. Two exceptions exist: core symfony classes start with `sf`, which is lowercase, and variables found in templates use the underscore-separated syntax.
 413  
 414  Code Organization
 415  -----------------
 416  
 417  Now that you know the different components of a symfony application, you're probably wondering how they are organized. Symfony organizes code in a project structure and puts the project files into a standard tree structure.
 418  
 419  ### Project Structure: Applications, Modules, and Actions
 420  
 421  In symfony, a project is a set of services and operations available under a given domain name, sharing the same object model.
 422  
 423  Inside a project, the operations are grouped logically into applications. An application can normally run independently of the other applications of the same project. In most cases, a project will contain two applications: one for the front-office and one for the back-office, sharing the same database. But you can also have one project containing many mini-sites, with each site as a different application. Note that hyperlinks between applications must be in the absolute form.
 424  
 425  Each application is a set of one or more modules. A module usually represents a page or a group of pages with a similar purpose. For example, you might have the modules `home`, `articles`, `help`, `shoppingCart`, `account`, and so on.
 426  
 427  Modules hold actions, which represent the various actions that can be done in a module. For example, a `shoppingCart` module can have `add`, `show`, and `update` actions. Generally, actions can be described by a verb. Dealing with actions is almost like dealing with pages in a classic web application, although two actions can result in the same page (for instance, adding a comment to a post in a weblog will redisplay the post with the new comment).
 428  
 429  >**TIP**
 430  >If this represents too many levels for a beginning project, it is very easy to group all actions into one single module, so that the file structure can be kept simple. When the application gets more complex, it will be time to organize actions into separate modules. As mentioned in Chapter 1, rewriting code to improve its structure or readability (but preserving its behavior) is called refactoring, and you will do this a lot when applying RAD principles.
 431  
 432  Figure 2-3 shows a sample code organization for a weblog project, in a project/ application/module/action structure. But be aware that the actual file tree structure of the project will differ from the setup shown in the figure.
 433  
 434  Figure 2-3 - Example of code organization
 435  
 436  ![Example of code organization](/images/book/F0203.png "Example of code organization")
 437  
 438  ### File Tree Structure
 439  
 440  All web projects generally share the same types of contents, such as the following:
 441  
 442    * A database, such as MySQL or PostgreSQL
 443    * Static files (HTML, images, JavaScript files, style sheets, and so on)
 444    * Files uploaded by the site users and administrators
 445    * PHP classes and libraries
 446    * Foreign libraries (third-party scripts)
 447    * Batch files (scripts to be launched by a command line or via a cron table)
 448    * Log files (traces written by the application and/or the server)
 449    * Configuration files
 450  
 451  Symfony provides a standard file tree structure to organize all these contents in a logical way, consistent with the architecture choices (MVC pattern and project/application/module grouping). This is the tree structure that is automatically created when initializing every project, application, or module. Of course, you can customize it completely, to reorganize the files and directories at your convenience or to match your client's requirements.
 452  
 453  #### Root Tree Structure
 454  
 455  These are the directories found at the root of a symfony project:
 456  
 457      apps/
 458        frontend/
 459        backend/
 460      batch/
 461      cache/
 462      config/
 463      data/
 464        sql/
 465      doc/
 466      lib/
 467        model/
 468      log/
 469      plugins/
 470      test/
 471        unit/
 472        functional/
 473      web/
 474        css/
 475        images/
 476        js/
 477        uploads/
 478  
 479  Table 2-1 describes the contents of these directories.
 480  
 481  Table 2-1 - Root Directories
 482  
 483  Directory  |  Description
 484  ---------- | ------------
 485  `apps/`    | Contains one directory for each application of the project (typically, `frontend` and `backend` for the front and back office).
 486  `batch/`   | Contains PHP scripts called from a command line or a scheduler, to run batch processes.
 487  `cache/`   | Contains the cached version of the configuration, and (if you activate it) the cache version of the actions and templates of the project. The cache mechanism (detailed in Chapter 12) uses these files to speed up the answer to web requests. Each application will have a subdirectory here, containing preprocessed PHP and HTML files.
 488  `config/`  | Holds the general configuration of the project.
 489  `data/`    | Here, you can store the data files of the project, like a database schema, a SQL file that creates tables, or even a SQLite database file.
 490  `doc/`     | Stores the project documentation, including your own documents and the documentation generated by PHPdoc.
 491  `lib/`     | Dedicated to foreign classes or libraries. Here, you can add the code that needs to be shared among your applications. The `model/` subdirectory stores the object model of the project (described in Chapter 8).
 492  `log/`     | Stores the applicable log files generated directly by symfony. It can also contain web server log files, database log files, or log files from any part of the project. Symfony creates one log file per application and per environment (log files are discussed in Chapter 16).
 493  `plugins/` | Stores the plug-ins installed in the application (plug-ins are discussed in Chapter 17).
 494  `test/`    | Contains unit and functional tests written in PHP and compatible with the symfony testing framework (discussed in Chapter 15). During the project setup, symfony automatically adds some stubs with a few basic tests.
 495  `web/`     | The root for the web server. The only files accessible from the Internet are the ones located in this directory.
 496  
 497  #### Application Tree Structure
 498  
 499  The tree structure of all application directories is the same:
 500  
 501      apps/
 502        [application name]/
 503          config/
 504          i18n/
 505          lib/
 506          modules/
 507          templates/
 508            layout.php
 509            error.php
 510            error.txt
 511  
 512  Table 2-2 describes the application subdirectories.
 513  
 514  Table 2-2 - Application Subdirectories
 515  
 516  Directory    | Description
 517  ------------ | -----------
 518  `config/`    | Holds a hefty set of YAML configuration files. This is where most of the application configuration is, apart from the default parameters that can be found in the framework itself. Note that the default parameters can still be overridden here if needed. You'll learn more about application configuration in the Chapter 5.
 519  `i18n/`      | Contains files used for the internationalization of the application--mostly interface translation files (Chapter 13 deals with internationalization). You can bypass this directory if you choose to use a database for internationalization.
 520  `lib/`       | Contains classes and libraries that are specific to the application.
 521  `modules/`   | Stores all the modules that contain the features of the application.
 522  `templates/` | Lists the global templates of the application--the ones that are shared by all modules. By default, it contains a `layout.php` file, which is the main layout in which the module templates are inserted.
 523  
 524  >**NOTE**
 525  >The `i18n/`, `lib/`, and `modules/` directories are empty for a new application.
 526  
 527  The classes of an application are not able to access methods or attributes in other applications of the same project. Also note that hyperlinks between two applications of the same project must be in absolute form. You need to keep this last constraint in mind during initialization, when you choose how to divide your project into applications.
 528  
 529  #### Module Tree Structure
 530  
 531  Each application contains one or more modules. Each module has its own subdirectory in the `modules` directory, and the name of this directory is chosen during the setup.
 532  
 533  This is the typical tree structure of a module:
 534  
 535      apps/
 536        [application name]/
 537          modules/
 538            [module name]/
 539                actions/
 540                  actions.class.php
 541                config/
 542                lib/
 543                templates/
 544                  indexSuccess.php
 545                validate/
 546  
 547  Table 2-3 describes the module subdirectories.
 548  
 549  Table 2-3 -  Module Subdirectories
 550  
 551  Directory    | Description
 552  ------------ | ------------
 553  `actions/`   | Generally contains a single class file named `actions.class.php`, in which you can store all the actions of the module. You can also write different actions of a module in separate files.
 554  `config/`    | Can contain custom configuration files with local parameters for the module.
 555  `lib/`       | Stores classes and libraries specific to the module.
 556  `templates/` | Contains the templates corresponding to the actions of the module. A default template, called `indexSuccess.php`, is created during module setup.
 557  `validate/`  | Dedicated to configuration files used for form validation (discussed in Chapter 10).
 558  
 559  >**NOTE**
 560  >The `config/`, `lib/`, and `validate/` directories are empty for a new module.
 561  
 562  #### Web Tree Structure
 563  
 564  There are very few constraints for the `web` directory, which is the directory of publicly accessible files. Following a few basic naming conventions will provide default behaviors and useful shortcuts in the templates. Here is an example of a `web` directory structure:
 565  
 566      web/
 567        css/
 568        images/
 569        js/
 570        uploads/
 571  
 572  Conventionally, the static files are distributed in the directories listed in Table 2-4.
 573  
 574  Table 2-4 - Typical Web Subdirectories
 575  
 576  Directory  | Description
 577  ---------- | -----------
 578  `css/`     | Contains style sheets with a `.css` extension.
 579  `images/`  | Contains images with a `.jpg`, `.png`, or `.gif` format.
 580  `js/`      | Holds JavaScript files with a `.js` extension.
 581  `uploads/` | Must contain the files uploaded by the users. Even though the directory usually contains images, it is distinct from the images directory so that the synchronization of the development and production servers does not affect the uploaded images.
 582  
 583  >**NOTE**
 584  >Even though it is highly recommended that you maintain the default tree structure, it is possible to modify it for specific needs, such as to allow a project to run in a server with different tree structure rules and coding conventions. Refer to Chapter 19 for more information about modifying the file tree structure.
 585  
 586  Common Instruments
 587  ------------------
 588  
 589  A few techniques are used repeatedly in symfony, and you will meet them quite often in this book and in your own projects. These include parameter holders, constants, and class autoloading.
 590  
 591  ### Parameter Holders
 592  
 593  Many of the symfony classes contain a parameter holder. It is a convenient way to encapsulate attributes with clean getter and setter methods. For instance, the sfResponse class holds a parameter holder that you can retrieve by calling the `getParameterHolder()` method. Each parameter holder stores data the same way, as illustrated in Listing 2-15.
 594  
 595  Listing 2-15 - Using the `sfResponse` Parameter Holder
 596  
 597      [php]
 598      $response->getParameterHolder()->set('foo', 'bar');
 599      echo $response->getParameterHolder()->get('foo');
 600       => 'bar'
 601  
 602  Most of the classes using a parameter holder provide proxy methods to shorten the code needed for get/set operations. This is the case for the `sfResponse` object, so you can do the same as in Listing 2-15 with the code of Listing 2-16.
 603  
 604  Listing 2-16 - Using the `sfResponse` Parameter Holder Proxy Methods
 605  
 606      [php]
 607      $response->setParameter('foo', 'bar');
 608      echo $response->getParameter('foo');
 609       => 'bar'
 610  
 611  The parameter holder getter accepts a default value as a second argument. This provides a useful fallback mechanism that is much more concise than possible with a conditional statement. See Listing 2-17 for an example.
 612  
 613  Listing 2-17 - Using the Attribute Holder Getter's Default Value
 614  
 615      [php]
 616      // The 'foobar' parameter is not defined, so the getter returns an empty value
 617      echo $response->getParameter('foobar');
 618       => null
 619  
 620      // A default value can be used by putting the getter in a condition
 621      if ($response->hasParameter('foobar'))
 622      {
 623        echo $response->getParameter('foobar');
 624      }
 625      else
 626      {
 627        echo 'default';
 628      }
 629       => default
 630  
 631      // But it is much faster to use the second getter argument for that
 632      echo $response->getParameter('foobar', 'default');
 633       => default
 634  
 635  The parameter holders even support namespaces. If you specify a third argument to a setter or a getter, it is used as a namespace, and the parameter will be defined only within that namespace. Listing 2-18 shows an example.
 636  
 637  Listing 2-18 - Using the `sfResponse` Parameter Holder Namespace
 638  
 639      [php]
 640      $response->setParameter('foo', 'bar1');
 641      $response->setParameter('foo', 'bar2', 'my/name/space');
 642      echo $response->getParameter('foo');
 643       => 'bar1'
 644      echo $response->getParameter('foo', null, 'my/name/space');
 645       => 'bar2'
 646  
 647  Of course, you can add a parameter holder to your own classes to take advantage of its syntax facilities. Listing 2-19 shows how to define a class with a parameter holder.
 648  
 649  Listing 2-19 - Adding a Parameter Holder to a Class
 650  
 651      [php]
 652      class MyClass
 653      {
 654        protected $parameter_holder = null;
 655  
 656        public function initialize ($parameters = array())
 657        {
 658          $this->parameter_holder = new sfParameterHolder();
 659          $this->parameter_holder->add($parameters);
 660        }
 661  
 662        public function getParameterHolder()
 663        {
 664          return $this->parameter_holder;
 665        }
 666      }
 667  
 668  ### Constants
 669  
 670  Surprisingly, you will find very few constants in symfony. This is because constants have a major drawback in PHP: you can't change their value once they are defined. So symfony uses its own configuration object, called sfConfig, which replaces constants. It provides static methods to access parameters from everywhere. Listing 2-20 demonstrates the use of sfConfig class methods.
 671  
 672  Listing 2-20 - Using the `sfConfig` Class Methods Instead of Constants
 673  
 674      [php]
 675      // Instead of PHP constants,
 676      define('SF_FOO', 'bar');
 677      echo SF_FOO;
 678      // Symfony uses the sfConfig object
 679      sfConfig::set('sf_foo', 'bar');
 680      echo sfConfig::get('sf_foo');
 681  
 682  The sfConfig methods support default values, and you can call the sfConfig::set() method more than once on the same parameter to change its value. Chapter 5 discusses `sfConfig` methods in more detail.
 683  
 684  ### Class Autoloading
 685  
 686  Classically, when you use a class method or create an object in PHP, you need to include the class definition first.
 687  
 688      [php]
 689      include 'classes/MyClass.php';
 690      $myObject = new MyClass();
 691  
 692  But on large projects with many classes and a deep directory structure, keeping track of all the class files to include and their paths takes a lot of time. By providing an __autoload() function (or a `spl_autoload_register()` function), symfony makes `include` statements unnecessary, and you can write directly:
 693  
 694      [php]
 695      $myObject = new MyClass();
 696  
 697  Symfony will then look for a `MyClass` definition in all files ending with `php` in one of the project's `lib/` directories. If the class definition is found, it will be included automatically.
 698  
 699  So if you store all your classes in lib/ directories, you don't need to include classes anymore. That's why the symfony projects usually do not contain any `include` or `require` statements.
 700  
 701  >**NOTE**
 702  >For better performance, the symfony autoloading scans a list of directories (defined in an internal configuration file) during the first request. It then registers all the classes these directories contain and stores the class/file correspondence in a PHP file as an associative array. That way, future requests don't need to do the directory scan anymore. This is why you need to clear the cache every time you add or move a class file in your project by calling the `symfony clear-cache` command. You will learn more about the cache in Chapter 12, and about the autoloading configuration in Chapter 19.
 703  
 704  Summary
 705  -------
 706  
 707  Using an MVC framework forces you to divide and organize your code according to the framework conventions. Presentation code goes to the view, data manipulation code goes to the model, and the request manipulation logic goes to the controller. It makes the application of the MVC pattern both very helpful and quite restricting.
 708  
 709  Symfony is an MVC framework written in PHP 5. Its structure is designed to get the best of the MVC pattern, but with great ease of use. Thanks to its versatility and configurability, symfony is suitable for all web application projects.
 710  
 711  Now that you understand the underlying theory behind symfony, you are almost ready to develop your first application. But before that, you need a symfony installation up and running on your development server.


Généré le : Fri Mar 16 22:42:14 2007 par Balluche grâce à PHPXref 0.7