TinyMCE and the relative URLs SNAFU

My CMS, cms34, uses a few third-party tools for certain complex features. One of the most useful is TinyMCE, a JavaScript/DOM-based drop-in WYSIWYG text editor. If that doesn’t mean anything to you, you probably want to stop here, but in case you’re a glutton for punishment, it is, in short, a way to produce HTML-formatted text with a word processor-like interface. Think Microsoft Word in a web browser, with the results being formatted for display on a web page. Slick.

Anyway, there’s been one nagging problem: When users paste in URLs for links, TinyMCE converts any on-site links into “relative URLs” — it strips out the domain name. This is not necessarily bad; in fact, for the most part I would want it to do that. But for some reason the nature of my CakePHP-based CMS seems to confound TinyMCE’s ability to properly determine the relative URL. And what’s worse, the CMS includes an enewsletter editor which has to have absolute URLs, but TinyMCE was converting them to relative URLs even if the user pasted in an absolute URL.

A little research led me to a handy explanation in the TinyMCE Wiki. Basically, if you want your URLs to always be absolute, make sure your TinyMCE configuration includes the following:

relative_urls : false,
remove_script_host : false,
document_base_url : “http://www.site.com/path1/”

Of course, you’ll want to change the value of document_base_url to be the actual base URL of your website. As it happens, my CMS has a global JavaScript file that creates a variable called baseUrl that I can use anywhere in JavaScript to substitute for the full base URL of the website. So, in my case, I set the value for document_base_url equal to baseUrl.

And, voilà, it seems to work!

CakePHP paginator sorting problem solved!

I’ll keep this brief, because I need to get back to writing code, but I wanted to share the solution I found to a CakePHP problem that has been nagging me for a while and for which I had never found a simple resolution.

I’m using the $paginator->sort() method to create links in the column headers for tables of paginated search results in my CMS. The method works great, except for one small problem: I could never get it to reverse the order. Intuitively, with links like these, you should be able to click them once to sort in ascending order, and then click again to reverse into descending order. But the reverse was never working for me.

Some research showed that you can pass in all sorts of options to the method, but I wanted to avoid having to make a change like that to about a dozen views; plus, it just didn’t seem right — the method is supposed to do the reverse by default.

At last I have discovered the source of my trouble: you need to explicitly name the model in the parameter that defines the sort field. I’ve been getting more diligent about always naming my models explicitly, but back when I set up these paginated tables (which was about the first thing I did in writing the application), I wasn’t doing it yet. Adding in the model, the reverse order on a second click works perfectly. Here’s a before-and-after example to illustrate the problem and its resolution.

Before:

<?php echo $paginator->sort('Title', 'title'); ?>

After:

<?php echo $paginator->sort('Title', 'Article.title'); ?>

CakePHP headaches

CakePHPI’m in the midst of my second big CakePHP-based project for a client, still loving CakePHP and the MVC concept overall, but I am definitely having some headaches with CakePHP this time around.

First off, I ran into some issues early on in the project that were attributable to CakePHP’s caching mechanism. Not sure why though, because caching was off by default (in fact, I was only even vaguely aware of its existence) on the first project I did; this one is building on that one; and I didn’t change any settings for caching in the core.php configuration file.

Caching is nice in a production environment, but it is a pain in the butt, to say the least, in a development environment. At least now I have it turned off. One less thing to worry about.

Today I’ve been struggling with some other frustrations that have nothing, really, to do with what I’m working on. What I’m working on would be frustrating enough, trying to wrap my brain around the intricacies of hasAndBelongsToMany relationships. But I can’t even get to that because of a pair of other issues.

First up, something I think I’ve finally got figured out. I’m writing my admin tool right now, so all of the pages I’m working on are using admin routing. Again, it should just be working; this is building upon stuff I already wrote for the first big project, which is working great and has been live for over a month now. And, for the most part, the admin routing has been working, but every once in a while I’ll click on a page that tries to load in the default template, and when it does, I get this:

Notice (8): Undefined variable: javascript [APP/views/themed/neutral/layouts/default.ctp, line 23]

OK, first off, I have the JavaScript helper defined in my controller. Second, why is it trying to load the default page layout instead of the admin layout? Well, that second question is probably irrelevant, because I viewed source on the page and found what the real error is, and what is apparently triggering CakePHP to load the default layout: there was a missing controller. And that was just because I had copied one of my other controllers as a starting point for this new one, and had not yet edited any of the code within it. In other words, I just shouldn’t click that link yet.

Fine, I can handle that. But when I was clicking on some pages that should be working, they just wouldn’t load, triggering the browser’s “server unavailable” error page, which I recognized as being the result of a segmentation fault error in Apache. So what within my PHP code, or in CakePHP, is crashing Apache? That was my real problem, and the reason for this blog post.

I googled “segmentation fault PHP” and got my answer in the form of the following:

Apache Segmentation Fault from CakePHP 1.2 Caused by Zend Optimizer

Thank you very much! This problem is happening for me in my local development environment, running MAMP. So I dug into MAMP’s php.ini file, and sure enough, Zend Optimizer was configured. I commented out all of the pertinent lines, bounced Apache, and we’re in business!

Well, sort of. The page still isn’t working, of course. It’s just now that its not working is not causing Zend Optimizer to crash Apache. Fortunately, I can see CakePHP’s error messages now, and it looks like I’ve got some problems in my model that are generating MySQL errors. Fair enough. At least I know what’s wrong now and can do something about it!

This is not a rant against CakePHP. Its error messaging is generally very useful, and its stack trace functionality rocks. Most of the time. Unfortunately it was a dangerous confluence of unrelated issues in my application today that caused the system to break down. But ultimately it was the result of issues with Zend Optimizer. I’m extremely thankful to “One Insightful M*******cker” for saving my sanity, and I just wanted to return the favor with a link back.

Wheeler Kearns website launches

Wheeler Kearns ArchitectsI usually avoid mixing business and Blather, but I want to make an exception in this case. As of today, the new website for Wheeler Kearns Architects has gone live. Wheeler Kearns is an award-winning Chicago-based architecture firm. I love their clean, geometric designs and the open, welcoming spaces they create. I could spend hours looking through the vast archive of photos, sketches, models and renderings of their projects featured on the site.

But I have a special interest in this website as well, because I developed it. The project consisted of a custom, CakePHP-based CMS with a WYSIWYG editor (TinyMCE), extensive tagging and image management tools, and a polished user interface with lots of cool interactivity — fading slideshows, custom scrollbars, sliding navigation menus, etc. — courtesy of jQuery.

Time tracking methods for the freelancer

I’ve been a full-time freelancer for about 6 weeks now, and one of the challenges an independent worker faces is tracking time, most notably for the purpose of being able to bill clients for it! My business isn’t big yet, and the number of projects I’m working on is easily manageable with a few text files and a little dedicated mental real estate, so I don’t have a formal tracking system set up yet.

Since I’m a web developer, and in particular since I’m looking for opportunities to work more with frameworks (most specifically CakePHP), my intention at the outset was to devote my first couple of weeks to building my own feature-rich project tracking web app, but the real projects started piling on more quickly than I expected, and within a couple of days I had to set that project aside.

Today I was thinking more about keeping myself organized, so I took a few minutes to research pre-built, web-based (so I can work with them both on my iPhone and my computer) time tracking tools. I still haven’t found the ideal solution, but I did find a radically different approach that I find extremely compelling, especially since I already have a couple of buckets of Legos on my desk. Unfortunately I also have a couple of kids who are frequently in close proximity, and the risk of inadvertent data tampering is just too great for me to use this method myself.