Welcome, Guest. Please login or register.
Did you miss your activation email?
Jul. 04, 2009, 07:20:09 PM
50802 Posts in 11235 Topics by 6001 Members
Latest Member: CocoChanels
News: PRADO 3.1.3 is released!
 
The PRADO Community » Prado v3.x » Tips, Snippets and Tutorials » [Tip] Using data received by TActiveRecord in TDataBoundControl « previous next »
Pages: [1] Print
Author Topic: [Tip] Using data received by TActiveRecord in TDataBoundControl  (Read 2732 times)
aztech
Platinum Member
****

Karma: 34
Offline Offline

Posts: 694



View Profile WWW
« on: Feb. 06, 2007, 12:03:11 AM »

As U know, using ActiveRecord is very handy, but useless when we want to databind result from TActiveRecord to any TDataBoundControl like TDataList, TDataGrid, TRepeater, TDropDownList, etc. because ActiveRecord can't be source for those controls.
But there is a light in a tunel Smiley
First what we must to do is to extend our ActiveRecord class

<?php

PRADO
::using('System.Data.ActiveRecord.TActiveRecord');

class 
TOurActiveRecord extends TActiveRecord {

  public function 
onInit($param) {
  
	
parent::onInit($param);
  
	
$this->clearData();
  }

  
/**
   * Our activeRecord data as array()
   *
   * @var array
   * @access private
   */
  
protected static $_data;

  
/**
   * Tell us thet result should be populated as object or as array
   *
   * @var boolean
   * @access protected
   * @static
   */
  
protected static $_populateAsObject true;

  
/**
   * Returns data
   *
   * @return array
   * @access protected
   */
  
private function getData() {
    return 
TOurActiveRecord::$_data;
  }

  
/**
   * Save data
   *
   * @param array $value
   * @access protected
   */
  
private function setData ($value) {
    
TOurActiveRecord::$_data TPropertyValue::ensureArray($value);
  }

  
/**
   * Our main and most important extension of standatd populateObject implementation
   *
   * @param string $type
   * @param array $data
   * @return mixed
   */
  
protected function populateObject($type$data) {
    
$this->setData($data);
    if (
$this->getPopulateAsObj() === true) {
    
	
return 
parent::populateObject($type,$data);
    }
    else {
       return 
$data;
    }
  }

  
/**
   * Ustawia znacznik zwracanego obiektu
   *
   * @param boolea $value
   * @access public
   */
  
public function setPopulateAsObj($value) {
    
TOurActiveRecord::$_populateAsObject TPropertyValue::ensureBoolean($value);
  }

  
/**
   *Setting out flag: if true, activeRecord will return data as Object when false as array
   *
   * @return boolean
   * @access public
   */
  
public function getPopulateAsObj() {
    return 
TOurActiveRecord::$_populateAsObject;
  }

  
/**
   * Return our data as array()
   *
   * @return array
   * @access public
   */
  
public function asArray() {
  
	
return 
TOurActiveRecord::$_data;
  }

  
/**
   * Clear data, to avoid situation, when ActiveRecord returns null and we still have data from last object
   *
   * @return array
   * @access public
   */

  
public static function clearData() {
  
	
TOurActiveRecord::$_data null;
  }

}
?>

Now we can use our extended ActiveRecord class as a base class for all ActiveRecords. But this is not all what we must to do. Second thing is simple extension for every ActiveRecord class e.g. UserRecord, which I put below:

<?php

PRADO
::using('Application.Path_to.TOurActiveRecord');

class 
UserRecord extends TOurActiveRecord {

  public 
$user_id;
  public 
$username;
  public 
$email;
  public 
$pass;
	

  public static 
$_tablename="my_user_database_table_name";

  
/**
   * This is main and most important extension, without this extensions made in TOurActiveRecord are useless!
  *  Setting populateAsObject property we decide what should be returned: object (true) or array (false)
   * @param boolean $populateAsObject
   * @return object
   */

  
public static function finder($populateAsObject true) {
    
self::$_populateAsObject TPropertyValue::ensureBoolean($populateAsObject);
  
	
return 
self::getRecordFinder('UserRecord');
  }
}
?>

Now we can use our UserRecord results as DataSource for TDataBoundControls

  public function onLoad($param) {
    
parent::onLoad($param);
    if (
$this->IsPostBack) {
     
$id $this->Request['id']; //id received by Request
     
$users UserRecord::finder(false)->findByPk($id); //ActiveRecord usage
     
$repeater->DataSource $users//voila!
     
$repeater->dataBind();  //works! adm everybody are happy :)
   
}
  }

I think this approach is much better than declaring SqlMap for such simple query or using sql statement in CreateCommand(). Why? Because we can use full Active Record support for findBy, findAll findByPks and this is huge profit in code readability and really helps when refactoring is needed
« Last Edit: Feb. 06, 2007, 12:25:31 AM by aztech » Logged

MickyMax
Senior Member
***

Karma: 2
Offline Offline

Posts: 107



View Profile
« Reply #1 on: Feb. 06, 2007, 06:47:09 AM »

God work ! Grin Maybe can we add this to the default class ?
Logged
wei
PRADO v3.x Developer
Diamond Member
*****

Karma: 65
Offline Offline

Posts: 2869



View Profile
« Reply #2 on: Feb. 06, 2007, 08:43:40 AM »

you don't need to use arrays in TRepeater if I recall, and it should probably work in other databound controls as well... why is array necessary?
Logged
aztech
Platinum Member
****

Karma: 34
Offline Offline

Posts: 694



View Profile WWW
« Reply #3 on: Feb. 06, 2007, 10:36:47 AM »

Array is necessary because when I use this code:
  $criteria = new TActiveRecordCriteria();
  
$criteria->Condition 'username LIKE :username';
  
$criteria->Parameters[':username'] = '%'.$txt.'%';
  
$criteria->OrdersBy['username'] = 'ASC';
  
$users UserRecord::finder()->findAll($criteria); //its array of objects now
  //..some coding
   
$repeater->DataSource $users;
   
$repeater->dataBind();
I got an error
Code:
<b>Fatal error</b>:  Cannot use object of type UserRecord as array in <b>C:\wamp\www\prado\framework
\TComponent.php(386) : eval()'d code</b> on line <b>1</b><br />
Logged

wei
PRADO v3.x Developer
Diamond Member
*****

Karma: 65
Offline Offline

Posts: 2869



View Profile
« Reply #4 on: Feb. 06, 2007, 10:56:20 PM »

What's the template code for the repeater's item template? you can use, for example

Code:
<%# $this->DataItem->username %>
Logged
aztech
Platinum Member
****

Karma: 34
Offline Offline

Posts: 694



View Profile WWW
« Reply #5 on: Feb. 06, 2007, 11:15:55 PM »

Ohh... now I understand my fallacy. I realize where I make mistake. I though that DataItem must be an array by design - now I know it's not true Smiley thanks
Logged

wei
PRADO v3.x Developer
Diamond Member
*****

Karma: 65
Offline Offline

Posts: 2869



View Profile
« Reply #6 on: Feb. 06, 2007, 11:26:42 PM »

aaah, now you see how powerful the active record can be... also, you can store the PKs in the CustomData entry of any control (e.g. even in the ItemTemplate object).
Logged
aztech
Platinum Member
****

Karma: 34
Offline Offline

Posts: 694



View Profile WWW
« Reply #7 on: Feb. 06, 2007, 11:56:31 PM »

I'm not sure that I good underestand U, when U said that I can store PK in the CustomData entry. Exactly I'm not sure how to receive PK fieldname from ActiveRecord or how to check which public property of ActiveRecord class is a PK. Is there any method to archieve this information?
P.S. Off course I know which should be PK, because I know  database design Smiley
« Last Edit: Feb. 06, 2007, 11:59:25 PM by aztech » Logged

wei
PRADO v3.x Developer
Diamond Member
*****

Karma: 65
Offline Offline

Posts: 2869



View Profile
« Reply #8 on: Feb. 07, 2007, 12:28:24 AM »

something like,
Code:
$gateway = TActiveRecordManager::getInstance()->getRecordGateway();
$columns = $gateway->getMetaData($record)->getColumns();
$pks=array();
foreach($columns as $property=>$column)
{
    if($column->IsPrimaryKey)
        $pks[] = $record->{$property};
}
var_dump($pk);

alot of code, may be a help method can be created.
Logged
aztech
Platinum Member
****

Karma: 34
Offline Offline

Posts: 694



View Profile WWW
« Reply #9 on: Feb. 07, 2007, 12:38:36 AM »

I suggest:
/**
 * $param mixed $record array or single value
 *
**/
TActiveRecord::getPkCol($record)
/**
 * Return array of strings for composite Pk or name of Pk as string
 * @return array or single value
 *
**/
TActiveRecord::getPkNames() or TActiveRecord::getPkName()

ticket #537
« Last Edit: Feb. 07, 2007, 12:43:15 AM by aztech » Logged

Pages: [1] Print 
« previous next »
Jump to: