Difference between revisions of "Workshop - week 03"

From mi-linux
Jump to navigationJump to search
m
 
(11 intermediate revisions by 6 users not shown)
Line 1: Line 1:
[[Main Page]] >> [[Web Frameworks]] >> [[Web Frameworks - Workbook]] >> Workshop - week 03
+
[[Main Page]] >> [[CP2132|Web Frameworks]] >> [[Web Frameworks - Workbook|Workbook]] >> Workshop - week 03
  
===4. Creating the Layout===
+
===Creating the Layout===
  
 
We can think of the [http://framework.zend.com/docs/quickstart/create-a-layout layout page] as a template that defines a consistent look and feel for all pages within the MVC application. The controllers provide views that fill in what is unique about a particular page. Combined together, they provide us with a complete HTML/XHTML page. As the tutorial suggests, this is the reason why the layout is a good place to set up headers and footers that we want to remain the same for all our pages.
 
We can think of the [http://framework.zend.com/docs/quickstart/create-a-layout layout page] as a template that defines a consistent look and feel for all pages within the MVC application. The controllers provide views that fill in what is unique about a particular page. Combined together, they provide us with a complete HTML/XHTML page. As the tutorial suggests, this is the reason why the layout is a good place to set up headers and footers that we want to remain the same for all our pages.
  
===5. Configuration and Registry===
+
You may have noticed that the view scripts in the previous sections were HTML fragments- not complete pages. This is by design; we want our actions to return content only related to the action itself, not the application as a whole.
  
In older web programming methodologies, programmers would often create a file to be 'included' by all pages that needed access to database connections. This had many disadvantages, such as providing all the code for database connectivity often to every page, even when a database connection was not required for the page. There was also the security considerations of having a file with all the database connection details in a location where it may be accessible by anonymous users.
+
Now we must compose that generated content into a full HTML page. We'd also like to have a consistent look and feel for the application. We will use a global site layout to accomplish both of these tasks.
 +
 
 +
There are two design patterns that Zend Framework uses to implement layouts: Two Step View and Composite View. Two Step View is usually associated with the Transform View pattern; the basic idea is that your application view creates a representation that is then injected into the master view for final transformation. The Composite View pattern deals with a view made of one or more atomic, application views.
 +
 
 +
In Zend Framework, Zend_Layout combines the ideas behind these patterns. Instead of each action view script needing to include site-wide artifacts, they can simply focus on their own responsibilities.
 +
 
 +
Occasionally, however, you may need application-specific information in your site-wide view script. Fortunately, Zend Framework provides a variety of view placeholders to allow you to provide such information from your action view scripts.
 +
 
 +
To get started using Zend_Layout, first we need to make some modifications to our bootstrap.php file:
  
A more modern take on the concept is to have a [http://framework.zend.com/docs/quickstart/create-a-configuration-and-registry registry / configuration file], and classes to provide access to the data. It works much like an .ini file for desktop applications - providing a place to store application-wide settings, such as database connection strings. It works much like a hashtable, where data can be retrieved by key name. [http://framework.zend.com/docs/quickstart/create-a-configuration-and-registry We need to create] our app.ini file, and modify the boostrap.php file to include a reference to the app.ini. In the case of our QuickStart application, we will then be able to access the database settings from any page we choose.
+
<pre>
 +
// application/bootstrap.php
 +
//
 +
// Add the following code prior to the comment marked "Step 5" in
 +
// application/bootstrap.php.
 +
//
 +
// LAYOUT SETUP - Setup the layout component
 +
// The Zend_Layout component implements a composite (or two-step-view) pattern
 +
// With this call we are telling the component where to find the layouts scripts.
 +
Zend_Layout::startMvc(APPLICATION_PATH . '/layouts/scripts');
  
===6. Model and Database===
+
// VIEW SETUP - Initialize properties of the view object
 +
// The Zend_View component is used for rendering views. Here, we grab a "global"
 +
// view instance from the layout object, and specify the doctype we wish to
 +
// use. In this case, XHTML1 Strict.
 +
$view = Zend_Layout::getMvcInstance()->getView();
 +
$view->doctype('XHTML1_STRICT');
  
See [http://framework.zend.com/docs/quickstart/create-a-model-and-database-table here].
+
// CLEANUP - remove items from global scope
 +
// This will clear all our local boostrap variables from the global scope of
 +
// this script (and any scripts that called bootstrap). This will enforce
 +
// object retrieval through the applications's registry.
 +
unset($view);
 +
</pre>
  
====Database====
+
Calling startMvc() registers a plugin with the front controller, allowing layouts to work seamlessly and without further interaction in most cases. An action helper is registered, as is a view helper, in case you do need to interact with the layout object.
  
=====Database Connection=====
+
Note the call to the doctype() view helper; this is one of the placeholders mentioned above. By setting this in the bootstrap, we can assure that other doctype-aware view helpers know the selected doctype.
  
Next, we need somewhere to store our data. We modify the app.ini file to include the database connection details (We are setting up a SQLite database - it is not a database you will necessarily be familiar with. Rather than having a database program running on a server, SQLite can have an entire database stored within a file - like using an XML file, but with all the benefits of SQL queries.)
+
Now that we've initialized Zend_Layout, let's create our site-wide layout:
  
We then need to modify the bootstrap.php file, to include the new connection details to the database we are about to create.
+
<pre>
 +
<? /* application/layouts/scripts/layout.phtml
  
=====Database Schema=====
+
      This line outputs the doctype we set in the bootstrap */ ?>
 +
<?= $this->doctype() ?>
 +
<html xmlns="http://www.w3.org/1999/xhtml">
 +
<head> 
 +
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 +
  <title>Zend Framework Quickstart Application</title>
 +
  <?= $this->headLink()->appendStylesheet('https://mi-linux.wlv.ac.uk/~<YourStudentNumber>/QuickStart/public/css/global.css') ?>
 +
</head>
 +
<body>
  
We then create two SQL script files - one that defines the structure of the database that we want to set up, and another with some initial test data to be inserted into the new database.
+
<!--
 +
    Layouts are a great place to put header and footer content that will be
 +
    needed on all pages that share the same layout.  To understand fully what
 +
    having layouts inside a MVC application mean, check out the Zend_Layout
 +
    section of the manual.
 +
    http://framework.zend.com/manual/en/zend.layout.html
 +
    -->
 +
<div id="header" style="background-color: #EEEEEE; height: 30px;">
 +
    <div id="header-logo" style="float: left">
 +
        <b>ZF Quickstart Application</b>
 +
    </div>
 +
    <div id="header-navigation" style="float: right">
 +
        <!-- To keep urls consistent with the applications router (right now we
 +
            are using the default router), we will employ the use of the url
 +
            view helper
 +
            http://framework.zend.com/manual/en/zend.view.helpers.html
 +
            -->
 +
        <a href="<?= $this->url(
 +
            array('controller'=>'guestbook'),
 +
            'default',
 +
            true) ?>">Guestbook</a>
 +
    </div>
 +
</div>
  
=====Setup Script=====
+
<!-- This next call will now include any content that was generated in the
 +
    dispatching of a controllers action (or series of actions).  -->
  
This PHP file will be run just once, and will create our database by executing the first script, and fill it with data as outlined by our second script. Once scripts/load.sqlite.php has been executed successfully, the file can be deleted - but don't do so until you have a fully working application, in case you need to execute the database setup again.
+
<?= $this->layout()->content ?>
  
'''Pro Tip:''' Remember that the directories that the database is being set up within - data/db/ - need to have the correct permissions set. At this stage, CHMOD it to 777 (read, write and execute for all) to help get the application running.
+
<!-- If your application requires it, this would be a great place to put a
 +
    footer for all pages. -->
  
====Coding====
+
</body>
 +
</html>
 +
</pre>
  
=====Data Connector=====
+
We grab our application content using the layout() view helper, and accessing the "content" key. You may render to other response segments if you wish to, but in most cases, this is all that's necessary.
  
Now we need a small class to define how our normal database queries (update, insert, delete) should be handled. In our system, we only require an insert method, as we'll be only allowing inserts into the guestbook. However, to follow best practice we include an update method, but set it so that it will throw an exception error if the update is called. Our insert method with automatically add the date and time of the insert to the database.
+
Note also the use of the headLink() placeholder. This is an easy way to generate the HTML for <link> elements, as well as to keep track of them throughout your application. If you need to add additional CSS sheets to support a single action, you can do so, and be assured it will be present in the final rendered page.
  
 +
====Checkpoint====
  
=====Set-up Model File=====
+
Now go to http://mi-linux.wlv.ac.uk/~YourStudentNumber/QuickStart/public ; and check out the source. You should see your xhtml header, head, title, and body sections.
  
The model is what establishes business rules within our application. All methods relating to how our page does what it does should be defined here. We need to be able to retrive records from our database, so that the guestbook can display entries. It includes a function to return one entry, all entries - as well as a function that uses the insert we just set up to save new entries to the database.
 
  
We have one more line that needs changing in here:
+
===Configuration and Registry===
  
<pre>    protected function _getGuestbookForm()
+
In older web programming methodologies, programmers would often create a file to be 'included' by all pages that needed access to database connections. This had many disadvantages, such as providing all the code for database connectivity often to every page, even when a database connection was not required for the page. There was also the security considerations of having a file with all the database connection details in a location where it may be accessible by anonymous users.
    {
+
 
        require_once APPLICATION_PATH . '/forms/GuestBook.php';
+
A more modern take on the concept is to have a [http://framework.zend.com/docs/quickstart/create-a-configuration-and-registry registry / configuration file], and classes to provide access to the data. It works much like an .ini file for desktop applications - providing a place to store application-wide settings, such as database connection strings. It works much like a hashtable, where data can be retrieved by key name. [http://framework.zend.com/docs/quickstart/create-a-configuration-and-registry We need to create] our app.ini file, and modify the boostrap.php file to include a reference to the app.ini. In the case of our QuickStart application, we will then be able to access the database settings from any page we choose.
        $form = new Form_GuestBook();
 
        $form->setAction($this->_helper->url('sign'));
 
        return $form;
 
    }
 
</pre>
 
  
Should become:
 
  
 +
===Create a Configuration and Registry===
 +
Application configurations are an important part of creating modular and configurable applications. This is where Zend_Config comes into play. First we will create an application configuration file and put it inside application/config/app.ini.
 
<pre>
 
<pre>
    protected function _getGuestbookForm()
+
;; application/config/app.ini
    {
+
;;
        require_once APPLICATION_PATH . '/forms/GuestBook.php';
+
;;This is a sample app.ini file. Your application will dictate the format and the
        $form = new Form_GuestBook();
+
;;type of sections and data that can be found in this ini file.  It will also dictate
        $form->setAction($this->_request->getBaseUrl() . $this->_helper->url('sign'));
+
;;how many ini files will be contained in your config/ directory.  For the puropose
        return $form;
+
;;of our application, this one file makes the most sense.
    }
+
 
 +
;;We always have our "production" section first, because it will define ALL of the
 +
;;keys that our application is expecting to see, and reduce deployment issues
 +
;;resulting from configuration.
 +
 
 +
[production]
 +
 
 +
[development : production]
 +
 
 +
[testing : production]
 
</pre>
 
</pre>
  
=====Guestbook Controller=====
+
Zend_Config has several adapters for parsing configuration files; each returns an object with which you can then access the values in the configuration using an object-oriented interface. In this case, we will use Zend_Config_Ini.
 +
Now, what if we want to access this configuration object elsewhere in our application? The standard design pattern used in such situations is the Registry. Zend_Registry is Zend Framework's implementation of this pattern.
 +
In this next code sample, we will instruct our bootstrap file to load the proper section of the config file and add it to our application registry.
  
[http://framework.zend.com/docs/quickstart/create-a-form In our final steps], we need to create a form through which entries can be inserted.
+
<pre>
To tie all the functionality together we have just implemented, we need our guestbook controller. This will call functions in the data connector class we just completed, so that data to be saved can be passed to it, and retrieved records can be displayed through our view.
+
// application/bootstrap.php
 +
//
 +
// CONFIGURATION - Setup the configuration object
 +
// The Zend_Config_Ini component will parse the ini file, and resolve all of
 +
// the values for the given section.  Here we will be using the section name
 +
// that corresponds to the APP's Environment
 +
$configuration = new Zend_Config_Ini(
 +
    APPLICATION_PATH . '/config/app.ini',  
 +
    APPLICATION_ENVIRONMENT
 +
);
  
=====Guestbook View=====
+
// REGISTRY - setup the application registry
 +
// An application registry allows the application to store application
 +
// necessary objects into a safe and consistent (non global) place for future
 +
// retrieval.  This allows the application to ensure that regardless of what
 +
// happends in the global scope, the registry will contain the objects it
 +
// needs.
 +
$registry = Zend_Registry::getInstance();
 +
$registry->configuration = $configuration;
 +
 
 +
// CLEANUP - remove items from global scope
 +
// This will clear all our local boostrap variables from the global scope of
 +
// this script (and any scripts that called bootstrap).  This will enforce
 +
// object retrieval through the Applications's Registry
 +
unset($frontController, $view, $configuration, $registry);
 +
</pre>
  
And as we have our guestbook controller, we need a guestbook view. This will be used to display our guestbook records, as well as offering a link to set our guestbook action to sign, so that a record can be inserted.
+
==References==
 
  
===7. Form===
+
All work relating to the QuickStart tutorial is © 2006 - 2009 by Zend Technologies Ltd. All rights reserved.
  
We now [http://framework.zend.com/docs/quickstart/create-a-form need a form]; somewhere our users can actually insert their entry. We create a function to initialize the class, which includes all the controls needed for the form, such as the text boxes and the captcha. As can be seen, a captcha control exists within the Zend Framework - we simply state what kind we want, how many letters should be displayed, and what the timeout is before it becomes invalid.
+
http://framework.zend.com/docs/quickstart/
  
We then modify our GuestbookController to include a sign action; providing users with a means of signing our guestbook.
+
http://www.johnmee.com/2008/11/zend-framework-quickstart-tutorial-deploy-to-a-subdirectory-instead-of-web-root/
  
And as we know by know - new code in the Controller giving us something new to process = new view, so we create a new view for our signing action.
+
== Ready to move on? ==
  
And with the signing view complete, we should have a fully working GuestBook application. Load it up and test it out.
+
When you're happy you understand what you've done here, take a look at the [[Workshop_-_week_04|Week 4 Workshop]]

Latest revision as of 08:14, 23 July 2009

Main Page >> Web Frameworks >> Workbook >> Workshop - week 03

Creating the Layout

We can think of the layout page as a template that defines a consistent look and feel for all pages within the MVC application. The controllers provide views that fill in what is unique about a particular page. Combined together, they provide us with a complete HTML/XHTML page. As the tutorial suggests, this is the reason why the layout is a good place to set up headers and footers that we want to remain the same for all our pages.

You may have noticed that the view scripts in the previous sections were HTML fragments- not complete pages. This is by design; we want our actions to return content only related to the action itself, not the application as a whole.

Now we must compose that generated content into a full HTML page. We'd also like to have a consistent look and feel for the application. We will use a global site layout to accomplish both of these tasks.

There are two design patterns that Zend Framework uses to implement layouts: Two Step View and Composite View. Two Step View is usually associated with the Transform View pattern; the basic idea is that your application view creates a representation that is then injected into the master view for final transformation. The Composite View pattern deals with a view made of one or more atomic, application views.

In Zend Framework, Zend_Layout combines the ideas behind these patterns. Instead of each action view script needing to include site-wide artifacts, they can simply focus on their own responsibilities.

Occasionally, however, you may need application-specific information in your site-wide view script. Fortunately, Zend Framework provides a variety of view placeholders to allow you to provide such information from your action view scripts.

To get started using Zend_Layout, first we need to make some modifications to our bootstrap.php file:

// application/bootstrap.php
//
// Add the following code prior to the comment marked "Step 5" in
// application/bootstrap.php.
//
// LAYOUT SETUP - Setup the layout component
// The Zend_Layout component implements a composite (or two-step-view) pattern
// With this call we are telling the component where to find the layouts scripts.
Zend_Layout::startMvc(APPLICATION_PATH . '/layouts/scripts');

// VIEW SETUP - Initialize properties of the view object
// The Zend_View component is used for rendering views. Here, we grab a "global" 
// view instance from the layout object, and specify the doctype we wish to 
// use. In this case, XHTML1 Strict.
$view = Zend_Layout::getMvcInstance()->getView();
$view->doctype('XHTML1_STRICT');

// CLEANUP - remove items from global scope
// This will clear all our local boostrap variables from the global scope of 
// this script (and any scripts that called bootstrap). This will enforce 
// object retrieval through the applications's registry.
unset($view);

Calling startMvc() registers a plugin with the front controller, allowing layouts to work seamlessly and without further interaction in most cases. An action helper is registered, as is a view helper, in case you do need to interact with the layout object.

Note the call to the doctype() view helper; this is one of the placeholders mentioned above. By setting this in the bootstrap, we can assure that other doctype-aware view helpers know the selected doctype.

Now that we've initialized Zend_Layout, let's create our site-wide layout:

<? /* application/layouts/scripts/layout.phtml

      This line outputs the doctype we set in the bootstrap */ ?>
<?= $this->doctype() ?>
<html xmlns="http://www.w3.org/1999/xhtml"> 
<head>  
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
  <title>Zend Framework Quickstart Application</title>
  <?= $this->headLink()->appendStylesheet('https://mi-linux.wlv.ac.uk/~<YourStudentNumber>/QuickStart/public/css/global.css') ?>
</head> 
<body>

<!-- 
    Layouts are a great place to put header and footer content that will be
    needed on all pages that share the same layout.  To understand fully what
    having layouts inside a MVC application mean, check out the Zend_Layout
    section of the manual.
    http://framework.zend.com/manual/en/zend.layout.html
    -->
<div id="header" style="background-color: #EEEEEE; height: 30px;">
    <div id="header-logo" style="float: left">
        <b>ZF Quickstart Application</b>
    </div>
    <div id="header-navigation" style="float: right">
        <!-- To keep urls consistent with the applications router (right now we
             are using the default router), we will employ the use of the url
             view helper
             http://framework.zend.com/manual/en/zend.view.helpers.html
             -->
        <a href="<?= $this->url(
            array('controller'=>'guestbook'), 
            'default', 
            true) ?>">Guestbook</a>
    </div>
</div>

<!-- This next call will now include any content that was generated in the
     dispatching of a controllers action (or series of actions).  -->

<?= $this->layout()->content ?>

<!-- If your application requires it, this would be a great place to put a
     footer for all pages. -->

</body>
</html>

We grab our application content using the layout() view helper, and accessing the "content" key. You may render to other response segments if you wish to, but in most cases, this is all that's necessary.

Note also the use of the headLink() placeholder. This is an easy way to generate the HTML for <link> elements, as well as to keep track of them throughout your application. If you need to add additional CSS sheets to support a single action, you can do so, and be assured it will be present in the final rendered page.

Checkpoint

Now go to http://mi-linux.wlv.ac.uk/~YourStudentNumber/QuickStart/public ; and check out the source. You should see your xhtml header, head, title, and body sections.


Configuration and Registry

In older web programming methodologies, programmers would often create a file to be 'included' by all pages that needed access to database connections. This had many disadvantages, such as providing all the code for database connectivity often to every page, even when a database connection was not required for the page. There was also the security considerations of having a file with all the database connection details in a location where it may be accessible by anonymous users.

A more modern take on the concept is to have a registry / configuration file, and classes to provide access to the data. It works much like an .ini file for desktop applications - providing a place to store application-wide settings, such as database connection strings. It works much like a hashtable, where data can be retrieved by key name. We need to create our app.ini file, and modify the boostrap.php file to include a reference to the app.ini. In the case of our QuickStart application, we will then be able to access the database settings from any page we choose.


Create a Configuration and Registry

Application configurations are an important part of creating modular and configurable applications. This is where Zend_Config comes into play. First we will create an application configuration file and put it inside application/config/app.ini.

;; application/config/app.ini
;; 
;;This is a sample app.ini file.  Your application will dictate the format and the
;;type of sections and data that can be found in this ini file.  It will also dictate
;;how many ini files will be contained in your config/ directory.  For the puropose
;;of our application, this one file makes the most sense.

;;We always have our "production" section first, because it will define ALL of the 
;;keys that our application is expecting to see, and reduce deployment issues
;;resulting from configuration.

[production]

[development : production]

[testing : production]

Zend_Config has several adapters for parsing configuration files; each returns an object with which you can then access the values in the configuration using an object-oriented interface. In this case, we will use Zend_Config_Ini. Now, what if we want to access this configuration object elsewhere in our application? The standard design pattern used in such situations is the Registry. Zend_Registry is Zend Framework's implementation of this pattern. In this next code sample, we will instruct our bootstrap file to load the proper section of the config file and add it to our application registry.

// application/bootstrap.php
//
// CONFIGURATION - Setup the configuration object
// The Zend_Config_Ini component will parse the ini file, and resolve all of
// the values for the given section.  Here we will be using the section name
// that corresponds to the APP's Environment
$configuration = new Zend_Config_Ini(
    APPLICATION_PATH . '/config/app.ini', 
    APPLICATION_ENVIRONMENT
);

// REGISTRY - setup the application registry
// An application registry allows the application to store application 
// necessary objects into a safe and consistent (non global) place for future 
// retrieval.  This allows the application to ensure that regardless of what 
// happends in the global scope, the registry will contain the objects it 
// needs.
$registry = Zend_Registry::getInstance();
$registry->configuration = $configuration;

// CLEANUP - remove items from global scope
// This will clear all our local boostrap variables from the global scope of 
// this script (and any scripts that called bootstrap).  This will enforce 
// object retrieval through the Applications's Registry
unset($frontController, $view, $configuration, $registry);

References

All work relating to the QuickStart tutorial is © 2006 - 2009 by Zend Technologies Ltd. All rights reserved.

http://framework.zend.com/docs/quickstart/

http://www.johnmee.com/2008/11/zend-framework-quickstart-tutorial-deploy-to-a-subdirectory-instead-of-web-root/

Ready to move on?

When you're happy you understand what you've done here, take a look at the Week 4 Workshop