Quando você tentar apontar o Zend_Db_Table_Abstract do Zend Framework com o Oracle, para gerar comandos SQL é possível que você enfrente o mesmo problema que nós enfrentamos, aspas duplas aparecem e fazem seus comandos SQL inválidos. Para resolver isso adicione a seguinte linha:
resources.db.params.options.autoQuoteIdentifiers = 0
no seu application.ini e seja feliz.
Versão Longa,
Quando o Zend_Db_Table_Abstract gera erros ao tentar executar seus comandos SQL triviais, gerados automaticamente, qual é o 1º passo? Eu costumo gerar o assemble() do comando SQL para poder testa-lo diretamente no banco de dados.
Como o problema que temos é com qualquer método, então testamos no mais simples, sobrescrevendo o getAll e fazendo isso:
public function getAll($where = null, $order = null, $count = null, $offset = null)
{
var_export( $this->select()->assemble() );
exit();
}
Então obtemos:
SELECT "tb_estado".* FROM "db_projeto"."tb_estado"
Sabemos agora qual é o problema: As consultas geradas automaticamente pelo Zend estão colocando aspas duplas no nome das tabelas e do schema, o que não é aceito no Oracle.
Após pesquisar um pouco achei esse link http://doczf.mikaelkael.fr/1.10/pt-br/zend.db.select.html que informa:
O método
quoteIdentifier()
usa aspas no SQL para delimitar o identificador, o que deixa claro que ele é um identificador de uma tabela ou coluna e não parte da síntaxe SQL.
Agora qual é o problema: As consultas geradas automaticamente pelo Zend estão colocando aspas duplas no nomes devido ao método _quoteIdentifier, que funciona do seguinte modo:
1009 /**
1010 * Quote an identifier.
1011 *
1012 * @param string $value The identifier or expression.
1013 * @param boolean $auto If true, heed the AUTO_QUOTE_IDENTIFIERS config option.
1014 * @return string The quoted identifier and alias.
1015 */
1016 protected function _quoteIdentifier($value, $auto=false)
1017 {
1018 if ($auto === false || $this->_autoQuoteIdentifiers === true) {
1019 $q = $this->getQuoteIdentifierSymbol();
1020 return ($q . str_replace("$q", "$q$q", $value) . $q);
1021 }
1022 return $value;
1023 }
1010 * Quote an identifier.
1011 *
1012 * @param string $value The identifier or expression.
1013 * @param boolean $auto If true, heed the AUTO_QUOTE_IDENTIFIERS config option.
1014 * @return string The quoted identifier and alias.
1015 */
1016 protected function _quoteIdentifier($value, $auto=false)
1017 {
1018 if ($auto === false || $this->_autoQuoteIdentifiers === true) {
1019 $q = $this->getQuoteIdentifierSymbol();
1020 return ($q . str_replace("$q", "$q$q", $value) . $q);
1021 }
1022 return $value;
1023 }
O nosso problema agora tem um foco bem mais específico. Como fazer o atributo protegido _autoQuoteIdentifiers ser falso. Logicamente se o atributo fosse público ou ao menos tivesse um setAutoQuoteIndentifiers ou algo similar, estaria agora resolvido o problema, na nossa classe pai que herda o Zend_Db_Table_Abstract, algo muito parecido com:
public function init()
{
$this->_db->setAutoQuoteIndentifiers( false );
}
Mas, para nossa tristeza e agonia esse método setter não existe. Então precisamos descobrir como esse atributo recebe um valor.
Fazendo uma busca na classe, vemos que esse atributo pode ter seu valor atribuído caso ele venha no Array que é recebido no método construtor da classe
238
239 // obtain quoting property if there is one
240 if (array_key_exists(Zend_Db::AUTO_QUOTE_IDENTIFIERS, $options)) {
241 $this->_autoQuoteIdentifiers = (bool) $options[Zend_Db::AUTO_QUOTE_IDENTIFIERS];
242 }
243
239 // obtain quoting property if there is one
240 if (array_key_exists(Zend_Db::AUTO_QUOTE_IDENTIFIERS, $options)) {
241 $this->_autoQuoteIdentifiers = (bool) $options[Zend_Db::AUTO_QUOTE_IDENTIFIERS];
242 }
243
Tentando entender como essa variável $options é montada, vemos que essa variável é um Array que é inicializado com os valores padrões:
185 $options = array(
186 Zend_Db::CASE_FOLDING => $this->_caseFolding,
187 Zend_Db::AUTO_QUOTE_IDENTIFIERS => $this->_autoQuoteIdentifiers
188 );
186 Zend_Db::CASE_FOLDING => $this->_caseFolding,
187 Zend_Db::AUTO_QUOTE_IDENTIFIERS => $this->_autoQuoteIdentifiers
188 );
Mas que tem esses valores alterados conforme os elementos que são recebidos no campo "options" do $config. Sendo $config o Array que é recebido no construtor.
190
191 /*
192 * normalize the config and merge it with the defaults
193 */
194 if (array_key_exists('options', $config)) {
195 // can't use array_merge() because keys might be integers
196 foreach ((array) $config['options'] as $key => $value) {
197 $options[$key] = $value;
198 }
199 }
191 /*
192 * normalize the config and merge it with the defaults
193 */
194 if (array_key_exists('options', $config)) {
195 // can't use array_merge() because keys might be integers
196 foreach ((array) $config['options'] as $key => $value) {
197 $options[$key] = $value;
198 }
199 }
Procurando então em que local do Zend_Db_Table_Abstract que é instanciado o atributo $this->_db
Chegamos nas seguintes linhas:
575 /**
576 * @param mixed $db Either an Adapter object, or a string naming a Registry key
577 * @return Zend_Db_Table_Abstract Provides a fluent interface
578 */
579 protected function _setAdapter($db)
580 {
581 $this->_db = self::_setupAdapter($db);
582 return $this;
583 }
Seguindo o rastro, vamos ao método _setupAdapter:
594
595 /**
596 * @param mixed $db Either an Adapter object, or a string naming a Registry key
597 * @return Zend_Db_Adapter_Abstract
598 * @throws Zend_Db_Table_Exception
599 */
600 protected static function _setupAdapter($db)
601 {
602 if ($db === null) {
603 return null;
604 }
605 if (is_string($db)) {
606 require_once 'Zend/Registry.php';
607 $db = Zend_Registry::get($db);
608 }
609 if (!$db instanceof Zend_Db_Adapter_Abstract) {
610 require_once 'Zend/Db/Table/Exception.php';
611 throw new Zend_Db_Table_Exception('Argument must be of type Zend_Db_Adapter_Abstract, or a Registry key where a Zend_Db_Adapter_Abstract object is stored');
612 }
613 return $db;
614 }
595 /**
596 * @param mixed $db Either an Adapter object, or a string naming a Registry key
597 * @return Zend_Db_Adapter_Abstract
598 * @throws Zend_Db_Table_Exception
599 */
600 protected static function _setupAdapter($db)
601 {
602 if ($db === null) {
603 return null;
604 }
605 if (is_string($db)) {
606 require_once 'Zend/Registry.php';
607 $db = Zend_Registry::get($db);
608 }
609 if (!$db instanceof Zend_Db_Adapter_Abstract) {
610 require_once 'Zend/Db/Table/Exception.php';
611 throw new Zend_Db_Table_Exception('Argument must be of type Zend_Db_Adapter_Abstract, or a Registry key where a Zend_Db_Adapter_Abstract object is stored');
612 }
613 return $db;
614 }
Para testar essa hipótese eu vou imprir o $config do construtor do Zend_Db_Table_Abstract. Como qualquer alteração feita no código do Zend Framework isso é apenas para auxiliar o nosso entendimento e deverá ser desfeita em breve.
Ao adicionar no construtor a seguinte linha:
public function __construct($config)
{
var_export( $config );
exit();
// (...)
Obtemos o seguinte resultado:
array (
'host' => 'banco_do_projeto',
'username' => 'usuario_do_servidor',
'password' => '******',
'dbname' => 'db_projeto',
'charset' => 'utf8',
'profiler' =>
array (
'enabled' => '1',
),
)
Precisamos adicionar uma linha no nosso application.ini para testar se essa chegará até o $config. Mas qual seria o valor dessa linha. Por semelhança aos demais elementos que chegaram, deve ser algo similar a resources.db.params.options.xxxxxxxxxxx = 0. Mas, para encontrarmos o valor que desejamos, precisamos saber qual é o valor da chave. Esse valor nós podemos ver aqui:
185 $options = array(
186 Zend_Db::CASE_FOLDING => $this->_caseFolding,
187 Zend_Db::AUTO_QUOTE_IDENTIFIERS => $this->_autoQuoteIdentifiers
188 );
186 Zend_Db::CASE_FOLDING => $this->_caseFolding,
187 Zend_Db::AUTO_QUOTE_IDENTIFIERS => $this->_autoQuoteIdentifiers
188 );
Usando o CRTL+Click da IDE, já fui direto para a declaração desta constante, conforme:
const AUTO_QUOTE_IDENTIFIERS = 'autoQuoteIdentifiers';
Logo a nossa nova linha no application.ini, deve ser:
resources.db.params.options.autoQuoteIdentifiers = 0
Obtemos o seguinte resultado:
array (
'host' => 'banco_do_projeto',
'username' => 'usuario_do_servidor',
'password' => '******',
'dbname' => 'db_projeto',
'charset' => 'utf8',
'options' =>
array (
'autoQuoteIdentifiers' => '1',
),
'profiler' =>
array (
'enabled' => '1',
),
)
Esse novo elemento no $config vai alterar o atributo protegido _autoQuoteIdentifiers retirando as aspas dos SQL gerados e resolvendo o nosso problema.
Espero que isso tenha ajudado.
Um grande abraço.
Um comentário:
Sou muito grato a Elegantloanfirm por me ajudar a obter um empréstimo de US $ 600.000,00 ajudando o agente de empréstimos Russ Harry e sou eternamente grato a você. Minha vida mudou, meu dinheiro acabou, agora possuo um negócio comercial que costumava cuidar das necessidades de minha família. Sou grato a você, Sr. Russ, e que Deus o abençoe. Você pode contatá-los para obter assistência financeira via e-mail: Elegantloanfirm@hotmail.com para obter sua ajuda financeira.
Postar um comentário