Files
2021-09-17 12:41:45 +02:00

486 lines
18 KiB
PHP

<?php
/**
* Classe generica che si interfaccia con le varie classi di risorsa da utilizzare con le funzione generiche delle query
*
* Versione: 1.0.2
* Data Update: 16/02/2021
*
* Elenco Funzionalità implementate:
*
* - countTotal
* - getList con paginazione
* - getList con ricerche complete di parametri ORWHERE e ANDORWHERE
* - getList con gestione completa dell'ordinamento in base alla stringa passata anche con valori multipli | array (rimane intatto)
* - getList con selectList (opzionele) | '*'
* - getList con joinData (opzionale) inclusa anche la possibilità di inserire join multipli nell'array
* - getList con groupBy (opzionale)
* # Per utilizzare getList e groupBy bisogna fare l'overload delle funzioni checkIfSetJoinData | checkIfSetGroupBy nel controller della risorsa
* - countFiltered() non utilizza il getList
* - getByColumnName()
* - customQuery()
* - inserito l'overload della funzione getList che ora è utilizzabile con due intestazioni di metodo "classica" o "con array di parametri"
* - inserita la gestione dell'having per la getList
*
* Class App_Model_AbstractGeneric
*/
abstract class App_Model_AbstractGeneric
{
protected $_resources = array();
const JOIN_TABLE_NAME = "JOIN_TABLE_NAME";
const JOIN_CONDITION_NAME = "JOIN_CONDITION_NAME";
const JOIN_COLUMNS_NAME = "JOIN_COLUMNS_NAME";
const JOIN_TYPE = "JOIN_TYPE";
const JOIN_FUNCTION_NAME_ALLOWED = array('join', 'joinInner', 'joinLeft', 'joinRight', 'joinFull', 'joinCross', 'joinNatural');
const ALLOWED_GETLIST_ARRAY_OPTIONS = array('page', 'count', 'where', 'order', 'selectList', 'joinOptions', 'groupBy', 'fetchRow', 'having');
/**
* @param $name
* @return App_Model_Resource_Abstract
* @throws App_Controller_Errors_WebServiceError
*/
public function getResource($name)
{
if (!isset($this->_resources[$name])) {
$class = implode('_', array(
$this->_getNamespace(),
'Model_Resources',
ucfirst($name)));
//Controllo l'esistenza della classe
if (!class_exists($class)) {
throw new App_Controller_Errors_WebServiceError("Errore generazione la classe risorsa '$class' potrebbe non esistere");
}
$this->_resources[$name] = new $class();
}
return $this->_resources[$name];
}
private function _getNamespace()
{
$ns = explode('_', get_class($this));
return $ns[0];
}
/*====================================================================================================
*======================= FUNZIONI GENERICHE PER OGNI TABELLA ==========================
*====================================================================================================*/
/**
* @param $resourceName
* @param $info
* @return mixed
* @throws App_Controller_Errors_WebServiceError
*/
public function insert($resourceName, $info)
{
return $this->getResource($resourceName)->insert($info);
}
public function update($resourceName, $id, $info)
{
$resource = $this->getResource($resourceName);
$idString = (is_int($id)) ? " = $id" : " = '$id'";
return $resource->update($info, $resource->getPrimaryKey() . $idString);
}
public function updateWhere($resourceName, $condition, $info)
{
//Se passo un array di condizioni viene construita la stringa
if (is_array($condition)) {
$last_key = key(array_slice($condition, -1, 1, TRUE));
$str = "";
foreach ($condition as $key => $val) {
$str .= str_replace('?', $val, $key);
if ($key != $last_key) $str .= " AND ";
}
$condition = $str;
}
$resource = $this->getResource($resourceName);
return $resource->update($info, $condition);
}
public function delete($resourceName, $id)
{
$resource = $this->getResource($resourceName);
$idString = (is_int($id)) ? " = $id" : " = '$id'";
return $resource->delete($resource->getPrimaryKey() . $idString);
}
public function deleteWhere($resourceName, $condition)
{
//Se passo un array di condizioni viene construita la stringa
if (is_array($condition)) {
$last_key = key(array_slice($condition, -1, 1, TRUE));
$str = "";
foreach ($condition as $key => $val) {
$str .= str_replace('?', $val, $key);
if ($key != $last_key) $str .= " AND ";
}
$condition = $str;
}
$resource = $this->getResource($resourceName);
return $resource->delete($condition);
}
public function getById($resourceName, $id)
{
$resource = $this->getResource($resourceName);
return $resource->getAdapter()->query('SELECT * FROM ' . $resource->getTableName() . ' WHERE ' . $resource->getPrimaryKey() . ' = ?', array($id))->fetch();
}
public function getLastId($resourceName)
{
$resource = $this->getResource($resourceName);
return $resource->getAdapter()->query('SELECT id FROM ' . $resource->getTableName() . ' ORDER BY ' . $resource->getPrimaryKey() . ' DESC LIMIT 1')->fetchColumn(0);
}
public function getCountTotal($resourceName)
{
$resource = $this->getResource($resourceName);
return $resource->getAdapter()->query('SELECT COUNT(*) as num FROM ' . $resource->getTableName())->fetchColumn(0);
}
// FUNZIONE GET LIST CON OVERLOAD
public function getList()
{
$args = func_get_args();
$functionName = (func_num_args() === 2 && is_array($args[1])) ? 'getListOptions' : 'getListDefault';
return call_user_func_array(array(&$this, $functionName), $args);
}
/**
* #Overload
* Funzione get list che accetta i parametri inseriti in un array in modo da non dover più rispettare l'ordine di inserimento
*
* @param $resourceName
* @param array $options
* @return Zend_Paginator
* @throws Zend_Exception
* @throws Zend_Paginator_Exception
*/
public function getListOptions($resourceName, array $options = [])
{
foreach ($options as $optionKey => $val) {
if (!in_array($optionKey, self::ALLOWED_GETLIST_ARRAY_OPTIONS)) {
throw new App_Controller_Errors_WebServiceError("'$optionKey' non e' una opzione valida per la funzione getList()");
}
}
return $this->getListDefault($resourceName,
$options['page'], $options['count'], $options['where'],
$options['order'], $options['selectList'], $options['joinOptions'],
$options['groupBy'], $options['fetchRow'], $options['having']);
}
/**
* Funzione getList completa (può sostituire anche la funzione getFilteredList)
*
* @param $resourceName
* @param null $paged
* @param null $count
* @param array $where
* @param null $order
* @param string $selectList
* @param null $joinData
* @param null $groupBy
* @param bool $fetchRow
* @return Zend_Paginator
* @throws Zend_Exception
* @throws Zend_Paginator_Exception
*/
public function getListDefault($resourceName, $paged = null, $count = null, $where = array(), $order = null, $selectList = '*', $joinData = null, $groupBy = null, $fetchRow = false, $having = false)
{
$resource = $this->getResource($resourceName);
// definizione della select list
$selectList = (!is_null($selectList)) ? $selectList : $resource->getDefaultSelectColumns();
if (is_string($selectList)) {
$selectList = explode(',', $selectList);
}
$select = $resource->getAdapter()->select()->from($resource->getTableName(), $selectList);
//Gestione dell'eventuale Join
$joinData = (!is_null($joinData)) ? $joinData : $resource->getDefaultJoinData();
if (is_array($joinData)) {
$select = $this->applicateJoinData($select, $joinData);
}
//gestione dei parametri di ricerca
if (is_array($where)) {
foreach ($where as $key => $value) {
// se trovo l'operatore '#OR' o '#ANDOR' significa che devo applicare l'or per gli elementi passati nel campo value, NB: il value deve essere una string separata da virgole
if (preg_match("/#OR/", $key)) { // #ANDOR accoda la query es: WHERE ... OR (nome_campo = ?)
$select = $this->applicateOrWhere($select, $key, $value, '#OR');
} else if (preg_match("/#ANDOR/", $key)) { // #ANDOR compone la query es: WHERE ... AND ( campo1 = ? OR campo2 = ?)
//salvo le condizioni presenti e resetto temporaneamente le condizini
$oldWhereConditions = $select->getPart(Zend_Db_Select::WHERE);
$select->reset(Zend_Db_Select::WHERE);
// genero le condizioni or
$select = $this->applicateOrWhere($select, $key, $value, '#ANDOR');
// recupero le condizioni or generate e resetto di nuovo tutte le condizioni
$orWhereConditions = $select->getPart(Zend_Db_Select::WHERE);
$select->reset(Zend_Db_Select::WHERE);
// reimposto le vecchie condizioni e accodo le nuove condizioni or
if ($oldWhereConditions) $select->where(implode(' ', $oldWhereConditions));
$select->where(implode(' ', $orWhereConditions));
} else {
//Di default utilizzo where con la AND
$select->where($key, $value);
}
}
}
//Gestione dell'eventuale grouBy
if ($groupBy) {
$select->group($groupBy);
}
//gestione dell'ordinamento
$order = (!$order) ? $resource->getDefaultOrder() : $order;
if (is_string($order)) {
$tmpOrder = explode(',', $order);
foreach ($tmpOrder as &$ord) {
// il '.' serve a definire il nome della tabella altrimenti imposto quella di default della risorsa che chiama la query
if (!preg_match("/\./", $ord)) {
$ord = $resource->getTableName() . "." . trim($ord);
}
// Se non esiste un verso di ordinamento assegno quello di default della risorsa per ogni campo ordinamento passato
if (!preg_match("/(ASC|DESC|desc|asc)$/", $ord)) {
$ord = explode(' ', trim($ord))[0] . ' ' . strtoupper($resource->getDefaultTipoOrder());
}
}
$order = $tmpOrder;
}
$select->order($order);
//Gestione dell'eventuale grouBy
if ($having && is_array($having)) {
foreach (array_keys($having) as $key) {
$select->having($key, $having[$key]);
}
}
// Zend_Registry::get('log')->info(print_r($select->__toString(), true));
//Esecuzione della query di ricerca
if (null !== $paged && null !== $count) {
$adapter = new Zend_Paginator_Adapter_DbSelect($select);
$paginator = new Zend_Paginator($adapter);
$paginator->setItemCountPerPage($count)->setCurrentPageNumber((int)$paged);
return $paginator;
}
$stmt = $resource->getAdapter()->query($select->__toString());
//Gestione del Fetch
if ($fetchRow)
return $stmt->fetch();
else
return $stmt->fetchAll();
}
/**
* @param $resourceName
* @param $where
* @param null $order
* @param null $selectList
* @param null $joinData
* @param null $groupBy
* @return Zend_Paginator
* @throws Zend_Exception
* @throws Zend_Paginator_Exception
*/
public function getFiltered($resourceName, $where, $order = null, $selectList = null, $joinData = null, $groupBy = null)
{
return $this->getList($resourceName, null, null, $where, $order, $selectList, $joinData, $groupBy, true);
}
/**
* Con questa funzione posso recuperare il numero di elementi di una tabella in base a parametri
* @param $resourceName
* @param $where
*
* @return Zend_Paginator
*/
public function countFiltered($resourceName, $where)
{
//Definizione della risorsa
$resource = $this->getResource($resourceName);
$select = $resource->getAdapter()->select()->from($resource->getTableName(), 'COUNT(*) as num');
//Applico le eventuali condizioni di ricerca
foreach ($where as $key => $value) {
$select->where($key, $value);
}
$stmt = $resource->getAdapter()->query($select->__toString());
return $stmt->fetchColumn(0);
}
/**
* Questa funzione passato il nome della colonna su cui cercare cerca il valore scelto;
* l'operatore di default è 'uguale'
* altriemnti è possibile specificarne un altro trimete il parametro @op
*
* @param $resourceName
* @param $columnName
* @param $value
* @param $fetchRow | Se impostato a true ritorna la riga come oggetto
* @param $op
* @param $joinData | per eseguire un join con altre tabelle
*
* @return mixed
*/
public function getByColumnName($resourceName, $columnName, $value, $op = "=", $fetchRow = false, $order = null, $joinData = null)
{
$resource = $this->getResource($resourceName);
//GESTIONE OPERATORI
switch ($op) {
case'LIKE':
$value = "%" . $value . "%";
break;
case'LIKEPRE':
$value = "%" . $value;
break;
case'LIKEPOST':
$value = $value . "%";
break;
default:
break;
}
$select = $resource->getAdapter()->select()->from($resource->getTableName());
//Gestione dell'eventuale Join
if (is_array($joinData)) {
$select = $this->applicateJoinData($select, $joinData);
}
$select->where($columnName . ' ' . $op . ' ?', $value);
if ($order != null && (is_array($order) || is_string($order))) {
$select->order($order);
}
if ($fetchRow) {
if ($order != null && (is_array($order) || is_string($order))) {
return $resource->fetchRow($resource->select()->where($columnName . ' ' . $op . ' ?', $value)->order($order));
} else {
return $resource->fetchRow($resource->select()->where($columnName . ' ' . $op . ' ?', $value));
}
} else {
return $resource->getAdapter()->query($select->__toString())->fetch();
}
}
/**
* @param $query
* @param null $params
* @param bool $fetchRow
* @return mixed
*
* @throws App_Controller_Errors_WebServiceError
*/
public function customQuery($query, $params = null, $fetchRow = false)
{
$resource = $this->getResource('Abstract');
$stmt = $resource->getAdapter()->query($query, $params);
//Gestione del Fetch
if ($fetchRow)
return $stmt->fetch();
else
return $stmt->fetchAll();
}
/**
* @param $select
* @param $joinData
* @return mixed
*
* @throws App_Controller_Errors_WebServiceError
*/
private function applicateJoinData($select, $joinData)
{
if (!isset($joinData[0])) {
if (!array_key_exists(self::JOIN_TABLE_NAME, $joinData))
throw new App_Controller_Errors_WebServiceError("Nome tabella per il join non trovato");
if (!array_key_exists(self::JOIN_CONDITION_NAME, $joinData))
throw new App_Controller_Errors_WebServiceError("Nome del campo di condizione per il join non trovato");
$colonne = (!$joinData[self::JOIN_COLUMNS_NAME]) ? array('*') : $joinData[self::JOIN_COLUMNS_NAME];
$joinFunctionName = (in_array($joinData[self::JOIN_TYPE], self::JOIN_FUNCTION_NAME_ALLOWED)) ? $joinData[self::JOIN_TYPE] : 'join';
return $select->$joinFunctionName($joinData[self::JOIN_TABLE_NAME], $joinData[self::JOIN_CONDITION_NAME], $colonne);
} else { // Gestione di più join contemporanei
foreach ($joinData as $key => $join) {
if (!array_key_exists(self::JOIN_TABLE_NAME, $join))
throw new App_Controller_Errors_WebServiceError("Nome tabella per il join non trovato per il join index: [$key]");
if (!array_key_exists(self::JOIN_CONDITION_NAME, $join))
throw new App_Controller_Errors_WebServiceError("Nome del campo di condizione per il join non trovato per il join index: [$key]");
$colonne = (!$join[self::JOIN_COLUMNS_NAME]) ? array('*') : $join[self::JOIN_COLUMNS_NAME];
$joinFunctionName = (in_array($join[self::JOIN_TYPE], self::JOIN_FUNCTION_NAME_ALLOWED)) ? $join[self::JOIN_TYPE] : 'join';
$select->$joinFunctionName($join[self::JOIN_TABLE_NAME], $join[self::JOIN_CONDITION_NAME], $colonne);
}
return $select;
}
}
private function applicateOrWhere($select, string $keyNomeCampo, $valoriOr, string $op = '#OR')
{
$valueOrDaApplicare = null;
if (is_string($valoriOr))
$valueOrDaApplicare = explode(',', $valoriOr);
elseif (is_array($valoriOr))
$valueOrDaApplicare = $valoriOr;
if (!$valueOrDaApplicare) {
throw new App_Controller_Errors_WebServiceError("Valori per la condizione '$op' non validi per generare la query", App_Controller_Errors_WebServiceError::WEBSERVICE_GENERIC_ERROR);
}
$keyDaApplicare = str_replace($op, '=', $keyNomeCampo);
if (is_array($valueOrDaApplicare) && count($valueOrDaApplicare) > 0) {
foreach ($valueOrDaApplicare as $val) {
$select->orwhere($keyDaApplicare, $val);
}
}
return $select;
}
}