<?php
/**
* A PGBDataBlock is a window to your actual ( database ) data. It can be used
* to show, create, update and delete data on its associated {@link PGBRecordSet}.
*
* The data block is the glue that ties all the framework's components together.
* It links relational tables to the browser screen; coordinates the rendering
* work, translating data from internal to visual formats; materialises, in a
* visual fashion, the relationships among objects and data hierarchies; and
* controls user interaction with the application in almost every aspect. It can
* be seen as a crucial part of PIRAGIBE's persistency scheme backbone.
*
* Each screen in an application built with PIRAGIBE is a set of coordinated,
* master x slave style, data blocks.
* @package Piragibe
* @author Francisco Piragibe
* @version 1.08
* @copyright Copyright © 2006, Francisco Piragibe
* This file is part of The PIRAGIBE Framework.
*
* The PIRAGIBE Framework is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* The PIRAGIBE Framework is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with The PIRAGIBE Framework; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
class PGBDataBlock {
/**
* Is the block operating in query mode?
* @var boolean query mode flag
*/
var $m_queryMode; // bloco esta em query mode?
/**
* The block properties array.
*
* This is a very complex structure, containing all of the block behaviour
* description. As many keys have been named in portuguese, an additional layer
* of difficulty has been posed to the foreign developer. For this, I must apologise.
* The array entries are:
* - Nome - > (string) the block name (this is mandatory).
* - Titulo -> (string) the block title (this will be rendered on the top of the block - no defaults).
* - Pagina -> (integer) how many records should be shown on the screen (default is ALL records).
* - Seletor -> (boolean) should a pin be rendered next to each record, allowing for record selection?
* (a pin will be rendered anyway if the block has coordinated slaves) (default is context dependent).
* - Rs -> (PGBRecordSet) the {@link PGBRecordSet} that should be linked to the block (only for
* MASTER data blocks; slave blocks should have the SlaveRs entry set, instead of this one) (no defaults).
* - InsertOk -> (boolean) can the block be used to create new records? (default is NO)
* - UpdateOk -> (boolean) can the block be used to update records? (default is NO)
* - DeleteOk -> (boolean) can the block be used to delete records? (default is NO)
* - QueryOk -> (boolean) should the block support an automatic "query by example" screen for data
* filtering? (default is NO).
* - SingleRecord -> (boolean) should the block contain ONLY ONE record? (default is NO).
* - AgenteNls -> ({@link PGBNlsAgent}) the national language support agent object that should be used when
* rendering NLS dependent data (no default).
* - SlaveBlocks -> (array of PGBDataBlocks) the set of blocks that are slaves to this one (default is
* NO SLAVES).
* - SlaveRs -> (string) if the block is a slave block, the slave recordset NAME. The name should point
* to one of the master data block's recordset's slave. This entry is ignored for master data blocks.
* - RenderDefs -> (array of {@link PGBRenderDefs}) rendering definitions for the block fields. Only fields
* having a rendering definition will be rendered. This array has the field names (case sensitive) as keys and
* PGBRenderDefs as values.
*
*/
var $m_props; // array com definicoes do bloco
// ['Nome'] -> nome do bloco
// ['Titulo'] -> titulo, para renderizacao
// ['Pagina'] -> numero de registros a exibir por vez
// ['Seletor'] -> renderiza ou nao um pino de selecao de registros a esquerda
// ['rs'] -> REFERENCIA ao recordset principal base para o bloco
// ['InsertOk'] -> podem ser criados registros no bloco?
// ['UpdateOk'] -> podem ser atualizados registros no bloco?
// ['DeleteOk'] -> podem ser excluidos registros no bloco?
// ['QueryOk'] -> podem ser feitas pesquisas por exemplo?
// ['SingleRecord'] -> bloco deve conter apenas UM registro?
// ['AgenteNls'] -> agente NLS a utilizar nas edicoes
// ['RenderDefs'] -> array com definicoes de renderizacao para os campos do bloco
// apenas os campos constantes deste array serao renderizados
// formato:
// [<nome do campo>] -> PGBRenderingDefinition referente ao campo
// ['SlaveBlocks'] -> array com definicoes de blocos escravos deste
// cada definicao segue o mesmo layout das definicoes de blocos, EXCETO:
// ['SlaveRs'] -> nome do recordset escravo
// ['rs'] -> nunca esta definido
/**
* The message error array.
* @var array array of message errors to be displayed
*/
var $m_erros; // mensagens de erro do bloco
/**
* This array maps block positions to recordset positions (saying record 354 of the
* recordset occupies position 5 in the block, for instance).
* @var array the block x recordset map array
*/
var $m_pos; // array mapeando ordem de aparicao no bloco x numero do registro
// ex. $m_pos[1] = 356 => o 2o. registro do bloco eh o 356o. do recordset
/**
* This array records whether a given record should be shown with additional details
* visible or hidden.
*
* This only makes sense for multi-line records or tree rendering.
* @var array additional details status for each record
*/
var $m_deta; // array mapeando numero de registro -> detalhes adicionais abertos
/**
* This array stores field contents for the block. The first subscript is the field name;
* the second is the block record number. Each node has a {@link PGBField} object.
* @var array field contents array
*/
var $m_fields; // array com campos representados
// [<nome do campo>] -> array com valores por posicao no bloco
// [n] -> objeto PGBField que representa o campo
/**
* Block status.
*
* Possible status are:
* - 0 -> created (and possibly empty)
* - 1 -> queried (contains data retrieved from a query, unchanged)
* - 2 -> changed (contains modified data - should be saved)
* @var integer the block status code
*/
var $m_status; // estado do bloco
/**
* Auxiliary array to control rendering of multiline records in a tabular fashion.
*
* As there is no obligation to define block fields ordered by row, this is used to
* perform ordering before the actual rendering begins.
* @var array map of fields that should be rendered in each row.
*/
var $m_rendsl; // array auxiliar para renderizacao de tabelas multilinha
/**
* The record position IN THE UNDELYING RECORDSET that will be taken as the starting
* one.
*
* The block can show only a section of the recordset's records (10 records, for example).
* This variable controls where in the recordset we are.
* @var integer the absolute (recordset) record position of the block's first record.
*/
var $m_abspos; // posicao absoluta, para controle de exibicao
/**
* Standard constructor.
* @param array $pParms the array of definitions
*/
function PGBDataBlock( $pParms ) {
$this->m_erros = array();
$this->m_status = 0;
$this->m_abspos = 0;
$pProps = new PGBPropertyBag( $pParms );
$this->m_props = $pProps->getBag();
$this->m_pos = array();
$this->m_fields = array();
$this->m_rendsl = array();
if ( !isset( $this->m_props['agentenls'] ) ) {
$this->setNlsAgent( new PGBNlsAgent('pt') );
}
if ( !isset( $this->m_props['nome'] ) ) {
$this->setName( 'xpto' );
}
if ( !isset( $this->m_props['titulo'] ) ) {
$this->setTitle( '' );
}
if ( !isset( $this->m_props['pagina'] ) ) {
$this->setPageSize( 0 );
}
if ( !isset( $this->m_props['seletor'] ) ) {
$this->setSeletor( false );
}
if ( !isset( $this->m_props['renderdefs'] ) ) {
$this->m_props['renderdefs'] = array();
}
if ( !isset( $this->m_props['slaveblocks'] ) ) {
$this->m_props['slaveblocks'] = array();
}
else {
$this->setSlaveBlocks( $pProps->get('slaveblocks') );
}
if ( !isset( $this->m_props['slavers'] ) ) {
$this->m_props['slavers'] = NULL;
}
if ( !isset( $this->m_props['insertok'] ) ) {
$this->m_props['insertok'] = false;
}
if ( !isset( $this->m_props['updateok'] ) ) {
$this->m_props['updateok'] = false;
}
if ( !isset( $this->m_props['deleteok'] ) ) {
$this->m_props['deleteok'] = false;
}
if ( !isset( $this->m_props['queryok'] ) ) {
$this->m_props['queryok'] = false;
}
if ( !isset( $this->m_props['singlerecord'] ) ) {
$this->m_props['singlerecord'] = false;
}
$this->m_queryMode = false;
}
/**
* Validates a field.
*
* Should be implemented by each heir.
* @return mixed the error message to be displayed, or NULL, if validation is successful
* @param PGBField &$pField the field to be validated
*/
function validate( &$pField ) {
// valida o campo que corresponde ao objeto PGBField dado - deve ser implementado pelo herdeiro
// se houver erro, deve retornar o texto da mensagem; senao, deve retornar NULL
return NULL;
}
/**
* Validates a record (a set of related fields).
*
* Should be implemented by each heir, and shouldn't return anything. If there are error
* messages to show, heir should call newError() as many times as necessary.
* @param integer $pRn the record position within the block
* @param array &$pFields array of {@link PGBField}s that make up the record
*/
function validateRecord( $pRn, &$pFields ) {
// valida um registro, definido como um array de campos, cada qual identificado por seu nome,
// passado como parametro - ser implementado pelo herdeiro e deve preencher o bloco de erros
// nao retorna nada
}
/**
* Validates the entire data block. This is a hook for inter-record validation rules.
*
* Should be implemented by each heir, and shouldn't return anything. If there are error
* messages to show, heir should call newError() as many times as necessary. Access to the
* records and fields can be obtained by calling suitable getters.
*/
function validateBlock() {
// valida relacoes inter registros que o bloco por acaso deva ter - o herdeiro implementa esta -
// deve alimentar o array de erros e nao retornar nada
}
/**
* Block validation coordinator.
*
* This calls validate() for every field, validateRecord() for every record in the block
* and, finally, calls validateBlock(). These three methods should be implemented by each
* heir; their default implementation have null bodies (i.e. always return OK). It's worth
* saying that record and block validations are called only if there are no errors in
* field validations. In other words, record and block validation methods can be sure they
* will receive only valid fields.
*/
function validateBlockArray() {
// valida o bloco inteiro e seus registros - deve ser implementado pelo herdeiro quando houver
// necessidade de validacoes intercampos ou interregistros - deve preencher o bloco de erros
// em primeiro lugar, valida os registros...
$rs = &$this->getRecordSet();
if ( !is_a( $rs, 'PGBRecordSet' ) ) {
return;
}
$w_contador = count( $this->m_pos );
$w_kont = 0;
for( $j=0; $j < $w_contador; $j++ ) {
if ( !$rs->isDeleted( $this->m_pos[ $j ] ) ) {
$a_fields = array();
reset( $this->m_fields );
while( list( $fn, $af ) = each( $this->m_fields ) ) {
//print '<pre>' . $fn . ' => ' . $this->m_fields[ $fn ][ $j ] . '</pre>';
$a_fields[ $fn ] = &$this->m_fields[ $fn ][ $j ];
if ( is_a( $a_fields[ $fn ], 'PGBField' ) ) {
// campos de eco de registros novos nao estao preenchidos ainda...
$m = $this->validate( $a_fields[ $fn ] );
if ( $m ) {
$this->newError( $j, $m );
$w_kont++;
}
}
}
if ( $w_kont == 0 ) {
// so validamos registro e bloco se nao houver erros a nivel de campo
//print '<pre> validando registro ' . $j . '</pre>';
$this->validateRecord( $j, $a_fields );
}
}
}
// finalmente, valida o bloco como um todo (o herdeiro deve implementar esta)
if ( $w_kont == 0 ) {
// so validamos registro e bloco se nao houver erros a nivel de campo
$this->validateBlock();
}
}
/**
* Getter for the NLS agent associated to the block.
* @return PGBNlsAgent the NLS agent associated to this block
*/
function &getNlsAgent() {
return $this->m_props['agentenls'];
}
/**
* Setter for the NLS agent.
* @param PGBNlsAgent $pNls the NLS agent to associate
*/
function setNlsAgent( $pNls ) {
if ( is_a( $pNls, 'PGBNlsAgent' ) ) {
$this->m_props['agentenls'] = $pNls;
}
}
/**
* Getter for the message error array.
* @return array the message error array
*/
function getErrors() {
return $this->m_erros;
}
/**
* Standard beautifier for a given record.
*
* beautify() acts according to the set of rendering definitions associated to the data
* block. The method is responsible for retrieving echo fields (names related to a given
* code, for instance) and preparing the record for rendering. Its services are consumed
* mainly by the rendering methods (renderForm and renderTabular, for example).
* @param PGBRecord &$pRecord the record to be beautified
*/
function &beautify( &$pRecord ) {
// complementa o registro, formando campos dependentes e outros - deve ser complementado pelo
// herdeiro, e retornar o proprio registro, finalizado
if ( !is_a( $pRecord, 'PGBRecord' ) ) {
return $pRecord;
}
$o_rsb = &$this->getRecordSet();
$o_conn = &$o_rsb->getConnection();
$p_rowdef = $this->getRenderingDefinitions();
reset( $p_rowdef );
while( list( $k, $c ) = each( $p_rowdef ) ) {
//print '<pre>' . $k . ' -> '; print var_dump( $c ) . '</pre>';
$w_f = &$pRecord->getField( $k );
$w_ed = $c->get( 'ExtraDefs' );
if ( $w_ed ) {
$w_pc = $w_ed->get( 'PostChange' );
if ( $w_pc ) {
// substitui ? pelo valor do campo corrente
$w_sqlr = str_replace( '?', $w_f->getValue(), $w_pc );
//print '<pre>F1: ' . $w_sqlr . '</pre>';
// substitui campos :XXX: pelos valores correspondentes
$a_sqlr = explode( ':', $w_sqlr );
reset( $a_sqlr );
while( list( $pp, $ps ) = each( $a_sqlr ) ) {
if ( isset( $p_rowdef[ $ps ] ) ) {
$w_f1 = $pRecord->getField( $ps );
$a_sqlr[ $pp ] = $w_f1->getValue();
}
}
$w_sqlr = implode( '', $a_sqlr );
//print '<pre>F2: ' . $w_sqlr . '</pre>';
// executa o comando
$o_rs = $o_conn->query( $w_sqlr );
//print '<pre>' . $w_sqlr . ' - ' . $o_rs->rowCount() . "</pre>";
if ( $o_rs->rowCount() > 0 ) {
$o_rec = $o_rs->getCurrentRecord();
$a_flds = $o_rec->getFields();
reset( $a_flds );
while( list( $fn, $ff ) = each( $a_flds ) ) {
$pRecord->updateField( $ff );
}
}
}
}
}
return $pRecord;
}
/**
* Getter for the block x recordset map array.
* @return array the block x recordset map array
*/
function getPosArray() {
// retorna o array mapa de posicoes bloco x registro
return $this->m_pos;
}
/**
* Getter for the block fields array.
* @return array the block fields array
*/
function &getBlockFieldsArray() {
return $this->m_fields;
}
/**
* Getter for a specific block field, identified by name and record position.
* @return PGBField the field
* @param string $pNome the field name
* @param integer $pPos the record position
*/
function &getBlockField( $pNome, $pPos ) {
// retorna o PGBField que ocupa a posicao dada
if ( isset( $this->m_fields[$pNome][$pPos] ) ) {
return $this->m_fields[$pNome][$pPos];
}
else {
return NULL;
}
}
/**
* Counts errors in this block and in its slave blocks, that is, in the entire
* block hierarchy.
* @return integer the error count
*/
function countErrors() {
$w_resp = count( $this->getErrors() );
foreach( $this->m_props['slaveblocks'] as $sbi ) {
$w_resp += $sbi->countErrors();
}
return $w_resp;
}
/**
* Getter for the block title.
* @return string the block title.
*/
function getTitle() {
return $this->m_props['titulo'];
}
/**
* Setter for the block title.
* @param string $pTit the new block title.
*/
function setTitle( $pTit ) {
$this->m_props['titulo'] = $pTit;
}
/**
* Adds an error message to the error message array.
*
* Error messages are linked to the block records through the record number parameter.
* Record number -1 means the block as a whole, not any particular record. This allows
* for messages related to the entire set of records, rather than to a single one.
* @param integer $pRn the record position the message is related to.
* @param string $pMens the message text.
*/
function newError( $pRn, $pMens ) {
// armazena uma nova mensagem de erro
if ( ! is_null( $pMens ) ) {
//print '<pre> erro ' . $pRn . ' => ' . $pMens . '</pre>';
$this->m_erros[$pRn][] = $pMens;
}
}
/**
* Getter for the block status.
* @return integer the block status code.
*/
function getStatus() {
return $this->m_status;
}
/**
* Is the block in query mode?
* @return boolean the answer.
*/
function isInQueryMode() {
return $this->m_queryMode;
}
/**
* Can the block be used to create new records?
* @return boolean the answer.
*/
function canInsert() {
return $this->m_props['insertok'];
}
/**
* Setter for the insert allowed flag.
* @param boolean $pFlag the new insert allowed flag
*/
function setInsertOk( $pFlag ) {
$this->m_props['insertok'] = ($pFlag === true ? true : false);
}
/**
* Can records be updated through the block?
* @return boolean the answer.
*/
function canUpdate() {
return $this->m_props['updateok'];
}
/**
* Setter for the update allowed flag.
* @param boolean $pFlag the new update allowed flag.
*/
function setUpdateOk( $pFlag ) {
$this->m_props['updateok'] = ($pFlag === true ? true : false);
}
/**
* Can records be deleted through this block?
* @return boolean the answer.
*/
function canDelete() {
return $this->m_props['deleteok'];
}
/**
* Setter for the delete allowed flag.
* @param boolean $pFlag the new delete allowed flag.
*/
function setDeleteOk( $pFlag ) {
$this->m_props['deleteok'] = ($pFlag === true ? true : false);
}
/**
* Should query mode be provided for this block?
*
* Query mode allows the user to ask for the entering of filtering criteria that
* should be applied to the underlying recordset, thus retrieving only a subset
* of its original records.
* @return boolean the answer.
*/
function canQuery() {
return $this->m_props['queryok'];
}
/**
* Setter for the query allowed flag.
* @param boolean $pFlag the new query allowed flag.
*/
function setQueryOk( $pFlag ) {
$this->m_props['queryok'] = ($pFlag === true ? true : false);
}
/**
* Should the block contain only a single record?
*
* Single recorded blocks are useful for representing 1:1 relationships, for instance,
* or control blocks, where more than one record doesn't make any sense.
* @return boolean the answer.
*/
function isSingleRecord() {
return $this->m_props['singlerecord'];
}
/**
* Setter for the single record flag.
* @param boolean $pFlag the new single record flag.
*/
function setSingleRecord( $pFlag ) {
$this->m_props['singlerecord'] = ($pFlag === true ? true : false);
}
/**
* Setter for the slave recordset name.
*
* Only makes sense if the block is a slave block.
* @param string $pRsName the slave recordset name.
*/
function setSlaveRsName( $pRsName ) {
$this->m_props['slavers'] = $pRsName;
}
/**
* Getter for the slave recordset name.
* @return string the slave recordset name.
*/
function getSlaveRsName() {
return $this->m_props['slavers'];
}
/**
* Getter for the array of slave blocks (blocks that are slaves to this one).
* @return array the entire array of slave blocks.
*/
function &getSlaveBlocks() {
return $this->m_props['slaveblocks'];
}
/**
* Setter for the slave block array.
* @param array $pSlaves the new slave block array.
*/
function setSlaveBlocks( $pSlaves ) {
if ( ! is_array( $pSlaves ) ) {
print 'FATAL: slave block array is not an array';
die;
}
$this->m_props['slaveblocks'] = array();
foreach( $pSlaves as $ps ) {
$this->setSlaveBlock( $ps->getName(), $ps );
}
}
/**
* Getter for a single, named, slave block.
* @return PGBDataBlock the requested slave block, or NULL, if the block doesn't exist.
* @param string $pName the requested slave block name.
*/
function &getSlaveBlock( $pName ) {
if ( isset( $this->m_props['slaveblocks'][ strtolower( $pName ) ] ) ) {
$sb = &$this->m_props['slaveblocks'][ strtolower( $pName ) ];
$w_rs = &$this->getRecordSet();
$wr = &$w_rs->getCurrentRecord();
//print $this->getName() . ': ' . $sb->getName() . ': ' . $w_rs->getRecordPointer() . '<br>';
//var_dump( $wr );
if ( $wr ) {
$srs = &$wr->getSlave( $sb->getSlaveRsName() );
$sb->setRecordSet( $srs );
}
//$this->m_props['slaveblocks'][ strtolower( $pName ) ] = $sb;
return $sb;
}
else {
return NULL;
}
}
/**
* Setter for a new, named slave block.
* @param string $pNome the new slave block name.
* @param PGBDataBlock $pBloco the slave block object.
*/
function setSlaveBlock( $pNome, $pBloco ) {
if ( !is_a( $pBloco, 'PGBDataBlock' ) ) {
print 'FATAL: slave block ' . $pNome . ' is not a PGBDataBlock';
die;
}
$this->m_props['slaveblocks'][ strtolower($pNome) ] = $pBloco;
}
/**
* Getter for the block name.
* @return string the data block name.
*/
function getName() {
// retorna o nome do data block
return $this->m_props['nome'];
}
/**
* Setter for the data block name.
* @param string $pNome the data block name.
*/
function setName( $pNome ) {
// seta o nome do data block
$this->m_props['nome'] = strtolower( $pNome );
}
/**
* Getter for the block's underlying recordset.
* @return PGBRecordSet the underlying recordset.
*/
function &getRecordSet() {
// retorna o recordset
return $this->m_props['rs'];
}
/**
* Setter for the block's underlying recordset.
* @param PGBRecordSet &$pRS the recordset to attach to the block.
*/
function setRecordSet( &$pRS ) {
// seta o recordset do bloco, se o tipo do objeto estiver correto
if ( is_a( $pRS, 'PGBRecordSet' ) ) {
$this->m_props['rs'] = &$pRS;
}
else {
print 'FATAL: ' . $this->getName() . ' recordset do bloco nao e record set';
// die;
}
}
/**
* Getter for the block's rendering definitions.
* @return array the set of rendering definitions associated to the block.
*/
function &getRenderingDefinitions() {
// retorna todas as definicoes de renderizacao
return $this->m_props['renderdefs'];
}
/**
* Setter for the entire set of block rendering definitions.
* @param array $pDefs the new set of rendering definitions.
*/
function setRenderingDefinitions( $pDefs ) {
// atualiza todas as definicoes de renderizacao
if ( is_array( $pDefs ) ) {
while( list($k,$c) = each($pDefs) ) {
if ( !is_a( $c, 'PGBRenderDefs' ) ) {
print 'FATAL: definicoes nao estao em um conjunto de definicoes de renderizacao';
die;
}
}
$this->m_props['renderdefs'] = $pDefs;
}
}
/**
* Getter for a specific, named, rendering definition.
* @return PGBRenderDefs the requested definition (or NULL, if it's not defined)
* @param string $pnome the rendering definition name.
*/
function &getRenderingDefinition( $pnome ) {
// retorna UMA definicao de renderizacao, dado o nome da coluna
if ( isset( $this->m_props['renderdefs'][$pnome] ) ) {
return $this->m_props['renderdefs'][$pnome];
}
else {
return NULL;
}
}
/**
* Setter for a specific, named, rendering definition.
*
* If there is no rendering definition bearing the given name, one will be created.
* @param string $pnome the definition name.
* @param PGBRenderDefs $prd the rendering definition.
*/
function setRenderingDefinition( $pnome, $prd ) {
// seta UMA definicao de renderizacao
if ( is_a( $prd, 'PGBRenderDefs' ) ) {
$this->m_props['renderdefs'][ $pnome ] = $prd;
}
}
/**
* Getter for the page size (the number of records to be displayed)
* @return integer the page size.
*/
function getPageSize() {
// retorna o tamanho da pagina logica de exibicao, em registros/ pagina
return $this->m_props['pagina'];
}
/**
* Setter for the page size.
* @param integer $p_maxrec the new page size.
*/
function setPageSize( $p_maxrec ) {
// seta o tamanho da pagina logica de exibicao
if ( is_integer( $p_maxrec ) ) {
$this->m_props['pagina'] = $p_maxrec;
}
}
/**
* Should a selector pin be rendered for each record?
*
* A selector pin allows a record to be selected, that is, to be made the current
* record. It's rendered anyway if the block has slave blocks, once a record's slave
* records can only be reached for the block's current record (even the tree renderer
* will only render updateable slaves for a record that is current).
* @return boolean flag for selector pin.
*/
function hasSelectorPin() {
// retorna flag de presenca ou nao do pino seletor
if ( $this->canDelete() or count($this->m_props['slaveblocks']) > 0 ) {
// blocos com capacidade de exclusao ou que tem escravos SEMPRE tem pino seletor...
$this->setSeletor( true );
}
return $this->m_props['seletor'];
}
/**
* Setter for the selector pin flag.
* @param boolean $pSeletor the new selector pin flag.
*/
function setSeletor( $pSeletor ) {
// seta indicador de presenca ou nao do pino seletor
$this->m_props['seletor'] = $pSeletor;
}
/**
* Renders the error messages associated to a given record position.
*
* Record position -1 means "the block as a whole"; these messages are rendered on
* the top of the block.
* @param integer $pRn the record position.
*/
function renderErrors( $pRn ) {
// renderiza tabela de erros
//print '<pre> recuperando erro ' . $pRn . '</pre>';
if ( count( $this->m_erros ) <= 0 ) {
//print '<pre> sem erros definidos </pre>';
return NULL;
}
elseif ( count( $this->m_erros[$pRn] ) <= 0 ) {
//print '<pre> sem erros definidos na posicao</pre>';
return NULL;
}
$r = '<table width="100%">';
while( list( $k, $m ) = each( $this->m_erros[$pRn] ) ) {
$r .= '<tr class="erro"><td>';
$r .= $m;
$r .= '</td></tr>';
}
$r .= '</table>';
//print $r;
$this->m_erros[$pRn] = array();
return $r;
}
/**
* Clears the entire error message array.
*/
function clearErrorArray() {
//print '<pre>reset errors</pre>';
$this->m_erros = array();
}
/**
* Renders a toolbar on the top of the block's visual area.
*
* A toolbar can be "flat" or "full" (the default). A flat toolbar doesn't have support
* for recording the current record position, nor it has navigational controls.
* @param boolean $pFlat should the toolbar be flat?
*/
function renderToolbar( $pFlat = false ) {
// renderiza uma barra de navegacao, dependendo do caso
$p_recordset = &$this->getRecordSet();
$p_maxrec = $this->getPageSize();
$m_recordpointer = $p_recordset->getRecordPointer();
$m_recordcount = $p_recordset->rowCount();
$x = split( '/', $_SERVER['REQUEST_URI'] );
$w_prefix = '/' . $x[1] . '/images';
print '<table width="100%"><tr>';
print '<td>';
$n = $this->getName();
if ( !$pFlat ) {
print '<input type="hidden" name="__' . $n . '_p" value="-1">';
}
$ma = array(
'exeqry' => array( 'pt' => 'executa a pesquisa',
'en' => 'execute query'
),
'entqry' => array( 'pt' => 'registra critério de busca',
'en' => 'enter query criteria'
),
'down' => array( 'pt' => 'próxima página',
'en' => 'next page'
),
'up' => array( 'pt' => 'página anterior',
'en' => 'previous page'
),
'last' => array( 'pt' => 'última página',
'en' => 'last page'
),
'first' => array( 'pt' => 'primeira página',
'en' => 'first page'
),
'delrec' => array( 'pt' => 'exclui o registro corrente',
'en' => 'delete current record'
),
'crerec' => array( 'pt' => 'cria um novo registro',
'en' => 'add new record'
),
'commit' => array( 'pt' => 'salva tudo',
'en' => 'commit all changes to database'
),
'de' => array( 'pt' => ' de ',
'en' => ' of '
)
);
$oIN = $this->getNlsAgent();
$oIN->setMessageArray( $ma );
if ( $this->isInQueryMode() ) {
print '<input type="image" id="__' . $n . '_exeqry" name="__' . $n . '_exeqry" src="' . $w_prefix . '/exeqry.gif" border=0 title="' . $oIN->getMessage('exeqry') . '" value="1">';
}
else {
if ( $p_maxrec > 0 and !$this->isInQueryMode() and !$pFlat ) {
print '<input type="image" src="' . $w_prefix . '/aflup.gif" border=0 title="' . $oIN->getMessage('first') . '" onClick="javascript: document.__prg_form.__' . $n . '_p.value=0">';
print '<input type="image" src="' . $w_prefix . '/aflleft.gif" border=0 title="' . $oIN->getMessage('up') . '" onClick="javascript: document.__prg_form.__' . $n . '_p.value=' . max($m_recordpointer - $p_maxrec,0) . '">';
print '<input type="image" src="' . $w_prefix . '/aflright.gif" border=0 title="' . $oIN->getMessage('down') . '" onClick="javascript: document.__prg_form.__' . $n . '_p.value=' . max($m_recordpointer + $p_maxrec,0) . '">';
print '<input type="image" src="' . $w_prefix . '/afldown.gif" border=0 title="' . $oIN->getMessage('last') . '" onClick="javascript: document.__prg_form.__' . $n . '_p.value=' . max($m_recordcount - ($m_recordcount-(floor($m_recordcount/$p_maxrec)*$p_maxrec)),0) . '">';
}
// so renderiza botoes de interacao com o BD se o recordset tiver vindo do DBX
if ( $this->canDelete() and !$pFlat ) {
print '<input type="image" id="__' . $n . '_delrec" name="__' . $n . '_delrec" src="' . $w_prefix . '/afflddel.gif" border=0 title="' . $oIN->getMessage('delrec') . '" value="1" onClick="javascript: delecao();">';
}
if ( $this->canInsert() and !$pFlat and ( !$this->isSingleRecord() or $m_recordcount == 0) ) {
print '<input type="image" id="__' . $n . '_crerec" name="__' . $n . '_crerec" src="' . $w_prefix . '/affldnew.gif" border=0 title="' . $oIN->getMessage('crerec') . '" value="1">';
}
if ( !$pFlat and ($this->canInsert() or $this->canUpdate() or $this->canDelete()) ) {
print '<input type="image" id="__commit" name="__commit" src="' . $w_prefix . '/affldsav.gif" border=0 title="' . $oIN->getMessage('commit') . '" value="1">';
}
if ( is_a( $p_recordset, 'PGBDbxRecordSet' ) and $this->canQuery() and !$pFlat ) {
print '<input type="image" id="__' . $n . '_entqry" name="__' . $n . '_entqry" src="' . $w_prefix . '/entqry.gif" border=0 title="' . $oIN->getMessage('entqry') . '" value="1">';
}
}
print '</td>';
print '<td align="right" valign="top"> <small>';
if ( $p_maxrec > 0 and !$this->isInQueryMode() and !$pFlat ) {
print '<select name="__' . $n . '_px" size="1" onChange="javascript: document.__prg_form.__' . $n . '_p.value=-1000; document.__prg_form.submit();">';
for( $i=1; $i <= $m_recordcount; $i += $p_maxrec ) {
print '<option value="' . ( $i - 1 ) .'" ';
$if = min($i+$p_maxrec-1,$m_recordcount);
if ( $m_recordpointer >= ($i-1) and $m_recordpointer <= ($if-1) ) {
print ' selected ';
}
print '>';
print $i . '-' . $if . $oIN->getMessage('de') . $m_recordcount;
print '</option>';
}
print '</select> ';
print '[ ' . ($m_recordpointer+1) . ' ]';
}
else {
print '<input type="text" name="dummy" disabled size="10" value="' . ($m_recordpointer+1) . ' / ' . $m_recordcount . '">';
}
print '</small></td></tr></table>';
}
/**
* Stores the recordset's record pointer in the block x recordset position map.
*
* A null parameter means (store the CURRENT record pointer).
* @param integer $pPos the recordset's record pointer to store.
*/
function recordPosition( $pPos = NULL ) {
$w_pk = $pPos;
if ( !$w_pk ) {
$w_rs = &$this->getRecordSet();
$w_pk = $w_rs->getRecordPointer();
}
$this->m_pos[] = $w_pk;
}
/**
* Renders a form like screen, that shows one record at a time.
*
* A form like screen show the fields one below the other, captions to the left of
* content. An optional title can be given. If it's given, it'll override the block
* title.
* @param string $pTitulo the block title.
*/
function renderForm( $pTitulo = NULL ) {
// renderiza um recordset inteiro no formato de um form simples (um registro por vez)
$this->setSeletor( true ); // fingimos que o pino esta exibido...
$p_rowdef = &$this->getRenderingDefinitions();
$p_maxrec = $this->getPageSize();
$w_titulo = $pTitulo;
if ( is_null( $pTitulo ) ) {
$w_titulo = $this->getTitle();
}
$this->setPageSize( 1 );
$o_rend = new PGBRenderer( $this );
$p_recordset = &$this->getRecordSet();
if ( ! $p_recordset ) {
return;
}
$m_rowcount = 0;
$m_recordpointer = $p_recordset->getRecordPointer();
$rp = $m_recordpointer;
$m_recordcount = $p_recordset->rowCount();
$this->m_pos = array();
$this->m_fields = array();
$e = $this->renderErrors( -1 );
if ( !is_null( $e ) ) {
print $e;
}
$this->renderToolbar();
print '<table width="100%" border="1">';
print '<tr>';
print '<th colspan="2">';
print $w_titulo;
print '</th>';
print '</tr>';
$e = $this->renderErrors( 0 );
if ( !is_null( $e ) ) {
print '<tr>';
print '<td colspan="2">';
print $e;
print '</td>';
print '</tr>';
}
reset( $p_rowdef );
$this->clearErrorArray();
$r = &$this->beautify( $p_recordset->getCurrentRecord() );
if ( $r ) {
$this->recordPosition();
$o_rend->setIndex( count( $this->m_pos ) - 1 );
// os cabecalhos e seus campos
while( list( $k, $c ) = each( $p_rowdef ) ) {
if ( $this->isInQueryMode() ) {
print '<tr class="query">';
}
elseif ( $p_recordset->isCurrentRecordDeleted() ) {
print '<tr class="erased">';
}
else {
print '<tr class="formH">';
}
$w_field = $r->getField( $k );
$w_sc = $c->get('StyleClass');
print '<td valign="top" class="dados">';
print $c->get('Caption') . ':';
print '</td>';
print '<td valign="top" class="dados">';
if ( $this->isInQueryMode() ) {
$o_rend->renderQueryField( $c->get('Renderer'), $w_field, $c->get('ExtraDefs') );
}
else {
$this->m_fields[ $w_field->getName() ][] = new PGBField($w_field->getName(), $w_field->getValue());
$o_rend->renderField( $c->get('Renderer'), $w_field, $c->get('ExtraDefs') );
}
print '</td>';
print '</tr>';
}
}
print '</table>';
$this->setPageSize( $p_maxrec );
}
/**
* Renders data in a tabular fashion. The number of records displayed and the aspect
* are controlled by the block properties.
*
* There are several subformats for tabular blocks, as implied by the parameters. A
* block can be rendered:
* - alone (i.e. containing only the block records) or nested (i.e. containing the slave
* records associated to each record, too);
* - readonly (no record updating capabilities supported) or updateable;
* - in <b>report mode</b> (no updating capabilities and no record selection support) or
* standard mode.
* @param string $pTitulo the block title (if given, overrides standard title).
* @param boolean $pTree should the block be rendered nested (tree like structure, containing record and its slaves)?
* @param boolean $pReadOnly should the block be a readonly unit (no updateable fields)?
* @param boolean $pReportMode should report mode be used?
*/
function renderTabular( $pTitulo = NULL, $pTree = false, $pReadOnly = false, $pReportMode = false ) {
// renderiza um recordset inteiro no formato de uma tabela, com opcao para paginar em
// grupos de registros (neste caso, uma barra de navegacao aparece)
if ( $this->isInQueryMode() ) {
$this->renderForm( $pTitulo );
return;
}
$p_recordset = &$this->getRecordSet();
if ( ! $p_recordset ) {
return;
}
$w_titulo = $pTitulo;
if ( is_null( $pTitulo ) ) {
$w_titulo = $this->getTitle();
}
$x = split( '/', $_SERVER['REQUEST_URI'] );
$w_prefix = '/' . $x[1] . '/images';
$p_rowdef = &$this->getRenderingDefinitions();
$p_maxrec = $this->getPageSize();
if ( $pReadOnly or $pReportMode ) {
// se o bloco estiver sendo renderizado read only, nao ha paginacao
$p_maxrec = 0;
}
else {
$this->m_fields = array();
$this->m_pos = array();
}
$o_rend = new PGBRenderer( $this );
$m_rowcount = 0;
$m_recordpointer = $p_recordset->getRecordPointer();
$rp = $m_recordpointer;
$m_recordcount = $p_recordset->rowCount();
// monta uma estrutura auxiliar para renderizar tabelas multilinha, a menos que
// ela ja esteja montada
if ( count( $this->m_rendsl ) <= 0 ) {
$a_rends = array();
reset( $p_rowdef );
while( list( $k, $c ) = each( $p_rowdef ) ) {
$w_li = $c->get('Row');
if ( !$w_li ) {
$w_li = 1;
}
if ( ! is_array( $a_rends[ $w_li ] ) ) {
$a_rends[ $w_li ] = array();
}
$a_rends[ $w_li ][$k] = $c;
}
$this->m_rendsl = $a_rends;
}
$cs = 0;
reset( $this->m_rendsl );
while( list( $k, $tl ) = each( $this->m_rendsl ) ) {
$cs = max( $cs, count( $tl ) );
}
// continua
if ( !$pReadOnly ) {
$e = $this->renderErrors( -1 );
if ( !is_null( $e ) ) {
print $e;
}
}
$this->renderToolbar( $pReadOnly or $pReportMode );
print '<table width="100%" border="1">';
reset( $p_rowdef );
// os cabecalhos
if ( $this->hasSelectorPin() ) {
$cs++;
}
if ( $w_titulo and !$pReportMode ) {
print '<tr>';
print '<th colspan="' . ($cs+1) . '">';
print $w_titulo;
print '</th>';
print '</tr>';
}
print '<tr>';
// temos seletor de registros ? (pino seletor)
if ( $this->hasSelectorPin() ) {
print '<th> ';
print '</th>';
}
// renderiza cabecalhos
reset( $this->m_rendsl );
$tl = $this->m_rendsl[ 1 ];
reset( $tl );
$w_lspan = $cs - count( $tl ) + 1;
$w_cont = 0;
while( list( $k2, $c ) = each( $tl ) ) {
$w_cont++;
if ( $w_cont == count( $tl ) ) {
print '<th colspan="' . $w_lspan . '">';
}
else {
print '<th>';
}
print $c->get('Caption');
print '</th>';
}
print '</tr>';
// o conteudo
$w_posrec = 0;
if ( $p_maxrec <= 0 ) {
//print '<pre>reposicionando no 1o registro</pre>';
$p_recordset->firstRecord();
$m_recordpointer = $p_recordset->getRecordPointer();
}
else {
$w_posrec = ($p_maxrec * floor( $p_recordset->getRecordPointer() / $p_maxrec ));
}
while( ($r = &$this->beautify( $p_recordset->getRecord($w_posrec) ) ) and ($m_rowcount < $p_maxrec or $p_maxrec <= 0 ) ) {
$pCurrent = ( $w_posrec == $rp );
//var_dump($r);
$m_rowcount++;
if ( $pReportMode ) {
print '<tr class="branco">';
}
elseif ( $pCurrent ) {
print '<tr class="current">';
}
elseif ( $p_recordset->isDeleted( $w_posrec ) ) {
print '<tr class="erased">';
}
elseif ( $m_rowcount % 2 ) {
print '<tr class="odd">';
}
else {
print '<tr class="even">';
}
$m_cellcount = 0;
if ( !isset( $this->m_deta[ $w_posrec ] ) ) {
$this->m_deta[ $w_posrec ] = 0;
}
if ( $this->hasSelectorPin() ) {
$ma = array(
'pin' => array( 'pt' => 'seleciona este registro',
'en' => 'make this record current'
),
'mais' => array( 'pt' => 'exibe/ oculta detalhes adicionais',
'en' => 'show/ hide additional details'
)
);
$oIN = $this->getNlsAgent();
$oIN->setMessageArray( $ma );
print '<td valign="top" class="dados">';
if ( !$pReadOnly and !$pReportMode ) {
print '<input type="image" src="' . $w_prefix . '/aspin.gif" border=0 title="' . $oIN->getMessage('pin') . '" onClick="javascript: document.__prg_form.__' . $this->getName() . '_p.value=' . $w_posrec . '">';
}
print '<input type="hidden" id="__' . $this->getName() . '_lgdeta_' . $w_posrec . '" name="__' . $this->getName() . '_lgdeta_' . $w_posrec . '" value="' . $this->m_deta[ $w_posrec ] . '">';
if ( count( $this->m_rendsl ) > 1 or ($pTree and count( $this->getSlaveBlocks() ) > 0 ) ) {
// ha mais de uma linha por linha detalhe; precisamos ver se hah dados nestas linhas adicionais
// ou nao, renderizando o simbolo apropriado
$this->m_abspos++;
reset( $this->m_rendsl );
$w_cont = 0;
while( list( $k2, $tl ) = each( $this->m_rendsl ) ) {
reset( $tl );
if ( $k2 > 1 ) {
while( list( $k, $c ) = each( $tl ) ) {
$w_field = $r->getField( $k );
if ( is_a( $w_field, 'PGBField' ) ) {
if ( !is_null( $w_field->getValue() ) and $w_field->getValue() <> '' ) {
$w_cont++;
}
}
}
}
}
if ( $w_cont == 0 and !$pTree ) {
// nenhum dado esta preenchido
print '<img src="' . $w_prefix . '/mais_vazio.gif" border=0 title="' . $oIN->getMessage('mais') . '" onClick="javascript: toggleDisplay( \'' . $this->getName() . '\', ' . $this->m_abspos . ', ' . $w_posrec . ');">';
}
else {
// ha dados preenchidos
print '<img src="' . $w_prefix . '/mais.gif" border=0 title="' . $oIN->getMessage('mais') . '" onClick="javascript: toggleDisplay( \'' . $this->getName() . '\', ' . $this->m_abspos . ', ' . $w_posrec . ');">';
}
}
print '</td>';
}
if ( !$pReadOnly and !$pReportMode ) {
$this->recordPosition( $w_posrec );
}
$o_rend->setIndex( count( $this->m_pos ) - 1 );
if ( $p_recordset->isDeleted( $w_posrec ) ) {
$o_rend->renderField( 'hiddentext', new PGBField( '__lg_deleted', 'X' ) );
}
reset( $this->m_rendsl );
$w_k2save = -1;
while( list( $k2, $tl ) = each( $this->m_rendsl ) ) {
$w_lspan = $cs - count( $tl ) + 1;
$w_k2save= $k2 - 2;
if ( $k2 > 1 ) {
// se nao estamos na primeira linha, devemos renderizar cabecalhos para linhas de
// continuacao e marca de divisão...
print '</tr>';
$w_lgsec = '';
if ( $this->m_deta[ $w_posrec ] == 1 ) {
print '<tr id="__' . $this->getName() . '_dmt_' . $this->m_abspos . '" >';
}
else {
print '<tr id="__' . $this->getName() . '_dmt_' . $this->m_abspos . '" style="display: none">';
$w_lgsec = 'sec';
}
if ( $this->hasSelectorPin() ) {
print '<td valign="top" class="dados"> </td>';
}
reset( $tl );
$w_cont = 0;
while( list( $k, $c ) = each( $tl ) ) {
$w_cont++;
if ( $w_cont == count( $tl ) ) {
print '<th class="subc" colspan="' . $w_lspan . '">';
}
else {
print '<th class="subc">';
}
print $c->get('Caption');
print '</th>';
}
print '</tr>';
if ( $pReportMode ) {
print '<tr id="__' . $this->getName() . '_dm_' . ($w_k2save) . '_' . $this->m_abspos . '" class="branco' . $w_lgsec . '">';
}
elseif ( $pCurrent ) {
print '<tr id="__' . $this->getName() . '_dm_' . ($w_k2save) . '_' . $this->m_abspos . '" class="current' . $w_lgsec . '">';
}
elseif ( $p_recordset->isDeleted( $w_posrec ) ) {
print '<tr id="__' . $this->getName() . '_dm_' . ($w_k2save) . '_' . $this->m_abspos . '" class="erased' . $w_lgsec . '">';
}
elseif ( $m_rowcount % 2 ) {
print '<tr id="__' . $this->getName() . '_dm_' . ($w_k2save) . '_' . $this->m_abspos . '" class="odd' . $w_lgsec . '">';
}
else {
print '<tr id="__' . $this->getName() . '_dm_' . ($w_k2save) . '_' . $this->m_abspos . '" class="even' . $w_lgsec . '">';
}
if ( $this->hasSelectorPin() ) {
print '<td valign="top" class="dados"> </td>';
}
}
reset( $tl );
$w_cont = 0;
while( list( $k, $f ) = each( $tl ) ) {
$w_cont++;
//print '<h2>' . $k . ' / ' . $f . '</h2>';
$w_field = $r->getField( $k );
if ( is_a( $w_field, 'PGBField' ) ) {
$w_sc = $f->get('StyleClass');
if ( is_null( $w_sc ) ) {
print '<td valign="top" class="dados"';
}
else {
print '<td valign="top" class="' . $w_sc . '"';
}
if ( $w_cont == count( $tl ) ) {
print ' colspan="' . $w_lspan . '"';
}
print '>';
if ( !$pReadOnly and !$pReportMode ) {
$this->m_fields[ $w_field->getName() ][] = new PGBField($w_field->getName(), $w_field->getValue());
$o_rend->renderField( $f->get('Renderer'), $w_field, $f->get('ExtraDefs') );
}
else {
// se estamos renderizando em arvore e este NAO E o registro corrente, nao podemos permitir
// edicao - neste caso, renderizamos tudo como plaintext
$o_rend->renderField( 'plaintext', $w_field, $f->get('ExtraDefs') );
}
print ' </td>';
}
$m_cellcount++;
}
}
print '</tr>';
if ( !$pReadOnly ) {
$e = $this->renderErrors( $m_rowcount - 1 );
if ( !is_null( $e ) ) {
print '<tr>';
print '<td colspan="' . ($cs+1) . '">';
print $e;
print '</td>';
print '</tr>';
}
}
if ( $pTree ) {
// se se pediu renderizacao em ARVORE, renderiza os blocos escravos dentro de uma linha adicional da
// tabela de renderizacao deste bloco
foreach( $this->m_props['slaveblocks'] as $sbi ) {
//print '<pre>' . $sb->getName() . '</pre>';
$p_recordset->setRecordPointer( $w_posrec );
$sb = &$this->getSlaveBlock( $sbi->getName() );
$w_k2save++;
if ( $this->m_deta[ $w_posrec ] == 1 ) {
print '<tr id="__' . $this->getName() . '_dm_' . ($w_k2save) . '_' . $this->m_abspos . '" class="branco" >';
$sb->openAll( $pReportMode );
}
else {
print '<tr id="__' . $this->getName() . '_dm_' . ($w_k2save) . '_' . $this->m_abspos . '" class="brancosec" >';
}
print '<td colspan="' . ($cs+1) . '" align="center">';
$sb->renderTree( !$pCurrent or $pReadOnly, $pReportMode );
print ' </td>';
print '</tr>';
}
}
$w_posrec++;
}
print '</table>';
if ( !$pReadOnly ) {
$this->clearErrorArray();
}
$p_recordset->setRecordPointer( $rp );
}
/**
* Renders data in a nested tabular fashion.
*
* In a nested tabular rendering environment, the user can control which records he/ she
* wants to see through special buttons, rendered next to each record. They allow them
* to show or hide the slave records, thus "opening" or "closing" a tree of records.
* This is a convenience alias for {@link renderTabular}.
* @param boolean $pReadOnly should the block be a readonly unit (no updateable fields)?
* @param boolean $pReportMode should report mode be used?
*/
function renderTree( $pReadOnly = false, $pReportMode = false ) {
$this->renderTabular( NULL, true, $pReadOnly, $pReportMode );
}
/**
* Renders data in a nested tabular fashion using report mode.
*
* This is a convenience alias for {@link renderTree}.
*/
function renderTreeReport() {
$this->openAll( true );
$this->renderTree( true, true );
}
/**
* Marks all nodes in a tree like tabular structure as "opened".
*
* This will show all records and, within them, all their slave records. If
* report mode is stated, all records will be opened regardless of previous
* user decisions; if not, only the records not explicitly acted upon will be
* marked as opened.
* @param boolean $pReportMode the report mode flag.
*/
function openAll( $pReportMode = false ) {
$p_recordset = &$this->getRecordSet();
for( $i=0; $i <= $p_recordset->rowCount(); $i++ ) {
if ( !isset( $this->m_deta[ $i ] ) or $pReportMode ) {
// so mudamos o que nao estiver explicitamente setado, para nao violar as escolhas
// que o usuario fez depois de abrir a tela pela primeira vez
$this->m_deta[ $i ] = 1;
}
}
}
/**
* PIRAGIBE will execute this code before anything else when "posting".
*
* This should be implemented by each heir. It's originally empty (i.e. will do nothing).
* It's worth saying that the method will be called <b>BEFORE THE DATA CAPTURING PHASE</b>;
* so, no new data is available yet.
*/
function prePost() {
}
/**
* Captures and processes user input for a block, including recordset updates.
*
* This should be called from pages rendering the block. Calling post for a block
* implicitly calls post for each slave block attached to the block, and so on (i.e.
* if a slave block has slaves of its own, post will be called for them, too), in the
* proper order. POST processing is divided in several steps, which are:
* 1. <b>Pre Posting</b> -> an optional step, that each heir should implement.
* 2. <b>Data Collecting</b> -> the HTML form fields are captured and translated to
* their internal representation.
* 3. <b>Validation</b> -> data is validated, at field, record and block levels.
* 4. <b>Recordset Update</b> -> valid data are applied to the underlying recordsets.
* 5. <b>Repositioning</b> -> positional commands are executed, and a new record positioning
* context is obtained.
*
* This is by far the most complex, error prone and sensitive method of the entire
* framework. So, be very careful if you choose to override it!
*/
function post() {
// aplica mudancas feitas pelo usuario
$this->prePost();
//print '<pre>' . $this->getName(); print '</pre>';
$n = $this->getName();
$rs = &$this->getRecordSet();
if ( !is_a( $rs, 'PGBRecordSet' ) ) {
return;
}
$rpoi = $rs->getRecordPointer();
$p_rowdef = $this->getRenderingDefinitions();
$this->clearErrorArray();
$o_rend = new PGBRenderer( $this );
// salva o array de exibicao de detalhes adicionais em blocos multilinha
reset( $this->m_pos );
while( list( $bpos, $rpos ) = each( $this->m_pos ) ) {
if ( isset( $_POST[ '__' . $n . '_lgdeta_' . $rpos ] ) ) {
$this->m_deta[ $rpos ] = $_POST[ '__' . $n . '_lgdeta_' . $rpos ];
}
}
// salva, no array de campos do bloco, tudo o que foi digitado
if ( (!$this->isInQueryMode()) and $_SERVER[ 'REQUEST_METHOD' ] == 'POST' ) {
reset( $p_rowdef );
//print '<pre> colhendo post de ' . $this->getName() . '</pre>';
while( list( $fn, $rd ) = each( $p_rowdef ) ) {
//print '<pre> colheita ' . $this->getName() . ': ' . $fn . '</pre>';
if ( is_array( $this->m_fields[ $fn ] ) and $rd->get('Renderer') != 'plaintext' ) {
//print '<pre> colheita II ' . $this->getName() . ': ' . $fn . '</pre>';
reset( $this->m_fields[ $fn ] );
while( list( $i, $f ) = each( $this->m_fields[$fn] ) ) {
$fv = $f->getValue();
//print '<pre> colheita III ' . $this->getName() . ': ' . $fn . '[' . $i . '] = ' . $fv . '</pre>';
$fvn = NULL;
if ( isset( $_POST[ '__' . $n . '_' . $fn ][ $i ] ) ) {
$fvn = $_POST[ '__' . $n . '_' . $fn ][ $i ];
// se houver conversor definido, aplica a conversao
$edefs = $rd->get( 'ExtraDefs' );
if ( $edefs ) {
$fvn = $o_rend->unformat( $fvn, $edefs );
}
}
// seta o novo valor, se o registro nao estiver excluido e se o campo nao
// for "read only"
$w_ed = $rd->get('ExtraDefs');
$w_ro = false;
if ( is_a( $w_ed, 'PGBPropertyBag' ) ) {
$w_ro = $w_ed->get('ReadOnly');
if ( ! ( $w_ro === true ) ) {
$w_ro = false;
}
}
if ( isset( $_POST[ '__' . $n . '_' . '__lg_deleted' ][ $i ] ) ) {
//print '<pre>' . $fn . ': deleted</pre>';
$this->m_status = 2;
}
elseif ( ! $w_ro ) {
//print '<pre>' . $fn . ': ' . $fv . ' => ' . $fvn . '</pre>';
if ( $fv != $fvn ) {
$this->m_status = 2;
}
$f->setValue( $fvn );
$this->m_fields[ $fn ][ $i ] = $f;
}
}
}
else {
//print '<pre>'; var_dump( $this->m_fields ); //var_dump( $rd ) ;
//print '</pre>';
}
}
if ( count( $this->getErrors() ) == 0 and !isset( $_POST['__' . $n . '_delrec_y'] ) ) {
//print '<h2>' . $n . ' validando block array</h2>';
$this->validateBlockArray();
}
}
//print '<h1>' . $n . ' processando</h1>';
// o salvamento sempre e geral (todos os blocos salvam o que tem...)
if ( count( $this->getErrors() ) == 0 ) {
if ( is_a( $rs, 'PGBRecordSet' ) and ( $this->canInsert() or $this->canUpdate() or $this->canDelete() ) ) {
//print '<pre>' . $this->getName() . ' atualizando o rs</pre>';
$rs->updateFromDataBlock( $this );
}
//print '<pre>' . $this->getName() . ' verificando escravos</pre>';
foreach( $this->m_props['slaveblocks'] as $sbi ) {
//print '<pre>' . $sbi->getName() . '</pre>';
$sb = &$this->getSlaveBlock( $sbi->getName() );
$sb->post();
}
}
$w_erros = $this->countErrors();
//print '<pre> erros: ' . $n . ': ' . $w_erros . '</pre>';
// se ha erros, paramos por aqui...
if ( $w_erros > 0 ) {
//print '<pre>'; var_dump( $this->m_erros ); print '</pre>';
return;
}
// os controles posicionais sao por bloco
//print '<h1>' . $n . ' analisando comandos</h1>';
//print '<pre>'; var_dump( $_POST ); print '</pre>';
if ( isset( $_POST['__' . $n . '_delrec_y'] ) ) {
$this->m_status = 2;
$rs->deleteRecord( $rpoi );
}
elseif ( isset( $_POST['__' . $n . '_crerec_y'] ) ) {
$this->m_status = 2;
$rs->insertBlank();
$rs->lastRecord();
}
elseif ( isset( $_POST['__' . $n . '_entqry_y'] ) ) {
$this->m_status = 1;
$this->m_queryMode = true;
}
elseif ( isset( $_POST['__' . $n . '_exeqry_y'] ) ) {
$this->m_status = 1;
$this->m_queryMode = false;
$p_rowdef = &$this->getRenderingDefinitions();
$filtro = array();
reset( $p_rowdef );
while( list( $k, $f ) = each( $p_rowdef ) ) {
$filtro[ $k ] = $_POST['__' . $n . '_' . $k][0];
}
$this->newError( -1, $rs->applyFilter( $filtro ) );
}
elseif ( isset( $_POST['__' . $n . '_p'] ) ) {
$p = $_POST[ '__' . $n . '_p' ];
if ( $p >= 0 ) {
//print '<pre>' . $n . ' I: posicionando em ' . $p . '</pre>';
$rs->setRecordPointer( $p );
}
elseif ( isset( $_POST['__' . $n . '_px'] ) and $p == -1000 ) {
$p = $_POST[ '__' . $n . '_px' ];
if ( $p >= 0 ) {
//print '<pre>' . $n . ' II: posicionando em ' . $p . '</pre>';
$rs->setRecordPointer( $p );
}
}
else {
//print '<pre>'; var_dump($_POST); print '</pre>';
}
}
//print '<pre>' . $this->getName() . ' -> ' . $w_erros . '</pre>';
if ( isset( $_POST['__commit_y'] ) and is_a($rs, 'PGBRecordSet') ) {
//print '<pre>' . $this->getName() . ' commit</pre>';
$mk = $rs->getMasterKeys();
if ( count( $mk ) == 0 and is_null($this->getSlaveRsName()) and $w_erros == 0 ) {
// apenas recordsets que NAO SAO escravos precisam ser postados -> a postagem de um mestre
// posta todos os seus escravos, tornando desnecessario postar os escravos de per si.
//print '<pre>' . $this->getName() . ' commit Ok</pre>';
$rs->post();
$rs->applyFilter( array() );
//print '<pre>' . $n . ' COMMIT: posicionando em ' . $rpoi . '</pre>';
$rs->setRecordPointer( $rpoi );
}
$this->m_status = 1;
}
//print '<h1>' . $this->getName() . ' terminando process</h1>';
}
/**
* This is an alias for {@link post}, kept here for historical reasons.
* @deprecated 1.00 - 01/07/2006
*/
function process() {
$this->post();
}
}
?>