- individual stylesheets are applied to a page
- Client-side script can be added
- Metadata such a description and keywords
Tuesday, 13 May 2008
Helpers are the way forward
Sunday, 4 May 2008
Using XSLTs as a template engine in Zend
I don't know why I like the idea so much. I think it's the extent to which the model doesn't care how the data is rendered, it's job is just to deliver it and it does that through XML. There is of course a parsing delay involved in doing transforms and I'm going to try to get some data or results of my own to try and analyse that, but for the time being I'm happy. There's even the possibility of processing the document client-side by either delivering pure XML with a stylesheet declaration, or using a javascript library like Sarissa and falling back to server-side transforms onlyZend to do XSLT transform instead of rendering templates and it's just about working. But it's led me to thinking about the bigger picture. XSLT allows us to include multiple stylesheets in one document by using expressions such as
import
and include
. So why can't we make a master XSLT template file which doesn't transform any XML itself, but simply matches the document root to apply its template only once, but then crucially providing a placeholder for an imported stylesheet in the right place. This would allow me to use it as a 'master view' which is combined with the view my controller action renders.There is however, a few problems. Whereas now my view renders whatever XML its passed using a single stylesheet, it now has to use the master stylesheet, but the master itself has to be aware of which view-specific stylesheet to include. This is getting a bit too much like a template language – replacing strings in the master template file with a path to the view specific stylesheet, and that's what I'm trying to avoid. The other problem is with CSS. Putting persistant navigation in the master stylesheet is fine, but what happens when you want to change the CSS class of one of the link elements? You have no hook to the master from the view specific stylesheet. I thought about having the navigation as its own XML file – easily editable and adaptable. Then view scripts can be used to change that nav XML, marking which link should have a CSS class of "current" and combining it with any data XML the view has received assuming there and some mechanisms are in place for the master stylesheet to find those flags, and produce the right XHTML output. Perhaps xml namespaces are the right way to go here, in order to differentiate between nav and content XML. Ideally, minimising the number of transforms is a good idea, so I don't want to have to transform the nav XML data, then use another template to transform that result to the final output including the actual content. The content XML and nav XML could be combined just before XSLT processing. It would be simple to wrap content XML from the model with persistent data. But the problem still remains to tell the master stylesheet which view specific stylesheet to include in order to render it correctly.
Javascript may be an alternative. Client-side transforms has the nice quirk of sorting through XSLT which is really neat, but Javascript is so horrible to code with. I have to think about it more.
Saturday, 3 May 2008
MySQL and "serial"
serial
can be used when setting up a column in a table. It's the same as writing bigint unsigned not null auto_increment
just a lot shorter to write.
Zend and XSLT as a template engine
If you have XML data that you need displayed, turn off automatic view rendering within you bootstrap file with
$controller->setParam('noViewRenderer', true);
This gives you more control over how Zend renders views. Then, in your controller action , create a new view and assign some variable from you application logic. You need to tell the view where the script is to execute. You do this using $view->setScriptPath('...');
. Once this points to the right directory, you can add a script in there you want the view to run. You do this by calling the render
method of the view instance you create, passing it a single string parameter as the script you want it to run. As the contents of the script is returned, the whole thing needs to either be echo
ed or print
ed from the controller action.
Within the view script, print anything you want to be rendered on the page. So here you can pair up the xml data passed from the controller action using $this
and an XSLT stylesheets you want to transform.
Brilliant hey? I sort of get this stuff.
Friday, 2 May 2008
Zend and MySQL
Zend currently uses the Pear library to do stuff with DBs. Whereas installing this library may be fine, you might not have access to the server to install more stuff. Instead, follow this article about Adding adapters to Zend which allow it to use PHP. Alternatively, get the latest source files here and put the Php
directory within Zend/Db/Adapter/
. It works a treat, just remember to set the connection type to php_mysql
as opposed to pdo_mysql
None of this is my own work. It all belongs to David Coallier (davidc@agoraproduction.com) and his blog http://blog.agoraproduction.com. Awesome job, thanks.
Apache mod_rewrite refusing to work
Apparently, some servers require FollowSymLinks
to be turned on. If mod_rewrite is refusing to work and just denying all access (particularly important when trying to implement MVC with a bootstrap file) try including this in the .htaccess file
:Options +FollowSymLinks
More cool stuff with http.conf
Ok, I'm getting there. I know know a bit more about Apache's VirtualHost directive:DocumentRoot /var/www/phpweb20/htdocs
This gives an absolute path to the directory where your web files will be served from. It can be anything you want.<Directory /var/www/phpweb20/htdocs>
AllowOverride All
Options All
</Directory>
This says, for a given directory (and it says which in particular with the path) AllowOverride
which allows me to use .htacess
files in that folder. Not too sure what Options
does yet.
The other cool bit is this line:php_value include_path .:/var/www/phpweb20/include:/usr/local/lib/pear
This tells the PHP module in Apache where to look for include files. Pretty handy.
Thursday, 1 May 2008
PHPDoc
Use PHPDoc rules for formatting:
/**
* functionName
*
* Brief description of the function. What it DOES,
* not how it does it
*
* @param string $name The name of the user
* @param int $age The age of the user
* @return string The generated welcome message
*/
function functionName($name, $age)
{
...
}
Pretty simple really.
Back ticks
you can call UNIX commands in PHP by putting commands in back ticks (`
). Similarly, shell_exec('...');
will run scripts too.
popen()
is also apparently useful, it allows you to open processes and talk to them.
Differences between echo and print
echo "$variable"
will get echo to replace the variable name with it's value. If echo is used with single quotes it won't work.Sunday, 6 April 2008
iPhone Problems #1 : Texts (minor concerns)
2. 'Conversation' is a misnomer.
The first message after an undesignated period of inactivity (it's less than 25 minutes but more than 6) gets time and date stamped. Which is fine, but clearly what Apple means by 'conversation' is 'a number of texts sent reasonably close together', regardless of whether they are replies to previous messages or entirely new trains of thought. This has the result of not only clumping together groups of texts in a slightly jolting way, but also leaving most messages without a time stamp. If you happen to text rapidly but over a reasonably long period - when arranging to meet someone, for example - you can easily end up with the final text in a string being hours newer than the first, with no way of differentiating it. I for one would like to know exactly what time a text saying 'just got on the bus' was sent, so I can judge how late I'm going to be in meeting said bus. It's the slightly random nature of this which bugs me - either time stamp each text, or don't bother at all.
3. Lack of delivery reports.
This is probably an O2 problem - to get a delivery report from a text, one is required to type *0# (note: that's a zero, not an O) before the message. Which is extraordinarily fiddly, and just too incredibly frustrating to do before every message. Why there's no option on the iPhone itself to turn delivery reports on or off, as there is on almost all other handsets sold in the UK, I've no idea.
4. Call/contact info scroll time
A very minor point, this one, but another example of Apple having wonderful intentions which fall a little short in practice. At the top of every text conversation are two highly useful buttons: 'Call' and 'Contact Info' (if it's an unknown number, the latter becomes 'Add to Contacts'). These have clearly been designed for no other purpose than to be helpful when one is in a rush and doesn't want to go back to the home screen, get into the contacts list, etc. This sort of unobtrusive handy-help is the reason I love my iBook, and Apple in general, so much. However, the text folders of those people I am most likely to want to call at the drop of a hat are, not surprisingly, rather full. So scrolling up from the latest text to the 'Call' button is painfully slow. The option to tap the screen once to have all of this displayed (as with Quicktime or Safari) would be much appreciated.
iPhone Problems #1 : Texts
1. There's no way to delete individual texts.
This issue has been commented on by many, and there are a few hacks around already to help out, although they're all a little clunky - a common problem seems to be their tendency to only show numbers, not names. I like having a different section for each contact, even when such sections are empty of any actual messages; I like that my replies aren't hidden in some 'sent' folder; I like that a line of the most recent text is displayed on the first page. But a big problem stems from my having, essentially, two different sorts of text messages - those containing humorous observances or Happy Birthday greetings, which I save as long as I have the phones, and those saying thinks like 'yes, 5 mins', which are usually deleted instantly. The choice is therefore to keep everything, no matter how long it takes to scroll through them and how difficult it is to find the interesting/useful/funny ones; or, to mercilessly delete them all. Not only can I not delete the ones I don't want, I also can't save the ones I do. Given that in the last ten days I've had over 70 texts from Michele alone (and I live with him), the former isn't really an option - I dread to think what people with real jobs are going through trying to find the date of a crucial meeting hidden among hundreds of 3-word exchanges about coffee and photocopiers (or whatever it is the employed discuss with their collegues).
So, for the moment, I'm following a strict regime of entering important dates in my calendar as soon as they arrive, and typing up into a word document any sentiments from friends I know I'll want to look back on. This way, I've covered all bases when I accidentally delete everything in one go. But I feel it somewhat defeats the purpose of the wonderful-looking, easy to use text app I have at my disposal. What I should be doing is signing up to O2's Bluebook, where Sean Bean nicely saves a copy of everything as it comes in, but I've found O2 almost as disappointing as Virgin Media during my short ten day spell as their customer, so I've been putting it off as long as possible.
Further minor problems to follow.
iPhone Problems - Introduction
cakePHP database config
For CakePHP, database configurations are saved in the
app/config/database.php
file. But notice each config is given a variable name. Any number of configs can be added in this file so that when you're working on a controller you can set the $useDbConfig
variable equal to a string of the same name as your config array. Simple.here's more info
CakePHP conventions
An interesting and useful paragraph is the following:
The first function you write for a controller might be the index() function. When a request specifies a controller but not an action, the default CakePHP behavior is to render the index() function of that controller. For example, a request to http://www.example.com/apples/ maps to a call on the index() function of the ApplesController, where as http://www.example.com/apples/view maps to a call on the view() function of the ApplesController.
Notice visibility is also mentioned on the page but starting a function name with an underscore
Saturday, 5 April 2008
Automatic Documentation in PHP
But basically, make a code block but use a double asterisk. The make elements with an
@
symbol:
/**
* This function builds a simple XML file for the client to parse.
*
* @author Michele Memoli
* @since Version 0.5.3-23
* @return string Returns an XML string.
* @see ui::get_xml( )
*/
Monday, 24 March 2008
Google Maps on the fly
GDownloadUrl(url)
Can be used to go off and get a remote file for you. This remote file can be an XML file and parsed using the GXml()
although this then leads to navigating the DOM to extract the data you want. Secondly, if the XML file your downloading is more specifically a KML file (very possible considering you may be producing that file from your database). You may want to just use the GGeoXML()
class. This class can be passed a KML directly and theoretically get displayed on a map using map.addOverlay(GGeoXML)
. However, this doesn't give you access to a function you may have to create (and therefore return) a marker. This function is useful because it allows stuff to be bound to particular marker instances (like code for click events). With GGeoXML
you loose this.I keep seeming to start by plotting an arbiturary XML file full of
<marker>
tags. I then decide to use a standard XML file like KML, get satisfied, then remember the GGeoXML
which could have done most of it for me.
Javascript: Binding and Scope
Saturday, 22 March 2008
Printing Arrays in PHP
print_r();
to debug an array. I guess echo
and print
just produce array
.When displaying stuff in web pages use a
foreach
loop.
VirtualHosts in Apache, Leopard
.conf
files, the most important being http.conf
. In Leopard this is at etc/apache2/
. Editing this file is pretty straight forward, it's very templatey - find out where it's done once, then copy, paste and edit.Virtual hosts are a good thing to set up if you're working with a lot of websites. People talking about enabling the following line beginning with
Include
in the http.conf
file:
# Virtual hosts
#Include /private/etc/apache2/extra/httpd-vhosts.conf
This is fine, but it doesn't really do anything, it just gets Apache to pull in that extra configuration file when starting up. In fact, you can keep that file commented out (not used) and put virtual directory right there, in the
http.conf
file. Here's the basic code for setting up a virtual host
<VirtualHost *:80>
#ZDS Name: redmonkey
ServerName redmonkey
DocumentRoot "/Users/michele/Sites/redmonkey"
ServerAlias redmonkey
ErrorLog error.log
Options Indexes MultiViews Includes
</VirtualHost>
I'm sure loads can be changed, and I'm not sure what all of it does yet, but get this in and edit the rest.
Once this is done, you need to setup your hosts file. This can be found in
/etc/
and it's simply called hosts
(note: no file extension). Here add the following:
127.0.0.1 redmonkey
The IP address is equivalent to "
localhost
" and then a name of your new hosts. From then on you should be good to go with your new hosting directory in Apache on Leopard.
Thursday, 20 March 2008
Unix Aliases
alias
.When using the bash shell, include aliases in
~/.bash_login
(create the file if it doesn't exist already). Some useful aliases I've already added in macOS are the following:alias ll='ls -la'
alias clr='clear'
alias here='open -a finder .'
The last one is really cool. It opens a finder window at the current terminal location.
MySQL wrapper class
Useful Links
Also Im using the google reader, you subscribe blogs to ur reader and it consolidates and displayes all unread blog posts. You can then throw a google reader widget onto ur igoogle page and see all the new posts from there. I should'nt miss any posts now...
Smarty: A PHP template Engine
libs/
directory. When copying in unix, remember to add option -r
to go into the internals/
and plugins/
directories within libs/
. With those files saved somewhere, your PHP has to find one file in particular-Smarty.class.php
(they also seem to be quite strict about the capital "S" in "Smarty"). That file needs to be referenced with an absolute path. This can be done a number of ways, look them up at Smarty's documentation. One cool way I've found so far is this:
// Use the absolute path for Smarty.class.php
$base_path= basename(dirname(__FILE__));
require($base_path.'/Smarty/Smarty.class.php');
Of course this assumes that you're writing this in a file which is in the document root of your webserver, and that the Smarty files are located further down in the folder
Smarty/
. The require_once
is similar to PHP's include statement apart from it will result in an error if it can't find the file (include
will just try and not care if it can't) and the _once
part ensures there's no errors if you accidentally try to require it again.Within that
Smarty
directory, make four folders: templates
, templates_c
, cache
and configs
. Link these files up with your code with
$smarty = new Smarty();
$smarty->template_dir = $base_path.'Smarty/templates';
$smarty->compile_dir = $base_path.'Smarty/templates_c';
$smarty->cache_dir = $base_path.'Smarty/cache';
$smarty->config_dir = $base_path.'Smarty/configs';
Put this immediately after the
required_once
statement. Then start making templates and go.
Wednesday, 19 March 2008
PHP: the ? operator
?
in PHP is shorthand for an if..else
statement. It works like this{expression} ? return_when_expression_true : return_when_expression_false;
Notice the
?
and the :
to separate everything apart.
Casting in PHP
$test = 1234;
$test_string = (string)$test;
Simple.
Unix pipes and other commands
|
"are really cool. They redirect output from one command and pass it as input into the next command. A useful command to use in this situation is grep
which pattern matches line by line and displays that line if the match succeeds, but grep -v
inverts how the command works, and displays every line that doesn't match the pattern, making it useful as a filter...very cool.
Tuesday, 18 March 2008
MySQL basics
USE database
command sets the default database for your stuff. All operations from that point on are applied to that database. When declaring numeric types, a number in brackets called a width specifier which tells MySQL to pad the field when retrieving it. With floats and decimals a precision parameter can also be specified such as FLOAT(7,4)
. Marking a field with the ZEROFILL
attribute will force MySQL to pad the value with zeros. UNSIGNED
forces only positive numbers.The
alter
can be used in a number of different ways to change name of fields within a table. If you try to convert field types using CHANGE
, MySQL may result in errors. Try using IGNORE
to get round them.Use
mysqldump
to backup and restore databases or tables. Delete stuff from databases and tables using DROP
.
.inc files and libraries
require_once()
to include files to use as a library. These files get interpreted by the interpreter but aren't called directly. They are conventionally given a .inc
file extension, and they allow you to call functions and stuff hidden inside them. Quite useful.
Monday, 17 March 2008
mod_rewrite
After that, it's quite simple really. Regex expressions: from, to. Use
^
and $
to mark the beginning and the end of the expression to match. Here is a good mod_rewrite cheat sheet although there's loads of help online. Try to set a RewriteBase
to set the base directory within the sitethe
[R]
flag will redirect the user and the URL in the browser window will change automatically. The [L]
flag will redirect behind the scenes but the users won't know. Use this for query-string stuff. Remember to turn the engine on (as it's off by default) with RewriteEngine on
.The only other thing I've discovered so far is there seems to be a default index being made by Apache which I haven't been able to disable yet. This default indexing causes Apache to ignore my rules and display any file in a directory by default if they share the same name i.e. if I have rules like
RewriteRule ^$ catalog/ [R]
RewriteRule ^catalog/$ hello.php [L]
and within the directory there's also a file called
catalog.php
, Apache seems to be ignoring the redirect to hello.php
and just displays catalog.php
as the index. I know this because if I change the filename and the redirect directory to something else I have the same affect. I'm still working on this, no idea how to do it.All of this can be written in a
.htaccess
file.