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 ); } } ?>