Les 6 – Update

Lesbeschrijving

In deze les ga je de update toevoegen aan het formulier.
Hiervoor moeten de volgende stappen gezet worden:

  • Tabel uitbreiden met een update optie per regel
  • Update actie opvangen en formulier met update optie tonen
  • Update formulier afhandelen in de GUI
  • Applicatie uitbreiden met de update actie in de database

Stappenplan

1. Tabel uitbreiden met een update optie per regel.
Op de plek waar de tabel getoond word maak je een extra kolom met een update knop.
De update knop bestaat uit een linkje naar dit formulier. Aan de link wordt een action meegegeven en het id waar het omgaat.

Eerst maken we de link aan op basis van de eerder gemaakte $base_url voor deze pagina. Daar voegen we de parameters action en id aan toe.

Open meo_admin_event_category.php en voeg de volgende code toe:

//** Show all event categories in the tabel
foreach( $cat_list as $event_cat_obj){

// Create update link
$params = array( 'action' => 'update', 'id' => $event_cat_obj->getId());

// Add params to base url update link
$upd_link = add_query_arg( $params, $base_url );

In de tabel moet een kolom met een update optie worden toegevoegd:

<td width="180"><?php echo $event_cat_obj->getName(); ?></td>
<td width="200"><?php echo $event_cat_obj->getDescription();?></td>
<td><a href="<?php echo $upd_link; ?>">Update</a></td>

2. Update formulier tonen

Om het update formulier te tonen moeten we de GET waarden die we mee geven opvangen. In de applicatie maken we een functie die de waarden opvraagt. Deze functie maken we eerst.

2.2. Applicatie aanpassen

Open EventCategory.php en voeg de volgende functie toe:

/**
* getGetValues :
*  Filter input and retrieve GET input params
* 
* @return array containing known GET input fields
*/
public function getGetValues(){
// Define the check for params
$get_check_array = array (

// Action
'action' => array('filter' => FILTER_SANITIZE_STRING ),

// Id of current row
'id'    => array( 'filter'    => FILTER_VALIDATE_INT ));

// Get filtered input:
$inputs = filter_input_array( INPUT_GET, $get_check_array );

// RTS
return $inputs;

}

Naast deze functie maak je ook een functie die de get action opvangt en eventuele functionaliteit afhandeld.

Voeg de volgende functie toe:

/**
*  Check the action and perform action on :
*  -delete
* 
* @param type $get_array all get vars en values
* @return string the action provided by the $_GET array.
*/
public function handleGetAction( $get_array ){
$action = '';

switch($get_array['action']){
case 'update':
// Indicate current action is update if id provided
if ( !is_null($get_array['id']) ){
$action = $get_array['action'];
}
break;

case 'delete':
// Delete current id if provided
if ( !is_null($get_array['id']) ){
$this->delete($get_array);
}
$action = 'delete';
break;

default:
// Oops
break;
}
return $action;
}

2.3 Admin GUI aanpassen

De functie wordt aangeroepen vanuit de GUI. Hiervoor voeg je de volgende code toe aan de admin GUI:

// Add params to base url
$base_url = add_query_arg( $params, $base_url );

// Get the GET data in filtered array
$get_array = $event_categories->getGetValues();

/*
echo '<pre>';
echo __FILE__.__LINE__.'<br />';
var_dump($get_array);
echo '</pre>';
//*/

// Keep track of current action.
$action = FALSE;
if (!empty($get_array)){

// Check actions
if (isset($get_array['action'])){
$action = $event_categories->handleGetAction($get_array);
}
}

Je kunt nu de functie testen door op de gemaakte update knop te klikken. Je krijgt dan een dump te zien van de ingelezen variabelen. Hierin zit een variabele action => ‘update’ en een id.

De variabele action ga je gebruiken om in de tabel de juiste rij te veranderen in update fields.

2.4 Aanmaken van het GUI formuiler

Start met het aanmaken van een formulier. Dit formulier moet helemaal om de tabel heenstaan.

Admin event categorie CRUD.<br />
( Uitje, excursie, etc)
<?php
echo ($add ? "<p>Added a new event</p>" : "");
// Check if action == update : then start update form
echo (($action == 'update') ? '<form action="'.$base_url.'" method="post">' : '');
?>
<table>

En stop het formulier weer aan het einde:

/table>
<?php                
// Check if action = update : then end update form
echo (($action == 'update' ) ? '</form>' : '');
?>

Om de tabel aan te passen en invoer velden te krijgen verander je de tabel op de volgende manier:

<tr><td width="10"><?php echo $event_cat_obj->getId(); ?></td>
<?php
// If update and id match show update form
// Add hidden field id for id transfer
if (($action == 'update') && ($event_cat_obj->getId() == $get_array['id'])){
?>                            
<td width="180"><input type="hidden" name="id" value="<?php echo $event_cat_obj->getId(); ?>">
<input type="text" name="name" value="<?php echo $event_cat_obj->getName(); ?>"></td>
<td width="200"><input type="text" name="description" value ="<?php echo $event_cat_obj->getDescription();?>"></td>
<td colspan="2"><input type="submit" name="update" value="Updaten" /></td>
<?php } else { ?>
<td width="180"><?php echo $event_cat_obj->getName(); ?></td>
<td width="200"><?php echo $event_cat_obj->getDescription();?></td>
<?php              if ($action !== 'update') { 
// If action is update don’t show the action button
?>
<td><a href="<?php echo $upd_link; ?>">Update</a></td>                   
<?php                   
} // if action !== update
?>
<?php } // if acton !== update ?> 
</tr>
<?php               } // foreach event category

Nu nog het insert formulier uitzetten wanneer er geupdate wordt:

// Check if action = update : then end update form
echo (($action == 'update' ) ? '</form>' : '');
/** Finally add the new entry line only if no update action **/
if ($action !== 'update'){
?>               
<form action="<?php echo $base_url; ?>" method="post">
<table>    
<tr><td><input type="text" name="name" ></td>
<td><input type="text" name="description"></td></tr>
<tr><td colspan="2"><input type="submit" name="add" 
value="Toevoegen" /></td>
</tr>
</table>
</form>      
<?php
} // if action !== update
?>
</div>

3. Update submit afhandelen

Het aangepaste formulier heeft zijn eigen submit button. Deze moet nog afgehandeld worden.
Hiervoor maken we de volgende aanpassingen:

In EventCategory.php :

/**
* getPostValues :
*  Filter input and retrieve POST input params
* 
* @return array containing known POST input fields
*/
public function getPostValues(){
// Define the check for params
$post_check_array = array (
// submit action
'add'   => array('filter' => FILTER_SANITIZE_STRING ),
'update'   => array('filter' =>FILTER_SANITIZE_STRING ),
// List all update form fields !!!

// event type name.
'name'   => array('filter' => FILTER_SANITIZE_STRING ),               

// Help text
'description'   => 
array('filter' => FILTER_SANITIZE_STRING ),

// Id of current row
'id'    => array( 'filter'    => FILTER_VALIDATE_INT )
);

In de admin GUI meo_admin_event_category.php:

// Get the GET data in filtered array
$get_array = $event_categories->getGetValues();

// Get the POST data in filtered array
$post_array = $event_categories->getPostValues();
/*
echo '<pre>';
echo __FILE__.__LINE__.'<br />';
var_dump($post_array);
var_dump($get_array);
echo '</pre>';
//*/

// Collect Errors
$error = FALSE;

// Keep track of current action.
$action = FALSE;

// Check the POST data
if (!empty($post_array)){
$add = FALSE;    

// Check the add form:
if (!is_null($post_array['add']) ){
// Save event categorie
$result = $event_categories->save($post_array);
if ($result){

// Save was succesfull
$add = TRUE;

} else {
// Indicate error
$error = TRUE;
}
}
// Check the update form:
if (isset($post_array['update']) ){
// Save event categorie
$event_categories->update($post_array);
}
}

4. Update aan de applicatie toevoegen

Om de update werkend te krijgen moet er in de applicatie de update functie worden toegevoegd. Omdat je steeds in de EventCategory class in dezelfde tabel zit te werken, willen we de kans op typefouten zo klein mogelijk maken. Hiervoor maak je een nieuwe private functie aan die de tabel naam terug geeft.

In een klasse staan functies in alfabethische volgorde en de private functies staan onderaan na de public functies. Op deze manier kun je ze makkelijk terug vinden.

Voeg aan EventCategory.php de volgende code toe:

/**
* 
* @global type $wpdb
* @return type string table name with wordpress (and app prefix)
*/
private function getTableName(){
global $wpdb;
return $table = $wpdb->prefix . "meo_event_category";
}

Voeg aan EventCategory.php de volgende code toe:

/**
* 
* @global type $wpdb WordPress database
* @param type $input_array post_array
* @return boolean TRUE on Succes else FALSE
* @throws Exception
*/
public function update($input_array){
try {
$array_fields = array('id', 'name', 'description');
$table_fields = array( 'id_event_category', 'name' , 'description');
$data_array = array();

// Check fields
foreach( $array_fields as $field){

// Check fields
if (!isset($input_array[$field])){
throw new Exception(__("$field is mandatory for update."));
}

// Add data_array (without hash idx) 
// (input_array is POST data -> Could have more fields)
$data_array[] = $input_array[$field];
}
global $wpdb;
// Update query
//*
$wpdb->query($wpdb->prepare("UPDATE ".$this->getTableName()."
SET `name` = '%s', `description` = '%s' ".
"WHERE `wp_meo_event_category`.`id_event_category` =%d;",$input_array['name'], 
$input_array['description'], $input_array['id']) );
/*/
// Replace form field id index by table field id name
$wpdb->update($this->getTableName(), $this->getTableDataArray($data_array),
array( 'id_event_category' => $input_array['id']), // Where
array( '%s', '%s' ),    // Data format
array( '%d' ));         // Where format
//*/
} catch (Exception $exc) {
// @todo: Fix error handlin
echo $exc->getTraceAsString();
$this->last_error = $exc->getMessage();
return FALSE;
}
return TRUE;
}

4.2 Uitleg update query

Laten we eens naar het volgende stukje code uit voorgaande kijken:

//*
$wpdb->query($wpdb->prepare("UPDATE ".
$this->getTableName()."
SET `name` = '%s', `description` = '%s' ".
"WHERE `wp_meo_event_category`.`id_event_category` =%d;",$input_array['name'], 
$input_array['description'], $input_array['id']) );
/*/

// Replace form field id index by table id name
$wpdb->update($this->getTableName(), field 
$this->getTableDataArray($data_array),
array( 'id_event_category' =>  // Data format
array( '%d' ));         // Where format
//*/$input_array['id']), // Where
array( '%s', '%s' ),   

In bovenstaande code staan twee manieren om een update uit te voeren. De eerste manier is hier in gebruik. Er wordt gebruik gemaakt van twee functies:

  • $wpdb->prepare: Deze functie zorgt er voor dat de variabelen in het SQL statement worden ingevoegd. De manier waarop dat gebeurd lijkt heel erg op de sprintf manier. Er zijn voor de verschillende soorten variabelen verschillende placeholders. Hier zijn dat de %s (string) en %d (integer). De functie levert dus een compleet SQL statement.Probeer maar eens om de $wpdb->prepare(…) op het scherm te zetten.
  • $wpdb->query: Deze functie zorgt voor het uitvoeren van de query. Dit lijkt om de mysqli variant die je al kent. Om deze functie werkend te maken verwijder je het eerste commentaar streepje:
/*
$wpdb->query($wpdb->prepare("UPDATE ".
$this->getTableName()."
SET `name` = '%s', `description` = '%s' ".
"WHERE `wp_meo_event_category`.`id_event_category` =%d;",$input_array['name'], 
$input_array['description'], $input_array['id']) );
/*/

// Replace form field id index by table id name
$wpdb->update($this->getTableName(), field 
$this->getTableDataArray($data_array),
array( 'id_event_category' =>  // Data format
array( '%d' ));         // Where format
//*/$input_array['id']), // Where
array( '%s', '%s' ),   

Om deze functie werkend te krijgen moet je nog de functie getTableDataArray aanmaken. Deze functie zorgt ervoor dat de tabel namen worden toegevoegd aan de formulier data. Eigenlijk overschrijf je de formulier naam met de tabel namen.

Voeg onderstaande code toe aan EventCategory.php:

/**
* The function takes the input data array and changes the 
* indexes to the column names
* In case of update or insert action
* 
* @param type $input_data_array  data array(id, name, descpription)
* @
param type $action            update | insert
* @return type array with collumn index and values OR FALSE
*/
private function getTableDataArray($input_data_array, $action=''){
// Get the Table Column Names.
$keys = $this->getTableColumnNames($this->getTableName());

// Get data array with table collumns
// NULL if collumns and data does not match in count
// 
// Note: The order of the fields shall be the same for both!
$table_data = array_combine($keys, $input_data_array);

switch ( $action ){
case 'update':  // Intended fall-through

case 'insert':
// Remove the index -> is primary key and can 
// therefore not be changed!

if (!empty($table_data)){
unset($table_data['id_event_category']);
}
break;
// Remove 
}

return $table_data;
}

Neem onderstaande functie ook over. Deze functie levert de kolommen van de tabel:

/**
* Get the column names of the specified table
* @global type $wpdb
* @param type $table
* @return type
*/
private function getTableColumnNames($table){
global $wpdb;
try {
$result_array = $wpdb->get_results("SELECT `COLUMN_NAME`"."FROM INFORMATION_SCHEMA.COLUMNS".
" WHERE `TABLE_SCHEMA`='".DB_NAME."' AND TABLE_NAME = '".$this->getTableName() ."'", ARRAY_A);
$keys = array();
foreach ( $result_array as $idx => $row ){
$keys[$idx] = $row['COLUMN_NAME'];
}
return $keys;
} catch (Exception $exc) {
// @todo: Fix error handlin
echo $exc->getTraceAsString();
$this->last_error = $exc->getMessage();
return FALSE;
}
}

4.3 Wanneer gebruik je welke functie?

$wpdb->query Als je eerst een applicatie hebt gebouwd en daarna in WordPress implementeerd kun je het beste de eerste functie gebruiken. Dan hoef je het minst te veranderen aan de bestaande functionaliteit.
$wpdb->update Wanneer je je plugin direct in wordpress ontwikkeld begruik je de $wpdb->update. Hiervoor heb je geen kennis van MySQL nodig.

Je kunt nu de applicatie testen door de update uit te voeren. Als je het goed hebt gedaan werken bovenstaande functies dus allebei op dezelfde manier!