Sunday, May 31, 2015

Preparing for drupal 8

Why now?

It look like the drupal 8 betas are going to end soon. Last month there still were 40 critical bugs, it looked like there was no progress. But with beta 11 the critical bug count got cut in half!

This was a sign for me to get up to speed with the last developments. For that i'm using the great talk by Larry Garfield at last years drupalcon in Amsterdam.

Going through the motions

I have downloaded beta 11 on my windows machine and i'm using xampp to run it.

He said a controller can return a string, this seems not true anymore. I got an error the return should be a Response instance.

Installing modules aren't mentioned in the talk, but I got a strange error enabling the custom module. It appears to be a mysql setting issue.

In the routing.yml file he doesn't quote the path value, but it seems a lot of other modules do. So I guess it is a best practice to do so.

When he makes the module themeable, he uses the template folder. This generates an error saying you have to use templates.

This must be an oversight, the BlockBase class is in the Core folder.

Observations

Drupal 8 is major evolution for the platform. As Larry mentioned even drupal 7 is based on php4 practices, when it is almost ten years ago that php5 came out. It is my biggest gripe and drupal 8 wipes it out.

I'm not that found on the mix of yaml files and annotations for configuration, but splitting up the configuration is a developers dream after the hooks for everything way.

In drupal 7 it would have been more difficult to find the errors, but with the modern architecture errors made it easy to get to the problem and fix it. Goodbye common.inc, we won't miss you.

They didn't only modernized the architecture, they also added new default modules and an improved way of doing things, that make it an amazing content management platform.

With the mordernized architecture come great tools, instead of the devel module people have ported the web profiler from the symfony framework.

Questions from great readers

Why don't you use drush?

It looks like drush has still a long way to go to support drupal 8 on windows.

You need to use drush 8 to have drupal 8 support. There are a lot of articles that say drush 7 supports drupal 8, but drush 7 mentions otherwise.

When you install drush 8 with composer, the only way at the moment, the drush command doesn't work in the command prompt because it has linux syntax. The drush.bat command doesn't work either of the same reason.
The drush.php.bat command seems to work if you use it without parameters, but once you use it with parameters it can't find the tasks.

There is an alternative, drupal console. It works on windows.

Why can't I uncheck the custom module, once it's enabled?

It seems like a security measure to prevent a compromised data integrity. You can uninstall modules, so the unchecking hasn't disappeared.

Saturday, May 30, 2015

Code doesn't care who wrote it

Only people care

Computers just don't care.

I just saw a github conf post, and I was as thinking who cares?

My view

For all I know the code could have been written by an alien from starcluster 5574564, if it's code that is readable or at least has a predictability I love the programmer(s) that wrote it.

I know programming looks like it is a boys world, but I'm almost 40 so I am not a boy and I still surprise the boys at my current firm.
It isn't all about knowledge if you are a real programmer. You have to analyse problems and translate that into code.

I can understand the sociological aspect of hiring a programmer as HR but that it is human nature. You hire the people you can connect with. A more technical person comes in to evaluate that aspect. And when it is all smoothied you get the conclusion.

Small victory

While I'm not against focusing on groups that are statistically are under represented in the programming community. But showing that there are amazing people out there that need to get hired is great.

I believe people who do good things will get noticed. I am a cook/waiter if you only follow my school education. I work in IT for a little than 10 years now. I always improved my knowledge and sharpened my problem solving skills.

I will always try to improve myself, it has nothing to do with work. it has to do with the person I want to be, better stronger faster smarter, until the day I die.

Sunday, May 24, 2015

PHP 7 spaceship operator

Wait what?

The spaceship operator isn't a name for a language that wants to get enterprise credibility.

Take a pause, and look at it for a distance

The operator probably solves a problem many php developers face.

stackoverflow

Instead of only having a boolean check, it is a ternary check without the logic you need to write yourself.

One thing php as a language was always good at is solving real world problems, sometimes with flawed implementations, but they make it easier for others to understand the code.

epilogue

Don't be square and make your code php 7 compatible as soon as possible.

Friday, May 22, 2015

Lazy and hungry at night

It's been almost a week i'm riding past the barrio cantina site, so I'm really curious if food trucks can become a thing in Belgium.

It's too late foor clicking on all the links to see the food truck descriptions, so i open web tools and type in the console

Now I just read and dream of the food I will get in a few hours.

Saturday, May 16, 2015

HTML up and down

I just found a html to json parser, himalaya, and i though this needs a json to html parser.

It isn't fancy, but it gets the work done and it's readable.

Friday, March 27, 2015

How not to prove your php skills

I'm always interested learning about ways of doing things. So when I came across an article about routing in php I was curious.

And then I saw the code.

32 lines to get one route?

The getCurrentUri function does 'magical' things with the SCRIPT_NAME and REQUEST_URI server variables.
The first thing I thought of was why don't they use the parse_url function?

And then it got worse on line 14 and 15, two $routes variables?
The idea is to get a array of the url segements. Line 15 is enough.

Now we are getting to the meat, the actual router. It reminds me of the time I used an asteriks in sql queries and referred to the fields as numbers, because I'm too lazy to type their actual names.

Because I was so outraged by this abundance of code, I wrote my own.

On line 3 you see how I get the path from the server global. For some reason PATH_INFO isn't set anymore, but REDIRECT_URL has the same value.

And then I'm doing my magic. Looking for the /search/book segments, stripping them when found and echoing everything that comes after them.

From 32 lines to 3, that is amazing!

PS: I commented on the article first but that was two weeks ago. My voice must be heard!

Sunday, March 15, 2015

How (not) to use SPA software

I see more and more solutions on what shouldn't be a problem in the first place, SEO of pages.

As a developer I understand wanting to use the new and shiny things. But that is a poor excuse to make them an hammer, because everything is a nail.

Google is getting a lot of attention with its angular SPA framework. It's strange that they as an search engine started to guide people to misuse angular by adding escaped_fragment to the url for crawlable content.

Because it's a google only solution people turned to server rendered SPA content, an example. The author of the example uses the term isomorphic javascript in a too narrow definition, but that is another discussion.

The keyword in the acronym is application. An application by definition is dynamic and therefore SEO is not an issue.
A website is static, don't be fooled by the dynamic backend, and SEO is very important.

So don't make an application of a website.

Tuesday, February 10, 2015

An alternative to the laravel 5 contact form

Introduction

I was reading the contact form tutorial, and after that I'm trying to get the tutorial working on my pc.

There was a bit of information missing, but that's because the writes wants you to buy his book. And there are a few ways the code can be written different.

Get on your marks, GO!

If you don't know how to install laravel, check the excellent documentation.
To run the development server, run php artisan serve in the command line.

alternative routes

Laravel has a way to prefix the controller methods with the http verbs, they call it implicit controllers.

In the file app/Http/routes.php you add the line Route::controller('contact', 'ContactController');.

To create the controller, run php artisan make:controller ContactController --plain.
The --plain parameter creates the controller without methods.

The controller

You can ignore line 5 and 6 for the moment, they will be created later.

Add the lines 10 to 23 to your controller.

To get the getIndex method working the index.blade.php file needs to exist.

index.blade.php

This file has to be created in the resources/views/contact directory

The missing information in the original article is to make the Form methods work.

  1. Add "illuminate/html": "5.*" to the required section of the composer.json, and run composer update
  2. Add 'Illuminate\Html\HtmlServiceProvider', to the config/app.php file in the providers array.
  3. Add 'Form'=> 'Illuminate\Html\FormFacade', to the file above in the aliases array

intermezzo

If you put the postIndex method of the controller and lines 5 and 6 in comments. And start the development server, you will see the contact form at http://localhost:8000/contact.

ContactFormRequest

run php artisan make:request ContactFormRequest.

On line 14 you change false to true, because you want anonymus users to send the contact form.

In the rules method you add the items from the code above.

ContactFormValid event

The original article lets you add the mail sending code to the store controller method. This gives the controller to much responsibility. I will use an event to trigger the mail sending.

In the app/Providers/EventServiceProvider.php listen array you add following item;
'App\Events\ContactFormValid' => ['App\Handlers\Events\EmailContactForm', ],

As you can see the event itself is in the app/events directory and all the code that needs to be executed is in the app/Handlers/Events directory.

Then you run php artisan event:generate.

ContactFormValid.php

As you can see in the controller on line 18 the ContactFormRequest instance is added to the constructor.
In the event file the all method is called to fill the data variable.

EmailContactForm.php

On line 2รง you see the data variable is added to the Mail send call.

Because it is an array you can use this handler for other events, the only thing you need to check are the data keys and their value.

contact.blade.php

In the handler on line 28 we defined this view file, which is in resources/views/emails directory.

The big finish

Remove all comments from the controller and fill the contact form in your browser.

Now the controllers only function is to display a view. And when the form is posted with valid data it fires an event and redirects the user to the form.

Saturday, January 31, 2015

No more static site generators

Preface

I read the article Getting started with web components and I thought how can I create a product with this knowledge. A static generator came to mind because the solutions out there want to fix the problem of reusing html snippets.

The workhorse

If you don't want to browse the code, just scroll down to see the usage.

Usage

To create a page with reusable parts you have to at least create the page itself and the reusable part.

On line 3 you see the link to the reusable part.

On line 6 I added the tag which will contain the content of the reusable part.

On line 7 there is the link to our workhorse.

On line 9 the addTemplate function to add a specific reusable part to the page

The specific reusable part in this case is;

The content of the reusable is inside the template tag. And by convention the id of the template tag has the same value than the filename. Developers will recognize this pattern, because they use it for classes.

On line 73 of the workhorse code you can see there is also a addHeader function. It works as follows:

  • There needs to be a header tag on the page.
  • The header.html needs to exist and added to the import links of the page.
  • When you call the function it has to have a title parameter

To get a better idea of how it works you can check the demo.

Is this a dream?

let me say it's a very lucid dream.

The code is more proof of concept than a product I want to ship.

At the moment the only browsers this will work on out of the box are chrome and opera.

All in all I think this could become a product with a lot more work.

Tuesday, November 18, 2014

From node to website

This post is for people who want to learn to create a website with node.js

During the process some steps are there to let you understand what the code does, this doesn't mean you should use the code as a part of a real website.

Setting up the project

After installing node on your computer, you open the command prompt or terminal and create a directory which will contain your files.

When you are in the directory you run npm init. This command will ask you some questions and generate a package.json file.

Starting to create the site

On the front page of the site you see how to create a webserver which shows Hello world when you go to the url in your browser

I named the file app.js so to run the website with npm start you need to change "start": "node index" to "start": "node app" in the package.json file.

The first webpage

The code above displays plain text but most of you know browsers display html nicer than plain text. So lets change the code to make this possible.

The changes I made:

  1. I moved the output of the site to its own function. This keeps the webserver code clean.
  2. I put the html code in a separate file. This allows you to change the html without changing the code.
  3. I used the fs module to read the file with the html in.
  4. Thanks to the callback parameters of the readFile method I can show a page not found error if the file isn't found.
  5. And to end it I display the html code that was read from the file.

If the website is running you need to stop it with the key combination ctrl+c, and start it again. Now you see that hello world is bigger and bolder.

More pages

A website has more than one page. It is possible to create multiple pages in the browser using frameworks, but we are going to keep using node to do this.

The changes I made

  1. I added page2.html
  2. I added a link to page2 in index.html and a link to home in page2.html
  3. I added a new parameter to the render function to make it possible to read different files.
  4. I checked if the browser send a GET request. At the moment we don't care about POST, PUT, DELETE or PATCH requests
  5. Then I checked which url the browser wants

After restarting the webserver again you will see the link to the second page. And clicking on it will display the second page.

Cleanup the webserver code

Because checking the routes is a responsibility of the app it's best to move the code out the webserver code.

  1. Created a Router object with the public methods get, nopage and handle. And one private method find.
  2. Added an instance of the Router object with the name router.
  3. Added the pages with get method, and the 404 page with the nopage method.
  4. Used router.handle instead of a anonymus function to let the app decide which content should be visible.

  5. Changed the render function to set the status code of the page if there is an error. This is important for SEO and other automated page visits.
  6. Added the 404.html file to display a nice page.

Making it real

We can build websites with this code but it isn't very powerful, for instance you have to add all the routes instead of using variables for groups of similar routes.

The most used framework is express

run npm install express --save, mac os users will need to add sudo in front of the command. This will add the express package to the project in the node_modules directory.

Express takes care of the routing for us, and allows us to add a template engine. At the moment we use static html files but when the data comes from somewhere else the html code is going to contain variables and logic.

As you can see express also has a get method to set GET request routes. To display a html 404 error you need to define it with the use method below all other routes.

Express needs to know the root template engine files directory, what method the template engine uses to render the template and declare the default template engine. You can use multiple template engines but this is not a good idea if you want performance and consistency.

Express also has a listen method so you don't need to create the webserver yourself.

Conclusion

I hope this gives you a clue how we went from a webserver that only displayed hello world to a website with multiple pages and html output.

Wednesday, October 29, 2014

Meteor and the findOne no result problem

Now that meteor has a version 1.0 release I wanted to give it another try.
As a test I was creating a simple blog.

The problem I encountered was when i tried to display a post detail. The code looked simple enough.

Router.route('/:_id', function(){
   this.render('detail', {
       data: function(){ 
           var templateData = { post: Posts.findOne({_id: this.params._id}) };
           return templateData;
       }    
   });
});

this.params._id looks almost like req.params._id from the express framework.
And I was sure the document with the _id existed because it came from the database.

During my search I found a few different ways to pass the _id to the findOne function.

The first one I tried comes from the official documentation:

Posts.findOne(this.params.id)

It looks like the mongo library that comes with meteor adds a little abstraction to the mongodb method. Great, but it didn't work.

Next there the id key without the underscore. That didn't work either.

Then i got the idea the hexstring wasn't enough. I needed the ObjectId instance like it's needed in the mongodb shell.
Of course the mongo ObjectId isn't available in Meteor.

After a bit of searching i found that the meteor Mongo library has a ObjectID method.

Router.route('/:_id', function(){
   this.render('detail', {
       data: function(){ 
           var postId = new Mongo.ObjectID(this.params._id); 
           var templateData = { post: Posts.findOne({_id:postId}) };
           return templateData;
       }    
   });
});

And the document data was visible.

Update

It looks like the meteor mongo shell produces _ids that are ObjectId objects, but inserting documents with the meteor Mongo library produces _ids that are 'plain' hexstrings.

So to insert documents you best use the meteor Mongo library because that's the way you interact with mongo the most.

Saturday, January 04, 2014

Belgian rail and usability

After the bus company, De lijn, introduced the sms-ticket I never use other way to buy tickets for a bus ride. Now the Belgian rail introduced a sms-ticket and I wanted to see if it is going to be the way to buy train tickets from now on.

I suspected it to be a little more difficult because of the price range between short and long rides but the experience was much harder than expected.

First attempt

There are two ways to buy a ticket, an iphone app and the mobile website. Why is there only an iphone app? As a developer I know there are tools to create apps for the different smartphone operating systems form a single code base. And Belgian rail has an official app for android, so why not update that app for sms-tickets?

Some bright minds probably already started thinking, why do they call it an sms-ticket if you need an internet connection. The ticket is send to your phone in an sms.

So I go to the mobile site and before you can buy a ticket you need to have an account.  If you want to buy a ticket on the regular website you need to provide you name and address, so I guess creating an account is their solution to make the buying easier because it is a one time deal.
I'm filling in the form. After I click on the what I think is the last step to complete the account I get an error message.

For a spur of the moment buyer this is enough reason never to buy an sms-ticket.

The long way

Because I'm crazy or addicted to technology or both I really want to know how to buy an sms-ticket. So I go to the Belgian rail website on my computer and create an account.

The first thing that strikes me as a webdeveloper is that the form to create an account is in a popup. What other things do you want to do other than creating an account at that time?
For your date of birth they use the JQuery UI datepicker with default settings which makes it impossible to select your date faster than you can type. There is a demo on the JQuery UI site which makes it a better datepicker.

After I completed the form I get a message to confirm the account. I guess you also need to do this on the mobile site so if you are on a smartphone you need to switch between apps, which is another threshold before buying a ticket.

Back to the mobile site now. I log in and go through the ticket data selection. When I come to the payment part there are only creditcard options. This is strange because on the regular website you have more options.
After selecting a creditcard option there is a checkbox to remember Belgian rail as seller to make the payments easier. It seems that the service Belgian rail uses to handle the payments only provides this option for creditcards?

 Conclusion

After creating an account and having a creditcard and remebering Belgian rail as a seller, the only one that makes it hard to buy an sms-ticket is the bank you are with. Some banks make you to verify the online creditcard purchase so you need to have your digipass with you and also your creditcard.

SMS is a quick platform for on the road and buying and sms-ticket isn't, there are too much actions needed  and less options than on the regular website. 

Aftermath analysis (how I would create the sms-ticket) 

After looking at all the data they need and all the ticket options they have it looks like the sms ticket is a six step process.

  1. Personal data and data about the ride 
  2. ride options provided by Belgian rail
  3. ride option selection sms
  4. payment info by Belgian rail
  5. payment sms
  6. sms-ticket by Belgian rail
So it takes three sms messages without the need of an internet connection.

Personal data and data about the ride

They use parts of the account information, date of birth gets mentioned in their faq, to secure the sms ticket.
Why not make the personal information that they need required lines in the sms.

The ride data they need is begin and end station, go date and return date is optional.

An example sms could be:
  1. START
  2. first name
  3. last name
  4. date of birth
  5. begin station
  6. end station
  7. go date
The first line is to make the sms service aware this is a new ticket. 

Ride options provided by Belgian rail

SMS is a peer to peer platform so there are no sessions and because it is a multistep process a token should be send to add to the following sms messages. The token should be as short as possible to make it easy to remember but big enough to allow all the travelers to create a ticket for a two day period. The two day period is in case the traveler starts making a ticket close to midnight.

The options should have numbers to identify them.

An example sms:
  1. abc123
  2. 1 adult : 2.5 €
  3. 2 child : 2 €

Ride option selection sms

The ticket buyer now needs to  verify which options he needs.

Example sms:
  1. OPTIONS abc123
  2. 1 1

Payment info by Belgian rail

Provide a code that the buyer can send to reduce his telecom account by the amount of the ticket and send the sms ticket to the buyer.
This is what the bus company does with the two options they provide.

Conclusion

It can be a bumpy ride especially the first sms because it needs a lot of information that has to verified. But it is a pure sms solution which makes the public who can use the sms ticket bigger.  

Thursday, August 29, 2013

Drupal 8 and Twig

Research

I want to create a Drupal 8 module which is up to the goals that are set for the version, especially the templates.  Drupal 8 includes Twig as template engine.

When you look for Drupal 8/Twig tutorials you get the explanation why it's good to have a template engine and how to use it. Which is great, but when you use symfony the views go in a Recources/views directory, and that is something the tutorials fail to mention most of the time.

When you see Twig files they are stored in a templates directory. The strange thing is that the templates directory is located in the root of the module. If you want a controller to use a template it feels wrong because that is stored in the lib/Drupal/module_name/Controller directory.

Solution

After a bit of code searching I found the twig loader instance is attached to the container as twig.loader. Which resulted in following controller code.

For people who are not familiar with controllers I will go line by line.

On line 3 you set the namespace of your controller. This prevents problems with other controllers in Drupal.

Lines 5 to 7 tell which objects are going to be used.

On line 9 you create the class.

The __construct method is called when the controller is created as an object.
Line 12 is the line I was searching for. This adds the View directory on the same level as the Controller directory to the loader, and this is how twig will find your templates.
On line 14 twig is attached to controller.

The create method is called by Drupal, and it makes an object of the class. 

The displayTwig method shows how to render a Twig file from the View directory.

Caveats

It seems best to prefix the Twig files of your module with the module name to prevent similar named views to be loaded.

If you have multiple controllers it is best to create a class your actual controllers can inherit form so you don't have to repeat the Twig binding code.

Wednesday, November 07, 2012

Crowdsourcing code equals good code?

I just read about a new crowdsoursing site and curious as I am i was checking which code gets the money.

I found a php task for a dollar. It's a nine line solution, with two updates, which does following things:

  • parses the input
  • looks for a specific key from the parsed array
  • seaches for www. substring
  • removes the www. substring if it's found

One solution uses str_ireplace, which is a step in the right direction.
What they needed to use is preg_replace.

$cleaned = preg_replace('#^(?:https?://)?(?:www.)?(.+)$#', '$1', $input);

The regex has three groups, two of them that aren't needed for the output.

One dollar of one line of code is still too low, I just gave it away for free.

Sunday, October 14, 2012

Blog layout

In my previous post I added a PS to create a theme.

The reason for this was i didn't have much control over it I thought.
I was wrong.

What I wanted

  • code highlighting
  • scrollbar if the code width is bigger than the content area

As this is a blog about code the examples should stand out.
I could use gists for every code example but for the examples in my previous article it seems like overkill.

What i did

Being lazy i changed my theme to a dynamic blogger theme. That kept my code in the content area, but it's an ugly theme.
And i didn't have syntax highlighting. So I changed back to my old theme.

Having a scrollbar isn't that hard in css. I just needed to know the content area width.

pre { overflow-x: auto; width: 700px; }

The side effect is that the gists all have a scrollbar or two, but scrollbars are fun.

Syntax highlighting isn't a big problem either because a lot of programmers blog, and they also want that.

When you search for syntax highlighting on blogger the first results are about SyntaxHighlighter.
My gripe with it is that it uses colons in classnames. I know from experience it causes troubles.

So I used shjs.
The installation requires you to add at least 3 files, two javascript files and a css file.

On the bog dashboard there is a template link and when you go there you find a button 'edit html'.
After a warning you see blogger xml code. I added following just before the ean head tag.

<link href='http://shjs.sourceforge.net/sh_style.css' rel='stylesheet' type='text/css'/>
<script src='http://shjs.sourceforge.net/sh_main.min.js'/>
<script src='http://shjs.sourceforge.net/lang/sh_php.min.js'/>

You may notice script is a self closing tag, this doesn't work in html.

the body tag needed the onload attribute to call the sh_highlightDocument function.
There are better ways to do this but I'm not using any other javascript that needs to be run on page load.

And now I have what i needed with the theme I like.

Friday, October 12, 2012

idiomatic php

It has been over a year since i blogged. It seems work is always taking over my free time. But I will never let my blog die.

Today i read an article about idiomatic python and I thought lets reproduce the code in php as an exercise. Working with .NET languages makes me rusty.
I will stay away from the style examples to avoid discussions that go nowhere.

I'm going to take the subtitles of the article and add the php code, enjoy!

Avoid using a temporary variable when swapping two variables

$a = 'a'; $b = 'b';
list($foo,$bar) = array($bar,$foo);

Use tuples to unpack data

There are no tuples in php, an array will do.

$list_from_comma_seperated_value_file = array('dog','Fido',10);
list($animal, $name, $age) = $list_from_comma_seperated_value_file;

Use ''.join when creating a single string for list elements

Join in php is an alias for implode. In php 5.4 square brackets can be used to create an array.

$result_list = ['True','False','File not found'];
$result_string = join('',$result_list);

Use the 'default' parameter of dict.get() to provide default values

The closest thing in php is the ternary operator.

$log_severity = isset($configuration['severity']) 
                    ? $configuration['severity'] : $loginfo;

Use Context Managers to ensure resources are properly cleaned up

It would be nice to have this in php.

Avoid repeating variable name in compound if Statement

if(array_search($name,['Tom', 'Dick', 'Harry']) !== false) {
    $generic_name = true;
}

Use list comprehensions to create lists that are subsets of existing data

The closest thing in php is to use an anonymous function and array_map.

$some_other_list = range(1,100);
$my_weird_list_of_numbers = array_map(
                              function($element){ 
                                if(is_prime($element){ return $element + 5; }                             
                              }
                            ,$some_other_list);

Use the 'in' keyword to iterate over an Iterable

The foreach loop in php uses the keyword as

$my_list = [ 'Larry' , 'Moe' , 'Curly' ];
foreach($my_list as $element){
    echo $element;
}

Use the enumerate function in loops instead of creating an 'index' variable

No need to use a function in a foreach loop to do this. It feels good to write that.

foreach($my_list as $index=>$element){
    echo $element;
}

PS note to self: create own blogger theme and never use blogger compose again.

Sunday, September 11, 2011

My first knockout.js experience

Because I wanted to see what the hype is all about, I dove in the documentation and tutorials of knockout.js.

The tutorial site is great!
But the first thing that bothered me was the data-bind attribute everywhere.

So I pulled up my sleeves and pimped the 'templates and lists' tutorial

The easiest way to test the code is to copy and paste the gist content from the article in the html and javascript fields of the tutorial site.

The html

The final markup of the tutorial looks like this:

As you can see the data-bind attribute is all over the place.

And this is my markup:

The data-bind attribute is only in the template.
The other bound elements have an id.

Instead of putting the seat count in the title, I put it together with the surcharge sum.
The tutorial code displays the surcharge sum when there actually is a surcharge, my code displays it from the moment a passenger is present.

The javascript code

The tutorial code looks like this:

Very readable if you are used to do all the legwork in jQuery.
I'm in the knockout camp if I need to create complicated interfaces from now on.

Before I show you my code I will do a blow-by-blow on what I did and what the hurdles were.

The first thing I wanted was to remove the data-bind attribute from the markup.
I knew someone wrote a jQuery plugin to make this possible.

It works fine until you want to use the plugin to bind the html elements in the template.
Because I didn't want to spend too much time looking for a way to make it work, I left the data-bind attributes.

Instead of using a ko.dependentObservable to make a sum of the surcharges I added it to the view model.
You should only use the method if the code depends on outside factors.

When I added the remove functionality it didn't work. I did some debugging and found out the this in the remove function was the view model object where it needs to be the seatReservation object.

I guess the unobtrusive plugin has to do something with it, but the quick solution is to bind the seatReservation object to the remove function.
Because jQuery is loaded I used $.proxy.

The tutorial adds an anonymous passenger but because that isn't allowed anymore, I added a prompt to the addSeat function.

So my code comes down to:

Conclusion

Amazing you can achieve so much with so little code. And the tutorial is still verbose because the availableMeals will be fetched using AJAX or generated by a server language, <?php echo json_encode($availableMeals); ?>

I grabbed it and I will not let it loose until something better comes along.

Tuesday, September 06, 2011

Ugling: the start of the template engine

The changes

If you look at the previous build.xml file you know processing content in phing will turn in spaghetti code very soon. So I moved it to the template task.

The new build.xml file is easy to read because now you just have two tasks.

To get the build result I want i needed to add an attribute to the markdown task, removefilesetdir.
For me it was a cleaner way to process the markdown files and add the processed files to another directory than the way the rSTTask documentation shows.

The template engine vision

I want working with the generator to be as easy as possible so I try to stay away from code-like constructions as much as possible.
But at the same time it has to be as flexible as possible too.

The first problem I encounter is how can I provide a default template but allow specific templates at the same time.

Because i started to work with base template I got the idea that each directory could have a template.html that wraps all files in that directory and its subdirectories.
The only exception is the root template directory, it's required to have a template.html there.

To allow file specific templates it seemed the most logical to use the name of the file, so if your content file is called test.md and you want a file template you create a test.html file in the templates directory.

The template task today

I took my MarkdownTask.php code to start the TemplateTask.php code.
I concentrated on getting it to work so the code isn't that clean yet.

The default template code is working.

To prevent placeholders showing up in the online files they are set to an empty string before the actual content is added or generated.

Next time

The next blog post I will have the template vision working and have come up with a plan to add generated navigation content.

Saturday, September 03, 2011

Ugling: the phing powered static site generator (the begin)

Preface


I was looking for a project to use phing in a way that isn't expected.

Using it to remove version software directories or run tests is done so many times before.


The cool programmers started using static site generators like jekyll and petrify.

Why would you need a database if most of your content is static.


So why not use phing to do the same thing.


I also want to make the threshold as low as possible.
Markdown is one thing but other elements like the navigation are going to be not that easy.


Transforming the markdown


Creating a task in phing is easy, certainly if someone already did a similar task.


I just copied the code from the rSTTask, removed the parts i didn't need and changed the code to use the markdown class.



The source layout



  • content

    • index.md



  • media

  • online

  • templates

    • base.html



  • build.xml


As you can see the content directory holds the markdown files.


You can add as many subdirectories as needed. And use index.md files to display content for an url without the html extension.


The media directory will hold css files, js files, and other public content.

I'm not sure i'm going to keep it because the only phing action will coppy the files to the online directory.


The online directory holds all the files you can place online.


The templates directory holds html files that have placeholders.
This will be for the 'expert' users.


The build.xml file is the phing hook which will take care of all the actions.


Later there can come a build.properties file to move the user accessible properties outside the build script.


Build.xml content



I think it's a readable file.



  1. Set the start target: default="loop"

  2. Add properties

  3. Add markdown task

  4. Find all markdown files and send the file names to the single target

  5. Process the markdown file and move it to the online directory


The future


Now that the easy part is over I can go to work on the necessary plugins.
Navigation is the first that needs attention.

Wednesday, August 17, 2011

My first phing buildscript

Because I get more and more components from version management tools it gets harder and harder to move from development to staging level. SVN repositories are the worst offenders, certainly if you see how clean the get and mercurial repositories are.

If you clone or checkout a repository most of the time it also includes test files, build files, and so on. It's stuff you don't need for your application.
Swiftmailer for example comes with a full blown test suite. What if hackers find a way to use it to their advantage?

The phing installation via pear is painless.

The way to delete a directory didn't appear in any of the searches i did. So i moved on to the documentation and I found what i needed.



It's not very elegant but i'm taking babysteps at the moment.