Tobiasz Cudnik

Posts Tagged ‘php’

Get Gmail search queries as terminal output or RSS feeds

In QueryTemplates, Snippets, Workflow on 19.03.2009 at 2:53

Since i’ve implemented GTD in my Gmail account i always find myself in need to see a specific query result, outside gmail interface. Such functionality was one of the main reasons of using Remember The Milk, where queries was really powerful.  IMAP wasn’t an answer, since it was able to export only one label.

Meanwhile i’ve found out about libgmail, a Gmail API for Python. After couple of minutes i’ve got a custom search results inside my terminal :) This could allow to embend it almost everywhere and mainly in conky. After that i’ve decided to build an RSS feeds, scheduled in cron which send them to external server. Problem was that i didn’t want to store the password inside the script nor type it in each time.

As i’m (un)happy user of KDE4 and i know that it comes with quite wide range of language binding so why not try them out. That was PyKDE4 and PyQt4 modules. This one took some more time, since for example every app communicating with KWallet needs to have a window instance, even if it’s windowless. But there were also good sides. I’ve already had my username and password inside KWallet – i’ve configured kopete before. So basically, script doesn’t need any account information. After some struggling i’ve ended up with something like this (gmail-search.py):

Read the rest of this entry »

Personal torrent stream (part 1)

In Web Scraping, phpQuery on 19.03.2009 at 2:52

I really don’t like reading movie reviews before actually seeing them. For this reason, i found a new nanocrowd.com service quite useful. It claims to provide very specific movie recommendations based on opinions of anonymous masses. Although it’s accounts are unfortunately still in private beta, we can test recommendations based on one movie.

Long time i’ve been thinking about downloading movies, without actually downloading them. Finding out nanocrowd convinced me to do this. Of course i’ve used phpQuery’s WebBrowser plugin. Scenario is as follows:

  1. Connect to torrentz.net
  2. Fill search box and submit
  3. Filter results
  4. Print results and ask which to download
  5. Get result sites and find supported one
  6. Download to local filesystem
  7. Optionally, send via SSH to another machine

To be practically usefull, script supports following filters:

–min-size
–max-size
–min-peers

So to get a 1st matching movie in most common cases would be

echo 1 | torrent-download.php “Movie Name” –min-peers=50 –max-size=1500 –min-size=500

Now almost every decent torrent downloading app supports autoloding torrent files found in specified directory. As for today, only thing you need to do is to type movie name. Like i’ve mentioned before, nanocrowd is still not open to registration. When it will be, i will post an update (or maybe someone have a free invitation ?). Anyway, don’t use this code to download illegal movies…

Read the rest of this entry »

QueryTemplates development progress

In QueryTemplates on 01.03.2009 at 1:06

QueryTemplates 1.0 Beta3 is out since a week or so and next release is around the corner, so i decided to do some wrap-up of latest facts in library development:

  • Extended data targets are no supported by all methods. This means each method can be re-targeted with jQuery insert methods like for example varsToSelectorBefore or even varsToSelectorAttr.
  • New codeTo method type. It simply injects code groups. Idea evolved from methodTo approach, which would inject method calls. I find codeTo amuch more flexible and useful, but it can be less readable.
  • New valuesToLoop method. In opposite to varsToLoop aka loop(), it will iterate existing data over DOM structure and commit it right away. This has less purpose on server side (but can be useful), but it’s essential on the client-side when you don’t want to make a server request.
  • New conditional chains methods – onlyJS() and onlyPHP(). They allow to highly customize template for certain language. For example, everything between onlyPHP() and endOnly() will be applied only to PHP template, even when the same chain is used to create JS template.
  • Light version for JavaScript is available. It contains all valuesTo methods which includes valuesToSelector, valuesToStack and valuesToLoop. Form methods and mutation events support will be next. It’s a jQuery plugin and demo is available.
  • formFromVars will generate full form templates from structure and variable informations. Such form supports error messages and default values. Of course input-wrapper template is customizable. As for today there are couple of things to be done in this area and formFromValues will also be available soon.
  • Syntax reference is complete. Each method has it’s own wiki page with 6-part example: markup, data, formula aka code, template, tree dump before and tree dump after. Also, new JavaScript Light version is included in this reference. User comment are allowed. Personally i think it’s the best part of project’s page ;)
  • Some API refactorings had taken place. Old names are still accessible, but marked as deprecated.
    • varsFrom type was created from such methods as saveTextAsVar, saveAsVar, valuesToVars.
    • loop, loopOne and loopSeparate now becomes varsToLoop, varsToLoopFirst and varsToLoopSeparate and are grouped in ToLoop type.
  • dumpTree is now more verbose and can be used both via HTML and plain text. Just do ->dumpTree() anywhere in the chain to see readable representation of selected structure. It’s used for syntax reference examples.

As you can see project is quite close to 1.0 final. Code seems stable and each method has pseudo-unit-test in form of example available in Syntax reference, which is generated as a real template. I just can’t wait to start implementing CSS interface i wrote before. Additionaly, as JavaScript version is out, there can be some use for jQueryServer.

Can CSS stylesheets be applied on the server-side ?

In Ideas, QueryTemplates, Workflow on 27.01.2009 at 3:23

The question is: can CSS stylesheet be applied in the server-side ? And if yes, would would be the purpose ? I should say yes, they can and i would explain how and why. So what for are stylesheets ? “Applying cascading styles onto the DOM” may be the answer. But i would focus more on that why actually stylesheets are used for such purpose?

  • Because they are clean ?
  • Because CSS selectors do so much job, that besides them only really needed things are simple properties with obligatory number of arguments ?
  • Because cascading inheritance is just right for the DOM ?
  • CSS selector are simply benefiting from DOM structure’s nature

So first thing which needs to be implemented on the server is the DOM. When we already got it, so we can query it thou selector, that’s the first half. Now the properties. What could be the property on the server ? border-color ? Rather not. Do we need to style the DOM on the server ? Is it shown anywhere ? Not right now. On the server, page’s DOM is being build. Typically by various ways of string concatenation.

So if we need to build a DOM and same time we can query it with selectors, then the style’s properties should build / modify it’s structure. For example, show some articles or blog posts on the page. So here is pure CSS parser-validable code with some proposed server properties.

.section.articles ul > li {
  /* loop "articles" variable as "article" using "num" as index
  after that remove all other-than-first LIs */
  loop-one: articles num article;

  /* apply filter method on next variable output */
  vars-filter: htmlentities;

  /* use "article" fields and populate them inside nodes
  matched by ".a-%k" where %k is field name, eg .a-title */
  vars-to-selector: articles var(articleFields) null ".a-%k";

  /* example custom method to adding class for 1st loop node using index "num" */
  add-class-to-first: num custom-class;
}
/* show .comments node if variable articleComments is true */
.comments {
  if-var: articleComments;
}
/* bubbled event */
.section.articles:inserted {
  /* another custom method */
  /* null means 0 arguments */
  strip-tables: null;
}

So what have we done here ?

  1. We simply build articles loop which prints it’s contents into proper child nodes automagically. It could have 3 fields or 345, but line in CSS is only one.
  2. We’ve also used a custom method do add class basing on the loop position.
  3. Comments presentance is conditional.
  4. One Mutation Event is used. Hidden in :insert pseudoclass, really named DOMNodeInserted will apply on all new nodes which matches prior selector and were just inserted into the DOM structure.
  5. Each unspecified event defaults to :load.

All properties should be simply methods which applies something on all matched nodes. Sound familiar ? That’s exactly what many of jQuery methods are doing. Take a look:

.section.articles {
  remove-class: section;
  attr: rel section;
  /* all css properties can be used
  but will result in inline "style" attributes */
  css: padding 2px;
}
/* this rule applies to all load-time nodes
and the new one too */
.change-me,
.change-me:inserted {
  text: "changed innerText";
  prepend: "
<div>changed</div>
";
  remove-class: change-me;
  /* reallocation, interesting... */
  insert-into: ".content";
  /* passing some data to forward ? */
  data: some-flag "some value for developer";
}

All from above properties are jQuery methods. Possibilities are huge. But let’s stick with simple things right now. How would it benefit ? Who will write those server-css-sheets ? I should say…

Read the rest of this entry »

Events in CSS selector-driven markup templates make them highly reusable

In Ideas, QueryTemplates on 25.01.2009 at 16:36

One of the biggest adventage of DOM oriented template engines such as QueryTemplates is events support. Using Event Delegation and some Mutation Events you can set global handlers for all templates. Purpose of such handlers may be varient. I’m presenting 6 of them as examples.

Let’s start from events table

Each event can easily have many handlers. One of them is a mutation event – DOMNodeInserted.

$globalHandlers = array(
  array('unload', 'everyTableHaveTbody'),
  array('load', 'insertNavigation'),
  array('DOMNodeInserted', 'newListsAlwaysOrdered'),
  array('unload', 'noAds'),
  array('unload', 'clearEmptyClasses'),
  array('load', 'stripTables'),
);

Here’s our global handlers

// global handlers
// can be functions, methods, create_function and closures (in PHP 5.3)

function everyTableHaveTbody($e) {
  pq($e->target->ownerDocument)
    ->find('table')
      // nested closure should be here
      ->each('everyTableHaveTbodyCallback');
}
function everyTableHaveTbodyCallback($table) {
  if (pq('> tbody', $table)->length == 0)
    pq($table)->contents()->wrapAll('
<tbody>');
}
function noAds($e) {
  pq($e->target->ownerDocument)
    ->find('.ads')->remove();
}
function newListsAlwaysOrdered($e) {
  if (pq($e->target)->is('ul'))
    pq($e->target)->replaceWith(
      pq('
<ol>')->append(
        pq($e->target)->contents()
      )
    );
}
function insertNavigation($e) {
  $nav = pq($e->target->ownerDocument)
    ->find('.navigation')
      ->empty()
      // nested closure should be here
      ->each('insertNavigationCallback');
}
function insertNavigationCallback($nav) {
  pq($nav)->append(file_get_contents('navigation.html'));
}
function stripTables($e) {
  pq($e->target)->find('table.strip-me')
    ->removeClass('strip-me')
    ->find('> tr:odd, > tbody > tr:odd')
      ->addClass('odd');
}
function clearEmptyClasses($e) {
  $nav = pq($e->target->ownerDocument)
    ->find('*[class=""]')
      ->removeAttr('class');
}

Read the rest of this entry »

QueryTemplates – template’s logic and markup in one file

In QueryTemplates, phpQuery on 25.01.2009 at 15:41

Using latest phpQuery revisions you can easily keep template’s markup and logic in one place with 2 extra lines of code. This heavily breaks the general concept, but it may be useful in some cases. Idea is based on support for callbacks as template sources. First you start dumping markup with 1 line.

<?php ob_start(); ?>

After that the markup goes

<html>
  <body>
<div>Hello world</div>
</body>
</html>

And at the end there is whole logic. $markup is dumped using new CallbackReturnValue, which takes a variable as parameter. When callback is called it just returns it.

<?php
require('../src/QueryTemplates.php');
$markup = new CallbackReturnValue(ob_get_clean());
require template('test')->parse($markup)
	->find('div')
		->text('Hello template!')
;

This approach could also be used for getting markup with requestAction in CakePHP views.

toReference() inside chains

In QueryTemplates, phpQuery on 25.01.2009 at 15:26

There is one extremely useful and not-so widely known toReference() method. It saves actually matched elements inside variable, by reference (as the name says). It can be used to target such cases as:

1. Preserving chain

// declare our variables (this is VERY important)
$deepClass = $section = null;
$template['div.main div.otherclass .deep-class:first']
  ->toReference($deepClass)
//  ->...  // do something
  ->find('.section')
    ->toReference($section)
//  ->...  // do something
  ->end()
  ->next()
    // highlighter but; only one empty()
    ->empty()
    ->append($deepClass->contents())
    ->eq(0)->add($section)->eq(1)
//      ->...  // do something, stack is [$section]
    ->end()->end()->end()
//      ->...  // stack is same as after ->next()
;

2. Splitting chains

// declare our variables (this is VERY important)
$row = $titleBody = null;
$template
  ->find('ul:first > li')
    ->loopOne('posts', 'postNum', 'r')
      // add dynamic class
      ->addClassPHP('if (! $postNum) print "first"')
      ->find('> .title, > .body')
        ->varsToStack('r["Post"]', $postFields)
        // save our $titleBody variable
        ->toReference($titleBody)
      ->end()
      // save our $row variable
      ->toReference($row)
//    ->...  // lots of code ;)
;
// just continue your work
$row->find('h3:first, .comments')
// ->...
;
// anywhere...
doSomethingOnFields($titleBody);

In SVN version of QueryTemplates there is a fix for cache issue. The workaround for beta2 is to do “if ($ref)” before, or turning off the cache with “$cacheTimeout = -1″.

Extending QueryTemplates with closures

In QueryTemplates, phpQuery on 25.01.2009 at 14:24

Lastest changes in phpQuery allows us to extend it much more easily. One of the ways to do this is directly same as in jQuery, using phpQuery::extend() method. When you combine this with upcoming closures in PHP 5.3, you will feel like-almost-in-browser. Take a look at this:

$source = dirname(__FILE__).'/table.html';
$rows = array(
	array(
		'field-1' => 'foo1',
		'field-2' => 'foo2',
	),
	array(
		'field-1' => 'bar1',
		'field-2' => 'bar2',
	),
);
// this will work in PHP 5.3
// this code will evaluate on onLoad event, thus is cache firendly
$onload = function() {
  $tableFirstRowClass = function($self, $var, $classname = 'first') {
    return $self->addClassPHP("
      if ($$var == 0)
        print '$classname';
    ");
  };
  // here we pass new closure into extend method, just like in jQuery
  // compact() creates array for us
  phpQuery::extend('phpQueryObject', compact('tableFirstRowClass'));
};
require template('table')->parse($source)
  // just bind it
  ->bind('onload', $onload)
  // just fire it up ;)
  ->trigger('onload')
  ->find('table > tr, table > * > tr')
    ->loopOne('rows', 'i', 'row')
      ->varsToSelector('row', $rows[0])
      // now you can use this just-like-this
      ->tableFirstRowClass('i')
;

But for now to extend phpQuery on-the-fly we have to use create_function or delegate existing one.

We can also use new Scripts plugin feature, which does almost the same. Just like all Scripts’ plugin script files, newly attached function will have all available variables. Example below works in PHP < 5.3:

function onload() {
  // in PHP 5.3, this can be done simply like this
//  phpQuery::script(...
  // but for now we have to use fake phpQuery::$plugins namespace
  phpQuery::$plugins->script('tableFirstRowClass', create_function(
    '$self, $params, &$return, $config', '
    $className = ! $params[1] ? "first" : $params[1];
    $self->addClassPHP("
      if ($$params[0] == 0) print '$className';
    ");
  '));
};
$onload = 'onload';

One major difference between extending Scripts and phpQuery itself is way of using new functions. With our new script, we have to small change to main code.

// using phpQuery::extend()
//->tableFirstRowClass('i')
// using Scripts extend
->script('tableFirstRowClass', 'i')

Test cases for websites using phpQuery and SimpleTest

In Ideas, phpQuery on 13.01.2009 at 23:09

Using phpQuery and some UnitTest framework (SimpleTest in this example) you can automatically test web page for presentence of specific part and it’s position. Set of such tests can save a lot of time during website development and after that even more.

Not only you can do simple tests like “are articles visible” but using WebBrowser plugin you can test whole process, let’s say a user registration. Example of such test i would like to present. This test will include following steps:

  1. Enter main page and follow the registration link
  2. Fill registration form and submit it
  3. Check if result is expected

Like i sad before, SimpleTest is framework of choice, but it doesn’t matter so much. What’s important:

  • WebBrowser needs callbacks
  • Callbacks should be declared as functions (for PHP < 5.3)
  • Inside callbacks, $this variable is unavailable
  • First step of the test should check if last step has succeeded

Full code below:

require('simpletest/autorun.php');
require('phpQuery/phpQuery.php');

class CustomerTest extends UnitTestCase {
	public static $_this;
	public static $registration = array(
		'username' => null,
		'success' => false
	);
	function testRegistration() {
		self::$_this = $this;
		phpQuery::browserGet('http://localhost/tested-site/',
			array('CustomerTest', '_testRegistrationLink')
		);
		$this->assertTrue(
			self::$registration['success'], "Registration unsuccessful"
		);
	}
	function _testRegistrationLink($browser) {
		$registrationLink = null;
		$browser->find('a:contains(rejestracja)')
			->WebBrowser(array('CustomerTest', '_testRegistrationForm'))
			->toReference($registrationLink)
				// jump to _testRegistrationForm
				->click();
		self::$_this->assertTrue(
			$registrationLink->length, "Registration link missing"
		);
	}
	function _testRegistrationForm($browser) {
		$registrationForm = null;
		$username = md5(microtime());
		$browser['.customers.form form']
			->toReference($registrationForm)
			->WebBrowser(array('CustomerTest', '_testRegistrationResult'))
			->find('input[name*=login]')->val($username)->end()
			->find('input[name*=email]')->val($username.'@test.com')->end()
			// jump to _testRegistrationResult
			->submit();
		self::$_this->assertTrue(
			$registrationForm->length, "Registration form missing"
		);
		self::$registration['username'] = $username;
	}
	function _testRegistrationResult($browser) {
		$loginForm = $browser->find('h2:text(Logowanie)');
		self::$_this->assertTrue($loginForm->length, "Login form missing");
		if ($loginForm->length)
			self::$registration['success'] = true;
	}
}

WebBrowser doesn’t support AJAX, so not all sites can be tested like this (although you can do it with AHAH after some work), but cookies and HTTP authentication should satisfy most needs.

Of course that’s noting new, projects accomplishing similar goal exist quite time now, eg jWebUnit, but neither of them have jQuery under the hood  ;)

Having fun using PHP 5.3 closures with phpQuery

In phpQuery on 08.01.2009 at 16:34

Some time ago i’ve wrote about new PHP 5.3 closures feature. Today i would like to show you it in action with phpQuery. If you’re using jQuery you will feel like in home :)

First example illustrates classic inline function, which is used to iterate over li nodes, incrementing each one’s content.

$markup = '
<ul>
	<li>1</li>
	<li>2</li>
	<li>3</li>
</ul>
';
$doc = phpQuery::newDocument($markup);
$doc['li']->each(function($node){
	pq($node)->text(
		pq($node)->text()+1
	);
});
print $doc;

Result will be someting like this (something because i’ve corrected indentation manually).

<ul>
	<li>2</li>
	<li>3</li>
	<li>4</li>
</ul>

Now more complicated stuff – scope inheritance. Scope inheritance means nothing else than ability to use variables declared outside code block (inline function in this case) inside this particular block. In JavaScript we have full inheritance right away. In PHP 5.3 we have to explicitly declare which variable we would like to inherit. It’s done by use keyword.

$markup = '
<div>
	<span>1</span>
	<span>2</span>
	<span>3</span></div>
<div>
	<span>1</span>
	<span>2</span>
	<span>3</span></div>
';
$doc = phpQuery::newDocument($markup);
$doc['div']->each(function($div){
	$div = pq($div);
	$div['span']->each(function($span) use ($div){
		pq($span)->insertBefore($div);
	});
});
print $doc;

We’ve nested one closure inside another. The inner one inherits $div variable from the outer. Lack of such feature for create_function was really problematic. Below you can see the result. Both divs are now empty.

<span>1</span>
<span>2</span>
<span>3</span>
<div></div>
<span>1</span>
<span>2</span>
<span>3</span>
<div></div>

Third example i want to show is about assigning inline function to a variable. It’s handful technique to avoid namespace collisions and of course allow easily pass closure thou the parts of code.

$markup = '
<div>1</div>
<div>2</div>
<div>3</div>
';
$callback = function($node){
	$node = pq($node);
	$node->text(
		'Callbacked: '.$node->text()
	);
};
print phpQuery::newDocument($markup)
	->find('div')->each($callback)->end();

Just how you suspect, every node’s content will be prefixed with “Callbacked: “.

<div>Callbacked: 1</div>
<div>Callbacked: 2</div>
<div>Callbacked: 3</div>

I think that this post clearly illustrates how closures work and that they are important for PHP as web development language.

If you would like to test code from this post and PHP 5.3 in general, download windows build from php.net or compile source yourself for other platform. CLI version will be enough, that means no apache module struggling.

Modify arrays easily using BAM – BulkArrayModifier

In Chainable, Ideas on 30.12.2008 at 22:46

Have you ever needed to modify certain fields in deeply nested array structure ? I’ve had such tasks writing CakePHP views quite often. Tried to use Set, but it only extracts data. When you modify it, you can use it standalone, but not with rest of the data it was stick to before extracting. That’s why i’ve always wanted to write something what will make this process cleaner and more natural, removing the need to write redundant code.

That’s why one evening i sat down and here it is – BulkArrayModifier. Standalone, chainable, ~120 lines class which extracts array’s content via references. It utilizes callbacks as much as possible. Consider this example:

// get all comments from all posts
bam($posts)->all()->key('Comment')->all()->each('modifyTitle');
// and use this callback to modify each one
function modifyTitle($comment) {
  $comment['title'] = "<a>{$comment['title']}</a>";
  return $comment;
}

There is also one-method query, like this:

bam($posts)->path('*.Comment.*')->each('modifyTitle');

You can also apply several callbacks to one bam() object

bam($posts)->path('*.Comment.*')->each('modifyTitle')->reset()
  ->path('*.Post.author')->each('modifyAuthor');

Read the rest of this entry »

QueryTemplates finally released

In QueryTemplates, plainTemplates on 03.12.2008 at 16:47

I’ve finally managed to release QueryTemplates, a pure HTML templating engine i’ve been working past months. There’re extensive examples which should allow anyone to easily understand the idea. Previously posted Pure HTML templates theory sums up some thoughts about this templating pattern. You can read more about new library on the wiki and there’s also an official blog. Feel free to post feedback.

PHP 5.3 introduces closures and inline functions

In The Net on 25.11.2008 at 0:31

I couldn’t believe it in first place, but there are ongoing works to bring closures power to PHP in upcoming 5.3 version! No more create_function() and backslashing backslashed quotes.

There are also some scope inheritance tries (using “use” keyword). Below you have some teasing snippet, after which head to wiki.php.net/rfc/closures for more…

function replace_in_array ($search, $replacement, $array) {
  $map = function ($text) use ($search, $replacement) {
    if (strpos ($text, $search) > 50) {
      return str_replace ($search, $replacement, $text);
    } else {
      return $text;
    }
  };
  return array_map ($map, $array);
}

Keep things from web up-to-date easily

In Web Scraping on 05.11.2008 at 17:11

When some project doesn’t use SVN or any other version-control system (or you can’t use it) you have to download things manually. I don’t have to say that nobody wants to do this, so what can you do to not do it ? You can simulate yourself doing it…

Example below downloads latest release of madwifi branch with new HAL (which i need for my WiFi adapter).

#!/usr/bin/php
find('table tr')->slice(-2, -1)->downloadTo('/target/local/path');
}
?>

Now, to get latest release all i need is to run above script from command line. One missing thing is checking if anything has changed but i leave it to you to resolve ;)

For files which names doesn’t change you can just use wget, like so:

wget 'http://host.net/somefile.zip' -O new-name.zip

jQuery Server Side ports

In The Net on 01.11.2008 at 11:03

jQuery besides achieving such successes as being used by Google or Micro$soft also has ports to other major languages. Most of them are designed to be server-side what opens doors for new uses to the library.

jQuery ports to other languages:

Below some snippets showing each implementation in few lines.

PHP

foreach($doc['ul > li'] as $li) {
  pq($li)->addClass('my-new-class');
      ->filter(':last')
        ->addClass('last-li');
}
$doc['ul > li:last']
  ->addClass('last-li');

Ruby

# load the RedHanded home page
doc = Hpricot(open("http://redhanded.hobix.com/index.html"))
# change the CSS class on links
(doc/"span.entryPermalink").set("class", "newLinks")

Perl

pQuery("http://google.com/search?q=pquery")
  ->find("h2")
    ->each(sub {
      my $i = shift;
        print $i + 1, ") ", pQuery($_)->text, "n";
      });

ActionScript

// add enterFrame event handler
$(stage).enterFrame(function(event:Event):void {
  $("RoundRect").attr("color", function(...args):uint {
    return Math.random() * 0xffffff;
  });
});

List comes from phpQuery wiki page. Do you know any other ports ? Share it in comments.

Update 09.12.08
New jQuery port has been released. This time it’s powered by Python and named PyQuery. Here’s the code:

Python

p = d("#hello")
p.addClass("toto")
p.attr.id = "plop"
p.prependTo(d('#test'))

Eclipse PDT 1.0.5 – Zend’s hidden release

In Software on 22.10.2008 at 10:04

When PDT 2.0 is still slow and DLTK 1.0 hasn’t reached final milestone, Zend guys are using unreleased PDT 1.0.5 in their Zend Studio 6.1. Most important thing is ZS is based on Eclipse 3.4 (Ganymade) and prior PDT 1.0.x builds worked only with 3.3 (Europa).

You can get it in 2 ways – first is to compile it from CVS according to these instructions and the second is just to download Zend Studio 6.1 and copy /features/org.eclipse.php* and /plugins/org.eclipse.php* to Eclipse 3.4 installation.

Update (17.11.2008):
PDT team have officially released 1.0.5 build for Eclipse 3.4. You can get it directly from download page.

Rails’ ActiveSupport ported to PHP

In The Net on 05.10.2008 at 17:16

It’s year old but found it today on benlog.org. I’m verry happy since i’ve been working on project providing similar chains and now i can use well-thought Rails equivalent. Yet i will still write my own implementation as it differs in many ways.

require_once('ActiveSupport.php');
// Outputs "14th"
_(14)->ordinalize();
// Returns number of bytes in 7.3 megabytes
_(7.3)->megabytes();
// Returns true
_("an example sentence")->endsWith("sentence");

I really liked the idea of ‘_‘ suffix to change returned type. See lots of great examples in Rails Rubyisms Advent.

phpQuery edits it’s own wiki

In phpQuery on 05.10.2008 at 3:05

phpQuery can connect to Google Code’s wiki editing form, authorize itself, replace page contents and finally submit the form.

// declare main variable
$pq = null;
// create dummy document as start point
phpQuery::newDocument('
<div>')
// authorize your google account
	->script('google_login')
// redirect authorized XHR component to googlecode's wiki form
	->location('http://code.google.com/p/phpquery/w/edit/test')
// save result as $pq, althought we could continue the chain
// but it would break in case of error...
		->toReference($pq);
if ($pq) {
// read about CallbackReference later in this post...
	$pq->WebBrowser(new CallbackReference($pq))
		->find('textarea:first')
			->val('lorem ipsum')
			->parents('form')
// first submit is Preview, so fire up second
				->find(':submit:eq(1)')
// triggering submit event thought input[type=submit]:click
// is a way to choose which submit is send
					->click();
	if ($pq) {
// print without  tags
		print $pq->script('safe_print');
	}
}

You can notice hot new feature – new CallbackReference($pq). Such callback sets first callback parameter to passed variable, by reference. Such pattern works with all methods accepting callbacks. Thanks to that, we can use if statements instead of function callbacks. In above example, CallbackReference object is called when click event is triggered.

Presented code snippet makes use of new Script plugin, particularly google_login.

Now it can be combined with automated XML documentation to wiki script, but this maybe for jQuery 1.3

Scripts plugin for phpQuery

In phpQuery on 05.10.2008 at 3:05

Scripts plugin is an easy file includer. Each script file have 4 variables in scope:

  • $self Represents $this
  • $params Represents parameters passed to script() method (without script name)
  • $return If not null, will be used as method result
  • $config Content of __config.php file

Possible use cases

  • Authorizations
  • Custom Chains
  • Simple phpQuery plugins
  • Sort functions
  • Website APIs
  • Event binding groups

Example

$return = $self->find($params[0]);

Actually there is only one script which is Google Login. It doesn’t support GMail yet, unfortunately.

Web Scraping with cli version of phpquery piped with sed

In Web Scraping, phpQuery on 05.10.2008 at 3:05

I’ve done what i was thinking about for some time. Terminal-firendly phpQuery CLI interface. Took about 10 minutes of coding… Works like this:

phpquery http://code.google.com/p/phpquery/downloads/list --find '.vt.col_4 a:first' --contents

This will return number of downloads latest phpQuery release file. Notice there is no need to quote url in any way. I was very happy with this so i’ve added callback support in text() and htmlOuter() methods, like so:

phpquery http://code.google.com/p/phpquery/downloads/list --find '.vt.col_4 a:first' --text strip_tags trim

When i had all stuff working, i’ve used it straight away to scrap forums and categories lists from old IPB v1.x. I’ve piped phpQuery result with sed, filtering final output.

// Fetch categories
./phpquery http://forum.wiadomosc.info/ --find '.maintitle a' | sed -r 's/^.*?c=([0-9]+).+?>(.+?)]*>([^<]*)<.*$/1: // 2/g'

PHP in CLI using $argv

In Snippets on 05.10.2008 at 3:05

Just an example showing how easy it is to implement CLI in PHP scripts. Sandbox.php file:

#!/usr/bin/php
<?php
var_dump($argv);
?>

./sandbox.php param1 –param2 param3 param4 –param5 -p 6 -fbi

array(9) {
[0]=>
string(13) "./sandbox.php"
[1]=>
string(6) "param1"
[2]=>
string(8) "--param2"
[3]=>
string(6) "param3"
[4]=>
string(6) "param4"
[5]=>
string(8) "--param5"
[6]=>
string(2) "-p"
[7]=>
string(1) "6"
[8]=>
string(4) "-fbi"
}

phpQuery – a jQuery port to PHP

In phpQuery on 07.07.2007 at 10:56

This post is deprecated and some informations below are outdated.

phpQuery is PHP-port of jQuery – well known and great web2.0 JS library

It’s something different than jQPie, which is form of JS code generator and server-client layer.

For example You can do something like this:

print _('file.htm')
    ->find('body div.cls1.cls2 ul > li:first')
        ->parent()
            ->prepend('
	<li>my new first LI</li>
')
            ->parents('.myClass')
                ->remove()
                ->end()
            ->appendTo('body')
            ->parents('html')
                ->html();

Code above will find first LI inside specific UL, then move pointer into it’s parent (UL),
then prepend (add at the beginning) new LI, then pointer will move to parent element with class .myClass,
which will be removed, and pointer will go back to UL (with end() method), and then UL will be appended to BODY (moved, not copied).
Atfer all this operations parent with tag HTML will be searched and it’s content will be returned to print statement.

phpQuery acts almost like jQuery – it returns new instance on certain methods and allows to revert stack.

It works on DOM Extension and is designed for PHP5 only.

There is almost no docs yet, so please refer to jQuery’s one (DOM section).

Difference against jQuery

phpQuery differs in some cases from jQuery:

  1. Iteration
  2. Callbacks
  3. No DOM nodes
  4. In some method names (PHP reserved words)
  5. PHP specific addons
  6. Other addons

Iteration

phpQuery makes use of PHP’s SPL Iterator interface, so You can do:

foreach(_('ul>*') as $_li) {
	$_li->prepend('new beginning of every LI');
}

Callbacks

PHP doesn’t have closures, but You can still use callbacks – direct or created with create_function() like so:

function imTheCallback($_node){
	$_node->html("i'm changed content");
}
class imTheClass {
	static function imTheStaticCallback($_node){
		$_node->html("i'm changed content v2");
	}
	function imTheCallbackToo($_node){
		$_node->html("i'm changed content v3");
	}
}
$class = new imTheClass;
_('ul>*')
	.each('imTheCallback')
	.each(array('imTheClass', 'imTheStaticCallback'))
	.each(array($class, 'imTheCallbackToo'))
	.each(create_function('$_node', '
		$_node->html("i\'m changed content v4");'
	));
}

No DOM nodes

Every node passed to callback or inside iteration is phpQuery object, not a DOM node. Also there isn’t a get() method.

Method names

There are several methods in jQuery’s interface with names which couldn’t be used as PHP class method or was changed to preserve consistent naming convention.

All those methods have been prefixed with _underscore and here’s the list:

  • _clone
  • _next
  • _prev
  • _empty

PHP specific addons

There are couple of PHP specific addons in phpQuery for easier developement:

  • appendPHP($code) – equals to append(<?php $code ?>)
  • prependPHP($code) – equals to prepend(<?php $code ?>)
  • beforePHP($code) – equals to before(<?php $code ?>)
  • afterPHP($code) – equals to after(<?php $code ?>)
  • attrPHP($attr, $code) – equals to attr($attr, <?php $code ?>)
  • php($code) – equals to html(<?php $code ?>)
  • phpPrint($code) – equals to html(<?php print $code ?>)
  • phpMeta($selector, $code) – equals to find($selector)->php($code)->end()
  • __toString() – equals to htmlWithTag()

Other addons

There is/will be several methods not present in standard jQuery, which i use (with jQuery) in my projects. More about this later.

Development status

Actually phpQuery seems to be quite stable and is main part of plainTemplates lib, which powers this blog.

Although there are couple of things to be done:

  • Dedicated docs (copy jQuery’s one, add PHP specific, generate phpdoc)
  • Missing methods (css, val)

Download and links

Here are the link which could be helpfull when dealing with phpQuery: