Files
fdn2/app/private/lib/dao/GenericDao.php
T
2022-08-30 13:33:35 +02:00

467 lines
13 KiB
PHP

<?php
/*
Author: Riccardo Di Dato
Creation Date: 22/dic/2015
*/
class GenericDao{
/**
* Nome del database
* @var string
*/
private $dbName;
/**
* Contiene il controller del driver mongo
* @var MongoDB\Driver\Manager
*/
private $client;
/**
* La connection string viene passata interamente a MongoClient, richiede formato 'mongo://server:port'.
* host1 e database sono obbligatori
*
* @param string $connectionString
*/
public function __construct($dbName, $connectionString = null){
if (is_null($connectionString)){
$this->client = new MongoDB\Driver\Manager();
}
else {
$this->client = new MongoDB\Driver\Manager($connectionString);
}
$this->dbName = $dbName;
}
/**
* Restituisce il nome del database attualmente in uso
* @return string
*/
public function getDbName(){
return $this->dbName;
}
/**
* Ritorna un array di model
* @param string $modelClass classe da ritornare (DaoSaveable)
* @param array $filter array associativo della select formato mongo
* @param array $options (al momento supporta limit e sort)
* @param string $customReturnClass
* @throws CoreException se la CustomReturnClass non è valida
* @return DaoSaveable[]
*/
public function query($modelClass, array $filter = array(), array $options = array()){
$modelClass = trim($modelClass);
if (!is_null($modelClass)){
if (!is_subclass_of($modelClass, "DaoSaveable", true)){
throw new CoreException("Invalid return class passed to GenericDao::query ($modelClass)");
}
}
$collectionName = $modelClass::getCollectionName();
$useFilter = $filter;
if (!array_key_exists("deleted",$useFilter)){
$useFilter["deleted"] = false;
}
if (array_key_exists("id",$useFilter)){
$useFilter["_id"] = $useFilter["id"];
unset($useFilter["id"]);
}
if (array_key_exists("_id",$useFilter) && is_string($useFilter["_id"])){
$useFilter["_id"] = new MongoDB\BSON\ObjectID($useFilter["_id"]);
}
if (array_key_exists("sort",$options)){
if (array_key_exists("creationDate",$options["sort"]) && !array_key_exists("_id",$options["sort"])){
$options["sort"]["_id"] = $options["sort"]["creationDate"];
}
}
if (array_key_exists("limit",$options)){
$options["limit"] = intval($options["limit"]);
}
if (array_key_exists("skip",$options)){
$options["skip"] = intval($options["skip"]);
}
$query = new MongoDB\Driver\Query($useFilter, $options);
$cursor = $this->client->executeQuery($this->dbName.".$collectionName",$query);
$rval = array();
foreach ($cursor as $element){
$rval[] = $modelClass::buildFromSaveableObj($element);
}
return $rval;
}
public function count($modelClass, array $filter = array(), array $options = array()){
if (!is_null($modelClass)){
if (!is_subclass_of($modelClass, "DaoSaveable", true)){
throw new CoreException("Invalid return class passed to GenericDao::query ($modelClass)");
}
}
$collectionName = $modelClass::getCollectionName();
$useFilter = $filter;
if (!array_key_exists("deleted",$useFilter)){
$useFilter["deleted"] = false;
}
if (array_key_exists("id",$useFilter)){
$useFilter["_id"] = $useFilter["id"];
unset($useFilter["id"]);
}
if (array_key_exists("_id",$useFilter) && is_string($useFilter["_id"])){
$useFilter["_id"] = new MongoDB\BSON\ObjectID($useFilter["_id"]);
}
$command = new \MongoDB\Driver\Command( [ 'count' => $collectionName, 'query' => $useFilter ] );
$cursor = $this->client->executeCommand( $this->dbName, $command );
foreach ($cursor as $ele){
return $ele->n;
}
}
/**
* Come query ma ritorna il primo o null se non ci sono risultati
* @param string $modelClass
* @param array $filter
* @param array $options
* @return DaoSaveable
*/
public function getFirst($modelClass, array $filter = array(), array $options = array()){
$options["limit"] = 1;
$rval = null;
$list = $this->query($modelClass, $filter, $options);
if (sizeof($list)>0){
$rval = reset($list);
}
return $rval;
}
/**
* Salva...
* @param DaoSaveable $model
*/
public function save(DaoSaveable $model){
$collectionName = $model->getCollectionName();
$saveObj = $model->getSaveableObj();
$bulk = new MongoDB\Driver\BulkWrite();
if ( array_key_exists("_id", $saveObj) && !is_null($saveObj["_id"]) ){
if (is_string( $saveObj["_id"]) ){
$saveObj["_id"] = new MongoDB\BSON\ObjectID($saveObj["_id"]);
}
$bulk->update(array("_id"=>$saveObj["_id"] ),$saveObj);
}
else {
$saveObj["_id"] = new MongoDB\BSON\ObjectID();
$bulk->insert($saveObj);
$model->updateFromSaveableObj($saveObj);
}
$writeConcern = new MongoDB\Driver\WriteConcern(MongoDB\Driver\WriteConcern::MAJORITY, 100);
$result = $this->client->executeBulkWrite($this->dbName.".$collectionName", $bulk, $writeConcern);
//TODO: (Rik) Controllo sul write concern
}
/**
* Cancella... la cancellazione non è reale, viene solo settato il campo deleted a true.
* @param DaoSaveable $model
*/
public function delete(DaoSaveable $model){
$model->deleted = true;
$this->save($model);
}
/**
* Ritorna un array di model
* @param string $modelClass classe da ritornare (DaoSaveable)
* @param array $filter array associativo della select formato mongo
* @param array $options (al momento supporta limit e sort)
* @param string $customReturnClass
* @throws CoreException se la CustomReturnClass non è valida
* @return DaoSaveable[]
*/
public function aggregate($modelClass, array $pipeline = array(), array $options = array()){
$modelClass = trim($modelClass);
if (!is_null($modelClass)){
if (!is_subclass_of($modelClass, "DaoSaveable", true)){
throw new CoreException("Invalid return class passed to GenericDao::aggregate ($modelClass)");
}
}
$collectionName = $modelClass::getCollectionName();
$addDeleteMatch = true;
if (sizeof($pipeline)>0){
foreach ($pipeline as $ele){
if (is_array($ele)){
// Check se esistono match su deleted
if (array_key_exists('$match', $ele) && array_key_exists("deleted", $ele['$match'])){
$addDeleteMatch = false;
}
if (array_key_exists('$groupBy', $ele)){
// Sostituzione di id con _id
foreach ($ele as $key=>$val){
if (array_key_exists("id",$val)){
$val["_id"] = $val["id"];
unset($val["id"]);
}
}
// Sostituzione di _id stringa con MongoId
if (array_key_exists("_id",$val) && is_string($val["_id"])){
$val["_id"] = new MongoDB\BSON\ObjectID( $val["_id"] );
}
}
}
}
}
if ($addDeleteMatch){
if (array_key_exists('$match', $pipeline[0])){
$pipeline[0]['$match']["deleted"] = false;
// array_unshift($pipeline[0]['$match'], array("deleted"=>false));
}
else {
array_unshift($pipeline, array('$match'=>array("deleted"=>false)));
}
}
$command = new \MongoDB\Driver\Command( [
'aggregate' => $collectionName,
'pipeline' => $pipeline,
'cursor' => [
'batchSize' => 100
],
'allowDiskUse' => true
] );
$cursor = $this->client->executeCommand( $this->dbName, $command );
$rval = [];
foreach ($cursor as $ele){ // inganniamo il cursore, in realtà il risultato è uno
//TODO CHECK
$rval[] = json_decode( json_encode($ele) ,true );
}
return $rval;
}
/**
* Ritorna la lista dei notizia model ordinati per pertinenza
* @param string $modelClass
* @param string $searchWord
* @param array $filter
* @param array $options
* @throws CoreException
* @return DaoSaveable[]
*/
public function search($modelClass, $search, array $filter = array(), array $options = array()){
if ( is_a($modelClass, DaoSearchable::class, true ) ) {
return $this->query($modelClass, self::getSearchFilter( $modelClass, $search, $filter, $options, $modelClass::getSearchableFields() ), $options);
}
else {
return $this->searchUseIndex($modelClass, $search, $filter, $options);
}
}
public function searchCount($modelClass, $search, array $filter = array(), array $options = array()){
if ( is_a($modelClass, DaoSearchable::class, true ) ) {
return $this->count($modelClass, self::getSearchFilter( $modelClass, $search, $filter, $options, $modelClass::getSearchableFields() ), $options);
}
else {
return $this->searchUseIndexCount($modelClass, $search, $filter, $options);
}
}
/**
* Versione MODDATA di quello in PHPFramework (usa solo SEARCH_MODE_DAO in modalità regex)
* @param string $modelClass
* @param string $search
* @param array $filter
* @param array $options
* @param array $recursiveIgnore
* @throws CoreException
* @return array|string[]
*/
private function getSearchFilter($modelClass, $search, array $filter = array(), array $options = array(), array $searchFields){
$search = trim($search);
if ( strcmp($search, "")!=0 ){
$searchArr = preg_split("/\s+/", $search);
if (sizeof($searchFields)>0) {
$internalAnd = [ '$and' => [] ];
foreach ($searchArr as $ele){
$internalOr = [ '$or' => [] ];
foreach ($searchFields as $field){
$internalOr['$or'][] = [
$field => new MongoDB\BSON\Regex($ele,'i')
];
}
$internalAnd['$and'][] = $internalOr;
}
if (sizeof($filter)>0){
$andFilter = array();
$andFilter['$and'] = array();
$andFilter['$and'][] = $filter;
$andFilter['$and'][] = $internalAnd;
$filter = $andFilter;
}
else {
$filter = $internalAnd;
}
}
}
return $filter;
}
/**
* Ritorna la lista dei notizia model ordinati per pertinenza
* @param string $modelClass
* @param string $searchWord
* @param array $filter
* @param array $options
* @throws CoreException
* @return DaoSaveable[]
*/
public function searchUseIndex($modelClass, $search, array $filter = array(), array $options = array()){
$filter['$text'] = array('$search'=> trim($search) );
return $this->query($modelClass, $filter, $options);
}
public function searchUseIndexCount($modelClass, $search, array $filter = array(), array $options = array()){
$filter['$text'] = array('$search'=> trim($search) );
return $this->count($modelClass, $filter, $options);
}
/**
* Ritorna la lista dei notizia model ordinati per pertinenza
* @param string $modelClass
* @param string $searchWord
* @param array $filter
* @param array $options
* @throws CoreException
* @return DaoSaveable[]
*/
public function searchOld($modelClass, $searchWord, array $filter = array(), array $options = array()){
if (!is_null($modelClass)){
if (!is_subclass_of($modelClass, "DaoSaveable", true)){
throw new CoreException("Invalid return class passed to GenericDao::query ($modelClass)");
}
}
$collectionName = $modelClass::getCollectionName();
$collection = $this->database->$collectionName;
$useFilter = $filter;
$useFilter['$text'] = array('$search'=>$searchWord);
if (!array_key_exists("deleted",$useFilter)){
$useFilter["deleted"] = false;
}
if (array_key_exists("id",$useFilter)){
$useFilter["_id"] = $useFilter["id"];
unset($useFilter["id"]);
}
if (array_key_exists("_id",$useFilter) && is_string($useFilter["_id"])){
$useFilter["_id"] = new MongoId($useFilter["_id"]);
}
$cursor = $collection->find($useFilter,array('score' => array('$meta' => 'textScore')));
$sortArray = array();
if (array_key_exists("sort",$options)){
$sortArray = $options["sort"];
}
$sortArray = array_merge($sortArray,array('score' => array('$meta' => 'textScore')) );
$cursor->sort($sortArray);
if (array_key_exists("skip",$options)){
$cursor->skip($options["skip"]);
}
if (array_key_exists("limit",$options)){
$cursor->limit($options["limit"]);
}
$rval = array();
foreach ($cursor as $element){
unset($element->score);
$rval[] = $modelClass::buildFromSaveableObj($element);
}
return $rval;
}
public function searchCountOld($modelClass, $searchWord, array $filter = array(), array $options = array()){
if (!is_null($modelClass)){
if (!is_subclass_of($modelClass, "DaoSaveable", true)){
throw new CoreException("Invalid return class passed to GenericDao::query ($modelClass)");
}
}
$collectionName = $modelClass::getCollectionName();
$collection = $this->database->$collectionName;
$useFilter = $filter;
$useFilter['$text'] = array('$search'=>$searchWord);
if (!array_key_exists("deleted",$useFilter)){
$useFilter["deleted"] = false;
}
if (array_key_exists("id",$useFilter)){
$useFilter["_id"] = $useFilter["id"];
unset($useFilter["id"]);
}
if (array_key_exists("_id",$useFilter) && is_string($useFilter["_id"])){
$useFilter["_id"] = new MongoId($useFilter["_id"]);
}
$cursor = $collection->find($useFilter,array('score' => array('$meta' => 'textScore')));
return $cursor->count(true);
}
}
?>