Monday 1 September 2014

Save a zip file to a node.js server using node-webkit

It was so incredibly hard to do this. And it shouldn't be. So here's the code you need to do it.


nodeFileSystem = require('fs');
API.downloadItrData(newBook.isbn, newBook.version).then(function(response) {
    if (response.status === 200 && response.data.success) {

        var zipLocation = response.data.data.zipLocation;
        var zipSaveLocation = Constants.PATH_BASE + Constants.PATH_ITR_FOLDER + newBook.isbn + "/" + newBook.version + ".zip";

        $http.get(zipLocation,
            {
                responseType: "blob"
            }
        ).then(function(zipResult) {
                var reader = new FileReader();
                reader.addEventListener("loadend", function() {
                    nodeFileSystem.writeFile(zipSaveLocation, toBuffer(reader.result));
                });
                reader.readAsArrayBuffer(zipResult.data);
        });
    }
});

Ok, but what does the code do? Keep in mind this is just a stub, so this is more of a non-working example rather than code that can be copied and pasted into your work.

First, using an API, I check to see if my book (basically, an ebook) has an update. If it does, I take from the returned JSON to the location of the zip file (zipLocation), which I am going to save to the server (zipSaveLocation).

I then use the angular function $http.get() to download the zip. By setting the responseType in the config I can get the zip file as a "blob" instead of a string.

Once it has downloaded (the promise function .then fires) I use the HTML5 FileReader class to convert the JS Blob to a JS arrayBuffer so it can be converted to a Node.js Buffer so the node filesystem can save it.

I really hope this saves someone the 6 hours or so it took me to figure out :)


Tuesday 27 May 2014

Giving Back

So, after a long time between drinks, I've contributed to an open source project again. OctoberCMS. Let me explain why.

The first time was years ago, when I created a Joomla plugin called Menu Module Clone, to help users copy module settings between pages. At least, that's what I think it did. It's been a long time.

Recently, I've been keeping an eye on the php based CMS market. At work we went through a fairly rigorous process to narrow down the best CMS for our clients. Very very sadly, WordPress ended up winning. I say sadly because the code that it runs on is terrible. Joomla didn't get a look in as too many people didn't want it, and Drupal was just at the wrong point of it's development cycle for us to consider. If we'd gone down the road, would we have wasted a lot of time learning Drupal 7 before Drupal 8 came out? Probably. Especially since most clients just want a small site with a blog, and WordPress fits that bill very well.

Anyway, I digress.

OctoberCMS. It is awesome. At this point it is still in beta, and is definitely not ready for use in production. The sheer potential though is enough to get me very excited. So excited I ended up writing a plugin for it fill a perceived gap.

Menu Manager does exactly what it says. If you're interested, go and read up about it.

But why am I so excited?

I've done quite a bit of research over the last few months into the current state of the market. According to all the surveys I've seen, there are 3 big php frameworks. Symfony, Laravel and Phalcon. All 3 are pretty awesome. From where I sit though, doing very simple websites, I need a CMS rather than a framework. But because I also do love doing things the right way, I want it based on a modern php framework. There are quite a few CMS's built on these, but most are either based on old versions or are just not viable. Red Kite looked very promising, but the inability to get it running on my local Vagrant machine ruled it out. And I tried a lot of things.

However, when I found out about OctoberCMS I got more excited about coding than I had in a long time. And you should have seen me when I first found out how much nicer the sql will be with nested sets! It's backend structure is awesome and it gives you the ability to edit pages either in code directly or in the CMS. There is even inline editing.

You can also use markdown. But seriously?

So what have I learned writing my plugin? That I don't know how to use it mainly. But after scanning all the documentation and copying other people's code I'm finally confident that I can do basic stuff.

The only thing missing is to make this CMS a WordPress killer. I would dearly love to never use it again. I've also always wanted to get involved in an open source project, and I've finally found something that intersects with both what I want to learn and where I think I need to be to further my career.

So that's what I'm excited about. The change to get in at the ground floor on a new project that I think has the ability to transform the way we as a web development industry work. At this point it's just a plugin, but hopefully I can continue contributing and help the industry move forward.



Saturday 15 February 2014

Symfony Project on Ubuntu 13.10, using PhpStorm

This is far more complicated than it should be, and I've not found a reliable guide on it. But this is what we're going to end up with:

A Symfony 2 project running under a puphpet controlled virtual machine using Vagrant. We're going to be able to edit the project and run all the commands via PhpStorm.

Technically you probably don't need the Ubuntu bit ... but there are some specific gotchas in here. I've included the version numbers I've used in parentheses where applicable.


  1. Install Vagrant (1.4.2
  2. Install Virtual Box  (4.3)
  3. Use PuPHPet to create your manifest file. 
    1. Create 2 virtual hosts. One just for flat files to make sure editing our host works fine, and one for Symfony. I call them flathtml.vagrant and symfony.vagrant, so I know what they're referring to. 
    2. The document root for these is /var/www/flathtml/ and /var/www/symfony/ respectively.
    3. These map to the folders /var/www/vagrant/flathtml/ and /var/www/vagrant/symfony/ respectively. 
    4. At least, they will if I run Vagrant from /var/www/vagrant/.
    5. The mapping is taken care of automatically in the PuPHPet manifest, in the "Box Sync" section.
  4. Download those files to wherever it is you want the virtual server to be. I chose /var/www/vagrant/ 
  5. In the Vagrantfile, fine the line that starts with "config.vm.synced_folder" and add ":mount_options => ["dmode=777,fmode=777"]" to the end. Otherwise Symfony will not run.
  6. Using terminal, in /var/www/vagrant/, run "Vagrant Up"
  7. That should work after a while.
  8. Edit your hosts file "sudo gedit /etc/hosts/" and add your two virtual hosts to the file. 
  9. The ip address is your Local VM IP Address. Most likely you left it as 192.168.56.101
  10. Get a test site with flat html working within Vagrant. This ensures that your Virtual server works.
    1. I ran into a problem here once of not being able to get the flat html site working, because the IP address I was being assigned came from DHCP, or similar. The trick is to change the Vagrantfile networking section. I can't remember the exact details of that fix sorry.
  11. Once that is working, then we can start with Symfony
  12. In Terminal, type "cd /var/www/vagrant/symfony"
  13. Install composer by "curl -s https://getcomposer.org/installer | php"
    1. Personally, I like to install it in a central location, such as /var/www/includes/. 
  14. Now install Symfony by "php composer.phar create-project symfony/framework-standard-edition /var/www/vagrant/symfony/ 2.4.*"
  15. You may have to apt-get install php5-json as well.
  16. Now we can initialise the project in PhpStorm. We couldn't earlier as the create-project command will fail if anything is in the folder.
    1. Set up all your version control stuff now.
    2. I found this guy has some very good tips on setting up as well. In particular, steps 3-8.
  17. In app_dev.php and config.php, remove the lines that stop people on none localhost accessing. This will allow you to get to the configurator and make sure everything is working.
There are a lot more things you should be doing, but this is enough to get you up and running at least. I hope this helps someone.

Sunday 2 February 2014

PHPStorm, grunt.js and File Watchers

I had a pickle of a time getting grunt.js to work on my Mac. So eventually I gave up and decided to use PhpStorm's built in watchers to do my tasks.

I highly recommend you get this all working in Grunt first. Once things work as expected there, then you can set up PhpStorm.

Tested with PhpStorm 7.1.1, node 0.10.25, grunt-cli 0.1.13 and grunt 0.4.2.

Project Structure

In this project, we have a bunch of HTML sections that are baked together. For example, the header, nav, and footer are html files that are "baked" into a final file in the build directory. In a css subfolder we have all our css (/css/styles.less and /css/custom/, /css/vendor/ for Bootstrap) which are combined via Less into one final /build/css/styles.css file. And the JS files are also copied to the build folder.

LESS

This was by far the easiest. If you've already got this to work then you don't need any help. I simply had to change the default "Output paths to refresh" from "$FileNameWithoutExtension$.css" to be "$ProjectFileDir$/build/css/$FileNameWithoutExtension$.css" and it worked.

Grunt Tasks

This was the tricky bit, as I wasn't methodical enough. Assuming that you have installed grunt globally then the following settings will work. 
  • Name: Grunt Bake
  • Description: Builds HTML (obviously change these two to what you want them to be)
  • Turn off immediate file synchronization
  • File type: HTML files
  • Scope: Changed files. This is under VCS, probably at the bottom of the drop down. This stops the watcher being triggered when the file is created in the final build folder.
  • Program: On a mac, with grunt installed globally, it is /usr/local/bin/grunt. Run "which grunt" in your terminal to figure it out (sorry Window's users, I don't know the command for you).
  • Arguments: This is the name of the task. For me, I added this line to the Gruntfile.js. "grunt.registerTask('phpstorm-bake', ['bake'] );" Which means my argument is phpstorm-bake
  • Working directory: $ProjectFileDir$
That's it. 

It's beyond the scope of this article how to get grunt and it's associated tasks up and running. There are plenty of handy tutorials and documentation on the web for that already.