Query to Unordered/Ordered List with hierachy

This has been bugging me for ages – how to take a query object, and loop it into an unordered/ordered list, with the script working out when the various ‘LI’ and ‘UL’ elements should be closed or opened.

I didn’t want to specify a parent item in the query, all I wanted to do is specify the depth – i.e how many levels from the top the LI element is.

So here, for the greater good (or bad, depending if you like/agree with my code) is my solution….

<cfsilent>
<cfscript>
	menu=querynew("id,name,link,depth,sortorder", "integer,varchar,varchar,integer,integer");
    queryaddrow(menu, 10);
	
        counter=1;
        QuerySetCell(menu, "id", counter, counter);
        QuerySetCell(menu, "name", "Home", counter);
        QuerySetCell(menu, "link", "/", counter);
        QuerySetCell(menu, "depth", 1, counter);
		QuerySetCell(menu, "sortorder", counter, counter);
         counter=counter+1;
        QuerySetCell(menu, "id", counter, counter);
        QuerySetCell(menu, "name", "Home", counter);
        QuerySetCell(menu, "link", "/", counter);
        QuerySetCell(menu, "depth", 1, counter);
		QuerySetCell(menu, "sortorder", counter, counter);
         counter=counter+1;
        QuerySetCell(menu, "id", counter, counter);
        QuerySetCell(menu, "name", "Home", counter);
        QuerySetCell(menu, "link", "/", counter);
        QuerySetCell(menu, "depth", 2, counter);
		QuerySetCell(menu, "sortorder", counter, counter);
         counter=counter+1;
        QuerySetCell(menu, "id", counter, counter);
        QuerySetCell(menu, "name", "Home", counter);
        QuerySetCell(menu, "link", "/", counter);
        QuerySetCell(menu, "depth", 2, counter);
		QuerySetCell(menu, "sortorder", counter, counter);
         counter=counter+1;
        QuerySetCell(menu, "id", counter, counter);
        QuerySetCell(menu, "name", "Home", counter);
        QuerySetCell(menu, "link", "/", counter);
        QuerySetCell(menu, "depth", 3, counter);
		QuerySetCell(menu, "sortorder", counter, counter);
         counter=counter+1;
        QuerySetCell(menu, "id", counter, counter);
        QuerySetCell(menu, "name", "Home", counter);
        QuerySetCell(menu, "link", "/", counter);
        QuerySetCell(menu, "depth", 1, counter);
		QuerySetCell(menu, "sortorder", counter, counter);
         counter=counter+1;
        QuerySetCell(menu, "id", counter, counter);
        QuerySetCell(menu, "name", "Home", counter);
        QuerySetCell(menu, "link", "/", counter);
        QuerySetCell(menu, "depth",2, counter);
		QuerySetCell(menu, "sortorder", counter, counter);
         counter=counter+1;
        QuerySetCell(menu, "id", counter, counter);
        QuerySetCell(menu, "name", "Home", counter);
        QuerySetCell(menu, "link", "/", counter);
        QuerySetCell(menu, "depth", 3, counter);
		QuerySetCell(menu, "sortorder", counter, counter);
         counter=counter+1;
        QuerySetCell(menu, "id", counter, counter);
        QuerySetCell(menu, "name", "Home", counter);
        QuerySetCell(menu, "link", "/", counter);
        QuerySetCell(menu, "depth", 2, counter);
		QuerySetCell(menu, "sortorder", counter, counter);
         counter=counter+1;
        QuerySetCell(menu, "id", counter, counter);
        QuerySetCell(menu, "name", "Home", counter);
        QuerySetCell(menu, "link", "/", counter);
        QuerySetCell(menu, "depth", 1, counter);
		QuerySetCell(menu, "sortorder", counter, counter);
    </cfscript> 
    
<cffunction name="createListFromQuery" returntype="string" access="public" output="no">
    <cfargument name="menu" type="query">
    <cfargument name="type" type="string" default="ul">
    <cfset var previousRowDepth=1>
    <cfset var nextrowDepth=1>
    <cfsavecontent variable="output">
	<cfoutput> 
    <#arguments.type#>
    <cfloop query="menu">
    <cfquery name="query" type="query">
    SELECT * FROM arguments.menu WHERE id=<cfqueryparam cfsqltype="cf_sql_integer" value="#(currentrow + 1)#">
    </cfquery>
     
         <cfscript>
		 if (query.recordcount == 1){
		 	nextrowDepth=query.depth;
		 }
	 	if (depth == previousRowDepth && depth == nextrowDepth && currentrow != 1){
      		writeoutput("</li>");}
		if (depth > previousRowDepth){
			for(i=1; i <= #(Depth - previousRowDepth)#; i++) {
      			writeoutput("<#arguments.type#>");}
      	} 		
		if (depth < previousRowDepth){
			for(i=1; i <= #(previousRowDepth - Depth)#; i++) {		
				writeoutput("</#arguments.type#></li>");
			 }
		}
		writeoutput("<li><a href=""#link#"">#name# (Depth = #Depth#)</a>");
		 if (query.recordcount ==1) {
		  if (depth > previousrowDepth && depth >= nextrowDepth){
			writeoutput("</li>");}
		  if (previousRowDepth > depth && depth > nextrowDepth){
			writeoutput("</li>");}
		  if (nextrowDepth = depth && currentrow == 1){
			writeoutput("</li>");}
		  }
		  else if (currentrow == arguments.menu.recordcount) {
			  for(i=1; i <= #(previousRowDepth - Depth)#; i++) {
					writeoutput("</li></#arguments.type#>");}
					}			 
		  previousRowDepth=Depth;
		  </cfscript> 
       
    </cfloop>
	</cfoutput>
    </cfsavecontent>
    <cfreturn output />
</cffunction>
</cfsilent>
<cfoutput> 
<html>
<head>List Demo</head>
<body> 
#createListFromQuery(menu, 'ul')# 
</body>
</html> 
</cfoutput>

Ideas on how I might improve this to be more efficient welcomed!

Wordle me up

Wordle

Just popped my blog through Wordle. Who knew I said “just” that much?
http://www.wordle.net/

Using Helicon ISAPI_Rewrite 3 with cfwheels URL rewriting

Maybe one for the cfwheels docs..

The URL rewriting chapter in the CFWheels docs mentions Ionic’s ISAPI Rewrite Filter. However, I’ve got a machine which is running IIS6 and version 3 of the Helicon Tech ISAPI rewrite module. Version 3 of this module uses .htaccess, rather than the .ini files of version 2.

If you’re planning on running CFWheels with full rewriting using Version 3 of this module, you’ll need to modify the .htaccess file supplied for use with apache. Don’t worry, it’s just a full stop (that’s period to you USA people) needs removing..

in the last line:

RewriteRule ^(.*)$ ./rewrite.cfm/$1 [L]

Should read

RewriteRule ^(.*)$ /rewrite.cfm/$1 [L]

Then it appears to play nicely.

Discovering CFWheels

I’ve spent the past week or so with my head down, coding, and completely loving it.

CFWheels is a CFML framework based on Ruby on Rails – at least it shares a lot of the same concepts from what I can tell. My previous experience with frameworks hasn’t been too great. I got put off the ‘big player’ names like Model Glue, Fusebox et al, as when I investigated them (admittedly a few of years ago) I got instantly put off by XML configuration, and quite frankly, some concepts I just couldn’t grasp at the time. Also, loading 100’s of templates for the apps I was writing at the time was just unnecessary.

Maybe the timing’s good, but I’ve been blown away by CFWheels.

My own coding style has changed a lot in the last 12 – 36 months, and I was getting to the point where I was writing lots of custom code to do certain things – a good example would be URL rewriting – each application I’d write would have similar, if not the same requirements. I’m a big fan of logical and symantically meaningful URL paths, and where I can, I’ve been trying to gradually make all my apps follow some sort of pattern. Once you find something which works, you basically cut and paste it into every new app you make, and each application might it’s own quirks, meaning you have multiple, similar versions of the same block of code.

Basic CRUD operations too – it’s incredible how much code I’ve written over the years which is based around what I’d call a ‘CRUD switch’ – i.e  a cfswitch block with cases of ‘view,add,edit,delete’. Almost without realising it , I’d been gradually moving towards the MVC pattern of coding, it just made sense.

Enter CFWheels: I downloaded it, and started playing. Within about 2-3 hours, I’d mastered enough of the basics to port an existing (simple) site over. I even got to the point where I was using an internal Wheels function, and just *guessed* what the arguments should have been; low and behold, it worked. When you find a framework which actually ‘thinks’ like you do, it’s a pretty great feeling.

My particular highlights thus far:

  • Basic jawdropping when I realised the power of the internal ORM engine.
  • ‘Routes’ – very, very useful.
  • The separate configuration setting options for development/design/production etc
  • Caching is, well, just painless.
  • HasMany() – running out of superlatives, but to be able to say, ‘Departments hasMany People’ and then in the People model, ‘People BelongsTo Departments’, and then refer directly to the relationship without a line of SQL? cool.
  • The Form Helpers save a lot of code.
  • The CFWheels Google group guys have been really helpful, and the documentation is excellent.
  • The Global Helpers bit is very useful, previously, you’d have to cache all your Utility functions in a CFC and chuck it in the Application scope – now you just add it to one place to make it available to all your views.
  • All the internal Wheels functions – when I’d hit a point where I thought ‘there should be a function for this’, there was.
  • It’s fast. Especially on Railo (disclaimer: it just ‘feels’ fast! And no, i’ve not tried it on CF9, and no, I’ve got no figures to back this one up)

Naturally, some low points too:

  • Note to self: don’t casually, or accidently dump extremely large objects on a production server. It appears to eat up RAM very quickly.
  • Associations – amazing concept, but out of everything, took me the longest time to get my head around; then I found ‘shortcuts’ and it all made sense.
  • I did get initially confused when something which I expected to be a query turned out to be an object..(then I found you can override that behaviour!)
  • The routes system could really do with a better ‘catchall’ system – it works, but I don’t want to have to specify all my controllers routes: I want Wheels to introspect them and work it out 🙂 (I’m aware there is talk going on re: this issue)
  • I still want to see some more example applications of best practice / example apps generally.
  • It took me a while to be comfortable with *NOT* scoping everything 🙂

All in all, I’m really enjoying this one, and it’s made me reconsider my previously (slight naïve) position on frameworks.

Well worth a couple of hours of your life to try.

http://cfwheels.org/

Now Fully on Railo!

Well, I’ve finally moved everything over to my Railo  VPS, including this blog & website, and all the various sites I host. It’s been surprisingly easy – the biggest challenge has been getting the necessary Linux admin skills, and the initial install of Railo/Tomcat.

Things I’m loving about the move so far:

  • Being on Apache / Centos – if nothing else, this has made the whole enterprise worthwhile; my previous hosting, as good as it was, was simply far too limited in terms of space, bandwidth, and most importantly flexibility. Apache give me .htaccess & virtual hosting, whereas before, I was using ISAPI rewrite, which just doesn’t compare (at least in it’s v2, v3 is substantially better). Disk space and bandwidth on Windows servers is just more expensive per MB, most likely due to licensing costs.
  • Railo – the access to a server / web admin combo is a massive step up from standard CF shared hosting: the ability to have shared mappings (think frameworks, shared customtags, shared error handling, shared CFCs) alone has saved me hours of work
  • Slight ‘smug factor’ of running completely free open source software (and submitting bugs to the Railo queue!).

I’ve also moved this blog over Mango Blog from BlogCFC (sorry Ray!), for a couple of reasons:

  • the lack of an update feature in BlogCFC was killing me – having to redo all the theming every time there was an update was just the straw that broke the camel’s back;
  • themeing in Mango Blog is insanely simple, so simple, the theme I’m using here I decided to release to the wider Mango Blog community (it’s available in the Mango Blog admin as ‘OxAlto Capita’)
  • for speed, I really do like having a Rich Text Editor.

The less good:

  • Well, everyone hits a linux permissions issue at least once, don’t they?
  • Managing to delete the root account on my MySQL install – that was less than clever. At least now I know how to boot mySQL in safe mode and fix it.
  • trying to persuade ntp to use a certain UK server pool

Hinksey Studio 1st Exhibition

I’m very pleased to announce the Hinksey Studio are having their first exhibition:
Details here: http://www.hinkseystudio.co.uk/blog/post.cfm/first-exhibition

Come along for the opening drinks on Saturday 10th October at 6pm!

You actually have to be impressed by Spammers sometimes…

I’ve just been cleaning up the aftermath of an exploited WordPress install. I officially hate wordpress – this particular install had been updated a few mere weeks before, but an exploit had clearly got out for that version, and therefore – havoc.

On going through the files, database, changing all the passwords etc etc, I got to the point where I was actually quite impressed by what this automated attack had done.

Firstly, exploited files were stored in both /wp-content and elsewhere – traditionally, when you ugrade WordPress, you tend to overwrite everything but the wp-content directory, .htaccess file, and wp-config.php file; the wp-content directory stores uploads, so an upgrade to WordPress wouldn’t automatically overwrite the compromised files.

Secondly, everything was Base64 encoded – once you’ve got the hang of what they’re doing, it’s fairly simple to search for “gzinflate(base64_decode” or some such string, but a typical search for ‘Viagra’ or some such spam word will never show in a search of the source code.

Thirdly – and this one is fairly obvious – every output was hidden by inline CSS, either via “display:none;” or “height:0 width:0” etc. so as not to alert the blog owner.

The really clever bit which got me was the fact that browsing via a normal browser wouldn’t make the spam show up. You had to spoof a Googlebot user agent to see the damage (oh, and turn off CSS as well).

When was the last time *you* checked your site for spam? Google this to find out – ‘site:yourdomain viagra’

OxAlto Capita – A Free Theme for Mango Blog

As I’ve been exploring some more CF open source apps, I’ve come across Mango Blog which I’m really beginning to like.

So, as an attempt to get to the know the bits under the hood, I’ve written a theme which I’ve decided to release under Creative Commons – so that’s free to use for all you Mango Blog users.

It’s based on the Blueprint CSS framework, so hopefully you should be able to take advantage on the various layout schemes incorporated into that.

The banner image remains property of The Hinksey Studio, but has been released for use in this theme.

Edit: This is now available directly via the Mango Blog Admin interface – Thanks Laura!

BluePrint CSS wrapper for BlogCFC

Quick BlueprintCSS wrapper for BlogCFC v0.1

This is a set of starter stylesheets using the BluePrintCSS framework (see http://www.blueprintcss.org/ for full usage) for BlogCFC. As always, I take no responsibility whatsoever for anything you might do with this.

Essentially all I’ve done is add the BluePrintCSS as the main starting point, and added a few classes to the layout customtag so it works under Blueprints CSS concept. Also added a few custom classes in bp_custom.css to make it a bit prettier. Add your changes to bp_custom.css – as it’s the last one to be called, it’ll override anything set in the defaults.

Tested briefly on BlogCFC 5.9.3.006

NB: This is meant as a starting point – I’ve not spent ages with elements like the pods etc. Hopefully it’ll save someone somewhere some time – the reason I’ve bothered putting it in a zip is that I have to integrate blogCFC into most of my sites (which happen to always use BluePrint);

Install instructions:

  1. Backup/Move/Rename the file at /yourblog/tags/layout.cfm
  2. Download the zip and decompress
  3. Copy layout.cfm into /yourblog/tags/
  4. Copy the four stylesheets into /yourblog/includes/
  5. Restart the blogCFC cache using /?reinit=1

Credits:

Screenshot

Download

Railo / Apache / Tomcat / Mura CMS/ SES URL Gotcha

Another catchy title 🙂

I’ve been trying for a day or two to get SES Urls working on Tomcat/Railo/Apache/Mura;

Specifically, I’m thinking of the /index.cfm/something/ style syntax. Having installed Mura, I couldn’t get any of the actual pages past the front page to work. I got an Apache 404 error.

Sean Corfield’s Blog gave me a good starting point.

As I’d installed Railo via the Beta install script, my config was a little different to some which is what gave me the headache.

Firstly, I had to get Tomcat to receive the requests, as Apache was serving me the 404s;

In my Apache httpd.conf file, I had the following at the bottom:

JkMount /*.cfm ajp13
JkMount /*.cfc ajp13
JkMount /*.do ajp13
JkMount /*.jsp ajp13
JkMount /*.cfchart ajp13
JkMountCopy all
JkLogFile /var/log/httpd/mod_jk.log

Note, the *.cfm entry – this needs changing to:

JkMount /*.cfm* ajp13

This means apache matched the correct syntax to pass the request to Tomcat.

So at that point, I was getting 404’s served by Tomcat rather than Apache; at least they were getting to the correct place.

For me, my Tomcat install lives in /opt/railo/tomcat/, so I found the web.xml file in /opt/railo/tomcat/conf/ and changed added a servlet mapping:

CFMLServlet /index.cfm/*

And then tried again with Mura. No joy – still 404’s in Tomcat; Having re-read Sean’s entry, it turns out you have to specify if you want the pattern to match a directory;

So the servlet mapping I’d put up would match /index.cfm/*, but not, as Mura users know, the default Mura behaviour of /default/index.cfm/*

Changing to:

CFMLServlet /default/index.cfm/*

Sorts it.

I know there’s a jar file supplied by Mura to fix this – but with my seemingly different Tomcat config, I could work out how to get it working properly.

Next stage is going to have to be to get the URL rewriting working to get proper URLs like /about-us/, rather than /default/index.cfm/about-us/.