499 lines
14 KiB
PHP
499 lines
14 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 );
|
|
|
|
if (array_key_exists('cursor', $options) && $options['cursor'] == true) {
|
|
return $cursor;
|
|
}
|
|
else {
|
|
$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);
|
|
}
|
|
|
|
|
|
public function rawUpsert($modelClass, $query, $update) {
|
|
if (!is_null($modelClass)){
|
|
if (!is_subclass_of($modelClass, "DaoSaveable", true)){
|
|
throw new CoreException("Invalid return class passed to GenericDao::query ($modelClass)");
|
|
}
|
|
}
|
|
if (!array_key_exists('deleted', $query)) {
|
|
$query['deleted'] = false;
|
|
}
|
|
|
|
$collectionName = $modelClass::getCollectionName();
|
|
|
|
$command = new \MongoDB\Driver\Command([
|
|
'findAndModify' => $collectionName,
|
|
'query' => $query,
|
|
'update' => $update,
|
|
'upsert' => true,
|
|
'new' => false
|
|
]);
|
|
|
|
$this->client->executeCommand( $this->dbName, $command );
|
|
}
|
|
|
|
|
|
}
|
|
|
|
?>
|