Far from being Yet Another PHP Framework or Rails clone, Zoop has been in development since 2001 and in use for the last 6 years in a number of different production environments. While it predates the recent proliferation of PHP frameworks, it's based on solid MVC principles, including separation of display, logic, and data layers. It's designed to be efficient, modular, and extensible, striking a balance between lightweight and fully-featured.
The idea behind a framework is to offer a design you can use across multiple applications. All applications have a number of basic things in common. A framework is designed to provide a structure for those common elements (database interaction, presentation layer, application logic) so you spend less time writing up database interface code or presentation-layer interfaces and more time writing the application itself. The architecture represented by breaking an application up in this fashion is referred to as Model-View-Controller (MVC). Model refers to your data, View to your presentation layer, and Controller refers to the application or business logic.
-IBM
What you need to know about zoop.
Copyright 2008 Supernerd LLC and Contributors. All Rights Reserved.
This software is subject to the provisions of the Zope Public License, Version 2.1 (ZPL).
A copyright notice accompanies this license document that identifies the copyright holders.
This license has been certified as open source. It has also been designated as GPL compatible by the Free Software Foundation (FSF).
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
How to get and install Zoop
The Zoop framework for PHP is available for download at sourceforge.net.
There are 3 files at sourceforge.
Zoop is increasingly less depedent on PEAR, the Lib part is an optional download that contains the PEAR libraries Zoop is dependent on. It is mostly for those who won't have access to PEAR on their machines (shared hosts).
You'll need to have a working installation of php. Click here to download and install php. Zoop works great with php 4.3.10 or greater. We like php 5.2.
We also recommend using a php Accelerator like eAccelerator or APC. Begin by extracting the files, on Windows use 7 zip or something capable of tar.gz files. Zoop can be installed anywhere on your system. Some people put it in /usr/lib/zoop others put it in ~/zoop . It doesn't matter where you put it, just remember where it is, because you need to tell your application.
The lib should go inside of zoop, so you should have zoop/lib/pear/...You do not need the lib and can depend on your system's pear installation, but we provide this for ease of use.. especially on shared hosting, where you can't touch the system's pear installation.
You can now checkout the latest zoop code from subversion.
svn co "https://secure.supernerd.com/svn/zoop/zoop/trunk" zoopsvn co "https://secure.supernerd.com/svn/zoop/zoop_skeleton/trunk" zoop_skeletonsvn co "https://secure.supernerd.com/svn/zoop/lib" zoop/lib
Zoop PHP Framework is quite easy to install and deploy. This guide expects you to be familiar with such concepts as uncompressing files and editing files.
Download Zoop. We also recommend downloading the Zoop Skeleton, particularly if you are creating an application from scratch.
Uncompress the tarball into it's own directory. We recommend placing Zoop in a separate location from your program. Perhaps a place like /usr/local/zoop if you or on a unix machine. Zoop can be located pretty much anywhere that is accessible by php. Remember where you place Zoop because we are going to need that information in our program. The framework, and this guide references the location where Zoop is located on your system as "zoop_dir".
Uncompress the skeleton tarball into a directory for your project. The Skeleton should look like this screenshot does.
We need to edit the config.php file and tell our application where to find zoop. There is one definition:
define('zoop_dir','/path/to/zoop');
A few more things are involved in starting to program with the Zoop Skeleton, so we wrote a separate tutorial about that called Beginning Zoop.
The Zoop framework has a few dependencies on some Pear libraries. Starting with Zoop 1.2, Zoop now packages the necessary PEAR libraries and makes them available to download. These should be uncompressed and placed into zoop_dir/lib. This package should be used only when a standard Pear setup is not capable (such as on a shared hosting environment).
To Setup the necessary Pear dependencies you will need to copy and paste this into a terminal:
pear install DB pear install --force VFS pear install --force Log pear install --force Validate pear install --force XML_Util pear install --force XML_Parser pear install --force XML_Serializer pear install --force XML_RPC pear install --force Mail
It is likely you may already have some (most) of these. You also may not need them all, since many people probably won't be using all the components of Zoop, but there is no harm in installing them all. If you are on a shared system then you may have to ask someone else to do this for you. If you are upgrading zoop or using the zoop/lib for the first time, make sure the following line is in your config file below the line where "zoop_dir" is defined:
Since Zoop uses caching and other temporary files the webserver needs a place to store them. By default that is in your application directory (app_dir for short) in a subdirectory tmp. Please make sure that this directory is writable by the server. In a Unix Environment you would do something like
# cd /path/to/app_dir # sudo chgrp -R apache tmp # sudo chmod -R g+w tmp
A simple rewrite rule affords a far more attractive site URL structure. Instead of having URLs like this:
http://example.com/index.php/zone/ http://example.com/index.php/zone/param/param
You can use URLs that look like this:
http://example.com/zone/ http://example.com/zone/param/param
To enable URL rewriting, add the following snippet to your existing .htaccess file, or save it as a new file called .htaccess in the root of your project.
# .htaccess file for Zoop applications
# Applies rewrite rules for canonical domain names and sexier URI query strings.
<IfModule mod_rewrite.c>
RewriteEngine on
# Canonical domain name rewrite
# Modify the next two lines to redirect to a canonical domain name.
#RewriteCond %{HTTP_HOST} !^example\.com$ [NC]
#RewriteRule ^(.*)$ http://example.com/$1 [L,R=301]
# Modify the RewriteBase if you are using Zoop in a
# subdirectory and rewrite rules don't work.
RewriteBase /
# Rewrite URLs to the form 'index.php/x'.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L,QSA]
</IfModule>Note: This is a quick and dirty rewrite rule snippet, and I'm sure you could come up with a use case that will break it. I mostly use it on Linux/BSD with Apache. It may or may not work with lighttpd, IIS (with mod_rewrite support), etc. Let me know if you're struggling with it on another system, or if you find a way to break it, and I'll see what I can do to help.
overview
Zoop is a recursive acronym which stands for Zoop Object Oriented PHP Framework.
The Zoop Framework is stable, scalable, and portable. Far from being Yet Another PHP Framework or Rails clone, it's been in development since 2001 and in production use for the last 6 years in a number of different environments. It's designed to be fast, efficient, modular, and extensible. Although it predates the recent proliferation of PHP MVC frameworks, it not only supports but encourages separation of display, logic and data layers.
Zoop is licensed under a GPL compatible open source license. We have chosen to use the Zope License as we felt it best applied to scripted languages.
Zoop is a mature framework. Originally written for PHP 3, Zoop has been in production use since 2001 originally using the name pehppy. Zoop now supports PHP 4.3.10 and above including the newest PHP release, 5.2 at the time of this writing.
Note: Zoop will run on PHP 4. Doing so does not take advantage of the native features provided in PHP 5. If you are running Zoop in a PHP 5 environment you will experience lighter and faster code, particularly in the Database and Object Oriented operations.
Zoop built in a very modular approach. The framework is composed from separate parts, Zoop calls components. Conceptually, modules represent a separation of concerns, and improve maintainability by enforcing logical boundaries between components.It keeps the weight down, while providing many features. Zoop has advanced component handling enforcing dependencies and relationships.
Zoop requires only one component to run. By design Zoop has been built to be light, requiring you to include each piece you intend to use. If Zoop is too heavy for you, try CodeIgniter. It's even lighter, but compromises features to achieve this.
Zoop has a light controller that is quite fast. Zoop utilizes modern caching techniques to deliver a very quick experience. This includes support for memcache and integrated support in the View for output caching.
Zoop has been built from the ground up with security in mind. Zoop has configurable (secure by default) filters for all user input. Zoop attempts to make it more difficult for a programmer to do insecure things.
Zoop uses the Model-View-Controller approach, which allows great separation between logic and presentation.
- Model
- The domain-specific representation of the information on which the application operates. Domain logic adds meaning to raw data (e.g., calculating whether today is the user's birthday, or the totals, taxes, and shipping charges for shopping cart items).
- Many applications use a persistent storage mechanism (such as a database) to store data. MVC does not specifically mention the data access layer because it is understood to be underneath or encapsulated by the Model.
- View
- Renders the model into a form suitable for interaction, typically a user interface element. Multiple views can exist for a single model for different purposes.
- Controller
- Processes and responds to events, typically user actions, and may invoke changes on the model
This separation works especially well with a larger project/development team as the separation encourages specialization.
Zoop pioneered clean URLs for PHP frameworks. Our URLs are clean and Search Engine friendly. Zoop uses a simple, yet advanced segmented approach
example.com/users/13/photos/345
Note: By default the index.php file is included in the URL but it can be removed using a simple .htaccess file.
Zoop is not a port of an existing framework. As great as Ruby on Rails, Struts, .net, etc are, we believe that they have their place and that is in their language and environment.
Zoop is written in PHP for PHP with PHP development in mind. We don't use a java approach. We don't use a Ruby approach. Zoop is PHP.
The Zoop Framework is inclusive, cooperating with and containing components integrated from some existing projects including Smarty, the Prototype JS Framework, and a number of Pear Modules. We're not content just to cobble pieces together, however—for example, we've combined the above into an implementation that brings GuiControls to PHP, providing developers with easy access to rich form widgets with client-side validation completely integrated. We're also working to include support for pieces from some of the latest and greatest PHP and JavaScript projects, including the Zend Framework, PHP Doctrine, and jQuery, among others.
The system can be easily extended through the use of plugins and helper libraries, or through class extensions or system hooks.
For reasons we don't understand there is some debate about not using smarty, or rather using plain old PHP in templates. Zoop supports this, but in doing so you lose many of the benefits of using Zoop's integrated View powered by Smarty.
Most web applications are dominantly CRUD operations. Zoop has the excellent Forms library which automates CRUD operations requiring only a couple lines in the Controller.
Zoop is growing. Please join the conversation found in our Community Forums.
Buzzwords will come and go. It seems like every few months a new buzzword comes along and everyone tries to patch together something to support it. Whether the latest buzzword is XMLRPC, XML, or AJAX, or DHTML or whatever, no latest and greatest feature is a substitute for a proper foundation. Sure, Zoop has support for all of those buzzwords and will certainly support all useful buzzwords of the future, but that is besides the point, support for the latest thing != good foundation for your project.
Zoop PHP Framework has been written with that foundation in mind. It has been written in a modular nature using seperate components. You can use any or all of the components as you code. This modular nature also allows zoop to quickly implement a bunch of different technologies. Currently Zoop's feature set rivals that of popular web frameworks such as Ruby on Rails, Microsoft's .net, Struts, etc.
Zoop is a mature framework. Originally written for php 3, Zoop has been in production use since 2001 originally using the name pehppy. Zoop now supports php 4.3.10 and above including the recently released 5.2.
Zoop is built for PHP. PHP is the most widely used language on the internet, but until now there has not been a compelling framework that was capable of providing a productive framework for just about any project one may want to tackle. Zoop provides PHP that framework.
We invite you to download zoop and the skeleton app. Use the barebones skeleton app to start coding your application. Once you become familar with zoop you will wonder how you ever got anything done without it. We found that most programmers that switched to Zoop as their framework experienced substantial increases in their productivity levels. Particularly in applications that are heavy in CRUD.
This article is for all of those asking why zoop "limits" you to passing everything through index.php. Zoop uses a front controller. All requests are passed through index.php and then through the zone component to their final destination. There is a lot of information about front controllers.
The front controller design pattern has got a lot of bad press from php developers over the years. It seems like every article I've ever seen by a php developer first goes on to explain what a front controller is, gives a very simple example and then goes on to explain it's easier to just not use them at all. See:
For those who may have doubts about our use of the front controller design, you can use nearly all of the modules in zoop (gui, db, etc) without using the zones front controller. Hopefully, though, by the time you are done reading this article you will want to pass everything through index.php and the front controller and, in addition, you'll like it.
The front controller has gained a lot more traction in the java world. Notice that the first 6 links in the above google query are specifically written for Java developers.
Here is a definition of a front controller in my own words. A design pattern for web apps where you pass all of your requests through a single script, parse the url yourself and then use some systematic method for determining what to send back to the browser based on the url.
That is a gross oversimplification but it's simple and should get you started if you've never heard of it before. In this article I am going to explain the zoop implementation of a front controller (zones) and show how it goes beyond the over simplified examples shown in most articles on php front controllers. I will show how the zoop front controller actually adds value, makes development faster, and results in better more secure applications. I am going to show parallel examples of how certain problems are solved using a more traditional php approach and also using zoop zones.
I am sure I create just as biased straw man examples of the "traditional" php app as the anti-front controller people have created since I have used front controllers almost exclusively for about 5 years. I welcome a flame fest in the forum to provide more worthy examples for the other side of the fence.
Bascially the main benefit of using zones is that is provides a systematic way to structure and organize your code. A zone groups together common pages and allows you to perform operations on all of those pages collectively. It allows you to easily share functionality between similar pages.
The main problem that we are going to analyze first is the problem of implementing security by default. In order to illustrate this we are going to start developing a very simple bug tracker. I will provide examples of how to implement this using traditional php methods and another example using zoop.
Let's start with a simple hello world app.
at this point the traditional php "application" is ahead in terms of simplicity. Our zoop app has two files an entire class, method calls, several lines of code and has to link to an external library. Whereas the traditional php app has only one real line of code. Once we go beyond hello world though things start to even up.
Now in order to move from hello world to an application login we didn't have to even add files to the project. The traditional php app basically had to be started from scratch.
Notice that neither project is using a templating system. The reason for this is that I wanted to focus on zones, and not templating.
Also notice that although it could post anywhere the page function generally posts to the post function. When the url http://sampledomain/zoopapp/index.php/login is requested as a GET it only looks for the method pageLogin in zone_default. If that same url is requested as a POST operation it first looks for postLogin and only executes pageLogin if postLogin is not present.
For this a design pattern appears. Display the page in pageXXX, post to your own url. Then in postXXX first handle manipulating the model based on the post data. Then redirect to the next page to be viewed. This eliminates what I call the POST problem. Anyone who has used the back button on your browser or hit refresh and seen this:
Turn this into an image block of a screen shot of that bad message.
knows what I mean by "the POST problem". I hate it when this happens. Not only does it disrupt navigation but you never know if you've duplicated some operation that was never meant to be duplicated.
This article is not about MVC but I assume most web programmers understand MVC by now so I'll mention it. Now lets add in templates so that our view isn't merged with our controller and fix the post problem in the traditional app.
In order to scale the traditional way and not mix post and get files and not mix display logic and application logic we need 3 files for nearly every page. A get file, a post file, and a tempalte file. In zoop we have one file for the each zone and one for each template. The zone files are not intended to be huge. But often, especially if your model is also adequately abstracted from your controller, you end up with a whole bunch of tiny pages. In this case it's much nicer to have them collected into one zone file rather than having tons and tons of 10 line .php files all over the place. This is however a matter of preference and not the main benefit of using zones. As we expand our app these benefits will become more and more apparent.
also notice how we don't have any configuration file listing each page. We just have to make sure that each zone is included.
now get rid of the you are logged in page and add pageListIssues. Then add an extra zone. zone_issues. zone_issues will contain pageView, postView, pageEdit, postEdit.
file count: zoop: 7, traditional: 12
Notice the file count growing. But again that is not the main benefit. The main benefit is pageView, postView, pageEdit and postEdit all have certain things in common. They all require the user to be logged in and the all require an issueId. Here is where zones really come in handly.
We're now going to learn about certain methods in each zone that really show of the power of the front controller.
First, the constructor. In the constuctor is where we usually indicate the zoneParams. A zone param is a paramater that (generally) every page in the zone needs. Notice how in the traditional app the issue param has to be hand crafted into every url. In the zoop version we barely have to know about it except when we enter the zone. From then on it's just always there for us. Notice I should add in support for an issue class to properly separate out the model from the controller. Doing it this way illustrates the power of zone params. We will add some better OOP design in a later example in order to show even more features of zone.
Now here is the real kicker. The other special zone methods are initZone and initPages. They are both called before any of the page or post methods are called. In a later example we will learn the difference between them but for now just take my word for it that we want to use initZone here.
What are we going to use it for you ask? For security.
add a permissions.php to each project
function initZone()
{
if( !loggedIn() )
trigger_error('user not logged in');
}Now EVERY PAGE that is now in or EVER WILL BE IN zone_issue will get this security check. There is no having to remember because it just happens automatically one initZone has been set up. Now every time you create a new page in the traditional app you have to remember to include not just A header file but THE CORRECT header file. If you forget, no security. With zones you can't miss it. Even if you miss it, ou don't miss it. And the more zone's you have the more it useful it is. It is analogous to being able to set the permissions on a directory and having all files in that directory be automatically protected no matter what their individual permissions are. Can you imagine a file system that only had file level, and not directory level, permissions. After using zoop that's how you will feel about any method of developing web apps that doesn't cover that problem.
TODO:
now cover, nested zones, add comments to the issues.
create some tool to show a formatted url when you want to see it
show how initZone and initPages differ and how you can use zone_issue::initZone to enforce permissions in zone_note
then add a model and use $this->issue to set stuff up in initPages and use it down below
sequences - the added structure allows us to do this
tying zones into gui:
this->assign
this->display
show how it enforces organization of templates
different display templates
I think that when you compare the two different solutions to these problems the front controller starts to look a lot more elegant and useful that the straw man front controller used to illustrate the "anti-front-controller" articles.
A minimal Zoop application will have a directory structure and file layout including the following:
/
config.php
includes.php
index.php
zone_default.php
templates/
default/
default.tplWe'll cover config.php, includes.php, zone_default.php, and default.tpl.
The config.php file is used to configure the way Zoop interacts with your application, including what kind of error reporting is wanted, how to connect to databases, and what paths to find Zoop and your application.
define("app_status", 'dev'); define("app_dir", dirname(__file__)); if(app_status == 'dev') { define('zoop_dir', '/path/to/zoop'); } else { //when deploying to live or test servers, we deploy with Zoop in the current directory define('zoop_dir', dirname(__file__)); } define("LOG_FILE", dirname(__file__) . "/../log/errors.log.html"); define("app_temp_dir", dirname(__file__) . '/tmp');
There are more constants that can be used to configure Zoop's behavior. Future documentation will cover these, but for now you can find many documented in the skeleton's config.php, including important security settings.
The includes.php file is the place to include any files you require, such as objects, reports, PEAR objects, or other resources used in your code. This is also the place to initialize the Zoop object, and tell it which components your code will be using.
//////////////////////////////////////////////////// // Configuration stuff // //////////////////////////////////////////////////// include_once(dirname(__file__) . "/config.php"); include_once(zoop_dir . "/zoop.php"); $zoop = &new Zoop(app_dir); //////////////////////////////////////////////////// // This includes all the components being used // //////////////////////////////////////////////////// $zoop->addComponent('gui'); $zoop->addComponent('zone'); //////////////////////////////////////////////////// // include all zone subclasses here // //////////////////////////////////////////////////// $zoop->addZone('default'); //////////////////////////////////////////////////// // include all of your other objects here // //////////////////////////////////////////////////// $zoop->addObject('user'); //////////////////////////////////////////////////// // include PEAR classes/libs here // //////////////////////////////////////////////////// require_once('XML/Unserializer.php'); $zoop->init();
Components with dependencies will be handled in order. For example, the forms component depends on the db component, so db will be included before the forms component. If a dependency is not specified by the user, it will be loaded automatically, but it is best to be explicit where possible.
zone_default is the first zone to write. All requests(even those destined for other zones) pass through it, and its initZone function is called on every request. Expected urls for this zone would be:
class zone_default extends zone { function zone_default() { } function initZone($params) { echo("this is called on every request that this zone is a part of"); } function initPages($params) { echo("this is called on every request that ends in this zone"); } function pageDefault($params) { $this->guiDisplay('default.tpl'); } function postDefault($params) { echo_r(getPostText('actionField')); echo_r(getPostText('username')); echo_r(getPostText('password')); } }
To access this zone use the url:
http://example.com/path/to/index.php (pageDefault)
in addition, since this is the only zone we have,
http://example.com/index.php/anythingelse will also be served by pageDefault. A more thorough discussion of Zoop URLs can be found at The Undercarriage.
default.tpl is a smarty template. These are HTML mixed with very simple directives to allow dynamic generation of html pages.
<title>{$title}</title> <script> function submitForm(action) { document.main_form.actionField.value = action; document.main_form.submit(); } </script> <form name="main_form" method="post"> <input name="actionField" type="hidden"/> <table> <tbody><tr> <td> Username: </td> <td> <input name="username" type="text"/> </td> </tr> <tr> <td> Password: </td> <td> <input name="password" type="password"/> </td> </tr> </tbody></table> <a href="" onclick="submitForm('login');return false;">Login</a> </form>
Getting Started
Zoop doesn't have a automatic loader meaning you will need to define which zones, components and libraries you are using. Zoop does handle dependencies and uses __autoload quite well, but keeps things lean by requiring you to specify what you want to use.
<?php include_once(dirname(__file__) . "/config.php"); include_once(ZOOP_DIR . "/zoop.php"); $zoop = &new zoop(dirname(__file__)); //////////////////////////////////////////////////// // COMPONENTS // //////////////////////////////////////////////////// $zoop->addComponent('app'); $zoop->addComponent('db'); $zoop->addComponent('gui'); $zoop->addComponent('guicontrol'); $zoop->addComponent('doctrine'); $zoop->addComponent('pdf'); $zoop->addComponent('spell'); $zoop->addComponent('userfiles'); $zoop->addComponent('sequence'); $zoop->addComponent('forms'); $zoop->addComponent('mail'); $zoop->addComponent('auth'); $zoop->addComponent('cache'); //////////////////////////////////////////////////// // ZONES (CONTROLLERS) // // // //////////////////////////////////////////////////// $zoop->addZone('default'); $zoop->addZone('users'); $zoop->addZone('admin'); //////////////////////////////////////////////////// // OBJECTS // // // //////////////////////////////////////////////////// // $zoop->addObject('blocks'); //////////////////////////////////////////////////// // CLASSES // // // //////////////////////////////////////////////////// // $zoop->addClass('math'); //////////////////////////////////////////////////// // include other needed files here // //////////////////////////////////////////////////// // include_once(dirname(__file__) . "/misc.php"); //////////////////////////////////////////////////// // include PEAR classes/libs here // //////////////////////////////////////////////////// // include_once("XML/Unserializer.php"); // $zoop->init(); ?>
Reading a Zoop URL is important to coding in Zoop, because the url determines which zones have initZone called, which zone is the final zone and which page is executed, as well as the parameters that all those function calls have available.
An example zoop url is:
http://example.com/path/to/index.php/urlitem/urlitem/urlitem...
Each urlitem is one of four things:
Reading a Zoop url is easy with practice, but can be difficult at first. The following examples should help.
zone_default has no zone parameters, and a page called login and a default page.
zone_base has 2 zone parameters(id, text) and a default page.
zone_default->initZone($params) is called,
zone_default->initPages($params) is called,
zone_default->pageLogin($params) is called,
and the $params array would have:
Array {
[0] => login
}zone_default->initZone($params) is called,
zone_default->initPages($params) is called,
zone_default->pageLogin($params) is called,
and the $params array would have:
Array {
[0] => login
[1] => error
}zone_default->initZone($params) is called,
zone_default->initPages($params) is called,
zone_default->pageDefault($params) is called,
and the $params array would have:
Array {
[0] => default
[1] => error
}the above example would be true with error replaced with anything other than the name of another zone, or the name of another page in the default zone.
zone_default->initZone($params) is called,
and params would be:
Array {
[0] => base
[1] => 21
[2] => this is url encoded text
}zone_base->initzone($params) is called,
zone_base->initPages($params) is called,
zone_base->pageDefault($params)is called,
and params would be:
Array {
[0] => default
}The zone params are:
Array {
[id] => 21
[text] => this is url encoded text
}The Zoop PHP Framework is made up of a collection of components.
The forms component is a powerful programming tool. It provides seemless integration between database tables & records and the gui. It automates the processes that takes up much of webdevelopment, listing records in a table and creating, editing and deleting records. It uses guiControls to provide automatic form validation. It is compatible with all of the supported pear-DB databases (tested extensively on mysql and pgsql).
$this->requireComponent('db'); $this->requireComponent('gui'); $this->requireComponent('validate');
forms/forms.php
gui/plugins/function.forms_form.php
gui/plugins/function.forms_list.php
gui/plugins/function.forms_search.php
For the first example here we are going to use a scenario that many of you are probably familar with, managing a list of users. The task of managing a list of users can be split up into three seperate functions:
Forms has been designed to make this type of task as easy as possible. So we will go through the each step.
The first two steps deal with setting things up (database and zone). For the rest of the steps we will be using forms.
The first step is to have a database table that we want to be able to edit the records of.
We will go with a simple users table described as follows:
CREATE TABLE `users` ( `user_id` int(11) NOT NULL auto_increment, `username` varchar(100) NOT NULL default '', `password` varchar(100) NOT NULL default '', `company_id` int(11) NOT NULL default '0', PRIMARY KEY (`user_id`) ) TYPE=MyISAM;
The second step is to setup a zone to place the functions into. If you are not familiar with the concept of zones click here for an overview.
We will create a new zone, zone_users.php based on the zone template file provided in the skeleton app. To begin our zone_users.php file should look as follows:
class zone_users extends zone { function zone_users() { } function initZone($inPath) { } function initPages($inPath) { //do things here that you want to happen for every request that ends with a page in this zone, including posts } function pageDefault($inPath) { $guiDisplay->display("default.tpl"); } function postDefault($inPath) { } }
For this step we will be creating a new page that will list all the users in the database and allow us to edit and delete them.
function pagelistUsers($inPath) { global $gui; // create a new form if one isn't already in the zone if(!isset($this->form)) $this->form = &new form; $table = "users"; // define which table in the database you are using $this->form->initTable($table); // initialize the table inside the form object $cur_table =& $this->form->tables->$table; // create a reference for ease of use. $cur_table->setupenv($_GET); // setup the environment so sorting and paginating work properly $cur_table->limit = -1; // tell forms how many records you want on a page... -1 means all records $cur_table->fields["user_id"]->listshow = false; // set the property listshow to false to make it so that the field user_id doesn't show up in the list. $cur_table->getRecords(); // grab the records from the database $cur_table->listlink = "edit"; // tell forms which page function in this zone you want the clickable fields to execute $cur_table->zone = "{$this->zonename}"; // tell forms what zone you are using $cur_table->fields["username"]->clickable = 1; // set username as clickable $cu_table->fields["company_id"]->listshow = 0; // set company_id's property listshow set to false $cur_table->deleteColumn = false; // tell forms you want a delete column $cur_table->deletelink = "delete"; // tell forms which page function in this zone to run if delete is clicked $gui->assign("form",$this->form); // pass the form into the gui templating object $gui->assign("table",$table); // pass the table name into the gui templating object $gui->generate("list.tpl","users/side.tpl","mainmenu.tpl",""); // this function will take the 3 named tpl files and patch them together. You will need to change them to fit your liking.. // Except list.tpl which is included in the skeleton and is reusable by forms. }
Notice how the field names in forms match the field names in the database.
Since we want this page to be the default page for our zone will will change pageDefault to the following:
function pageDefault($inPath) { zoneRedirect("listUsers"); }
Now when we goto this page in our application:
http://hostname/path/to/index.php/users/listUsers
we should see a listing of the users in our database as such:
note: i obviously changed the password section here in gimp

Now the list that has been created is sortable and if we desired it would automatically support pagination. Additionally the sorting is smart enough that if there is only one page, it will sort using javascript, without communicating with the server. If there is more than one page it will make a new request from the server. It will also repaginate to reflect the new sort.
We need to create the function pageEdit in the zone_users.php file:
function pageEdit($inPath) { global $gui; $id = $inPath[1]; //assign the id from the path var. $table = "users"; // same as listing if(!isset($this->form))$this->form = & new form; // same as listing $this->form->initTable($table); // same as listing $cur_table =& $this->form->tables->$table; // same as listing $cur_table->fields["company_id"]->setIndexTable("companies","company_id","company_name"); // This will take the table companies and create a select drop down in the // form using company_id as the value and company_name as the label $Record =& $this->form->passRecord($table,$id); // this sends the data into the form $this->form->DescIntoFields($table,$id); // this assigns labels and types for the fields $gui->assign("form",$Record); // pass the record into the gui $gui->generate("form.tpl","users/side.tpl","mainmenu.tpl",""); // generate the page // again using a reusable form.tpl file that will automatically create the form. }
The result is this form. Currently we are not employing any type or format validation, but it would be easy to do so.

This function we have just written works for editing an existing user and creating a new user.
To create a new user you would pass the id 'new' to the function which is done through the url... so editing a new user would look like...
http://hostname/path/to/index.php/users/edit/new
This step is barely a step, maxing out at 4 lines.. but here goes..
The form will automatically post to the post function of the same name so we create postEdit as follow:
function postEdit($inPath) { $POST = getRawPost(); $this->form->saveRecord($POST); zoneRedirect("listUsers"); }
This will save the record and redirect you back to the listing page.. with all of your changes made.
And that is it... Listing and editing and creating records in less than 10 minutes !!
A few things to take note of:
We hope you find this useful.. If you did please drop us a line and let us know... or add your own comments below for others to benefit from as well.
The gui component of Zoop contains 3 seperate sections, Gui, GuiControls and ZoopFile.
The Gui Object is an extention of the Smarty object provided by smarty. The smarty class is well documented on their website and we do not intend to reproduce that documentation here. We will document some of the things our gui object has done to extend the smarty object so that those familar with smarty can easily transition to Zoop. Zoop also adds a substantial number of plugins to Smarty's already impressive library.
GuiControls work within the Zoop framework to provide easy form controls. They have built in validation using the validation component, so the support all the validation types found in validate. They can be called and defined from within the zone functions (php) or within the templates (smarty), or you can define they in the zone and call them from the template. They have been implemented in a way so that you can even embed a GuiControl within another GuiControl.
Zoopfile is a recent addition to the Zoop PHP framework (as of 1.1). It is a relatively simple class that provides public access to javascript librarys found in zoop. With the introduction of Zoopfile we have moved all javascript libraries out of the skeleton (out of the application), and into the framework. Now you can have one central location for all of your javascript libraries usable by all of your applications. We think this is pretty sweet. It also has built-in instructions to tell the browser to cache the javascript file if it hasn't been changed. So hopefully it will save you on loadtimes and bandwidth. It works seamlessly behind the scenes, so just point your includes to the right location and it goes to work.
Each GuiControl has its own documentation written for it:
Text GuiControl
Password GuiControl
Textarea GuiControl
Select GuiControl
Multiple GuiControl
Select_Update GuiControl
Checkbox GuiControl
Slider GuiControl
Additionally we have created a movie of a guiControl form in action
This is a perfect introduction for anyone wanting to use guiControls.
We have a specific need within a form. We need to be able to ask the user to specify a font face and font size. Additionally on the backend we want to store both of these in a string so they only take up one field in the database.
GuiControls are one of the most compelling reasons to use Zoop Framework for PHP. GuiControls are more or less reusable widgets that can be used within a webpage. One could think of them as an extension of the set of controls (widgets) built into html.
Html provides tools like textboxes, textareas, select boxes and so forth, unfortunately currently there isn't a specification for much more than that. Guicontrols provide essential features like type validation (both clientside and serverside) and more controls than come with the basic set of html, like sliders. Additionally the framework makes it easy for you to write your own controls that you may need to complete a specific function.
This document is intended to teach you how to begin to harness the power of GuiControls in your applications. If we were starting from where hello world leaves off we would begin by creating a function called pageGuiControlExample into zone_default.php.
In this function we will need to access the global variable $gui as we are using the gui (smarty template object).
Our basic function would look like so:
function pageGuiControlExample($inPath) { global $gui; // needed to send the variables to the template engine (smarty). }
Now Zoop is developed to make the programmers job easier, so GuiControls are callable 3 different ways:
This document will go through how to instantiate a guiControl the first two ways. The forms tutorial "Using Forms" shows you the final one.
function pageGuiControlExample($inPath) { global $gui; // needed to send the variables to the template engine (smarty). $text = &getGuiControl('text', 'text_guicontrol'); // instantiating the guiControl of type 'text' named 'text_guicontrol' $text->setParam('value', "i am the value"); // passing into the guiControl the value this field is set to. $text->setParam('validate', array('type' => 'int', 'required' => true)); // passing into the guiControl the type validation $gui->assign("text", $text); // passing the control into the gui template object $gui->display("examples/guiControls.tpl"); // display the compiled template }
We are referencing a template file, so we'd better create that as well. The following code should be placed in app_dir/templates/default/examples/guiControls.tpl:
{include file="head.tpl"} <body> <div align="center"> <h1>GuiControl Gallery</h1> <form method="post" name="main_form" enctype="multipart/form-data"> <div id="errorsbx"></div> <br> <table class='forms' width="550" cellpadding="2"> <thead> <th>Type</th> <th>Example</th> <th>Validating for</th> </thead> <tbody> <tr> <td> <label for="controls[text][text_guicontrol][text]"> Text: </label> (defined in the zone) </td> <td> <strong>{guicontrol guicontrol=$text}</strong> </td> <td>Integer</td> </tr> </tbody> </table> <br> <INPUT type="submit" onClick="return submitForm(form);"> </FORM> </div> </body> </html>
For the client side (javascript) validation to work properly, a few things need to be setup for our form to function properly.
For the serverside to work properly the form needs to be method=POST.
I suppose we could follow Rails' example and create a function to {form_start} and {form_submit} and {form_end}. Perhaps in the future 1.2 version of zoop we will do that.
The advantage of doing things this way is that the control is place in your hands, so if you want the error message box at the bottom, you can place it there. I am sure you can't wait to see what this looks like and how it operates. Here is the guiControl:
![]()
Here it is after you click "Submit Query":
![]()
For this approach we will continue the same codebase we used for the first way. The php function in the zone doesn't need to change at all from the previous way. We are only going to be working in the template. Here is what the template will look like. The bolded part is the part we added to demostrate this method. We are also demonstrating that we can use both methods in the same function / template.
{include file="head.tpl"} <body> <div align="center"> <h1>GuiControl Gallery</h1> <FORM method="POST" name="main_form" enctype="multipart/form-data"> <div id="errorsbx"></div><br> <table class="forms" width="550" cellpadding="2"> <tHEAD> <th>Type</th> <th>Example</th> <th>Validating for</th> </tHEAD> <tbody> <tr> <td><label for="controls[text][text_guicontrol][text]">Text:</label> (defined in the zone)</td> <td>{guicontrol guicontrol=$text}</td> <td>Integer</td> </tr> <tr> <td><label for="controls[text][another_text_control][text]">Text:</label> (defined in the template)</td> <td>{guicontrol type="text" name="another_text_control" value="too long" _validate_type="length" _validate_max=5 _validate_min=3 _validate_required=true }</td> <td>Length between 3 and 5</td> </tr> </tbody> </table> <br> <INPUT type="submit" onClick="return submitForm(form);"> </FORM> </div> </body></html>
Let's dissect that for a minute. Notice that the smarty function call is the same in the template file as when we pass it a control object. So the smarty function {guicontrol} accepts either a control object passed in from the zone, or the same parameters used to define the control object in the zone.
For simplicity reasons the parameters are named the exact same things in either the php or the template.
Smarty has a known limitation that it cannot easily set values within an array like validate['type'] = 'length' so we came up with a new syntax to do so within guicontrols. to setup an array like you would need to for the validate parameter, place an _ at the beginning and between levels so in php it would be validate['type'] = 'length', but in the smarty call it becomes _validate_type = 'length'.
Here is the guiControl:
Here it is after you click "Submit Query":
You may have noticed we haven't written any code to handle what happens after the form is acutally submitted. Isn't that lovely, we have an attractive form that validates in both javascript and falls back to validation in php, and we haven't even written any code that handles the $_POST. Not to mention, we have literally only spend a couple minutes writing this.
For this example I will show you how to access the POST and echo it to the screen, you can do what you want with it from there.
Following Zoop Protocol, we create a function also in zone_default with the same name as our current function, but with post instead of page as the prefix. This function will look like this:
function postGuiControlExample($inPath) { echo("the form has been posted to the postGuiControlExample function successfully.<br /> Here is the output of getRawPost()."); $POST = getRawPost(); echo_r($POST); }
And the output is:
the form has been posted to the postGuiControlExample function successfully.
Here is the output of getRawPost().
Array ( [text_guicontrol] => 3 [another_text_control] => right )
A few other niceties is that the guicontrol is processed and given to you in a nice array where the key is the name you gave to the control. Another nice thing is that the validation retains all the values of the form, so you don't frustrate users by making them reinput anything (anything correct at least).
I hope this is of some value to you. Leave a comment here if it is or if you have tips for others.
Checkbox GuiControl
The checkbox guiControl is a simple checkbox. It does provide a few advantages over the standard html checkbox. First, unlike the standard checkbox, it will provide a boolean true false value regardless if it is checked or not (the standard checkbox doesn't provide a value if it is unchecked). Secondly you can require it to be checked, useful for those 'check here if you agree to this...'.
All GuiControls use the following parameters:
Specific Accepted Parameters:
This control only supports the 'required' option. Given it is a checkbox that is all it could support.
$checkbox = &getGuiControl('checkbox', 'checkbox_guicontrol');
$checkbox->setParam('value', false);
$checkbox->setParam('validate', array('required' => true));
$gui->assign('checkbox', $checkbox);{guicontrol type=checkbox name=checkbox _validate_required=true}See the tutorial for more on using guiControls
Care to extend this to make your own guiControl, it is easier than you think, click here for a tutorial.
This is a perfect introduction for anyone wanting to learn either how to implement guiControls, or how to create their own guiControl.
We have a specific need within a form. We need to be able to ask the user to specify a font face and font size. Additionally on the backend we want to store both of these in a string so they only take up one field in the database.
After we create our own guiControl, we will continue on through this and show you how to use your own gui control through forms.
The first step is to create the guiControl file in the correct location. There are two possible locations:
So the guiControl should be placed in either:
Where $type should be the name of the guiControl that you choose, such as text or editor or email.
It is always nice to start with a skeleton or example of what you want to achieve. Here we will start with the text guiControl packaged with Zoop.
// Copyright (c) 2005 Supernerd LLC and Contributors.
// All Rights Reserved.
//
// This software is subject to the provisions of the Zope Public License,
// Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
// FOR A PARTICULAR PURPOSE.
class text extends GuiControl
{
function setValue($value)
{
$this->params['text'] = $value;
}
function getLabelName()
{
$label = $this->getName() . "[text]";
return $label;
}
function getPersistentParams()
{
return array('validate');
}
function render()
{
$html = $this->renderViewState();
$attrs = array();
$Sattrs = array();
foreach ($this->params as $parameter => $value)
{
switch ($parameter) { // Here we setup specific parameters that will go into the html
case 'title':
case 'maxlength':
case 'size':
case 'type':
if ($value != '')
$attrs[] = "$parameter=\"$value\"";
break;
case 'readonly':
if ($value)
$attrs[] = "readonly=\"true\"";
case 'validate':
$attrs[] = $this->getValidationAttr($this->params['validate']);
break;
case 'width':
case 'height':
if ($value != '')
$Sattrs[] = "$parameter:$value;";
break;
}
}
$name = $this->getName();
$value = $this->getValue();
$attrs[] = "style=\"" . implode(' ', $Sattrs) . "\"";
$attrs = implode(' ', $attrs);
$label = $this->getLabelName();
$html .= "<input name="\"{$label}\"" id="\"{$label}\"" $attrs="" value="\"$value\""/>";
if(isset($this->params['errorState']))
{
$errorState = $this->params['errorState'];
$html .=" <span red;\="">{$errorState['text']} {$errorState['value']}</span>";
}
return $html;
}
}There are two prominent methods used when creating a guiControl. The text guiControl above employs the first method, rendering html. All of the base guiControls employ this method. The second method is to embed guiControls within a guiControl and pass your necessary parameters into the embedded guiControls. Since our goal is to enable the user to choose a font we want to embed a select guiControl...
We will want to modify a few of the functions of the text control, specifically the getValue function and the render function. The render function will become...
function render()
{
$html = $this->renderViewState();
$attrs = array();
$value = $this->getValue();
$name = $this->getName();
if (preg_match('/([\\d]+?)\\s?pt\\s+?\'(.+?)\'/', $value, $regs))
{
$size = $regs[1];
$face = $regs[2];
}
else
{
$size = "";
$face = "";
}
$facecontrol = &getGuiControl('select', 'face');
$facecontrol->setParams($this->params);
$facecontrol->setParam('value', $face);
$facecontrol->setParam('index', array("Verdana" => "Verdana",
"Arial" => "Arial", "Tahoma" => "Tahoma", "Garamond" => "Garamond",
"Courier New" => "Courier New", "Times New Roman" => "Times New Roman"));
$facecontrol->setParent($name);
$html .= $facecontrol->render();
$this->controls = array(&$facecontrol);
if(isset($this->params['errorState']))
{
$errorState = $this->params['errorState'];
$html .=" <span>{$errorState['text']}{$errorState['value']}</span>";
}
return $html;
}The guiControl can be called up 3 different ways..
$basefont = &getGuiControl('base_font', 'base_font');
$basefont->setParam('value', "Verdana");
$basefont->display();
or
$html = $basefont->render();
echo ($html);{guicontrol type=base_font name=base_font value=$value}
$cur_table->fields["base_font"]->html = array("type" => "base_font");
Any way you call it, it's going to look like:

What fun would it be to only embed one guiControl. Since my intention is to ask the user for both the font face and the font size I will go ahead and embed a second select control to ask the user for the size.
The render function will now become...
function render()
{
$html = $this->renderViewState();
$attrs = array();
$value = $this->getValue();
$name = $this->getName();
if (preg_match('/([\\d]+?)\\s?pt\\s+?\'(.+?)\'/', $value, $regs))
{
$size = $regs[1];
$face = $regs[2];
}
else
{
$size = "";
$face = "";
}
$facecontrol = &getGuiControl('select', 'face');
$facecontrol->setParams($this->params);
$facecontrol->setParam('value', $face);
$facecontrol->setParam('index', array("Verdana" => "Verdana",
"Arial" => "Arial", "Tahoma" => "Tahoma", "Garamond" => "Garamond",
"Courier New" => "Courier New", "Times New Roman" => "Times New Roman"));
$facecontrol->setParent($name);
$html .= $facecontrol->render();
$sizecontrol = &getGuiControl('select', 'size');
$sizecontrol->setParams($this->params);
$sizecontrol->setParam('value', $size);
$sizecontrol->setParam('index', array("6" => "6",
"8" => "8", "10" => "10", "11" => "11",
"12" => "12", "14" => "14", "16" => "16", "18" => "18",
"20" => "20", "24" => "24"));
$sizecontrol->setParent($name);
$html .= $sizecontrol->render();
$this->controls = array(&$facecontrol, &$sizecontrol);
if(isset($this->params['errorState']))
{
$errorState = $this->params['errorState'];
$html .=" <span>{$errorState['text']}{$errorState['value']}</span>";
}
return $html;
}And the rendered guiControl will look like... (gimp'ed to show both select's at once):

We can write our own function to get and return the value(s) from the guiControls.
The getValue function will now become...
function getValue()
{
if(isset($this->params['face']))
$font = trim($this->params['size'] . "pt '" . $this->params['face'] . "'");
elseif(isset($this->params['value']))
$font = $this->params['value'];
else
$font = "";
return$font;
}This function will return a value looking like ...
8pt 'Courier New'
Which we can then take and store in the database or xml. We could also have returned an array if we deisred to store these values seperately, but for my purposes, I want them together so I can place those values straight into a css style.
This function is written to serve two different conditions:
For the second condition, guiControls sets paramaters with the names we assigned to the embedded guiControls making them easy to access.
The purpose of this tutorial is to give a quick introduction into what one can use guiControls for and the capabilities of guiControls. Here we have created a reusable object that has combined two html form objects into one and combined their values in a way we have specified, essentially creating a new type of form object. If we so desired we could have even written our own validation routine for this object. Such accomplishments are fairly difficult without guiControls, and pretty easy with them. So use guiControls, write your own GuiControls... Share your guiControls with others.
This guicontrol is an extension of the select GuiControl, it's usage and properties are the same, except the type is multiple instead of select and the multiple parameter is set to true by default. The same effect could be reached by using a select guiControl and setting the multiple parameter to true.
The select guiControl is a drop down select box. It allows a user to choose one item (default), or many items from a list of items. It will automatically select the given value if specified.
All GuiControls use the following parameters:
This control doesn't have any integrated validation.
$select = &getGuiControl('select', 'select');
$select->setParam('index', array('1' => 'option1', '2' => 'option2'));
$select->setParam('value', "1");
$gui->assign('select', $select); {guicontrol type='select' name='select_guicontrol' value=$value index=$index}
See the tutorial for more on using guiControls
Care to extend this to make your own guiControl, it is easier than you think, click here for a tutorial.
The select_update guiControl is an extension of the select guiControl. It adds one particularly nice feature, updating using AJAX. All you need to do is specify the url to grab the information and optionally the id of a div or other html element to place that url's output into. This requires the prototype javascript packaged with zoop. Make sure it is included somewhere (it is by default if you use the provided zoop skeleton tpl files).
All GuiControls use the following parameters:
Specific Accepted Parameters:
This control doesn't have any integrated validation.
$select_update = &getGuiControl('select_update', 'select_update');
$select_update->setParam('index', array('optionA' => 'optionA', 'optionB' => 'optionB'));
$select_update->setParam('url', SCRIPT_URL . "/SelectUpdateList");
$select_update->setParam('method', "POST");
$gui->assign('select_update', $select_update);{guicontrol type='select_update' name='select_update_guicontrol' value=$value index=$index url="`$BASE_HREF`/SelectUpdateList"}This given example would require a function created in the zone_default.php file called postSelectUpdateList, here is an example:
function postSelectUpdateList($inPath) // This function is called using ajax to populate a div in the pageGuiControlExample.
{
$newselectupdate = &getGuiControl('select', 'dynamically created select control');
$newselectupdate->setParam('index', array('C' => 'optionC', 'D' => 'optionD'));
$newselectupdate->display();
}See the tutorial for more on using guiControls
Care to extend this to make your own guiControl, it is easier than you think, click here for a tutorial.
Slider GuiControl
The slider guiControl provides an addition to the form elements provided in standard html. It adds a slider used commonly in programming to set things like color values, or volume. It depends on the scriptaculous javascript library included in zoop. Make sure to include it in your individual html file. It can be setup horizontally or vertically, and can have values given in a range, or from a set of numeric values.
Note: The scriptaculous javascript library this depends on is currently in development and some of these parameters may change names or functionality. We will try to maintain backwards compatibility here, but don't say you weren't warned.
All GuiControls use the following parameters:
Specific Accepted Parameters:
o format: "min, max"
This control doesn't have integrated validation.
$slider = &getGuiControl('slider', 'slider_guicontrol');
$slider->setParam('default', "30");
$slider->setParam('size', "150");
$slider->setParam('range', "5,50");
$slider->setParam('index', "5,10,15,20,25,30,35,40,45,50");
$gui->assign('slider', $slider);{guicontrol type=slider name=slider size=150 default=30 range='5,50' index='5,10,15,20,25,30,35,40,45,50'}See the tutorial for more on using guiControls
Care to extend this to make your own guiControl, it is easier than you think, click here for a tutorial.
The text guiControl is your basic textbox. It is probably the most widely used guiControl thanks to its tightly integrated type validation and because text boxes are used a lot in webforms.
The password guiControl is essentially the same as a text guiControl, but text entered within it is obscured. Its usage is otherwise the same.
This control supports all validation methods found in the validate component.
It also supports the 'required' option.
Screenshot:
Defined in PHP:
$text = &getGuiControl('text', 'text_guicontrol');
$text->setParam('value', "i am the value");
$text->setParam('validate', array('type' => 'int', 'required' => true));
$gui->assign('text', $text);
{guicontrol type='text' name='text_guicontrol' value='i am the value' _validate_type='int' _validate_required=true}
See the tutorial for more on using guiControls
Care to extend this to make your own guiControl, it is easier than you think, click here for a tutorial.
The textarea guiControl is a larger multiline textbox. It is probably the second most used guiControl (next to the text one) thanks to it's tightly integrated type validation and because textarea boxes are also used a lot in webforms.
All GuiControls use the following parameters:
Specific Accepted Parameters:
This control supports all validation methods found in the validate component. It also supports the 'required' option.
$textarea = &getGuiControl('textarea', 'text_guicontrol');
$textarea->setParam('value', "i am the value");
$textarea->setParam('validate', array('type' => 'length', 'min' => 50, 'max' => 512, 'required' => true));
$gui->assign('textarea', $textarea);{guicontrol type='textarea' name='textarea_guicontrol' value='i am the value'
_validate_type='length' _validate_min=50 _validate_max=512 _validate_required=true}See the tutorial for more on using guiControls
Care to extend this to make your own guiControl, it is easier than you think, click here for a tutorial.
The mail component provides it's own connection with an SMTP server providing better results than PHP's sendmail. Additionally it supports text, HTML and multipart messages. It has (optional) support for template based mailing as well (using Smarty).
$this->requireComponent('gui');
require_once 'Mail.php';
none
Check out the Documentation
Read through the API documentation
Chat it up in the Forum
Patterns
Here are some general patterns to follow when using Zoop that will make you like it better.
function define_once($name, $value)
{
if(!defined($name))
{
define($name, $value);
}
}These are just patterns and suggestions. Feel free to follow or not follow as you like. Zoop allows you to be as academic as you like, or as flexible as you need.
For more advanced information about the engine behind Zoop, look at The Zoop Engine, or read /zone/zone.php
Taken from Eric S Raymond's "The Art of Unix Programming". These principles are those which Zoop is built upon and we believe a solid recommendation to any programmer, but particularly Zoop programmers because Zoop was built with these principles in mind.
Rule of Modularity: Write simple parts connected by clean interfaces.
Rule of Clarity: Clarity is better than cleverness.
Rule of Composition: Design programs to be connected to other programs.
Rule of Separation: Separate policy from mechanism; separate interfaces from engines.
Rule of Simplicity: Design for simplicity; add complexity only where you must.
Rule of Parsimony: Write a big program only when it is clear by demonstration that nothing else will do.
Rule of Transparency: Design for visibility to make inspection and debugging easier.
Rule of Robustness: Robustness is the child of transparency and simplicity.
Rule of Representation: Fold knowledge into data so program logic can be stupid and robust.
Rule of Least Surprise: In interface design, always do the least surprising thing.
Rule of Silence: When a program has nothing surprising to say, it should say nothing.
Rule of Repair: When you must fail, fail noisily and as soon as possible.
Rule of Economy: Programmer time is expensive; conserve it in preference to machine time.
Rule of Generation: Avoid hand-hacking; write programs to write programs when you can.
Rule of Optimization: Prototype before polishing. Get it working before you optimize it.
Rule of Diversity: Distrust all claims for "one true way".
Rule of Extensibility: Design for the future, because it will be here sooner than you think.
One of the most important lessons I learned in doing this was how to properly debug php using php_backtrace and xdebug. I was able to speed up the framework and my applications using the framework considerably by analyzing which parts of the code were taking the longest to run.