Friday, December 30, 2011

Baby Steps with Dojo DataGrid and JsonRestStore Error Handling

These holidays I decided to teach myself something new.  I decided to take a look at Dojo, for being able to offer professional looking and behaving UI components in web based developments.

Instead of leaping into full prototypes of UI layout, I thought I better keep my first attempt at Dojo relatively simple.  I'm starting with a DataGrid that is using a JsonRestStore as the store.  The JsonRestStore is being serviced by a CakePHP 2.0 backend.  I've written a plugin component that will assist with converting between the JsonRestStore method of paging, and the CakePHP method of paging, but that's a topic for another post, and perhaps a release to GitHub.

For this experiment, I ended up using Dojo 1.6.1, even though Dojo 1.7.1 is available.  When I first started playing with Dojo, 1.7.1 had been released, but it was not available on the CDN.  Then I tried playing with an example that defined a custom module to interact with CakePHP pagination.  Unfortunately, there was a bug in 1.7.0 that meant mixing CDNs and local custom modules was out.  So I downloaded 1.7.1.  Then there was another bug that meant mixing local custom modules with the locale Dojo path was also out.  So I ended up falling back to 1.6.1. After all, all the tutorials were based on 1.6 anyway.  It's doco like this that makes me appreciate the work that the developers at cakephp.org put in to the manual, before the release goes live.  Cynical aside time: I recall watching a Dojo promo for what must have been the 1.6 release.  Many of the featured developers commented how the first step to learning Dojo was to look at the code.  Only a couple mentioned going through the tutorials.  One mentioned jumping on IRC, but was quick to qualify that you should only ask questions if you knew what you were talking about.  Dojos' current documentation might be an improvement on what it used to be, but it falls short of the mark if the recommendation is to look at the code, rather than read the manual.  On the flipside, the featured developers were right.  You're going to have to dive in to the code, given the doco in its current form.  Anyway, on with the show.

My end goal is to have a DataGrid that will allow inline editing, but report errors in saving in a manner that is consistent with CakePHP forms.  That is, after the post, the form keeps the edited values, but displays an indicator and message next to each offending field.  In the case of the grid, I've opted for a red border on the offending cell, and a tooltip that will display the associated error message on mouse over of the cell.

The first thing I did was run up a basic DataGrid using a JsonRestStore.  Inside the dojo.ready(), I defined the data store and the grid.

var dataStore = new dojox.data.JsonRestStore({
    target:"/my_datas/"          
});

var layout = [[
    {'name': 'Column 1', 'field': 'id', 'width': '100px'},
    {'name': 'Column 2', 'field': 'col2', 'width': '100px', cellType:dojox.grid.cells.Bool, styles:'text-align:center;'},
    {'name': 'Column 3', 'field': 'col3', 'width': '200px'},
    {'name': 'Column 4', 'field': 'col4', 'width': '150px'}
]];

var grid = new dojox.grid.DataGrid({
    id: 'grid',
    store: dataStore,
    structure: layout,
    rowSelector: '20px'
}, "gridDiv");

grid.startup();

Using examples found around the usual Dojo haunts, I added Add Row and Remove Selected Rows buttons, and functionality. The layout was updated to make columns 2 to 4 editable.

The Add and Remove functions worked well enough, but the inline editing wasn't persisting the changes to the server.  Here's where I learn my first DataGrid lesson.  DataGrid will sync the data to the store, but if the store needs persisting to a server, like a JsonRestStore does, then you are responsible for doing that yourself.  This should have been evident with the add and remove actions associated with the buttons calling dataStore.save().  So I set up a simple action for the onApplyEdit event to save the dataStore.

var applyEdit = function(rowIdx) {
    dataStore.save();
};
dojo.connect(grid, "onApplyEdit", applyEdit);

I should note that my code didn't actually look like that at the time. I had actually overridden the onApplyEdit directly in the grid definition. Since then, I've come to appreciate that if you're going to provide a function to the constructor arguments, defining one to a variable, then using dojo.connect() is the best course of action, since this will append your function to be called with the event, instead of overriding it. I think. I'm still a Dojo noob, so I'm just going to use dojo.connect() because it seems like the right thing to do.

Well, that editing is great if all is going well.  But if there's an error with the save action, or at least validation is failing, what to do?

Well, I spent hours trying to find an example of error handling for DataGrids and JsonRestStores, but I couldn't find a bloody thing.  Error handling is definitely something that you end up having to write yourself.  Here's how I deal with it.

First up, I needed to communicate the fact that validation had failed for an edit.  With CakePHP, you end up with a validationErrors array in your controller that gets passed to the view, and used in the form.  I created an error element that would display the session flash and the validationErrors in a JSON array.  I would strip the model name out of the validationErrors array, so I didn't have to deal with it in Dojo.  And if I did detect an error in the save, then I would return a 409 status code.

The next part was recording those errors in a place where I could then get at it to change how the grid was rendered.  First things first, storage.  And the dataStore was the best place for that storage.  Here is the modification to the applyEdit function, storing any validation errors.

var applyEdit = function(rowIdx) {

    var actions = dataStore.save();

    dojo.forEach(actions, function(action){
        var result = action.deferred.then(function(){
            if (action.target.validationErrors) {
                delete action.target.validationErrors;
            }
        },function(err){
            if (err.responseText) {                        
                try {
                    var responseText = JSON.parse(err.responseText);
                    action.target.validationErrors = responseText.validationErrors;
                } catch (e) {};
            }
        });
    });          
}; 

I eventually figured out that I would need to use Deferreds to be able to get a hook in to handling errors that might be returned in the JsonRest response for the JsonRestStore. Since it is possible for the save action on a store to save more than just one changed record, I would need to loop through all of the actions that were sent to the service, and perform the error checking against each one.

Thusly, I've attached a then() to the action.deferred. The first function in the then() is run on success.  This one will clear any validation errors for the target row, if any previously existed.  The second function is run if there was an error. Hopefully, the error responseText is parsable JSON containing validation errors.  I guess this part could do with further hardening.  What if the response didn't contain parsable JSON?  What if it did, but didn't contain validation errors?

Error handling in DataGrids with JsonRestStore is such a big deal.  It's such a pity that the subject does not get directly addressed in the available tutorials.

Now that I have the validation errors in the dataStore, I can use a cell formatter to detect and highlight the offending cell with a red border.  I'm actually just going to apply a CSS class, and let CSS take care of the rest.

var formatter = function(val, rowIdx, cell) {
    var item = grid.getItem(rowIdx);

    if (item.validationErrors && item.validationErrors[cell.field]) {
        cell.customClasses.push("validation-error");
    }
    return val;
};

Also add formatter: formatter to the records in the layout variable that are editable, namely, columns 2, 3 and 4. You'll also need to define the CSS.  You'll need to be specific, if you hope to have your CSS get included ahead of the other styles defined.

.claro .dojoxGridCell.validation-error {
    border: 1px solid red;
}

While I was at it, I also added the code for the tooltip that would display on mouse over of the offending cell.  This part of my code, I do believe is flawed, but I'll chat about that after the code.  First well, need some code to show the tooltip on mouse over, and hide it on mouse out.  I've also tried to add some code to prevent the tooltip from showing while the field is being edited.  I do this because I believe the HTML node of  the cell is actually replaced during editing, the lost with it is the reference to the displayed tooltip.

var tooltipNode;
var showTooltip = function(e) {
    if (gridTooltipEnabled) {
 var msg;
 var item = e.grid.getItem(e.rowIndex);
 if (item.validationErrors && item.validationErrors[e.cell.field]) {
     msg = item.validationErrors[e.cell.field].join('
');
 }
 if (msg) {
     dijit.showTooltip(msg, e.cellNode);
     // hold reference to cellNode with tooltip for easy hiding
     tooltipNode = e.cellNode;
 }
    }
};

var hideTooltip = function(e) {
    dijit.hideTooltip(e.cellNode);
    tooltipNode = null;
};

var gridTooltipEnabled = true;
// grid definition here ...

dojo.connect(grid, "onCellMouseOver", showTooltip);
dojo.connect(grid, "onCellMouseOut", hideTooltip);
  
// disable and hide tooltip while editing
dojo.connect(grid, "onStartEdit", function (cell, rowIdx) {
    gridTooltipEnabled = false;
    dijit.hideTooltip(tooltipNode); // can't get to a cellNode from cell
});

// enable tooltip when finished editing
dojo.connect(grid, "onCancelEdit", function(rowIdx) {
    gridTooltipEnabled = true;
});

This code constructs a tooltip from the validation errors, and displays it. If you start editing a cell, it will attempt to hide the tooltip, and prevent another from being displayed until you have cancelled editing or have applied the edit (I have a gridTooltipEnabled = true; at the top of applyEdit()).

What I really wanted to was to be able to identify a cellNode from the cell argument passed to onStartEdit, and call dijit.hideTooltip() against that.  But I just couldn't find a way to link these two items together.

The flaw is that if two tooltips are on display when editing starts, then only one of them, the most recently activated, is going to be hidden.

The last part to go is the behaviour of retaining the entered data after an error, and only removing it if the edit is cancelled, or another cell in the store is successfully saved.  You can't micro manage a JsonDataStore.  When you call save(), it applies for all dirty objects in the store, and when you call revert(), it applies for all dirty objects in the store.

To achieve this behaviour, you need to use the revertOnError property as an argument to the dataStore.save() function in applyEdit().  A slight side effect to this property is that the cell will not get redrawn if there is an error.  As a result, formatter is not called, and you don't get to see the red border until you go to a different page of data in the grid, and then go back.  To remedy this, you need to force a render with a grid.update() after assigning validationErrors to the target row in applyEdit().

However, if the user wishes to not attempt the fix the validation errors, and wishes to cancel the whole change, they can start editing the cell, and then cancel edit by pressing Escape.  I've added some code to the onCancelEdit action to revert if the row was dirty, and had validation errors.

dojo.connect(grid, "onCancelEdit", function(rowIdx) {
    gridTooltipEnabled = true;

    // if canceling editing and previously had errors, clear the errors and revert
    var item = grid.getItem(rowIdx);
    if (item) {
        if (dataStore.isDirty(item) && item.validationErrors) {
            // would rather revert the individual item, but this will do
            dataStore.revert();
        }
    }
});

As mentioned in the comments, I would rather just revert the individual row, instead of reverting the whole store. To do this, I have a feeling I would need to perform an explicit fetch on the item, and replace the dirty item in the store. I'll keep it simple for the moment.

There was a Dojo bug I had to apply a workaround for, when using the revertOnError property.  JsonRest.commit() has a bad reference to a dirtyObject variable that doesn't exist.  Simply changing it to dirtyObjects doesn't work either, but the bug reporter was good enough to provide a patch that did work when the problem was reported almost two years ago.  Unfortunately, this means that I'll never be able to use this with a CDN, and I'd need to patch and rebuild the Dojo 1.6.1 distribution.  My next task will be to upgrade this to use Dojo 1.7.1 (or 1.7.2, if it has been released by then).  Hopefully this bug will be fixed by then, or perhaps I'll be able to bump the ticket.

Well, that was my first look at Dojo, and in particular, the DataGrid and JsonRestStore.  I'm hoping that all the tutorials get an upgrade, the documentation improves and show stoppers like no local custom modules with CDNs are fixed before too long.  Even though this was just baby steps, it still seemed like I had to delve to an intermediate level to get the functionality to a point where it would be useful.

If  I can get this working with the 1.7.1 CDN, then I'll load the example to GitHub.  I'll also do an article on the CakePHP plugin that assists with JsonRestStore paging.

Tuesday, December 20, 2011

MySQL Schema Diffs

MySQL Schema Diffs. This particular issue crops up at the end of every project, so this is more of a note to self. You might find it handy, too.

Initially, I used to do it the hard way. A PHPMyAdmin export of the old schema (from the production release), and a similar export from the development release. Then do a compare, usually in Eclipse using the Compare To Each Other, and manually parse the file to generate a migration script. Yeck.

For a while, I was using DBSync, an online tool that took the two MySQL SQL dumps as input, and would generate SQL to perform a diff. While it worked, it worked fairly well, though for the last year, it has been reporting an error when trying the create the first database. Your mileage may vary.

Failing that, I had to go back to hand written SQL, however, every time I come across the issue, I do a little more research, to see if anything has changed.

Well, this time I got lucky. It turns out that the MySQL Workbench can generate the schema diffs I'm after. It's just a hard option to find. I actually found a guide at Simpcode that covers 5.0.22. I'm working with 5.2.36 CE, so here's how I do it.

  1. Get the scripts of the databases that need to be compared. I still fall back to using the PHPMyAdmin SQL dumps, making sure to not export the AUTO_INCREMENT value.

  2. Run Workbench. Close any Physical Schemata, if any.

  3. Select Create New EER Model to open the MySQL Model view.

  4. Select File > Import > Reverse Engineer MySQL Create Script...
    Select the SQL script for the new database, and select Execute.
    When the populated database view is shown, you may need to select a table in the view. Occasionally, I've found that I don't end up with the diff that I'm after. The 'default_schema' schema, generated by this import ends up getting dropped, and replaced with a 'new_schema' or 'my_schema' schema, created by the next step.

  5. Select File > Export > Forward Engineer SQL ALTER Script...
    Select the SQL script for the old database as the Input File.
    Leave the Output File blank, and select Next.

  6. After a couple of seconds, a script containing the differences will be created.
    Select Copy to Clipboard to copy this. Paste as a migration script.
    Select Cancel to close the window.

    If you don't have a proper diff, it is possible that an existing schema may have been opened. In this case, close Workbench, and start again.

  7. Remove the schema name from the CREATE and ALTER TABLE commands.
    Insert newlines before the ADD COLUMN clauses for readability.
    Double check any DROP INDEX clauses to make sure they are not accidentally being removed.
Even though I'm using CakePHP (only 1.3 in this particular instance), and Capistrano for deliveries, I'm not comfortable in handing over my schema migrations to an automated process that could be used in CakePHP and Capistrano.

Monday, October 24, 2011

CakePHP 2.0 : Autoloading Classes

The CakePHP 2.0 migration guide talks a lot about autoloading of classes.  For users of CakePHP, not much as changed.  There are just some new rules to follow when dealing with loaded classes.

Here are some guidelines that I'll be following:

  • When dealing with models in a controller, use $this->loadModel().  This should be nothing new.  If you're in a component, and have a reference to the operating controller, then $this->Controller->loadModel() will be more your style.
  • When dealing with models everywhere else, use ClassRegistry::init().  In fact, unless you need to load the model in to your current instance, $MyModel = ClassRegistry::init('MyModel') should be the usage.
  • When referencing a class, use App::uses().  Let us say that you have a model that needs to access a library that is going to do some REST, RPC or SOAP calls for you.  Before the class definition, you might have App::uses('MyRPCLib','Lib');  and in the code, you need $MyRPC = new MyRPCLib();  Autoloading only loads the class, it does not instantiate it.
  • When referencing a file that does not have classes, use App::import().  Usually used for Vendor files containing functions.
If you're finicky, you might also have App::uses('ClassRegistry','Utility'); at the top of any file using the ClassRegistry class.  However, if your application has any models defined, then chances are, ClassRegistry has already been loaded, as a part of the Model class.

It is highly recommended to have App::uses('ClassRegistry','Utility') at the top of any file using the ClassRegistry class.  In fact, it's highly recommended to have an App::uses() statement for any class that has not been previously seen in any given file.  This becomes relevant when you are setting up tests, and your component tests don't know where to load the Component class from.

Thursday, October 20, 2011

Preparing for CakePHP 2.0 : Views

CakePHP 2.0.0 has been released for a couple of days now.  I've been watching it go through the release candidate releases, but I haven't got my feet wet, or hands dirty until yesterday.

For anyone considering converting their CakePHP 1.X app to CakePHP 2.0, I recommend reading the migration guide, then reading the manual, from start to finishing, then read the migration guide again.

As a learning exercise, I'm converting one of my smaller projects to CakePHP 2.0.0.  I think I may have even skipped CakePHP 1.3, and jumped straight from CakePHP 1.2.

I've been following the migration guide, and as awesome as it is, there's so much stuff to think about.

So far, my approach has been as follows:

  • Delete the old cake directory, and global vendors and plugins, if they're empty.
  • Add in the new lib directory, containing the new Cake directory, and the global vendors and plugins directories.
  • Rename the app directories to match the new naming conventions.
  • Move app_controller.php to Controllers.
  • Update the Config files such as core.php, bootstrap.php and database.php.
  • Rename the controllers, components, models, behaviours, datasources, and helpers to the new naming convention.
  • Get a basic screen working! For me, that was the login screen, and even then, it was only the GET side of things that I wanted to get doing.
Make sure you're using some sort of source control, and check in after each step, or as often as you feel you need to do.  

If you're using Git and Windows, watch out for directory renames.  I ended up in a strange situation, where my app/config directory was split into app/config and app/Config in Git, even though there was only one app/Config directory on disk. I temporarily renamed to app/Configs, committed the change, then changed it back to app/Config.  That seemed to do the trick.

After getting the GET side of the login screen going, I've decided to convert all my Views first.  View conversion is fairly standard.  Even if you're not converting to CakePHP 2.0 right now (you're waiting for the first point release, right?) here are some things you can start doing now to make the conversion easier.

  • Stop using e(). It's gone in CakePHP 2.0, so just use echo.  There are a whole bunch of other functions that are going the way of the dodo, so perhaps hunt them down, and use PHP native alternatives now.
  • Start using echo __('Text', true); for your translatable strings, instead of relying on the echo inside __().  When you migrate, you can remove the ", true" at your leisure.  This is quicker than having to insert echo.
  • Stop using local variables for helpers.  You might have been in the habit of using $html->link().  You'll want to stop that now, and use $this->Html->link() instead, since the former won't work in CakePHP 2.0.
That's about all I've been doing with my views for the moment.  I've also been enjoying __() acting like sprintf(), and I've been able to remove sprintf() statements in quite a few places.

One of the things you can't prepare for is $this->data becoming $this->request->data, but that should be a search and replace.

One thing I'm not going to enjoy is converting the LdapDataSource to CakePHP 2.0.  Hopefully it shouldn't be a big deal, but it plays an important part of the login process.  Actually, it looks like CakePHP has an LDAPSource, but the conversion it not completed.  That might be a golden opportunity to contribute something back.

Thursday, October 6, 2011

Website Design : Things a programmer doesn't see

It's a bit of a misleading title, since I'm not actually going to give you a list of things that a web programmer doesn't see when it comes to web design.  That is firmly in the domain of "I don't know what I don't know", and I don't know web design.

But the chaps over at Primate do.  And I'm continually impressed with their contributions to expanding my knowledge of web design on their, for want of a better term, community site, 8 Gram Gorilla.

I've been following the gaming blog of one of the founders, Gordon, for some time, so when I saw that he'd started his own company (well, it might be a joint venture) and then put together 8 Gram Gorilla, I got very excited.  Gordon is quite an engaging blogger, and seeing that he also does web design (actual design, not just web programming code monkery*), I get a warm feeling like I'm witnessing brilliance.  If I was still working in the UK, I'd want to work for those guys.  Not sure that they'd take me with my lack of Ruby experience, but geez, it would be worth dropping tools for a few weeks, just to make a solid dent, and wrap my skull around those Ruby code blocks.

Any way, the gorilla has given me Compass/Sass this year, and now it's given me the grid system, from this article.  And not just one grid system, but two!  960.gs and 978.gs.  I didn't even know these were a thing!  The Holy Grail is nice and all, but I could have been using a grid system to position elements in a layout.

And now, having read a bit about these grid systems, and the tools that they provide for changes in CSS, particular when it comes to variable browser widths (like when you rotate your phone, and expect everything to make use of that extra width), the bubbles are beginning to form in my mind.  I've got some projects coming up, some changes to apply some of this grid system brilliance.

The question on my mind now is "What is best practice for using Compass/Sass and external CSS like 960.gs?".  Do you rename the CSS supplied by the grid system to .scss, and have it included in your Compass/Sass build?  Or do you keep the two separate, and define yourself a rule that your own CSS should never ever reference the classes supplied by the grid system.  Maybe this is a question for Stack Overflow.  But not tonight.  It's getting late, and my cockatiel has been waiting patiently on my shoulder while I read about web design and grid systems, and then blog it all.

* Monkery: Monkery is to monkey, as dickery is to dick, the type of dick that Wil Wheaton will block you from his Twitter and Google Plus for being.

Thursday, September 29, 2011

Plugin Models with CakePHP

I don't do plugin development with CakePHP much.  But here's a tip for young players.

When defining relationships in a plugin model, remember to include the plugin name in the className parameter, even if it's for a model in the same plugin.

Personally, I think you should only need to do this if you are using referencing a model in another plugin or in the main app. i.e. 'className' => 'App.CoreModel'.  This would make transitioning an app to a plugin, or visa versa not require much maintenance.

Friday, September 16, 2011

PHP Programming for Beginners

Sometime soon, I think someone is going to ask me for some tips about breaking into programming.  This person has an engineering background, but that's about all I know for the moment.  So this post is a bit of a pre-emptive answer on things that I think someone looking to get into programming should take a look at, as a part of a self training exercise.

But first, a bit of preamble.  In late 2004, I moved back home to Australia from the UK.  I'd been doing Progress Webspeed while I was over there, and had done a small project using PHP in my final month.  When I got back, I was determined to change programming languages.  I wanted to do Java.  I'd been wanting to do Java since about 1998 when I started my first web development project, an internal contact management system.  Whilst my specs for functionality in the project were approved, my choice of programming language was not.  I had to use Progress Webspeed, and it was very early days for that product.

Fast forward to 2004, and it was time to have another crack at breaking into Java.  By this time, I had nine years of software development experience under my belt, and a better understanding of the web.  I just needed to work out how to fit Java into that, in a practical way.  A good friend pointed out a few technologies to learn. Spring Framework with its Inversion of Control, Hibernate for database abstraction and JSP for the web pages.  So I spend a few months learning those things, and managed to land a contract doing Java with those technologies.  On the job, I also learned a bit more about Spring, a practical, but narrow application of MVC and the SunONE server, and how to deliver Spring and JSP functionality in Portlets.

Somewhere along the line, as a part of the contract, I delivered a content management system in a shared hosted environment.  That was done using Joomla!, and a very nasty but useful arrangement of soft links to allow upgrades across 240 sites at once, across 3 web servers.  And with this, I started to learn about PHP again.

In late 2007, I left that contract and started at my current job, doing PHP and web development as a full time role.  I remember fondly of those days spent programming in Java.  Strict types, IDE assisted refactoring, IoC and MVC.  It seemed to be a golden age.  Then annotations started to take hold in Java, for Spring, for Hibernate, for code injection.  And I was thrust into a world of legacy PHP code, and flat file structures.  It seemed like a return to the dark ages, and all that great Java knowledge was going out the window.  But the lessons are the same, and I hope to impart a few of those to anyone willing to read.

This tech, I do impart.



Since it's PHP I'm doing these days, I'm going to assume that's what you're interested in too.  And since I'm doing web, well, I'm going to focus on that as well.  And if you're interested in neither of those things, stick around, because there are some things any any programmer should be doing.  I might even knock those off first, just so you don't have to read to the end.  It's a warning.  If you haven't checked your scroll bar yet, this post could get lengthy.  About as long as my attention span.

So, before we even start with the actual programming stuff, I recommend you look at source control first.  Source control is how you record changes to your code, and share your code with others in a team, or even as third party contributions.  I strongly recommend Git.  It's light, it's free, it's available for all three platforms, use it.  It's a distributed source control tool, so you don't need to be online with a server (like SVN) to commit changes.

Next off, document!  Document your stuff.  Have a docs directory in the root of every project you do, and put stuff in it.  Put plain text documents in it.  They make it much easier for source control.  Maybe use a markdown format, maybe use a LaTeX format (nice for generating PDF manuals later on).  Just make sure you document.

Learn MVC.  That's Model-View-Controller.  Even if you haven't picked up programming language to use yet, most modern programming languages that you are likely to use are going to be able to support this coding arrangement.  Done well, it will help separate programming concerns, and make life easier for you.  Done badly, as long as it's still MVC, someone else might be able to refactor the code and make it look nice.  If you're playing in the Java world, you may want to investigate IoC as well.  That's Inversion of Control.  Good for configuration based frameworks.

Learn a Framework.  You might start looking at the MVC stuff, and baulk at the thought of having to implement a dispatcher to make use of all that MVC stuff.  Chances are, someone else has done it for you.  So pick a framework that implements MVC.  For Ruby, I recommend Ruby on Rails (is there anything else?) and for PHP, I recommend CakePHP (there are plenty of others). For PHP, you could also go with Symphony, Kohana, CodeIgniter, Yii or Lithium, just to name a few.  Some are PHP 5.3 only, some have hang ups from PHP 4.2, and haven't fully gone OO with all of their code.  For Java, my knowledge isn't really current, so I'll recommend Spring Framework, if it's still kicking around.  I remember something called Seam (from jBoss, I seem to recall).  Perhaps look that up too.  If you've gone down the Microsoft path, I guess .NET is going to be your bag.  But even that is not going to force you to use MVC.

Learn a development methodology.  Even if it's just the basics of requirements, design, development, development testing, user testing, documentation and delivery.  There's agile programming, rapid application development, test driven programming, the general umbrella of extreme programming, and the old "reliable" waterfall methodology.

Use your online resources.  Google has always been your friend, but I'm finding StackOverflow to be even better for specific programming questions, and awesome answers.

And I think that's about it for the programming agnostic stuff.  For those that read on, we're diving into the shallow end of PHP web development.  My attention span is waning, and it's 12:20am.

So, so far you've got Git for source control.  Next, you'll want an integrated development environment (IDE) to do your development in.  Something with syntax highlighting, something with a little integration for source control.  Some people get away with Textpad, or Textmate.  I'm going to recommend Eclipse with PHP Development Tools (PDT).  These also Aptana, which is based on Eclipse, which works well too, and takes care of the Git integration, using EGit, but you can install EGit separately if you want to.  I tend to use msysgit, and mix it up between the GUI and the bash shell.

Next, you'll want a PHP version.  In fact, you'll want a whole web server, PHP, MySQL stack.  Depending on your platform, there's LAMP (for linux), XAMPP (from Apache Friends on Windows), WAMP (also on Windows) and MAMP (I think that's what it is called, and it's for Macs).  I used to run XAMPP, then tried WAMP.  These days, I'm running a hack version of WAMP configured to run two Apache instances at the same time, to target PHP 5.2.17 in one, and PHP 5.3.6 in the other. (Oh, look at that, it's up to 5.3.8).

Officially, PHP 5.2 is no longer supported, but many web hosting companies are still running it.  I'm not sure what the take up of new languages features for PHP 5.3 in the frameworks.  I know Lithium only does PHP 5.3, using namespaces quite heavily.  CakePHP doesn't use any PHP 5.3 specific features yet.  CakePHP 2.0 (RC1 at the time of writing) supports 5.2 and 5.3.  I'd recommend know where you are deploying to, first, before making a decision of which PHP version to go with.  However, given a choice, definitely go with PHP 5.3.  All the online doco assumes PHP 5.3.  The online doco, BTW, is one of the winning features of PHP.  Sure, function calls don't have a consistent naming strategy, but at least there's some sort of documentation for most functions, with somewhat helpful, user contributed comments.

You may want to learn a bit of SQL.  Specifically, you'll probably be using MySQL or SQLite.  The cool kids are playing with simple, document driven databases like MongoDB or CouchDB.  Start with a relational database management system (RDMS) first, and learn about database design, normalization, primary keys, indexing and redundancy for performance.

Then start looking at your web technologies.  At a high level, it's HTML, CSS and Javascript.  Specifically, it's HTML5, CSS3 and Javascript.  Anyone running a browser that doesn't support HTML5 needs to get a new browser.  Web standards won't move forward, if we're all living in the past.

For HTML5 editing, just use the text editor.  Actually, first, read Dive Into HTML5.  Then use the text editor.  You may have heard about Frontpage.  It no longer exists. There's a reason for that. Don't use GUI HTML builder thingies, or zombie jebus will kill you in your sleep.

For CSS3, you'll be using a text editor again.  But you might like to spice it up with either SASS or Compass.  Since Compass uses SASS, that might be a nice place to start.

For Javascript, again with the text editor.  However, a framework is nice.  I'm going to recommend jQuery.  It's awesome.  There's also MooTools, DoJo, Prototype and script.aculo.us.  For JS based UI stuff, I tend to mix it up.  Usually, I use a bit of jQuery UI, but it really needs a lot of work.  ExtJS from Sencha looks really good, but it's not free for commercial use, and the dev team can be a bit abrupt with the newbies.

Then get a modern browser with decent debugging tools.  IE9 has finally caught up to Firefox and Chrome, but I'd start with the latter two first.  These days, I use Chrome for all my development, but you might like Firefox, and particularly the Firebug and WebDeveloper plugins.

It's 1am and I'm fading fast.  What have I forgotten?

Oh yeah, the PHP Framework.  Use CakePHP!  To see a pretty good application written in CakePHP, check out Croogo.  It's a CakePHP based CMS that you can extend any way you want to.

Okay, I've got to head to bed, and I've got a feeling that I've only scratched the surface.  If there are items you'd like me to expand upon, leave a comment, and I'll do some follow up posts, looking at things in a little more detail.

TL:DR. CakePHP, Eclipse, HTML5, Chrome, Git, jQuery, MVC.

Thursday, August 25, 2011

To Haml or not to Haml

I think I'm going to be standing quite alone when I say that I'm not much of a fan of Haml.

I've been in a but of a technology rut recently, with PHP, so I've been looking for new things.  In the past couple of weeks I've found Sass (via Compass), HTML5 and Apache Solr.

While Sass is awesome, and Haml seems to be a similar thing, but with HTML and Ruby (you can get PHP versions of Haml), I'm a little unconvinced that it's right for me.

I guess, playing with CakePHP, I'm finding it hard to see how that's going to flow nicely.  CakePHP splits files up in to layouts and views.  I haven't looked at Ruby as much as I should, but think Ruby may have done something similar.  Then, you'd normally use CakePHP Helpers, and specifically, the Html helper to generate form tags to assist with the auto magic of creating the right name attribute values to populate $this->data on the way back in.  Perhaps that's were Ruby on Rails and CakePHP differ.  Perhaps Rails doesn't have, need or use helpers and special name values for population in the controller.  That's one of the things I'm not a fan of, anyway. [Update: Here's an example of Haml and CakePHP in action.  It's a 4 year old reference, and I'm  only just hearing about Haml now. I guess Haml is perhaps just starting to reach critical mass.]

The next thing is the indenting style.  It might work for some, and I've know Python practitioners who sing its praises, but the indenting thing doesn't flow nicely in my eyes.  Sure, I indent my code, but I'm always looking out for { and } or similar constructs to tell me when the block starts and when the block ends.  You might also guess that I prefer the .scss style when I use Sass, because of the available blocks, and that is looks closest to natural CSS.

And lastly, well, I can't help but compare it to Smarty.  For a while, I thought Smarty would be my saviour for a template language.  You still have HTML, and a Smarty specific template language that "should" be easy for programmers and designers to learn, should they take the time to do so.  But that's the assumption that breaks the camels back.

The designers I work with aren't interested in working with a template language.  They're not even all that interested in cutting HTML or CSS.  They come up with an information architecture, website layouts, navigation and all the detail ends up getting captured in a Photoshop file.  Then I take that file, pull it a part, and turn it into HTML, CSS and whatever Javascript is necessary for the moving parts that a static Photoshop file doesn't capture.

So Haml ends up being another template language primarily used by programmers, not designers.

Though if you're a designer, and you're using Haml, then hats off to you.  Because you've probably had to learn about the language that hosting Haml (probably Ruby, maybe something else), controllers and views.  Here's hoping you didn't have to mess with models or complex business logic, because even just having to learn a programming language, and Haml, just to produce HTML is going beyond the call of duty.

At least Sass makes sense.  You can take a .css file, rename it to .scss and have it successfully parsed.  And then you can go to town and simply that .scss to make it easier to read.  I'm not sure you can do that with Haml.

Anyway, tune in, in a years time, when I've taken up Haml just the confuse the next person who has the maintain the HTML after me.

Wednesday, August 24, 2011

Up

Sometime in your life you may have experiences a feeling of vertigo, a sinking pit in your stomach, a fear filled with dread, accompanied by the phase "Oh gods, what have I done?".

Well, I'm getting married this coming Saturday, and there's no place for those kinds of thoughts this week, or next week, and any other time soon after that.

Caught up in that hustle and bustle of wedding preparations (which has been done most admirably by Annika) is the acceptance of other stuff that you'd normally take a step back and appraise with a discerning eye.  On of those things in the challenge of Up; a push up competition for the amateur.

From the 20th of October, 2011, I'll be doing push ups on a daily basis, until I hit an achieved goal of 10507.  I'm estimating this will take about 4 months to complete, if I keep at it every day.

If you'd like to join, or even observe, there's the public Facebook event and the #10507 hash tag.

Wednesday, July 27, 2011

Croogo, you yummy little CakePHP tart

I've been working with CakePHP for a while now.  Certainly not in at the ground level, since my first recorded usage is with CakePHP 1.2.1.8004, back in January 2009.  Since that time, I've been involved with the development of 7 projects that use the PHP MVC Framework, with most using in wholesale, and a couple to drag their legacy or CodeIgniter based butts into a land of comfortable OO MVC.

Most of these projects have involved providing basic CMS capabilities, from which I've ended up copying improved portions from one project to the next.  I've never bothered with plugins before, since portion of functionality had to be ready for anything that the particular project required.  It was always easier to copy what worked in the main application than develop a plugin that may or may not get used without taint from the application that required it.

At the start of this week, a team member referred me to Croogo, an open source CMS written with CakePHP.  At first, I was a little curious.  I'd only heard of one other CakePHP CMS, and that was Wildflower.  At the time, it was early days for Wildflower, and I needed something that worked out the box.  I guess with the CakePHP knowledge I have these days, I'm probably a little more at ease with third party CakePHP software.

So, this morning, I decided to take a little bit more of a look at Croogo, and its inner workings.  Oh my, I'm impressed.  It seems to have all the basics that I'm looking for in a CMS, and none of the cruft.  Content, menus, authentication, roles, contacts and a template system that any PHP developer would be comfortable with.  And by the looks of things, extensible!  You can create a regular CakePHP plugin, add a few file descriptors here and there, and you've got a Croogo compatible plugin.

I'm very impressed, and very excited.  Already, I've got two potential projects that I'm thinking of implementing Croogo for to provide basic CMS functionality, and then I'll create plugins to handle the parts that make the applications unique.

No doubt I'll have a few articles before the end of the year for things like extending the authentication, and adding application functionality to the CMS.  There are probably articles out there that do this already, it's just very early days for me.  Did I mention I was excited?

Back it up, pack it in

Note to self:

Next time I upgrade Eclipse from one major version to the next, also take a backup of the workspace, so that I can hook that old version of Eclipse in to it, if I need to.  It may not be able to read from the projects that are there, if they've been opened and converted to the new version, but at least I'll be able to tell quickly which Eclipse plugins I've installed in that old version, and where I got them from.

Monday, July 11, 2011

Meeces to pieces

Some one get me a cup of concrete.  I need to HTFU.

We found mice in the house on the weekend, so I purchased a couple of traps on Sunday.  Having pets already, getting traps that poison wasn't something I wanted to get.  I've seen the effects of RATSAK on a cat, and it's not pretty.  I don't want to inflict that sort of pain on a mouse, either.

So I got one of those live capture traps.  There's a ramp or two that let the mouse go in, but they don't get to leave.  Apparently, these traps will catch up to 10 mice at a time.  We've also got the ultra sonic emitters, too, but apparently they're a bit useless, since mice get used to all sorts of annoying sounds.

On Sunday night, we caught the two that were inside.  Here's hoping it was the same two from Saturday night, anyway.

And then tonight (Monday), I inspected the trap I laid downstairs.  It's a fairly open area, so the presence of mice is not surprising.  The more I think about it, the presence of mice down there is a given.  Anyway, four of the little buggers.

My release method is a little naive.  I go to the front of the driveway, and let them out.  Hopefully, they become someone else's problem.  More than likely, they'll just make their way back to my place.

I did see an article for a trap that involved a string on a stick, over a bucket of water.  I'm not plused about drowning either, but it beats prolonged agony of poison, and is a bit more permanent that catch and release (unless I drive them a distance down the road).

Anyone got any practical experience with live mouse disposal?

Monday, July 4, 2011

Magic words

I've got a list of magic words on my whiteboard at work.  If you ever find yourself saying any of these words, train yourself to have alarms bells going off in your head, and re-examine your statement for facts and sanity.

  • surely
  • maybe
  • assume
  • thought
  • hopefully
It's just a short list, easy to remember.

Thursday, June 23, 2011

I like the old stuff better than the new stuff

I've been listening to a few of my old favourites on my iPod, but there are a few tunes that never made it back on to the iPod after the great crash of 2008 ( or was it 2009, hard to remember).

Anyway, I went downstairs this evening and raided the CD collection, in search of a few other old favourites.

For my listening pleasure, the following will be ripped into my iTunes library, if not placed on the pod before the night is done.

  • Dinosour Jr, Where You Been
  • Prodigy, Fat Of The Land
  • Rage Against The Machine, self titled
  • Soundgarden, Superunknown
  • Eels, Beautiful Freak
  • Custard, Loverama
  • Live, V
  • Custard, We Have The Technology
  • Custard, Weisenheimer
  • Triple J Hottest 100, Volumes 1 to 5


The Triple J ones might not make it on the the pod tonight. I like to do a rename with collections like that, so they appear as TripleJ in the artist list, but have the artist in the song title. 10 CDs with usually 16 songs a disc is a lot to go through.

I still need to track down Eels, Daisies of the Galaxy and A Perfect Circle, Thirteen Steps. I used to own Powderfinger, Odyssey #5, but I think that took up residence somewhere else.

One day, the whole of the collection will make it back on to the pod.  I better remember to make a proper back up of it this time.

Saturday, May 28, 2011

Overriding Helpers in CakePHP 1.3

CakePHP 2.0 will sport an exciting new feature where you can change the alias of your helpers to something else.  For example, you've extended the FormHelper to automatically include JQuery UI classes for relevant widgets.  Instead of having to rename $this->Form in all your views to $this->JQueryUIForm, you can specify an alias that the helper should be loaded as, and override the default $this->Form.  Awesome!

But I can't wait for CakePHP 2.0 to be released.  I want to do it in CakePHP 1.3, and here's how.

First, if you extend an existing Helper, you'll need to make sure the original class is loaded before your extended class is.  For this, I've taken the lazy road, and have loaded Form, before my JQueryUIForm in the AppController.  If you wanted to be a bit neater, you could put a requires_once at the top of your extended helper file, just to make sure the definition is there.  I don't think you'll be able to get away with an App::import() for ClassRegistry::init(), because the base class will need to be loaded at compile time, not run time.

Next, add a beforeRender() to your extended helper. Grab the view for the context the helper is running in, and override the alias with a reference to your own helper. Job done!

class JQueryUIFormHelper extends FormHelper {
 
 function beforeRender() {
  $view =& ClassRegistry::getObject('view');
  $view->Form = &$this;
 }
   
 function text($fieldName, $options = array()) {
  $options = $this->addClass($options, 'ui-widget');
   
  return parent::text($fieldName, $options);
 }
  
}


I'm not sure that you'll be able to override the plain variable reference to the helper (i.e. $form->text()) with this method. Might have to have until CakePHP 2.0 for that feature.

Sunday, April 17, 2011

Minty Fresh!

I was very excited to discover that my local supermarket is now stocking Original Source Mint and Tea Tree Shower Gel.  I used to use this stuff all the time in the UK, and I've never been able to find something that even came close in Australia.

If you shower in the morning to wake yourself up (as well as get clean), and don't mind a bit of tingliness on your skin, then I thoroughly recommend this product.  They also have an extra strong minty version that I haven't tried yet, and will be looking forward to it greatly.  Is it bad to have two showers in one day?

Thursday, April 7, 2011

Excel AutoFilter and multiple criteria for a single column

I had a recently frustrating experience with Excel macros, AutoFilter and multiple search criteria for a single column.

For a single criteria in a single column, you may specify something along the lines of

Selection.AutoFilter Field:=1, Criteria1:="Fred"

To do two criteria, you can use an Or operator, like so

Selection.AutoFilter Field:=1, Criteria1:="Fred", Operator:=xlOr, Criteria2:="Barney"

But if you wanted to add more criteria to the search, you can not just tack on another Operator:=xlOr, Criteria3:="Wilma"

In my search for a solution, I found all sorts of wonderful kludges, involving multiple autofilters, saving range results and doing a union of those results.  Yeck.

The finally, I happened upon the xlFilterValues operator.

Selection.AutoFilter Field:=1, Criteria1:=Array("Fred","Barney","Wilma","Betty"), Operator:=xlFilterValues

Enjoy!

Wednesday, March 30, 2011

Maximum Compatibility My Ass

I'm looking at a welcome email I've been sent, for a website I need to join up for work related stuff.

In there is this notice, slightly modified to protect the website identity:
Please be advised that has been designed to operate with Internet Explorer being the software of choice.  Therefore to ensure maximum compatibility, please do not try and access via another Web Browser i.e. Safari or Mozilla Firefox
Have I mentioned how much it shits me when I see notices like this?

Maximum compatibility is when the website works on all browsers, not just that one that will support that nifty mouse over thing that you couldn't get to work anywhere else.

Perhaps "Therefore to ensure the website actually works, please do not..." would be more appropriate.

I'm sure it's just a throw away statement, anyway.  The primary users of the website are probably still running IE6 or IE7 on Windows XP machines anyway, and it's only pure luck that it still works under IE9, and would probably work just fine under Safari, Firefox and Chrome, if it wasn't for a Javascript or server side agent check that deliberately fails processing for any browsers other than Internet Explorer.

endrant;

Friday, March 25, 2011

Because 5.2 is the new 4.4 (follow up)

Just as a quick follow up from the previous Because 5.2 is the new 4.4 article.

Migrating to a VC9 Apache build ended up being a pretty simple thing to do.

Start with the initial VC9 Apache install from Apache Lounge, as recommended by PHP. Make sure you don't overwrite your VC6 build, if you still need it.

Then do the PHP 5.3.6 install.  For this, I didn't bother doing the web server setup, since I wasn't sure which installation of Apache it would end up modifying.

I then backed up the apache/conf directory, and copy the version from the previous apache version I was using for PHP 5.3.5 into the new apache install.  Then remember to update httpd.conf to point to the new PHP version.

I also did a compare of the php.ini files between PHP 5.3.5 and 5.3.6 using DiffMerge, so I could make sure all my major settings were the same, without missing out on any new directives that may have been introduced.

After that, I stopped and uninstalled the VC6 Apache build service, and installed the new VC9 Apache build service ("httpd -n wampapache2 -k uninstall" and "httpd -n apacheVC9 -k install", although that uninstall command will not stop the service before uninstalling it).

I'm sure many fun times will be had in the future when I start adding in the various PHP modules needed across the many projects I have, like Firebird, MS SQL, etc.

Thursday, March 24, 2011

Because 5.2 is the new 4.4

I was doing a quick technology update today, checking out some of the websites of some of the tech I was using in my day to day projects, when I came across the quote in the title.  It was found on the website of Andy Dawson, otherwise known as AD7six. It's referring to PHP versions, and how PHP 5.2 is going to be defunct.

Yeah, see that strike through?  My next visit was the PHP.net site, and with their announcement of PHP 5.3.6 is also the announcement that PHP 5.2.x is no longer supported, making PHP 5.2.17 the final stable release of the PHP 5.2 series.  This was announced on 17 March, 2011.

So what does that mean for me?  Well, all of my projects are written in PHP 5.2.  At a guess, none of our production environments are running the latest of the 5.2 series.  This means I need to come up with a development environment that can support both versions of PHP, and start doing new projects in PHP 5.3, and also migrate some of our maintained projects to PHP 5.3.

So, today, I started with the development environment task of running PHP 5.3 and PHP 5.2 at the same time.

First things first, you can not run two versions of PHP 5 in the same Apache installation.  So, my solution is to create two Apache installations on my machine.  Given that I use the office DNS to allow unique host names for all my projects, and I don't want to have to specify a different port for one or the other Apache installations, I opted for installing a second IP on my NIC.

When specifying a second IP, they'll both need to be static.  If your IP was previously dynamic through DHCP, make sure you take your nominated IPs out of the dynamic range, and document the static IP allocation.  Now go to your Properties for TCPv4, and specify the primary IP address, mask and DNS servers.  Then click Advanced and enter the second IP.  In my case, both IPs are in the same subnet.  Remember to enable NetBios over TCP if this was something typically enabled by your DHCP server.

Next, you'll want to configure your Apache installations.  Because each installation will be listening to a specific IP, you'll need to specify that IP where ever you see the Listen directive.

So in my primary Apache installation, I used to have "Listen 80".  I replaced that with "Listen 192.168.174.8:80" and because it's my primary install, I'd also follow this up with a "Listen 127.0.0.1:80" to catch localhost traffic.  Remember to do the same thing with any other Listen directives, including the SSL config file.

In my secondary Apache installation, I replaced "Listen 80" with "Listen 192.168.174.88:80" and did the same thing with the other Listen directives.

I make extensive usage of virtual hosts in my development environment.  I'm also lazy and copied my primary Apache installation to be my secondary Apache installation.  Make sure you comment out any vhost entries that you don't need, change any references to the old PHP version, to the new PHP version and copy the appropriate programs from the PHP install to the Apache/bin install.  If you use a PHPIniDir directive, remember to update that.  Also remember to rename any log files that may clash between the two Apache installs.

I had a bit of trouble with IP and port clashes.  I had port 7000 used in a couple of my projects, but had not altered the Listen directive.  To help see what was going on, I used the SysInternals TCPView to view what processes were listening to what ports, and which IP addresses they were bound to.  If you're still having troubles starting one of the web servers, try starting it from the command line to see what the issue is.  Also, when you install the second Apache install as a service, remember to give it a different name.

With my recent Windows 7 install, I've been using WAMP instead of XAMPP.  In this particular installation, I have PHP versions 5.2.11 and 5.3.5.  With the recent PHP announcement, I'll be looking to update to 5.2.17 and 5.3.6 respectively.  But here's the rub.

The PHP team have also announced that they will no longer be providing PHP builds using Visual Studio C++ 6.  It will all be done with Visual Studio C++ 9.  This means I'll also need an Apache install that has been built with VS C++ 9 as well.  At least PHP have recommended Apache Lounge to source this from, but it's going to be a major spanner in the works for the likes of WAMP and XAMPP who typically provide VC6 builds.

I'm not looking forward to doing another Apache install, just so I can update to 5.3.6.  At least the PHP 5.2.17 binaries will be staying at VC6, but have no option for VC9 (so you will need two separate installs of Apache, and wont be able to get away with copying one install for the other version of PHP).

Monday, March 21, 2011

Training with Astro

This Sunday just gone, we started a new training course with Urban Dog Training called Clicks and Tricks.

Clicks and Tricks is a bit of a fun training course where we use positive re-enforcement and shaping to teach our dog some new tricks, and to let the dog develop some new tricks for themselves by offering movements and behaviours.  The movements and behaviours that we find desirable are rewarded with an unambiguous click from a clicker, and are rewarded with food.

We've been using a clicker with Astro since we started Advanced Puppy Training with Astro about 5 or 6 weeks ago.  It's great for conveying a positive "yes!", for when he does things that we want to re-enforce, and is always accompanied by a high value food reward.  Whilst Astro is used to my "yes!" and Annikas' "yes!", he's not used to it from other people.  However, one clicker sounds much the same as any other clicker, and will allow relative strangers like our dog trainer to convey a job well done without Astro getting confused by the different sound in their voice.  And once again, each click must also be accompanied by food, if it's going to stick.

In training, our trainer Paul, was able to simply look at something, and have their dog Stevie interact with it in some manner.  For each movement or interaction that Stevie offered, he was rewarded with a click and some food.  Paul started Stevie down a path of interacting with a dropped key, with initial sniffing, then pawing and an end goal of picking the key up and returning it.  Stevie is a pretty smart dog, but even that would take more time than we had available in our 5 minute demonstration.  Nonetheless, he also had Stevie jumping up on to a bench and interacting with his crate.

Our homework is to have Astro interact with a box of some description, and then to bring that box in the next week and give a demonstration of what has been learned.

So last night, we had a little training session, interacting with our laundry basket.   Ideally, I'd love to teach Astro to put things in the basket, or move the empty basket around.  Astro loves taking off with socks!

Just by looking at the basket, and appropriately rewarding Astro, he got to a point where he was pawing the basket for rewards. Getting him to put things in the basket is a big task, so I'm going to be happy with a paw, nosing it around, and even jumping in.  The great thing about the exercise is that all these things will be behaviours that he has offered, instead of me showing how it's done or luring him.

And just to mix it up a bit, we also tried the same game with his new bean bag.  It's a bit full of beans at the moment, even though we've only put 2 out of the 3 bags of beans in it, but I'm sitting on it when Astro is in bed to compress them.  Anyway, we'd eventually like the bean bag to be Astros preferred place to sit inside, when we're watching TV and having some quiet time.  Very quickly, Astro offered jumping up on to the bean bag, and lay down on it.  Awesome!

After a few goes of that, I moved on to a netball that we'd got for him.  It's a cheap Crazy Clarks netball that's made from basketball material, so it's probably a bit harsh on his nose.  So far, he hasn't paid it a lot of attention.  However, it didn't take long for Astro to offer a paw on the ball to move it around.

Training sessions should be short, to keep the dogs attention.  I probably went for a bit longer than was needed, so after a quick revisit to all the toys we'd played with, I put the remainder of his reward food (chicken and capsicum) in his crate, but left the door open on it.

Astro has improved his behaviour in his crate, but I'd like it to be a place where he will hang out voluntarily.  Offering food in the crate will associate it with being a good place to be, not just the place where he has naps and sleeps at night.  To this end, every time I take him out for a bathroom break, I'll be putting 4 or 5 bits of kibble in his crate with him, when he goes back in, and I'll be making sure to let him in through the front door on the crate, instead of the roof.

Sunday, March 6, 2011

Pathway

I did a little bit of yard work today.  Mowing the lawn and laying some temporary pavers.  Sounds exciting, huh.

Pushed over by wind because of
fungus in the root ball.
That's our house in the background.
The lawn was a bitch.  I have a nice lawn mower that also does mulching.  Normally, it's great.  I just put the mulching attachment in, forget about the catcher, and mow, mow, mow with the occasional stop for fuel.  However, this summer has been pretty wet.  You know, Queensland floods and all that.  I've been pretty lucky.  A fast growing lawn and collection of weeds cut to look like lawn is the worst I've had to complain about.. oh, and there was that tree that fell and broke the back fence.

Anyway, so after a while, the mulching attachment doesn't cut the mustard, or the grass.  For the last month, I've had to put the mower up to the highest setting (10), to mow the pretty much most of the front yard.  Normally, the setting should be at 6, and I've been able to maintain that with the backyard, and a couple of spots out the front.  So today, the mulching attachment got side benched, and the catcher went on.  I guess you could say the grass was at about level 11 or 12.  It had been two weeks since the last cut, and it was getting reduced to 6.  I filled my garden bag that gets collected every month or so, and had enough spare for the compost tumbler and some dips in the fence line that I can't mow in because of the change in elevation.  Anyway, hopefully I'll be able to get away with the mulcher when I have to mow again, in two weeks time.

It's my pathway (and I'll cry if I want to)
So after that awesome fun, I decided to get a little temporary side project done.  And that side project is the front pathway.  We have a little dirt pathway that leads from the front corner of the house to the car port.  It had difficulty growing grass because of the high traffic, and every time it rains, it gets a bit muddy.  So today, I laid some pavers to provide us with a solid step and mud free walk, and to let the ground around it grow some grass, or weeds, or whatever can step up and grow there.  Lacking bedding sand, I just made do with the dirt and a little cut and fill to set them into the ground, so at least people walking down them won't stub their toes or trip.  But it's just temporary.

Despite having put a new bathroom in, and replacing the 40 year old roof, lifting up two crap driveways, and getting one good one with car port, and building a retaining wall down the side, there is still work to be done.

So this is the story of the work left to complete.  I almost have it memorized, and can get it out faster than the eyes glaze over (oh, and they do glaze over, eventually).  In some particular order, but not necessary the one I've used here the following needs to happen:
Redirect water from both back downpipes to the front
More drainage, a pathway and a new wall
  • The storm water drainage from the back of the house needs to be routed to the front.  At the moment, the back high side just flows to the back low side, tries to go down a drain, then bubbles back up and floods that corner.  I suspect it's a dispersion drain, instead of a proper storm water drain that's actually connected to anything, since I found similar happenings in the front yard when I digging the trenches for the storm water there.
  • While doing that particular bit of piping, I'll also put in a gravel pit and aggregate pipe running from the back to the front as well.  This will prevent water from collecting on the high side, then spilling over to flood the house.  But don't worry, the house is raised, and specifically designed to have water and air flow underneath it.  I'd just like there to be a whole lot less water flowing underneath.
  • The run off from the back retaining wall needs to be connected to the storm water also.  At the moment, it just bubbles up from the hole it comes out of, though it usually takes a lot of rain before it's noticeable.
  • A second mini retaining wall needs to be built, with perhaps a widening of the stairs that separates the current retaining wall, from what we like to call "The Rock Garden".  The Rock Garden is a collection of rocks, concrete, gravel, weeds and pepper tree.
  • Drainage from second retaining wall also needs to be connected to the storm water.
  • A water trap needs to be installed in the front corner of the car port, on its' high side.  All that water flowing from the high side of the property tends to collect along the concrete slab, that is the carport.  Luckily, we installed a join in the storm water pipe that runs along there, just in case this sort of thing should happen.
  • Rip up my temporary path, and the concrete path and replace the whole lot with gravel and very similar pavers that will run from the carport to the main entrance at the side of the house.
  • Replace rotting wood in side deck at the main entrance.
Anyway, that's the work I'll be doing sometime in the future, but not this year.  This year shall be a non-work saving year.  Yeah, right.  The trickiest part is going to be doing the back drainage in such a way that we don't have Astro digging his way out of the backyard.  And perhaps dealing with water that may not want to flow the way I want it to flow.  Fun times ahead, I'm sure.

(I had a bit of fun with Paint.NET, putting those pictures together).

Astro

Astro at Xmas, 2010.
It's high time I introduced Astro, our pet poodle cross American cross English spaniel, commonly referred to as spoodles or cockadoodles, depending on which side of the pond you're on.

We've had him since shortly before Xmas 2010.  Back then, he was a tiny 3kg, and a little ball of fluff.

Astro is lots of fun, but also a lot of hard work.

We go to Urban Dog Training.  So far, we've done Urban Puppy School and Urban Advanced Puppy School. He just graduated from his Advanced Puppy School today, but we've got to do a make up class tomorrow night, because we missed a class two weekends ago.  Today we started training in High Fives and Roll Overs using shaping.  We're going to enroll him in the next available Clicks and Tricks, which will be fun for him, and help us all do learning via shaping.

At night, Astro sleeps in a soft crate.  He takes a little while to settle, but once he's down, he's down.  Especially if he's been for walks or play groups.  I get the lucky job of staying up at late as possible to give him regular bathroom breaks.  I say lucky, because Annika gets to wake up early and let him out.  He's getting a lot better about holding on to his business until he can get to some place he's allowed to do it.

Astros' "uncle" lives next door as our back neighbour.  His name his Harvey, and one of his brothers from another litter is Astros' dad.  Harvey and Astro often have play dates together.  Sometimes Harvey is the fun police, but it takes a lot of energy to keep up with a boisterous puppy.  We've been surprised at how good Harvey is with him, because sometimes Harvey doesn't like to share.

We got Astro from Rivergum Designer Puppies.  We wanted to get a spoodle because of the lack of hair that they drop, and because Annika has dog allergies.  We really liked Harvey's nature as well.

We go to Greencross Vets for checks ups and vet stuff.  Moo Moo goes to the Brisbane Birds and Exotics for her vet stuff in the same building.

Today, he's a bit bigger, at 7kg.  Here are a couple of snaps of him, playing in the yard today.


A rare photo of Astro awake and still Because normally he's running around And making funny faces