Most recent Work update

Github-like headings in WordPress within few minutes

First of all GitHub is awesome, that’s what we all know so let’s get straight to the point. One of my favorite features is that link thing next to each heading, few days ago I thought it would be nice for my blog too. I’ve found many related plugins but none of them succeed to met my requirements. I wanted a small, efficient and smart plugin which will not update my database with tons of unused classes and HTML tags so I’ve made it on my own and now it’s available for anybody (for free). How it’s made? You might think that this little feature is simple as hell but in real life it takes advanced techniques to get thing work perfectly. First I wanted to do things as fast as possible so I decided to use a jQuery like interface in PHP but none of them handled the HTML fragment as I expected. (Most of them threw me parsing errors all the time.) After a day struggling with code parsing I’ve chosen pure regular expression over jQuery-like parsers. Oh man, it was a relief! With regular expression I managed to finish the parsing part in less than one hour. Here is how I get every single headings from a HTML fragment: $content = "<h1>H1</h1> followed by anything."; // Input content, anything you want. $regex ="/<(h1|h2|h3|h4|h5|h6)([^>]*)\>(.{0,1000})<\/(h1|h2|h3|h4|h5|h6)>/i"; $is_matching = preg_match_all($regex,$content,$match_set); That was pretty easy, right? Right. Of course that’s just the beginning but the further steps aren’t more difficult. If you are interested in the other parts of the fully operating code simply download the WordPress plugin and explore the main php file. This was just a little introduction. How to download You can install ONet Header Linkifier either via the plugin directory, or by uploading the files to your server. (If you want to contribute the plugin you can find the Git repo at BitBucket).

Most recent Blog update

Laravel (4.2): Single table inheritance for Eloquent

Originally I wanted to publish this article when Laravel 4.2 was only in development but it is out for a while now so I’m here to present my trait for this particular issue. Whilst the title may not be straight forward, here is the thing with more than 3 words: Multiple models sharing one table, auto-filtering queries based on column value. If you are familiar with WordPress you probably know that there is only one table with all the pages, posts, attachments and “custom post types“. This article is not about explaining all the little details, it’s for more advanced developers who can grab my code snippet. I assume you already know Laravel, Eloquent and PHP5.4. The problem I wanted to create a single table for different post types, easy. After that I decided to create a (main) Model for the table, that’s not hard either. But what if I want to access different post types using their own models? (Eg.: base model is Post and I want Article and Page model to return only posts where type column is article or page.) There was a “overwriting” method earlier in Laravel 4.1 which was not that sexy (at least it worked) and while it’s still works in Laravel 4.2 you don’t want to go down that way because it will mess up all your sub-queries. Okay, so now what? The solution will be similar to the new SoftDeletingTrait in Laravel 4.2. (If you haven’t met it yet click here.) Back to the drawing boards We will need two different file, one for the trait and one for the scope which will actually do the hard stuff. While your needs might be different than mines I think if you decided to go with child models you won’t need “column filtering removal method” so be aware (if somehow you need to be able to remove auto-filtered columns you can do that based on SofDeletingTrait and SoftDeletingScope). You can put these files wherever you want but I’ll put mine into models/traits. This will be the: app/models/traits/AutoFilterTrait.php <?php namespace Illuminate\Database\Eloquent; use DB; trait AutoFilterTrait { /** * Add AutoFilterScope to the global scope * @return void */ public static function bootAutoFilterTrait() { static::addGlobalScope(new AutoFilterScope); } } ?> Okay, the main trait is more less than, let’s move on to the scope file itself. This will be the: app/models/traits/AutoFilterScope.php <?php namespace Illuminate\Database\Eloquent; use DB; class <span class="hiddenSpellError" pre="class " data-mce-bogus="1"-->AutoFilterScope implements ScopeInterface { /** * Apply the scope to a given Eloquent query builder. * @param \Illuminate\Database\Eloquent\Builder $builder * @return void **/ public function apply( Builder $builder ) { $model = $builder->getModel(); $autofilters = $model->getAutoFilterData(); # If there is no autofilter variable set we can stop interrupting the Builder if ( !count( $autofilters ) ) return; foreach ( $autofilters AS $id => $data ) { $builder->where( $data['column'], $data['relation'], $data['value'] ); } } /** * Remove the scope from the given Eloquent query builder. * @param \Illuminate\Database\Eloquent\Builder $builder * @return void */ public function remove( Builder $builder ) { $model = $builder->getModel(); $autofilters = $model->getAutoFilterData(); # If there is no autofilter variable set we can stop interrupting the Builder if ( ! count( $autofilters ) ) return; $af_assoc = $this->autoFilterAssoc( $autofilters ); $query = $builder->getQuery(); $bindings = $builder->getBindings(); # We will ignore non-basic where items because only basic has bindings $bindkey = 0; # Exploring wheres of the current Builder foreach ( (array)$query->wheres AS $key => $value) { # If the where type is basic we can check if there is anything to remove. if ( strtolower($value['type']) == 'basic' ) $bindkey++; # If we used the column if ( isset($af_assoc[ $value['column'] ]) ) { # If the autofilter and the binded value is the same we can remove that if ( $bindings[$bindkey - 1] == $value['value'] ) { unset( $bindings[$key] ); } # Remove where entry unset( $query->wheres[$key] ); } } # Re-indexing keys $query->wheres = array_values($query->wheres); array_values($bindings); $builder->setBindings( $bindings ); } /** * Converts autofilter variable to associative variable that we can use for searching * @param array $items_raw Original autofilter set * @return array **/ public function autoFilterAssoc ( array $items_raw ) { $items = array(); foreach ( $items_raw AS $id => $data ) { $items[ $data['column'] ] = array( 'relation' => $data['relation'], 'value' => $data['value'] ); } return $items; } } ?> By default Laravel will attach our scope to sub queries too, that’s why we need the remove function (even though we don’t want to add our filtering to sub-queries). First I thought that this will be easy, I’ll just remove the where and I’ll be done, but the problem was more complicated, if you remove only the “where” entry the bindings will stay in its place therefore every single bindings will be in wrong place. So the affected binding has to be removed as well. If you created the two file and dumped the autoloader you can use the trait in you child models like this: <?php use Illuminate\Database\Eloquent\<span class="hiddenSpellError" pre="use " data-mce-bogus="1"-->AutoFilterTrait; class Article extends Post { use AutoFilterTrait; protected $autoFilter = array( array( "column" => "type", "relation" => "=", "value" => "article" ) ); ?> Also, you can add a saving listener to you boot method of your models like this (only code fragment): <?php class BaseModel extends Eloquent { /** * Column and value pairs **/ protected $autoFillColumn = array(); /** * Fill columns on save if the columns are empty (or fill process is in force mode) * @param bool $force (optional) force column value * @return bool **/ public function autoFillColumns ( $force = false ) { if ( count( $this->autoFillColumn ) ) { foreach ( $this->autoFillColumn AS $column => $data ) { $this->$column = $data; } return true; } else { return false; } } /** * Fires when the model is booting. * @return void **/ protected static function boot() { parent::boot(); static::saving( function( $model ) { if ( count( $model->autoFillColumn ) ) { $model->autoFillColumns(); } }); } } ?> I hope this helps and I wish you the best. If you have any question or comments I’m all ears.

Highlighted testimonial

“My previous developer delayed each deadline due to undisclosed reasons and I was patient in the begining but at some point I made a decision to fire him. I was frightened and despaired at that moment but I had to found a new developer who can finish my project in 2 days or less because I have to pay taxes and salaries even if I have no website. I’m glad I’ve found Jozsef at that time. We discussed the job on phone and it was done in no time. Jozsef was patient, quick and understanding. We will definitely choose him again for our further projects.” — Jónásné