J1.5

Difference between revisions of "Using the JTable class"

From Joomla! Documentation

(15 intermediate revisions by 7 users not shown)
Line 1: Line 1:
[[Category:Development]]
+
This tutorial is for {{JVer|1.5}} In Joomla! 1.5.
 +
 
 
== Writing an extension of JTable ==
 
== Writing an extension of JTable ==
  
The [[JTable]] class is an implementation of the [http://en.wikipedia.org/wiki/Active_record_pattern Active Record] design pattern. It is used throughout Joomla! for [http://en.wikipedia.org/wiki/Create,_read,_update_and_delete creating, reading, updating, and deleting] records in the database table.
+
The [http://api.joomla.org/1.5/Joomla-Framework/Table/JTable.html JTable] class is an implementation of the [http://en.wikipedia.org/wiki/Active_record_pattern Active Record] design pattern. It is used throughout Joomla! for [http://en.wikipedia.org/wiki/Create,_read,_update_and_delete creating, reading, updating, and deleting] records in the database table.
  
 
To use JTable, create an extension of the class. In this example, we have a database table containing recipes.
 
To use JTable, create an extension of the class. In this example, we have a database table containing recipes.
  
<pre>
+
<source lang="php">
 
<?php
 
<?php
  
Line 27: Line 28:
 
}
 
}
 
}
 
}
</pre>
+
</source>
  
 
When naming your class extension, the convention is to prefix it with 'Table', then follow with a [http://en.wikipedia.org/wiki/CamelCase CamelCased] version of the table's name. All of the member variables of your class should match the column names in the database. The default values should be valid according to the table schema For instance, if you have columns that are NOT NULL, you must use a value other than 'null' as the default.
 
When naming your class extension, the convention is to prefix it with 'Table', then follow with a [http://en.wikipedia.org/wiki/CamelCase CamelCased] version of the table's name. All of the member variables of your class should match the column names in the database. The default values should be valid according to the table schema For instance, if you have columns that are NOT NULL, you must use a value other than 'null' as the default.
 +
 +
An important thing to note here, is that the file containing your table class, has to be named the same as the class minus prefix in lowercase. So for this example, you would have to name your table class file 'recipes.php'.
  
 
Finally,  create a constructor for the class that accepts a reference to the current database instance. This will call the parent constructor which needs the name of the table, the name of the primary key column, and the database instance. The name of the table uses #__ instead of jos_, as the administrator can pick any table prefix desired during Joomla! installation.
 
Finally,  create a constructor for the class that accepts a reference to the current database instance. This will call the parent constructor which needs the name of the table, the name of the primary key column, and the database instance. The name of the table uses #__ instead of jos_, as the administrator can pick any table prefix desired during Joomla! installation.
Line 35: Line 38:
 
If you were using this class as a part of a component called 'Recipes', you would place this code in the file /administrator/components/com_recipes/tables/recipes.php.
 
If you were using this class as a part of a component called 'Recipes', you would place this code in the file /administrator/components/com_recipes/tables/recipes.php.
  
 +
You can use this functionallity just as well outside components, i.e. in plugins and modules. As a general rule you should avoid writing to the database from a module, and use plugins/components for this. Remember to use the built-in [[constants]] when linking to a custom path (outside the 'adminstrator/{com_yourcomponent}/tables' folder).
  
 
== Using a JTable class extension ==
 
== Using a JTable class extension ==
Line 40: Line 44:
 
Once the table class is in place, you can use it in any Joomla! extension. To include the file, place this line in your extension's source code (use com_nameofyourcomponent in place of com_recipes):
 
Once the table class is in place, you can use it in any Joomla! extension. To include the file, place this line in your extension's source code (use com_nameofyourcomponent in place of com_recipes):
  
<pre>
+
<source lang="php">
 
JTable::addIncludePath(JPATH_ADMINISTRATOR.DS.'components'.DS.'com_recipes'.DS.'tables');
 
JTable::addIncludePath(JPATH_ADMINISTRATOR.DS.'components'.DS.'com_recipes'.DS.'tables');
</pre>
+
</source>
  
 
To get an instance of the object, use this code:
 
To get an instance of the object, use this code:
  
<pre>
+
<source lang="php">
 
$row =& JTable::getInstance('recipes', 'Table');
 
$row =& JTable::getInstance('recipes', 'Table');
</pre>
+
</source>
 +
 
 +
If doesn't work use:
 +
<source lang="php">
 +
$row =& JTable::getInstance('recipes', 'NAMEOFCOMPONENTTable');
 +
</source>
 +
(Where NAMEOFCOMPONENT is the name of the component that contais the table).
  
 
Notice that the lowercase version of the suffix of your class name is used as the first parameter, with the prefix 'Table' as the second. Also, the getInstance() member function of JTable returns the object by reference instead of value; use =& to enforce this.  
 
Notice that the lowercase version of the suffix of your class name is used as the first parameter, with the prefix 'Table' as the second. Also, the getInstance() member function of JTable returns the object by reference instead of value; use =& to enforce this.  
Line 54: Line 64:
 
In a model class (extends JModel) you can also use:
 
In a model class (extends JModel) you can also use:
  
<pre>
+
<source lang="php">
 
$row =& $this->getTable('recipes');
 
$row =& $this->getTable('recipes');
</pre>
+
</source>
  
 
Notice that if you have not used the standard naming convention, you can supply the class prefix as the optional second parameter.
 
Notice that if you have not used the standard naming convention, you can supply the class prefix as the optional second parameter.
  
 
=== Checkout/Checkin ===
 
=== Checkout/Checkin ===
Common scenario is when multiple users are editing identical item (e.g article, category, user and etc) simultaneously, which in turn, may results in arbitrary data when saved by the users (depends on who last saved the item). Joomla! solves such cases of unknown modification ownership using Checkouts and Checkins in order to provide access only to one user at a time. For example, if one user began editing an article, then it is said that the article was '''checked out''' by the user, when finished working with the article (usually by closing it using a button), the article is '''checked in''' by the user. At the time the user was editing the article, no other user could edit the same article, unless manually specified by a user with right permissions. You can find further explanation [http://help.joomla.org/content/view/202/153/ here].
+
Common scenario is when multiple users are editing identical item (e.g article, category, user and etc) simultaneously, which in turn, may results in arbitrary data when saved by the users (depends on who last saved the item). Joomla! solves such cases of unknown modification ownership using Checkouts and Checkins in order to provide access only to one user at a time. For example, if one user began editing an article, then it is said that the article was '''checked out''' by the user, when finished working with the article (usually by closing it using a button), the article is '''checked in''' by the user. At the time the user was editing the article, no other user could edit the same article, unless manually specified by a user with the right permissions. You can find further explanation [http://help.joomla.org/content/view/202/153/ here].
 
The following examples demonstrate how Checkout/Checkin may be implemented.
 
The following examples demonstrate how Checkout/Checkin may be implemented.
  
 
'''Checkout'''
 
'''Checkout'''
<pre>
+
<source lang="php">
 
// retrieve item identifier from request
 
// retrieve item identifier from request
 
$itemId  = JRequest::getInt('itemId');
 
$itemId  = JRequest::getInt('itemId');
Line 71: Line 81:
 
$user    = JFactory::getUser();
 
$user    = JFactory::getUser();
  
// load the item's data so we'll with what item were dealing with
+
// load the item's data so we'll know with what item were dealing with
 
if (!$row->load($itemId)) {
 
if (!$row->load($itemId)) {
 
     return JError::raiseWarning( 500, $row->getError() );
 
     return JError::raiseWarning( 500, $row->getError() );
 
}
 
}
  
// check if the item was checked out, and if it does whether or not it was checked out by the user
+
// check out the item
 
if ($row->checkout($user->id)) {
 
if ($row->checkout($user->id)) {
     echo 'The item cannot be edited at the moment since it was checked out by another user.';
+
     echo 'Item was checked out by the user.';
 
} else {
 
} else {
     echo 'The item can be edited!";
+
     return JError::raiseWarning( 500, $row->getError() );
 
}
 
}
</pre>
+
</source>
 
'''checkout()''' will signal the item was checked out by the user whom ID we provided as an argument to the method.
 
'''checkout()''' will signal the item was checked out by the user whom ID we provided as an argument to the method.
  
 
'''Checkin'''
 
'''Checkin'''
<pre>
+
<source lang="php">
 
// retrieve item identifier from request
 
// retrieve item identifier from request
 
$itemId  = JRequest::getInt('itemId');
 
$itemId  = JRequest::getInt('itemId');
Line 92: Line 102:
 
$user    = JFactory::getUser();
 
$user    = JFactory::getUser();
  
// load the item's data so we'll with what item were dealing with
+
// load the item's data so we'll know with what item were dealing with
 
if (!$row->load($itemId)) {
 
if (!$row->load($itemId)) {
 
     return JError::raiseWarning( 500, $row->getError() );
 
     return JError::raiseWarning( 500, $row->getError() );
 
}
 
}
  
// check whether the item was checked out
+
// check if the item was checked out, and if it does - whether or not it was checked out by the user
 
if($row->isCheckedOut($user->id)) {
 
if($row->isCheckedOut($user->id)) {
 
     // check in the item
 
     // check in the item
Line 106: Line 116:
 
     }
 
     }
 
}
 
}
</pre>
+
</source>
 
We use '''isCheckedOut()''' to find out whether the item was checked out,  it returns TRUE in the following cases:
 
We use '''isCheckedOut()''' to find out whether the item was checked out,  it returns TRUE in the following cases:
 
<ul>
 
<ul>
 
<li>Item is empty (i.e no data was loaded to the item).</li>
 
<li>Item is empty (i.e no data was loaded to the item).</li>
 
<li>The item does not support checkout, which can be as a result of database design.</li>
 
<li>The item does not support checkout, which can be as a result of database design.</li>
<li>The supplied user ID does not match the ID of the user who checked out the item, meaning the item is probably being edited by another user already, or the user did not properly checked in the item. '''This is probably the most common scenario''' when dealing with items in the backend.</li>
+
<li>The supplied user ID does not match the ID of the user who checked out the item, meaning the item is probably being edited by another user already, or the user who last checked out the item did not properly checked in the item. '''This is probably the most common scenario''' when dealing with items in the backend.</li>
 
</ul>
 
</ul>
 
'''isCheckedOut()''' returns FALSE in the following cases:
 
'''isCheckedOut()''' returns FALSE in the following cases:
 
<ul>
 
<ul>
 
<li>The item was not checked out by any user.</li>
 
<li>The item was not checked out by any user.</li>
<li>The item was checked out, but by the same person who is checking out again (i.e the user with the ID we passed to checkout()).
+
<li>The item was checked out, but by the same user who checked it out (i.e the user with the ID we passed to isCheckedOut()).
 
</ul>
 
</ul>
  
Line 126: Line 136:
 
Once you have this array, you can pass it into the bind() method of JTable. Doing this will match the associated items of the array with member variables of the class. In the following example, the array is retrieved from JRequest::get('post') and immediately passed into bind().  
 
Once you have this array, you can pass it into the bind() method of JTable. Doing this will match the associated items of the array with member variables of the class. In the following example, the array is retrieved from JRequest::get('post') and immediately passed into bind().  
  
<pre>
+
<source lang="php">
 
if (!$row->bind( JRequest::get( 'post' ) )) {
 
if (!$row->bind( JRequest::get( 'post' ) )) {
 
return JError::raiseWarning( 500, $row->getError() );
 
return JError::raiseWarning( 500, $row->getError() );
 
}
 
}
</pre>
+
</source>
  
 
If bind() fails, you want to stop the application and explain the failure before your extension attempts to send the data. The raiseWarning() function of JError allows you to stop Joomla!, while the getError() function returns the error message stored in the JTable object.
 
If bind() fails, you want to stop the application and explain the failure before your extension attempts to send the data. The raiseWarning() function of JError allows you to stop Joomla!, while the getError() function returns the error message stored in the JTable object.
Line 136: Line 146:
 
When binding succeeds and your object is ready, call the store() function. Again, if something goes wrong, stop the application and explain why.  
 
When binding succeeds and your object is ready, call the store() function. Again, if something goes wrong, stop the application and explain why.  
  
<pre>
+
<source lang="php">
 
if (!$row->store()) {
 
if (!$row->store()) {
 
JError::raiseError(500, $row->getError() );
 
JError::raiseError(500, $row->getError() );
 
}
 
}
</pre>
+
</source>
  
 
Notes:
 
Notes:
Line 149: Line 159:
 
To load a specific row of the database with JTable, pass the key into the load() member function.
 
To load a specific row of the database with JTable, pass the key into the load() member function.
  
<pre>
+
<source lang="php">
 
$row->load( $id );
 
$row->load( $id );
</pre>
+
</source>
  
 
This relies on the key column you specified in the second parameter of parent::__construct() when you extended JTable.
 
This relies on the key column you specified in the second parameter of parent::__construct() when you extended JTable.
Line 158: Line 168:
 
Like read(), delete() allows you to destroy a specific row in the table based on the key specified earlier.
 
Like read(), delete() allows you to destroy a specific row in the table based on the key specified earlier.
  
<pre>
+
<source lang="php">
 
$row->delete( $id );
 
$row->delete( $id );
</pre>
+
</source>
  
 
If you want to delete multiple rows at once, you will need to write the query manually.
 
If you want to delete multiple rows at once, you will need to write the query manually.
Line 169: Line 179:
 
== Summary ==
 
== Summary ==
 
When properly extended, JTable gives you all of the basic functions you need for managing and retrieving records in a database table. Member functions take care of the rest when you add member variables, the table name, and the key column.
 
When properly extended, JTable gives you all of the basic functions you need for managing and retrieving records in a database table. Member functions take care of the rest when you add member variables, the table name, and the key column.
 +
 +
[[Category:Archived version Joomla! 1.5]]

Revision as of 02:54, 3 July 2013

The "J1.5" namespace is an archived namespace. This page contains information for a Joomla! version which is no longer supported. It exists only as a historical reference, it will not be improved and its content may be incomplete and/or contain broken links.

This tutorial is for Joomla 1.5 In Joomla! 1.5.

Writing an extension of JTable[edit]

The JTable class is an implementation of the Active Record design pattern. It is used throughout Joomla! for creating, reading, updating, and deleting records in the database table.

To use JTable, create an extension of the class. In this example, we have a database table containing recipes.

<?php

defined('_JEXEC') or die();

class TableRecipes extends JTable
{
	var $id = null;
	var $ingredients = null;
	var $instructions = null;
	var $serves = null;
	var $difficulty = null;
	var $prep_time = null;
	var $cook_time = null;
	var $published = 0;
	
	function __construct(&$db)
	{
		parent::__construct( '#__recipes', 'id', $db );
	}
}

When naming your class extension, the convention is to prefix it with 'Table', then follow with a CamelCased version of the table's name. All of the member variables of your class should match the column names in the database. The default values should be valid according to the table schema For instance, if you have columns that are NOT NULL, you must use a value other than 'null' as the default.

An important thing to note here, is that the file containing your table class, has to be named the same as the class minus prefix in lowercase. So for this example, you would have to name your table class file 'recipes.php'.

Finally, create a constructor for the class that accepts a reference to the current database instance. This will call the parent constructor which needs the name of the table, the name of the primary key column, and the database instance. The name of the table uses #__ instead of jos_, as the administrator can pick any table prefix desired during Joomla! installation.

If you were using this class as a part of a component called 'Recipes', you would place this code in the file /administrator/components/com_recipes/tables/recipes.php.

You can use this functionallity just as well outside components, i.e. in plugins and modules. As a general rule you should avoid writing to the database from a module, and use plugins/components for this. Remember to use the built-in constants when linking to a custom path (outside the 'adminstrator/{com_yourcomponent}/tables' folder).

Using a JTable class extension[edit]

Once the table class is in place, you can use it in any Joomla! extension. To include the file, place this line in your extension's source code (use com_nameofyourcomponent in place of com_recipes):

JTable::addIncludePath(JPATH_ADMINISTRATOR.DS.'components'.DS.'com_recipes'.DS.'tables');

To get an instance of the object, use this code:

$row =& JTable::getInstance('recipes', 'Table');

If doesn't work use:

$row =& JTable::getInstance('recipes', 'NAMEOFCOMPONENTTable');

(Where NAMEOFCOMPONENT is the name of the component that contais the table).

Notice that the lowercase version of the suffix of your class name is used as the first parameter, with the prefix 'Table' as the second. Also, the getInstance() member function of JTable returns the object by reference instead of value; use =& to enforce this.

In a model class (extends JModel) you can also use:

$row =& $this->getTable('recipes');

Notice that if you have not used the standard naming convention, you can supply the class prefix as the optional second parameter.

Checkout/Checkin[edit]

Common scenario is when multiple users are editing identical item (e.g article, category, user and etc) simultaneously, which in turn, may results in arbitrary data when saved by the users (depends on who last saved the item). Joomla! solves such cases of unknown modification ownership using Checkouts and Checkins in order to provide access only to one user at a time. For example, if one user began editing an article, then it is said that the article was checked out by the user, when finished working with the article (usually by closing it using a button), the article is checked in by the user. At the time the user was editing the article, no other user could edit the same article, unless manually specified by a user with the right permissions. You can find further explanation here. The following examples demonstrate how Checkout/Checkin may be implemented.

Checkout

// retrieve item identifier from request
$itemId  = JRequest::getInt('itemId');
// the user to test checkout with, could be any other user you want
$user     = JFactory::getUser();

// load the item's data so we'll know with what item were dealing with
if (!$row->load($itemId)) {
    return JError::raiseWarning( 500, $row->getError() );
}

// check out the item
if ($row->checkout($user->id)) {
    echo 'Item was checked out by the user.';
} else {
    return JError::raiseWarning( 500, $row->getError() );
}

checkout() will signal the item was checked out by the user whom ID we provided as an argument to the method.

Checkin

// retrieve item identifier from request
$itemId  = JRequest::getInt('itemId');
// the user to test checkout with, could be any other user you want
$user     = JFactory::getUser();

// load the item's data so we'll know with what item were dealing with
if (!$row->load($itemId)) {
    return JError::raiseWarning( 500, $row->getError() );
}

// check if the item was checked out, and if it does - whether or not it was checked out by the user
if($row->isCheckedOut($user->id)) {
    // check in the item
    if ($row->checkin()) {
        echo 'The item was checked in, and can now be edited by other users.';
    } else {
        return JError::raiseWarning( 500, $row->getError() );
    }
}

We use isCheckedOut() to find out whether the item was checked out, it returns TRUE in the following cases:

  • Item is empty (i.e no data was loaded to the item).
  • The item does not support checkout, which can be as a result of database design.
  • The supplied user ID does not match the ID of the user who checked out the item, meaning the item is probably being edited by another user already, or the user who last checked out the item did not properly checked in the item. This is probably the most common scenario when dealing with items in the backend.

isCheckedOut() returns FALSE in the following cases:

  • The item was not checked out by any user.
  • The item was checked out, but by the same user who checked it out (i.e the user with the ID we passed to isCheckedOut()).

checkin() will purge any checkout state that was applied to the item.

Create/Update[edit]

In a typical situation, you will have an HTML form submitted by the user which will PHP will interpret for you as an associative array. The JRequest class in Joomla! has functions ready to assist with retrieving this data safely. Use JRequest::get('post') to retrieve all of the elements in the HTTP POST request as a sanitized array.

Once you have this array, you can pass it into the bind() method of JTable. Doing this will match the associated items of the array with member variables of the class. In the following example, the array is retrieved from JRequest::get('post') and immediately passed into bind().

if (!$row->bind( JRequest::get( 'post' ) )) {
	return JError::raiseWarning( 500, $row->getError() );
}

If bind() fails, you want to stop the application and explain the failure before your extension attempts to send the data. The raiseWarning() function of JError allows you to stop Joomla!, while the getError() function returns the error message stored in the JTable object.

When binding succeeds and your object is ready, call the store() function. Again, if something goes wrong, stop the application and explain why.

if (!$row->store()) {
	JError::raiseError(500, $row->getError() );
}

Notes:

  • If any member variables of your JTable object are null when store() is called, they are ignored by default. This allows you to update specific columns of your table, while leaving the others untouched. If you wish to override this behavior to ensure that all columns have a value, pass true into store().
  • The JTable::bind() and JRequest::get() functions do not enforce data types. If you need a column to be a specific type (for instance, integer), you need to add this logic to your code before calling store().

Read[edit]

To load a specific row of the database with JTable, pass the key into the load() member function.

$row->load( $id );

This relies on the key column you specified in the second parameter of parent::__construct() when you extended JTable.

Delete[edit]

Like read(), delete() allows you to destroy a specific row in the table based on the key specified earlier.

$row->delete( $id );

If you want to delete multiple rows at once, you will need to write the query manually.

Member Functions[edit]

This package is not yet documented.

Summary[edit]

When properly extended, JTable gives you all of the basic functions you need for managing and retrieving records in a database table. Member functions take care of the rest when you add member variables, the table name, and the key column.