Injecting Closures into your Classes

I wanted to reuse a class of mine, which generated a <ul> with links, only this time I wanted to alter the link text using a custom function (closure) in the constructor.

<?= $this->generateUl($existing_arg1, $existing_arg2, function($args){ //do stuff } ); ?>

Inside the class constructor, I set the following:

public function __construct($existing_arg1, $existing_arg2, Callable $closure = null)
{
    $this->closure = $closure;
}

And here’s the wee catch: You can’t call it like a normal method, $this->closure($args); You need to assign it to a standard variable for whatever reason.

    /** 
     *  @param ESOS_Entity_Org $org
     *  @return string
     */
    private Function generateLinkText(ESOS_Entity_Organisation $org)
    {
        if(!$this->closure)
        {
            // This is my default functionality
            return $org->getName();
        }
        // There are two ways of doing this next bit:
        // $this->closure($args); won't work but $closure($args) will!
        // $closure = $this->closure; 
        // return $closure($org);

                // Here's the better way:
                return call_user_func($this->closure,$org);
    }

Doing this has made me realise just how awesome Callables can be, you could inject in all manner of functionality into a class! Play around with it!

Custom jQuery validator functions

The jQuery validator is really cool, and you can create your own validators. Here’s one that counts the words in a text area, and validates :

$('.word_count').each(function() {
 var input = '#' + this.id;
 var count = input + '_count';
 console.log(input);
 console.log(count);
 $(count).show();
 word_count(input, count);
 $(this).keyup(function() { word_count(input, count) });
 });
function word_count(field, count) {
var number = 0;
 var matches = $(field).val().match(/\b/g);
 if(matches) {
 number = matches.length/2;
 }
 $(count).text( number);
 }
jQuery.validator.addMethod("twentywords", function(value, element, param) { 
 if($(element+'_count').html() > 19){return true;}
 else{return false;}
 }, jQuery.validator.messages.url);

And in the rules section:

rules: {
f_review: {
 twentywords: true
 }
 },
 messages: {
f_review: "Please leave a review of the agent at least 20 words"
 }

I’ve hard coded the name input into the validator, as I’m in work and it needs done quickly, but I’m sure this could be tweaked. Finally there is a hidden element that the word cound gets stored in and the input textarea has a class of word_count:

<div id="f_review_count"style="display:none"></div>
 <textarea name="f_review" id="f_review" rows="8" cols="40" class="text-long word_count"></textarea>

The word count stuff can be used on its own without the validator too. 🙂