Mirmo Dynamics

Si tu kiffes pas reunoi, t'écoutes pas et puis c'est tout.

To content | To menu | To search

Sunday 8 March 2009

having fun with vim, an event tracker

The idea of this script came by realizing that the main reason I (almost) never fill my timesheet, is because I just forget it. How easier could it be if my editor (namely vim) could fill it for me ? Or at least, help me fill it. This script is meant to help this process. It will hook to every configured event (in the code below, BufRead and BufNewFile) and add a log line to the log file. Easy heh ? Of course, the script it self won't be of much use, I'll have to add some more events to track as well as writting some kind of frontend for it, with reporting & all.

if exists('trackloaded')
  finish
endif

" list of autocmd events:
" http://www.vim.org/htmldoc/autocmd.html#autocmd-events
let trackevents = ['BufRead', 'BufNewFile', 'BufEnter', 'BufWrite', 'BufLeave']
let trackfile   = '/tmp/timetrack.dat'
let trackloaded = 1

for event in trackevents
  execute 'autocmd '.event.' * call Track("'.event.'")'
endfor

unlet event

function Track(event)
  let l:filename = @%
  if l:filename != g:trackfile
    if match(l:filename, '/') != 0
      let l:filename = getcwd().'/'.l:filename
    endif
    silent execute '!echo `date +\%s` '.a:event.' '.l:filename.' >> '.g:trackfile
  endif
endfunction

You might note from this snippet that I'm not very comfortable with vimscripting :-) If you have a better way of doing this (I'm thinking mostly about the file writting here), don't hesitate to tell me.

Thursday 29 January 2009

Replacing short tags with proper PHP tags

This is a little script I made to get rid of those damned short tags.

<?php
 
while ($file = trim(fgets(STDIN)))
{
  $content = file_get_contents($file);
 
  $search  = array('/<\?=/', '/<\?(?!php|xml)/');
  $replace = array('<?php echo ', '<?php ');
 
  if ($content != ($new_content = preg_replace($search, $replace, $content)))
  {
    file_put_contents($file, $new_content);
  }
}

Just put this in a file, short_tags.php for example, and run something like:

$ find . -name "*.php" | php ./short_tags.php

I would have done it with sed, but it doesn't seem to support PCRE, and I don't know how to do negative lookahead (the (?!php|xml) thingy) with POSIX based regexp (if it's even supported) :/

UPDATE: Actually, POSIX Regexps DO support negative lookahead (as well as positive lookahead and lookbehind) with the same syntax as PCRE regexps. But grep doesn't use POSIX regexps, it uses things called BRE and ERE that I've never heard of before. Too bad.

Monday 24 November 2008

Why I switched from ZF

Please note all the reasons I'm about to give are the reason I had at the time I quited ZF, that's like 6 months ago or so, so be aware that things may have evolved, and since this is not a rant, I won't even check if they actually changed (as I really don't give a damn). Also, I'm writing this post only because I said I'd write it, I'm not trying to convince anyone, nor am I trying to start a discussion about the pros and cons of ZF.

First, I think the Zend Framework is a bit complex. That's quite vague for a framework of that size, but let me explain. There are a lot of things to know and do before you can even think of really working on your project. Zend Framework has a lot of classes, and you better know a lot of them to get productive.

Which lead to another problem: configuration over convention. This concept is deeply rooted inside the framework, and I think it's just wrong (although I know it's a pro for some people). It forces you to know instead of just being able to guess (and I think knowing how to guess is very important for a developer), so you just can't install the framework and start working ootb, you have to read docs (well, you always have to read docs, but), you have to read A WHOLE FUCKIN LOTS OF DOCS, and god, it's boring and greatly time-consuming.

Time-consuming, because the documentation is poorly structured. I've always found it hard to find exactly what you need in the documentation. Not sure why (and that's not a point I will expand on, since this is very subjective, and most of other frameworks have equally poorly structured doc).

Now my main point: Zend Framework is nothing more than a Zend sponsored PEAR. You have no tools to ease or speed application development, no coupling between components (yet again, I know this is a pro for some people ;), no code generation, no easy database management, no task handling, etc, etc. So what's the point using a framework if he doesn't really help you developing ? Not much if you ask me (and if you're reading this, we could assume you asked).

Add to all this poorly written components (some of them don't even follow the coding standard !), stupid decisions (i18n exceptions anyone ?) and marketing-drived release policy, and there you are, one less Zend Framework enthusiast (not that it matters anyway).

So thinking about all that, there's a single word that describe exactly why I've been disappointed by ZF: expectation. Zend Framework is just not meeting my expectations, it doesn't fit my needs, that's why I switched to another framework, that, for now, I'm fully satisfied with.

Monday 14 July 2008

About the self keyword in static methods

While setting up a test server for some software I wrote at the office, I eventually noticed the following notice:

Notice: Use of undefined constant self - assumed 'self'

That surprised me, because 1) I though self were some kind of "superglobal" constant or a special token of the parser, always automatically available in a static method and 2) the code works. So what's up in there ? Let's make a simple test:

<?php

class foo {
	static public function bar() {
		var_dump(is_callable(array('self', 'foobar')));
		var_dump(is_callable(array(self, 'foobar')));

		var_dump(class_exists('self'));
		var_dump(class_exists(self));

		self::foobar();
	}

	static public function foobar() {
	}
}

foo::bar();

Executing the above code will yeld the following result:

bool(true)

Notice: Use of undefined constant self - assumed 'self' in /home/geoffreyb/test.php on line 6
bool(true)
bool(false)

Notice: Use of undefined constant self - assumed 'self' in /home/geoffreyb/test.php on line 9
bool(false)

What do we learn here ? Not much actually. It seems like self as a constant is only available when used with the scope resolution operator, aka double-colon or paamayim nekudotayim. When you want to use it in, for example, a callback definition, use a string representation of self:

<?php

is_callable(array('self', 'bar'));
call_user_func(array('self', 'bar'));

Which, while making absolutely no sense at all, works. Another way to get around this is to use the get_class() function that, without any argument, will return the name of the class you're currently in (foo in my example).

After a bit more investiging, I found out that there is nothing special about the self token, which is actually a string token. You can check this very easily with the following code:

<?php

class foo {
	static public function bar() {
		self::foobar();
	}
}

var_dump(token_get_all(file_get_contents(__FILE__)));

Somewhere inside the output, you'll find the following piece of text:

  array(2) {
    [0]=>
    int(307)
    [1]=>
    string(4) "self"
  }

And the token id 307 is resolved by token_name to string.

Monday 31 March 2008

Zend Framework 1.5.1 PEAR package is available

A little late sorry, but ZF 1.5.1's package is now ready.

Thursday 27 March 2008

ruby: url_to_constant

A small bit of ruby to get a constant from an URL:

require 'uri'
def url_to_constant(url)
	return URI.parse(url).host.gsub(/^www\./, '').capitalize.gsub(/[^a-z][a-z]/i) { |m| m.gsub(/[^a-z]/, '').upcase }.constantize
end

Nothing exceptionnal here, just a pretext to post something.

Saturday 22 March 2008

Zend Framework 1.5 PEAR package is available

The long awaited 1.5 version of the Zend Framework has landed for some days already, and here comes its pear package. Please note the api version changed to 1.5 in this package.

Monday 10 March 2008

Plugin "related by tags" pour dotclear 2, deuxième

Après de longs mois d'attente, le related by tags nouveau arrive enfin ! Au menu des réjouissances, une interface de configuration, ainsi qu'un widget font leur apparition. Vous disposez donc désormais de deux manières d'afficher les billets liés, directement en modifiant le template comme avant:

{{tpl:include src="_related_by_tags.html"}}

ou tout simplement en activant le widget correspondant, que vous pouvez configurer comme vous l'entendez. Bien sur, ce widget ne s'affichera que lors de la visualisation d'un billet.

Au chapitre des fonctionnalités / bugfix manquant(e)s, on notera le bug lié à l'utilisation de postgresql, ainsi que la traduction française, qui sera pour plus tard.

Encore une fois, n'hésitez pas à poster tous vos commentaires ici même.

Wednesday 27 February 2008

Zend Framework 1.0.4 PEAR package is available

The package for the last 1.0.x release, 1.0.4, is now available on the phpmafia pear channel. Please report any issue in the comment of this post. The Zend_Locale's xml bug should now be fixed (they are now considered as php and thus put at the right place, which is not the best way to fix the bug I guess but at least it should work for now).

Sunday 2 December 2007

yaml, activerecord and acts_as_nested_set

I used to use this yaml_to_ar lib from christophe to load categories tree into my database, using acts_as_tree in the model that was perfect. Arrived the time when I felt the need to use acts_as_nested_set instead, for which I had to fill the lft and rgt columns. So I just rewrote the yaml_to_ar piece of code (put this in lib/yaml_to_ar.rb):

require 'yaml'
 
class YAML_to_AR
 
  def initialize(file, model)
    @data = File.open(file) { |yf| YAML::load( yf ) }
    @model = model
  end
 
  def process(data = @data, parent = nil)
    if data.is_a? Array
      data.each do |val|
        process(val, parent)
      end
    elsif data.is_a? Hash
      data.each do |key,val|
        parent = @model.create(:title => key)
        process(val, parent)
      end
    elsif data.is_a? String
      parent.add_child(@model.create(:title => data))
    end
  end
 
 end

This should handle both acts_as_tree and acts_as_nested. To ease things a bit further, I also wrote a rake task (to drop in lib/tasks/db_load_categories.rake for example):

namespace :db do
  desc "Loads categories defaults data"
  task :load_categories => :environment do
    require 'lib/yaml_to_ar'
    Category.delete_all
    categories = YAML_to_AR.new('db/categories.yml', Category)
    categories.process
  end
end

Now I just rake db:load_categories, and voila !

Wednesday 28 November 2007

my first rails plugin: named_resources

It's a simple plugin (2 lines of code beside class and modules declarations) which allows routes created via the map.resources mechanism to be customized. Say you have the following map:

map.resources :members

It will generate routes like:

/members
/members/:id
/members/new

No say you want to i18n your app, in french for example, what do you do ? You just can't out of the box. This is where my plugin enters into action, just add a :route_name parameter to the map.resources call and you're set:

map.resources :members, :route_name => 'utilisateurs'

will generate routes like:

/utilisateurs
/utilisateurs/:id
/utilisateurs/new

It shall also work for nested resources, although I did not test that.

The code is actually pretty simple:

module ActionController
  module Resources
    class Resource
      def path
        route_name = @options.include?(:route_name) ? @options[:route_name] : @plural
        @path ||= "#{path_prefix}/#{route_name}"
      end 
    end 
  end 
end

To install just use script/plugin:

script/plugin install http://tools.assembla.com/svn/riskle/rails/plugins/named_resources

or to install as an svn:external resource:

script/plugin install -x http://tools.assembla.com/svn/riskle/rails/plugins/named_resources

Wednesday 21 November 2007

Accessing raw post data in a controller

For some reason, $HTTP_RAW_POST_DATA does not seem to be set inside an action controller. You'll have to use the php://input stream wrapper to access raw http post data:

$raw_post_data = file_get_contents('php://input');

Monday 5 November 2007

Extending Zend_Controller_Router_Route: the singleton problem.

Today I ran into an issue while extending Zend_Controller_Router_Route. I wanted to add a little path pre/post processing in the match() and assemble() methods, so I just extended the Route class to add my tiny bits of code into the methods. Except it did not work at all. After a few debuging, it turned out that the Router uses Zend_Controller_Router_Route::getInstance() to retrieve a route object, which uses a new self(); statement to instantiate the route object. Problem is that self always refers to the current class definition we're in, if the method is called from a child class, without being overloaded, self will refer to the wrong class.

Example:

class Foo {
	public static function getInstance() {
		return new self;
	}
}
 
class Bar extends Foo {}
 
var_dump(Bar::getClass());

echoes something like:

object(Foo)#1 (0) {
}

Which is fscking wrong IMHO. A quick workaround is to overload the getInstance method, which is what I call pretty annoying as it does not follow the DRY principle.

Monday 22 October 2007

How I use the Zend Framework

Having started a few applications using the Zend Framework, I came out with a few practices that I tend to use over and over. In this post I'll quickly expose some of them and explain why I do things the way I do them. As you'll notice, most of them are already widely known and used over the ZF developer's community. Please remember that these practices are just what I do, and come with no garanty at all to be best practices.

Continue reading...

Thursday 4 October 2007

Plugin "related by tags" pour dotclear 2

update: nouvelle version disponible

Allez hop, j'ai codouillé rapidement aujourd'hui un plugin dotclear 2 pour afficher une liste des billets ayant le ou les mêmes tags que le billet en cours de lecture par l'internaute. Il est téléchargeable dès maintenant sous forme d'archive tar gzipée ou directement de package dotclear. Pour l'utiliser, rien de plus simple, il suffit d'ajouter le tag suivant dans votre template, à l'endroit où vous souhaitez afficher la liste des billets:

{{tpl:include src="_related_by_tags.html"}}

Et voilà c'est tout :-)

Bon par contre, il faut faire gaffe a comment on tag ses billets (genre pour celui là j'ai preferré ne pas le taguer php histoire d'avoir des résultats plus pertinents).

ps: si quelqu'un connait un moyen d'éviter d'avoir a rajouter un bout de code au template je suis preneur (mais j'ai la flemme de chercher là tout de suite).

Monday 1 October 2007

PDO not throwing an exception when it should

Today I ran into an issue that I already ran into a few weeks ago when I did not have time to dig up, but today I had this time (this plus it's a really annoying issue as you'll see). The main symptom is that PDO does not throws exceptions when you'd expect it to. It's very annoying. The reason, in my case, seems to be that I am querying an old mysql (3.23.x in my case but any 4.x will do according to this bug report). I was not able to find any info from google, so I'm posting this here so that people know :-)

Monday 1 October 2007

New home for pagination component documentation

For those caring, I just posted some quick documentation for the pagination component at my assembla space. More docs will follow (including extensive phpdoc docblocks I hope).

Sunday 30 September 2007

Zend Framework 1.0.2 PEAR package is available

A PEAR package for the 1.0.2 version of the Zend Framework is now available from the PEAR PHPMafia channel. As usual, to install just issue the following:

pear channel-discover pear.phpmafia.net
pear install phpmafia/Zend

Sunday 30 September 2007

Bugfixes release of Zend Framework pagination component

I just released on riskle's assembla space a new version of my pagination component for the Zend Framework which you can download right now:

Riskle Paginate r122

This release fixes a nasty bug in Riskle_Db_Table::fetchCols which prevented from retrieving the right count of cols involved in the query.

The table component has also been slightly rewritten following Erik's suggestion to move the parent mapping into _fetch. The parent mapping itself has been improved to allow "multi level" table joining. This will be best explained with an example:

Say you have three table, Foo, Bar and Quux, and you would like to execute the following query:

SELECT * FROM Foo JOIN Bar ON Foo.bar_id = Bar.id JOIN Quux ON Bar.quux_id = Quux.id

This is now possible with the following mapping (in Foo's class of course):

array(
    'Bar' => array('local' => 'bar_id', 'remote' => 'id'),
    'Quux' => array('local' => 'quux_id', 'remote' => 'Quux.id'),
);

Easy heh ?

As usual, any comments are appreciated, and please note that this code is released under the same license as the ZF itself, the new-bsd license.

Sunday 23 September 2007

Of controller plugins and directory layout

When anyone on #zftalk ask about where controller plugins should be kept, we usually responds something like have your own library namesapce alongside Zend/ and put it in it like YourNamespace/Controller/Plugin/YourPlugin.php. But what about application specific controllers ? There's a time where you have to write a plugin that relies on the application at such a level that using it elsewhere would make no sense. In that case, where can we store this plugin ? The question arised this morning, and we ended up to the fact that having a controller-level plugin directory would not hurt, after all. So one could have the following directory layout (simplified on purpose):

/application/modules/default
    /controllers
    /library/Plugin
        MyPlugin.php

The drawback is that in order to use autoload you would have to have each modules Plugin dir in the include path, which is a bit of a hassle. Instead, we could have the much more simple folloing layout:

/application
    library/Controller/Plugin
        MyPlugin.php

Which is simpler but does not allow for modules specific plugins. Anyway, the former layout would require a bit more logic in the bootstrap in order to extract every modules path as plugins are registered pre-dispatch.

Hope it helps with directory layout organization :-)

UPDATE

What I've finally decided to do is the following:

/application
    library/App/Controller/Plugin
        MyPlugin.php

So that application specific code gets prefixed with the App_ namespace.

- page 1 of 8