Converting Old Modules ---------------------------------- Introduction ---------------------------------- Three years ago when starting phpWebSite 1.0, the thought was that it should be totally completely backward compatible. In the beginning of development, it was, but eventually the features in phpWebSite outgrew the previous version. A decision had to be made. Do we want to limit the features of 1.x to allow full compatibility? I tried to balance them instead. Old modules will work in 1.x, but they require some modification. I have tried to keep the amount of changes to a minimum: I have to make them in all my modules as well. This document was written while converting PhotoAlbum. This module may be rewritten down the road, but for now if just needs to _work_. While working, I will go over what changes were made to make it functional again. Installing the module ---------------------------------- Boost has been written to install modules written before 1.x. So you should be able to get your module recognized in phpWebSite, you will just need to get it working again. One change you should make to your module before installing it is to update the permissions file. Before, permissions were kept in a file named module_rights.txt. It is in the conf/ directory. For PhotoAlbum, it looks like this: add_album::Add Album edit_album::Album Settings add_photo::Add Photo edit_photo::Edit Photo delete_photo::Delete Photo delete_album::Delete Album We are going to create a new file named permission.php and save it in the conf/ directory. Here is what it looks like: You will notice that I commented out item_permissions. We will get to that later. For now, keep it out or comment that line out. Modules from the old phpWebSite did not use item permissions. Once you create the permissions file, you can delete the module_rights.txt file. What we see ---------------------------------- Layout has changed a great deal from 0.x. 1) it doesn't make the developer use GLOBALS 2) it doesn't need a layout.php config file 3) it has a default setting for putting content in the BODY tag 4) the Default theme is no longer required 5) there are no _boxes_ anymore As a result of these changes, Layout is faster, easier to use, and avoids some of the pitfalls of the old software (i.e. missing boxes, extra boxes, etc.) In order to get your module showing up again, you need to open up your layout.php file in the module's conf directory. In PhotoAlbum, I find out that the content variable is "CNT_photoalbum" and the transfer variable is "body". With this information I can search for the CNT_photoalbum string. After a quick search I found: $GLOBALS['CNT_photoalbum']['content'] = "

$title

$content"; $GLOBALS['CNT_photoalbum']['title'] = $_SESSION['translate']->it("Photo Album") . ": " . $_SESSION['PHPWS_AlbumManager']->album->getLabel(); $GLOBALS['CNT_photoalbum']['content'] .= $this->_view(); This is bad because the html formatting is in the code but we'll ignore it for now. There is also a $_SESSION['translate'] in there. We'll come back to that as well. For now let's fix it to work with layout. $template['TITLE'] = $_SESSION['translate']->it("Photo Album") . ": " . $_SESSION['PHPWS_AlbumManager']->album->getLabel(); $template['CONTENT'] = "

$title

$content"; $template['CONTENT'] .= $this->_view(); $finalContent = PHPWS_Template::process($template, 'layout', 'box.tpl'); Layout::add($finalContent); The 'template' lines are just substitutions for the previous code. The finalContent portion needs a little explanation. Remember change number five (no boxes). The old phpWebSite expected these box templates to display the info. Since these are not used anymore, we use a substitution, Layout's own box.tpl. It is basic but functional. If you really wanted to, you can create your own box template and use it instead. Now we pass the complete text to Layout via the add function. Look back at the information from the layout.php config file. Notice that the transfer variable is "body". This is fortunate as Layout uses that as the default tag to print content. Body is always the main content area of a theme. So I can use: Layout::add($finalContent); If PhotoAlbum had a side box or a transfer variable that was NOT body, I would use the following instead: Layout::add($finalContent, 'photoalbum', 'CNT_photoalbum'); Notice we don't use the transfer variable at all. We can recycle the content variable as the place holder. The content variable name in 1.x just makes sure that the data ends up in the same place. So if had some data going to our CNT_photoalbum two times we could use: Layout::add($finalContent, 'photoalbum', 'CNT_photoalbum'); Layout::add($someOtherContent, 'photoalbum', 'CNT_photoalbum'); Using the same word makes sure that it appears in the same place. As such, Layout::add($finalContent); Layout::add($someOtherContent); would append the content in the "body" tag. Now I just search for CNT_photoalbum in the index.php file and all the classes, create the template array, pass it through the template class to Layout's default box.tpl and put the result into the 'add' function. Once you are done with this process you should start seeing your basic module screens appearing again. Translation ----------------------------------- Previous to 1.x, phpWebSite used its own translation class. This was clunky. 1.x uses 'po' files (see Language.txt for more information). Since the language module is no longer used, you should remove the old functions calls. You module will still function, but no one outside your native tongue will be able to use your module. Prepare for a search and replace. We need to change: $_SESSION['translate']->it('Hello World'); to dgettext('module_name', 'Hello World'); The quickest way to fix this is to replace $_SESSION["translate"]->it(" to dgettext('module_name', ' Make sure to try other searches such as: $_SESSION['translate']->it(" to dgettext('module_name', " $_SESSION["translate"]->it(' to dgettext('module_name', ' $_SESSION["translate"]->it(" to dgettext('module_name', " Notice the quote difference. It is very important. After you have changed all these translations, you will need to perform one last search and replace. The old translation system used [var1], [var2], etc. to fill in values into the string. PO files don't do that. So search for "[var" and add the 'sprintf' function. Here is an example: $message = dgettext('module_name', "The Photo Album [var1] was successfully saved.","" . $this->getLabel() . "") . "
\n"; change this to: $message = sprintf(dgettext('module_name', 'The Photo Album %s was successfully saved.'), '' . $this->getLabel() . '') . "
\n"; If you don't fix these first, you will get syntax errors. Working out the bugs --------------------------------------- If you module is now showing up, the next step is cleaning up the bugs. These should be pretty easy to spot as you click on forms and links. Below are some changes to make your software function properly again. Checking for Javascript -------------------------------------- The old way of checking to see if the user was using javascript was to query the user session: if($_SESSION['OBJ_user']->js_on) { doSomething(); } In 1.x use javascriptEnabled() if(javascriptEnabled()) { doSomething(); } WYSIWYG ----------------------------------- The old javascript wysiwyg (what you see is what you get) interface was really simplistic. You should allow users to access the new available interfaces. Look for something like the following: $tags['ALBUM_EXT'] = PHPWS_WizardBag::js_insert("wysiwyg", "PHPWS_Album_edit", "Album_ext") . $tags['ALBUM_EXT']; To fix this, first thing I do is go edit the template (editAlbum.tpl for this module) and remove the ALBUM_EXT tag. We won't be needing it. Then I find the code that makes the text box: $form->add("Album_ext", "textarea", $this->_blurb1); Now I just add the following: $form->useEditor('Album_ext'); You may have to check the text going into the text area but otherwise it should be fine. Error Class ----------------------------------- The error class has changed. One of the major changes is that you can log your errors. This makes the 'debug' option of the old error class obsolete. Errors dump a user to an error page. You must plan for errors and guide the user out gracefully. As such, when an error occurs, make sure your code logs the error and continues. The new Error class is based on the PEAR error class. The old one was written specifically for phpWebSite. To change over, you need to look for instances where the old error object was created. Here is an example from photoalbum. if(!is_dir(PHOTOALBUM_DIR . $this->getId() . "/")) { PHPWS_File::makeDir(PHOTOALBUM_DIR . $this->getId() . "/"); if(!is_dir(PHOTOALBUM_DIR . $this->getId() . "/")) { $message = $_SESSION['translate']->it("The photo album image directory could not be created."); $error = new PHPWS_Error("photoalbum", "PHPWS_Album::_save()", $message, "continue", PHOTOALBUM_DEBUG_MODE); $error->message("CNT_photoalbum"); $_REQUEST['PHPWS_Album_op'] = "edit"; $this->action(); return; } } $message = $_SESSION['translate']->it("The Photo Album [var1] was successfully saved.", "" . $this->getLabel() . "") . "
\n"; $_SESSION['PHPWS_AlbumManager']->message = new PHPWS_Message($message, "CNT_photoalbum"); $_REQUEST['PHPWS_Album_op'] = "view"; $this->action(); Now this code WILL work in 1.x. however I suggest you upgrade it to the new format. Here are my changes. $directory = PHOTOALBUM_DIR . $this->getId() . "/"; if(!@mkdir($directory)) { $message = dgettext('module_name', 'The photo album image directory could not be created.'); PHPWS_Error::log(PHOTOALBUM_NO_DIRECTORY, 'photoalbum', 'PHPWS_Album::_save', $directory); $_REQUEST['PHPWS_Album_op'] = "edit"; } else { $message = sprintf(dgettext('module_name', "The Photo Album %s was successfully saved."), "" . $this->getLabel() . "") . "
\n"; $_REQUEST['PHPWS_Album_op'] = "view"; } $_SESSION['PHPWS_AlbumManager']->message = new PHPWS_Message($message, "CNT_photoalbum"); $this->action(); First, a few code changes. mkdir does the job of PHPWS_File::makeDir and I don't need to check its existence after making it, I just catch the result of mkdir. I also put the directory into a variable so I am not concatenating the variables more than once. Now if the directory creation fails I am logging the error in the PHPWS_Error class. It then prints the failure message and goes back to the edit screen. If it succeeds, it prints the success message and goes to the view screen. The message will be recorded in the log via the PHOTOALBUM_NO_DIRECTORY assignment. If you are unfamiliar with how the Error class works, please read the Error.txt documentation. Adding Keys ----------------------------------- There are some modules that will not work with your module unless you give them 'keys'. The phpWebSite key class cross indexes all content within your site. This allows modules to "see" your content and help you organize it. Fortunately, it isn't really hard to add this functionality to your module. First, remove calls to modules that now depend on keys. Categories is one of those modules. In pre-1.x, to categorize an item, you had to insert a FatCat select box into your form. Categories doesn't work like that. So look for places that call Fatcat, and yank them out. Next, you need to add a key_id column to the item you want to index. I _could_ index the individual photos however I think I would prefer to index the albums. So I add a column to mod_photoalbum_albums: ALTER TABLE mod_photoalbum_albums ADD key_id INT NOT NULL AFTER id; Make sure to update your install.sql file (not with the above of course, add the column to your create table). I also create a new variable in the album class: var $_key_id = 0; Note that this module is using the Item class which expects an underline before the variable name. You need to do this, or it won't work correctly. Next I need to create a key for each album. Since I want to create the key after the item is saved, I look for the save function in the Album class. Once there, I add my key creation function: $this->saveKey(); My key creation function looks like so: function saveKey() { $update_album = FALSE; if (empty($this->_key_id)) { $key = & new Key; $update_album = TRUE; } else { $key = & new Key($this->_key_id); if (PEAR::isError($key->_error)) { $key = & new Key; $update_album = TRUE; } } $link = sprintf('index.php?module=photoalbum&PHPWS_Album_op=view&PHPWS_Album_id=%s', $this->_id); $key->setModule('photoalbum'); $key->setItemName('album'); $key->setItemId($this->_id); $key->setEditPermission('edit_album'); $key->setUrl($link); $key->setTitle($this->_label); $key->setSummary($this->_blurb0); $result = $key->save(); $this->_key_id = $key->id; if ($update_album) { $this->commit(); } return $key; } First I check for the existance of the key_id. If it is 0, we make a new key. Next I set all the relevant key information (see the Key documentation for more information). Next I save the key, set the key_id in the object, and, if this is a new key, update the album object. Serving the Key ------------------------------------ We are halfway done with updating the key! Once your key is saved with your item, you need to 'flag' it. Go to that item's 'view' function. For PhotoAlbum the function is '_view'. Get the key id and instantiate a new key object: $key = & new Key($this->_key_id); Now flag it: $key->flag(); Once the key raises its flag, all the modules that are looking for it will now be accessible. File types ------------------------------------ All file types (documents and images) are now kept in config/core/file_types.php. You can check if an image is allowed by using classes within the File Cabinet module: PHPWS_Core::initModClass('filecabinet', 'Image.php'); PHPWS_Image::allowType($filetype); For other documents use: PHPWS_Core::initModClass('filecabinet', 'Document.php'); PHPWS_Document::allowType($filetype); Other things I changed ------------------------------------ Here are some odds and end of things I changed in PhotoAlbum. PHPWS_Album checks for an error when it sets the id. Not needed as long as it isn't zero. I changed many the double quotes (") to single quotes (') where possible. Double quotes require the text between to be parsed whereas single quotes do not. This saves a wee bit of time. Removed the tab characters and substituted 4 spaces per.