RSS
 

Posts Tagged ‘HTML5’

Some new crazy (Cake)PHP tricks

01 Mar

Crazy – because these tips are not used that often probably. But for some rare occasions they might come in handy.

Inserting some rows into an array

$array = array(
	'one',
	'two',
	'three'
);
$newValue = 'one-point-five';
//with 0 as 3rd arg we can actually add values at the position of arg 2
array_splice($array, 1, 0, array($newValue));

Note that the 4th argument must be an array for this to work.

Using the same value for multiple select options

With a simpel key/value list and select() you won’t get far. You cannot use the same key twice in an array. That is a common beginner mistake.
To overcome this you need a bit more verbose array here:

$options = array(
 	...
 	array('name' => 'United states', 'value' => 'USA'),
	array('name' => 'USA', 'value' => 'USA'),
 );
 
 echo $this->Form->input('test', array('type'=>'select', 'options'=>$options));

This will then print

...
<option value="USA">United states</option>
<option value="USA">USA</option>

See the docs for more infos on select().

Setting additional attributes for some select options

You might want set some option elements to a specific class. The FormHelper::select() is powerful enough to support this:

// normal options
$options = array(1 => 'One', 2 => 'Two', 3 => 'Three');
// advanced (second elements has a class "extra")
$options = array(
	1 => 'One', 
	2 => array('name' => 'Two', 'value' => 2,  'class' => 'extra'), 
	3 => 'Three');
echo $this->Form->input('test', array('type' => 'select', 'options' => $options));

The result:

<div class="input select">
	<label for="ModelTest">Test</label>
	<select name="data[Model][test]" id="ModelTest">
		<option value="1">One</option>
		<option value="2" class="extra">Two</option>
		<option value="3">Three</option>
	</select>
</div>

You might want to check this site here if the styles you want to apply work in all browsers. Usually only some styles like background-color are apply-able cross-browser.

Autofocus

Not so much CakePHP as maybe HTML5 – but pretty useful for login forms:

echo $this->Form->input('login', array('autofocus'=>'autofocus'));

All new browsers support it out of the box. The user can start typing right away (no additional click necessary).

More HTML5 out-of-the-box

In general HTML5 is great, but still not fully supported by all browsers – or users just don’t update to a new version.
So we shouldn’t completely rely on those features. But where – as the above autofocus – the absence in unsupportive browsers doesn’t bother anyone we can easily apply those features for users with modern browsers.

Additionally, we can use fallback-js to "simulate" the behavior if not natively supported. I put together a well-working HTML5-fallback script for jquery. It checks if the browser supports a certain feature and if not it creates a JS workaround.

I bet there are lots of other similar implementations. The important part for those placeholders is that on submit the content needs to be cleared again. The placeholders must not be posted (otherwise your validation rules might not work as expected anymore). I used the $('form').live('submit', function() {} event to clear the forms in time.

echo $this->Form->input('url', array('placeholder'=>'http://'));

All these snippets work in all browsers. In those modern ones a little bit faster. But that’s about all. You can already use it without any worries. And some day you can just turn of the fallback.

Structure your controllers

UsersController is often one of the most bloated controllers having tons of actions and views.
At some point this might get very confusing with so much code in a single file.

You don’t have to put all 40ish actions that are related to the User model in a single UsersController. Divide them to keep things clean and clear. So for me this worked pretty well:

  • AccountController (login, logout, register, change_pw, edit, …): $uses = array('User')
  • MembersController (index, search, profile, mail, friend, …, admin backend actions): $uses = array('User')
  • OverviewController (index, admin index, … – specially routed): $uses = array('User')

As you can see they all use the user model but they separate the actions by category. This way the file stays kinda short and is better understandable in the long run. Imagine all those actions in a single controller. No way 🙂

But also bear in mind that you should not start dividing everything into tiny little pieces. Only do it where it makes sense.

Controllers without models

Until today you coudn’t just set $uses to false in Cake2. What used to work in 1.3 will fail hard in 2.x. It was a pretty annoying problem I reported right away (but it needed a second one to actually get things into motion). If you just used isset($this->Model) it would try to load a non-existent model and die. The current head now contains the new fixed version which works now the way one would expect it to work:

  • true Use the default inflected model name.
  • array() Use only models defined in the parent class.
  • false Use no models at all, do not merge with parent class either.
  • array('Post', 'Comment') Use only the Post and Comment models. Models will also be merged with the parent class.

The default value is true.

So basically, if we don’t want to use any models (or at least no default model):

class TestController extends AppController {
	public $uses = array();
}

Note: only use false if you are certain the extended controllers (the AppController usually) don’t rely on any models. Otherwise it will break this functionality. That is why array() usually suffices.

 
7 Comments

Posted in CakePHP

 

Interesting Links

18 Feb

A short post about some really interesting sites I found in the www and want to share:

Live Benchmark

phpbench.com
You can see live benchmarks about some basic PHP stuff. You can also copy and paste the code to try it out yourself.

HTML5 please

html5please.us
An interactive HTML5 list about what is supported already and what isn’t.

Payment network Dwolla

dwolla.com
A real competition for Paypal? It is way cheaper so it might.
Anyone tried the API yet?

Did I forget to mention an important new site? Drop me a line!

Tip

If you want to be notified when I publish a new article subscribe to my RSS feed.
I use the same thing for other blogs. With my Thunderbird I get instantly notified about news on those sites.

 

Making your apps future-proof

18 Jun

As we all know almost nothing changes as fast as the IT sector.
So in order to keep maintance work on your apps to a minimum, we should make sure that it will still run in several years. We don’t want to spend too much time refactoring and applying new standards. Otherwise we could re-create the whole app from scratch…

Probably the easiest way to keep the refactoring to a minimum is:

  • Use as much wrapper functions as possible (using form helper instead of normal html for example)
  • DRY – don’t repeat yourself (shared function/file for every piece of code you use more that once)

This way you only need to make (minor) changes at a single location. Everywhere you use those wrapper functions the code will automatically be up to date again.

Examples

SQL

// a simple find query via wrapper
$this->find('all', array('order'=>array('field'=>'ASC')));

If one day the SQL syntax for ordering changes from "order by" to "order from" the only thing thats needs to be changed would be the corresponding piece of code in the cakephp core. If you’d used manual queries you would need to run through all your code in order to replace all the bits and pieces containing the old syntax.

PHP

//You might use a specific method in order to sort sth for example
$x = $this->MyLib->doSomething($y);

If your class uses some PHP5.x only functions you will be glad that you have an isolated method you can quickly port to PHP6. Plus it’s easy to test.

HTML
With XHTML elements as well as HTML5 approaching (and god knows what else…) the syntax of HTML will change over and over. In many cases it does make sense to use helpers to ouput HTML. The overhead in time is minimal. The time saving in the future maximal.

Concrete scenarios

HTML Forms with Form Helper
See this source for infos about the new HTML5 elements.

$this->Form->input('number', array('min'=>2, 'max'=>10, 'step'=>2));

Most browsers cannot use all the HTML5 elements yet. But with wrapper functions we can switch in the future with one simply change. We could also enable it for browsers that support it and provide fallbacks (html/js/css) for older browsers. As soon as all browsers understand it we can turn off those fallbacks in the future. Everything in one spot.

PHP
Excerpt from a baked controller of mine (using custom bake templates – see my other article):

function admin_edit($id = null) {
		if (empty($id) || !($discount = $this->Discount->find('first', array('conditions'=>array('Discount.id'=>$id))))) {
			$this->Common->flashMessage(__('invalid record', true), 'error');
			$this->Common->autoRedirect(array('action' => 'index'));
		}
		if (!empty($this->data)) {
			if ($this->Discount->save($this->data)) {
				$var = $this->data['Discount']['name'];
				$this->Common->flashMessage(sprintf(__('record edit %s saved', true), h($var)), 'success');
				$this->Common->postRedirect(array('action' => 'index'));
			} else {
				$this->Common->flashMessage(__('formContainsErrors', true), 'error');
			}
		}
		if (empty($this->data)) {
			$this->data = $discount;
		}
	}

As you can see we have two methods that are used in all controllers:

  • autoRedirect: trying to redirect back to the previous page (using the referer) if possible
  • postRedirect: redirecting back to the content using correct headers

Now, postRedirect is the interesting part.
As of right now quite a few browsers don’t support the new XHTML status code 303 which is supposed to be used in this case. But maybe in a few months we can simply switch from 302 to 303 by changing this method

Here is the method:

/**
	 * should be a 303, but:
	 * Note: Many pre-HTTP/1.1 user agents do not understand the 303 status. When interoperability with such clients is a concern, the 302 status code may be used instead, since most user agents react to a 302 response as described here for 303.
	 * @see http://en.wikipedia.org/wiki/Post/Redirect/Get
	 * TODO: change to 303 with backwardscompatability for older browsers...
	 */
	public function postRedirect($whereTo, $status = 302) {
		$this->Controller->redirect($whereTo, $status);
	}

Of course there are many other examples why it is always good to wrap even stuff as simple as this redirect in wrapper functions.

Outline

Similar to the above for HTML/PHP it is also a good idea to use frameworks and wrappers for JS as well.
For example Jquery/Prototype to only name two big ones.
This is at least as important due to the many different browser versions out there. It really helps to know that those frameworks provide a simple solution that works on all those browsers. Ideally you should only have to update the framework lib in order to be safe for the changes of the future.

Feel free to comment.

 

Web Development Snippets

06 Mar

A couple of useful snippets for web developing. The list will grow over the years.

Jumping to anchors with JS

If we want to jump to an anchor dynamically (using javascript):

/* dont use this!!! */
//location.href = location.href  + '#searchbox';
/* and not this either: */
//location.href="#searchbox";
/* this is the correct way to go */
window.location.hash = "searchbox";

This has still some flaws if you click the anchor multiple times.
This worked for me:

var destinationLink = document.getElementById('targetId');
var destx = destinationLink.offsetLeft;  
var desty = destinationLink.offsetTop;
scrollTo(destx, desty);

So the above method should be used to set the hash of the page. The below one for jumping to anchors.

Prevent Right Click

This should be used wisely and only where it makes sense. It it neither waterproof nor convenient in most cases. Simply by displaying the source code the content can still be accessed (Shortcuts like STRG+U).

<body oncontextmenu="return false">
...
</body>

I like the browser solution more than the js solutions out there 🙂

Get HTML5 ready

<input name="url" placeholder="http://"/>

This is only one example of many. The Google Chrome browser already understands it as well as some beta browsers like FF4 etc.
Combine this with a javascript/jquery fallback and you have a nice (placeholder) functionality that will some day run natively in all user browsers.

And some more snippets from different external sources:

Forcing long strings to wrap

biostall.com/forcing-long-strings-and-urls-to-wrap-with-css

Print-Layout

www.alistapart.com/articles/goingtoprint/