PHP type comparison tables Digest

Comparisons of $x with PHP functions
Expression gettype() empty() is_null() isset() boolean : if($x)
$x = “”; string TRUE FALSE TRUE FALSE
$x = null; NULL TRUE TRUE FALSE FALSE
var $x; NULL TRUE TRUE FALSE FALSE
$x is undefined NULL TRUE TRUE FALSE FALSE
$x = array(); array TRUE FALSE TRUE FALSE
$x = false; boolean TRUE FALSE TRUE FALSE
$x = true; boolean FALSE FALSE TRUE TRUE
$x = 1; integer FALSE FALSE TRUE TRUE
$x = 42; integer FALSE FALSE TRUE TRUE
$x = 0; integer TRUE FALSE TRUE FALSE
$x = -1; integer FALSE FALSE TRUE TRUE
$x = “1”; string FALSE FALSE TRUE TRUE
$x = “0”; string TRUE FALSE TRUE FALSE
$x = “-1”; string FALSE FALSE TRUE TRUE
$x = “php”; string FALSE FALSE TRUE TRUE
$x = “true”; string FALSE FALSE TRUE TRUE
$x = “false”; string FALSE FALSE TRUE TRUE

Continue reading “PHP type comparison tables Digest”

HTTP POST by PHP without CURL

source: http://wezfurlong.org/blog/2006/nov/http-post-from-php-without-curl/

<?php
function do_post_request($url, $data, $optional_headers = null)
{
  $params = array('http' => array(
              'method' => 'POST',
              'content' => $data
            ));
  if ($optional_headers !== null) {
    $params['http']['header'] = $optional_headers;
  }
  $ctx = stream_context_create($params);
  $fp = @fopen($url, 'rb', false, $ctx);
  if (!$fp) {
    throw new Exception("Problem with $url, $php_errormsg");
  }
  $response = @stream_get_contents($fp);
  if ($response === false) {
    throw new Exception("Problem reading data from $url, $php_errormsg");
  }
  return $response;
}

Agile Toolkit JavaScript Digest

The purpose of JS chains in Agile Toolkit is to provide a glue between JavaScript and PHP. It is NOT to completely replace native JavaScript.

Agile Toolkit offers a better way to organise your JavaScript code. It is by putting it inside a jQuery namespace. The way you call your function will be slightly different:

// Before
myfunc(123);

// After
$.univ().myfunc(123);

// From PHP
$view->js(true)->univ()->myfunc(123);

 

Extending The Universal library

make a .js file in templates/js and put these codes:

$.each({
    myfunc: function(a){
        alert('myfunc: '+a);
    },
    mysum: function(foo,bar){
        return foo+bar+1;
    },
},$.univ._import);

now you can call js like this:

$page->add('Button')->set('Click Me')
    ->js('click')->_load('secret')
    ->univ()->myfunc('hello world');
/////////////////////////
$page->js(true)->_load('j')->univ()->myfunc(123);

Static Includes

If you are including some 3rd party code, they sometimes might not like dynamic loading. Third party code might assume that the on-ready is not yet triggered or do some other kind of magic. Google Maps code, for example, wants to be loaded along with your page.

If this happens, you can specifically instruct Agile Toolkit to put the include inside the HTML.

$this->api->jui->addStaticInclude('myfile');
// or
$this->api->jui->addStaticInclude('http://pathto/cdn/file.js');

You must be mindful to include this on the page, which is loaded directly, and can potentially open other pages through AJAX, requiring this include. If unsure, add this code to your API’s init() method.

If you want to go even more ‘hardcore’ with the include you can do this:

$this->api->template->append('js_include',
    '<script type="text/javascript" src="http://..."></script>'."\n");

Executing any JS code

One of the goals of JS Chains is security. JavaScript injection is a common problem and by having a nice interface between your JavaScript and server backend you become immune to it.

If you think that you know better, you can execute a string of JavaScript code from anywhere like this:

// DANGER: Contains JavaScript injection vulnerability
$view->js(true,"alert('$my_message')");

// SAFE: $my_message is escaped
$view->js(true)->univ()->alert($my_message);

.

 

Agile Toolkit Database Digest

Connecting to Database

Agile Toolkit API has a function dbConnect() which will automatically read DB configuration from your configuration file and initialize connection. When connection is created, the connection object is accessible through through $api->db property. If you wish, you can create connections to other databases by calling:

$dsn=array('mysql:host=localhost;dbname=testdb', $username, $password, $options);
$mydb=$this->add('DB')->connect($dsn);

.

Creating Query Object

DSQL objects are created by calling dsql() function of either DB object or other DSQL object. This function always returns empty query.

// use default connection
$q = $this->api->db->dsql();
// or
$q = $mydb->dsql();

You may also call $model->dsql() which will return initialized Query Object with your particular Model settings.

.

Query Config:

$db = $this->api->db->dsql();
$db
  ->table('user')
  ->where('type','admin')
  ->field('id');
  // configure more
$data = $db
  ->order('created_dts')
  ->field('name,surname')
  ->getAll();
// Produces: $data=array(
//   array('id'=>1, 'name'=>'John', 'surname'=>'Smith'),
//   array('id'=>2, 'name'=>'Joe', 'surname'=>'Blogs')
// );
//
foreach($this->api->db->dsql()->expr('show tables') as $row){
  $table_name = pop($row);
  $this->add('Text')->set('Table: '.$table_name);
}

 

Debugging:

$q->debug();

 

.

Fetching ways in DSQL:

$data = $q->get();    /* same as getAll();*/
$data = $q->getAll();   /* returns all data as array of hashes, array() if query produced no results.*/
$data = $q->getRow();     /* returns only first row of data, null if query produced no results.*/
$data = $q->getOne();     /* returns only single value, null if query produced no results or result was NULL.*/

//////////////////////////
while($row = $q->fetch()){
  /* Will loop through results fetching one row at a time.
 You can access your data through $row['fieldname'];*/
}
foreach($q as $row){
  // $row is associative array.
}
/////////////////////////

//PDO statement...
$q->execute();    /*Prepares and Executes statement*/
$stmt = $q->stmt;
/////////////////////////

.

Lister class and all derived classes (CompleteLister, Grid) accept Iterate-able classes through setSource() method.

$q=$this->api->db->dsql();
$q->table('user')->field('name')->field('surname');

$grid = $this->add('Grid');
$grid->addColumn('text','name');
$grid->addColumn('text','surname');

$grid->setSource( $q );   // Associate Grid with data-source.

.

=====================================

.

Adding condition to  DSQL

$q->where('id',1);        // where id=:a    'a'=>1
$q->where('id>',1);       // where id>:a    'a'=>1
$q->where('id!=',1);      // where id!=:a   'a'=>1
$q->where('id like',1);   // where id like :a   'a'=>1
$q->where('id in',array(1,2));      // where id in(:a,:b)   'a'=>1, 'b'=>2
/////////////////////////////////

$q->where('id',null);       /* where id is NULL*/
$q->where('id is',null);    /* where id is NULL*/
$q->where('id!=',null);     /* where id is NOT NULL*/
$q->where('id is not',null); /*where id is NOT NULL*/
////////////////////////////////

/*Using with Expressions: expr()
 Single argument mode*/
$q->where($q->expr('a=b'));

// Using operator with the first argument
$q->where('date>',$q->expr('DATE_SUB(CURDATE(), INTERVAL 2 MONTH)');

/* Expression may contain parameters. 
Unlike where('id',1) this will not use equation operator*/
$q->where('age',$q->expr('between 5 and 10'));

// both arguments may be expressions
$q->where($this->expr('length(password)'),$q->expr('between 3 and 10'));

// Alternative way to specify parameter
$q->where($this->expr('length(password)'),'>',5);

.

AND conditions: where(..)->where()

Calling where() multiple times will require all of the conditions to be met. Using “AND” operator.

.

OR conditions: where(array)

Callng where() with a single array argument will use OR to join those conditions. The same principles apply on the array as no the actual where() call. You can even specify arrays recursively.

$q->where(array(
  array('id',1),  
  array('id',2)
  ));/* where (id=:a or id=:b) array('a'=>1, 'b'=>2)*/

$q->where(array(
  array($q->expr('len(name)'),'>',5),
  array($q->expr('a=b'))    
  ));// where (len(name)>:a or a=b) array('a'=>5)

There is alternative way to use OR conditions. Use whichever you like more. on() method relies on expr() to produce a new query. (I think this way is better!)

$q->where( $q->or()->where('a',1)->where('b>',5) );

 

.

Subqueries

You may use $q->dsql() as a quick way to produce sub-queries. Calling this method will create a new DSQL object, which you can use similarly as expression.

$q
 ->table('author')
 ->field('name')
 ->where('book_id', $q->dsql()->table('book')->where('is_rented','Y') ); 
  /*by default "id" field is used.
   produces: 
select name from author where book_id in (select id from book where is_rented=:a)  array('a'=>'Y')
  Note: This is quite ineffective way for listing all authors who's books are rented */

$q
  ->table('author')
  ->field('name')
  ->where(
    $q->dsql()
      ->table('book')
      ->where('author_id', $q->getField('id'))
      ->field('count(*)'),
    '>',5);    
  /* produces:  
select name from author where (select count(*) from book where author_id=author.id)>5
   Displays names of authors who have more than 5 books. */

 

The second argument can be used to specify which table field is queried from. That’s handy when you are joining tables.

$q
  ->table('user')
  ->table('address')
  ->where($q->expr('address.user_id=user.id'))

  ->field('name','user')
  ->field('postcode','address');

/* Produces: 
select user.name, postcode.address from user,address where address.user_id=user.id
Similarly to expressions, you may use subqueries.*/
$q
->table('author')
->field('name')
->field( $q->dsql() ->table('book')->where('author_id',$q->getField('id')) ->field($q->expr('sum(pages)')) , 'total_pages');
/* Produces: select name,(select sum(pages) from book where author_id=author.id) total_pages from author */

 

.

.

.

Querying Data From Multiple Tables. Joins

$q->table('user');
$q->join('address');

echo $q->getField('name');   // will output `user`.`name`
echo $q->getField('name','address');   // will output `address`.`name`

The method join() has several ways to call it. The simplest is by specifying only one string argument.

In this case the table is joined and the table_id from main_table will be used in the “ON” condition.

$q->table('user')->join('address');
/* will produce select user.id from user join address on address.id=user.address_id;*/

/*
By default the "id" of JOINED table is linked with the table_id in the main table. 
This can be changed, however. The "id" of JOINED table can be set to a different 
field if you specify that field with a dot when joining:
*/
$q->table('user')->join('address.user_id');

 // will produce select user.id from user join address on address.user_id=user.id

/*
As you noticed, the field from the main_table was changed to "id". 
If we want to specify that field manually, we can use second argument in the join() method: 
*/

$q->table('user')->join('address.code','code');

 // will produce select user.id from user join address on address.code=user.code

/*Or we can also specify the table which should participate with the join if we use 
the dot in the 2nd argument also*/

$q->table('user')->join('manager');
$q->join('address.code','manager.code');

// will produce select user.id from user
//   join manager on manager.id=user.manager_id
//   join address.code=manager.code

.

Specifying join type

The third argument in the “join” method can be used to specify the type of join. You can use “left”, “right” or “outer” or whatever join type is supported by your SQL. By default the join type is not specified.

$q->table('user')->join('manager',null,'left');
$q->join('address.code','manager.code');

// will produce select user.id from user
//   left join manager on manager.id=user.manager_id
//   join address.code=manager.code

٫

Building a UNION support

First you would need to use a new template for union like this:

$q=$this->useExpr('[q1] UNION [q2]');

Next you need to assign the arguments with setCustom():

$q->setCustom('q1',$q->dsql()->table('book'))
$q->setCustom('q2',$q->dsql()->table('news'));

/* Result:
select * from `book` UNION select * from `news` 

*/

============

Insert:

$this->api->db->dsql()->table('table')->set($associative_array)->do_insert();
$this->api->db->dsql()->table('table')->set('field1','a')->set('field2','b')->do_insert();

Update:

   $this->api->db->dsql()->table('table1 x')
             ->where('id',$somevariable)
             ->set('col1',$somevalue)
             ->debug()
             ->do_update();

Delete:

  $this->api->db->dsql()->table('table1 x')
             ->where('id',$somevariable)
             ->do_delete();

Other Examples:

    $s=$p->add('Model_Story')->loadData($story);
       $s->set('points', $value);
       $s->update();

 

$authors = $this->add('Model_Author'); // selects ALL authors

foreach($authors as $junk){
  echo $authors['name'].': sold '.$authors['books_sold']."\n";
}

 

  $p=$this->add('Model_Purchase');
    $p->addCondition('user_id','in',$m->dsql()->field('id'));
    $p->deleteAll();

============================

$model->load($id);

$model->tryLoad($id)

$model->loadAny()

$model->tryLoadAny()

$model->loadBy($field,$condition,$value);
This have received a significant flexibility in the arguments. Actually it relies on addCondition(), but it’s still powerful.

 loadBy($model->dsql->expr(‘rand() > 0.2’) );
 loadBy($model->dsql->expr(‘rand()’), ‘>‘, $_GET[‘id’] ); // safe against injeciotn
 loadBy(‘calc_field’, 200); // using calculated field automatically switches to “having” clause.

$model->tryLoadBy($field,$condition,$value);

=====================

Another Examples:

$model->addCondition(‘gender’,’M’);
$model->loadAny();
$model->set(‘gender’,’F’);
$model->save();  
//

$boy=$this->add(‘Model_Person’)->addCondition(‘gender’,’M’);
$girl=$this->add(‘Model_Person’)->addCondition(‘gender’,’F’);

$boy->loadAny();
$boy->saveAs($girl);
//

$model->saveAndUnload();
This will save model into the database but will not load data back. The model loaded() will return false. Slightly better if you need performance.

$model->saveLater(); Will not save right away, but will save when model is being destroyed by Garbage Collector;

$model->loadBy('age','>','25');
$model->loadBy($model->dsql->expr('expire_dts>now()'));

//
//getBy($field,[$cond],$value)

/*This similar syntax will return array of hashes produced the model's select.*/
$data = $model->getBy($model->dsql->expr('expire_dts>now()'));
echo json_encode($data);


//getRows(array)
/*
This is similar to getBy but it allows to define which fields you are willing to retrieve:*/
$data = $model->getRows(array('id','name'))
echo json_encode($data);

Iterating Through Entities

foreach($this->add('Model_Book') as $book){
    $book['sale']++;
    $book->save();
}

…..

Agile Toolkit View Digest

View and AbstractView will replace tag <?$_name?> with the name of current object. They will also look for all occurrences of “template” tag and pass content of those tags through “locateURL” method of pathfinder.

 

$page->add('H1')
  ->set('View Demo');
////////////////////////////////
$page->add('Frame')
  ->setTitle('Sample Frame');
  ->add('LoremIpsum');

////////////////////////////////

 $li = $page->add('LoremIpsum')
 ->setLength(1,15);
 $page->add('Button')->set('Refresh')
 ->js('click',$li->js()->reload());

////////////////////////////////

$page->add('Text')
 ->set('sample text');
//To keep you safe from SQL injection, Text will automatically escape htmlentities.
//To avoid escaping use setHtml() method or you can use "Html" class instead.
////////////////////////////////
//Changing button system-wide:
class Button extends View_Button {}
////////////////////////////////////////
$button->setIcon('icon-name');

 

Re-usable HTML chunk of code:

$page->add('View',null,'corner',array('view/snippet'));

HTML snippet with enabled logic

What if your HTML code needs some additional logic? It’s then better to create a separate class for your view:

class Alex extends View {
    public $float='right';
    function init(){
        parent::init();
        $this->setElement('img');
        $this->setAttr('src',$this->api->url('template','images/PinkElephant.jpg'));
    }
    function render(){
        $this ->addStyle('float',$this->float);
        parent::render();
    }
    function align($side){
        $this->float=$side;
        return $this;
    }
}

Special page layout

Suppose your designer wants to put something special on one of your application pages. Redefine defaultTemplate() of your page first:

class page_test extends Page {
    function init(){
        parent::init();
        $this->add('LoremIpsum');
    }
    function defaultTemplate(){
        return array('page/test');
    }
}

Put the code designer asked you to use inside templates/default/page/test.html, but don’t forget to add <?$Content?> tag. It’s recommended that you also use the id=”<?$_name?> for the top-most element of template. That’s not mandatory but will enable event binding and reloading.