| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405 |
- <?php
- /*
- Copyright (c) 2009-2019 F3::Factory/Bong Cosca, All rights reserved.
- This file is part of the Fat-Free Framework (http://fatfreeframework.com).
- This is free software: you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation, either version 3 of the License, or later.
- Fat-Free Framework is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
- You should have received a copy of the GNU General Public License along
- with Fat-Free Framework. If not, see <http://www.gnu.org/licenses/>.
- */
- namespace DB\Mongo;
- //! MongoDB mapper
- class Mapper extends \DB\Cursor {
- protected
- //! MongoDB wrapper
- $db,
- //! Legacy flag
- $legacy,
- //! Mongo collection
- $collection,
- //! Mongo document
- $document=[],
- //! Mongo cursor
- $cursor,
- //! Defined fields
- $fields;
- /**
- * Return database type
- * @return string
- **/
- function dbtype() {
- return 'Mongo';
- }
- /**
- * Return TRUE if field is defined
- * @return bool
- * @param $key string
- **/
- function exists($key) {
- return array_key_exists($key,$this->document);
- }
- /**
- * Assign value to field
- * @return scalar|FALSE
- * @param $key string
- * @param $val scalar
- **/
- function set($key,$val) {
- return $this->document[$key]=$val;
- }
- /**
- * Retrieve value of field
- * @return scalar|FALSE
- * @param $key string
- **/
- function &get($key) {
- if ($this->exists($key))
- return $this->document[$key];
- user_error(sprintf(self::E_Field,$key),E_USER_ERROR);
- }
- /**
- * Delete field
- * @return NULL
- * @param $key string
- **/
- function clear($key) {
- unset($this->document[$key]);
- }
- /**
- * Convert array to mapper object
- * @return static
- * @param $row array
- **/
- function factory($row) {
- $mapper=clone($this);
- $mapper->reset();
- foreach ($row as $key=>$val)
- $mapper->document[$key]=$val;
- $mapper->query=[clone($mapper)];
- if (isset($mapper->trigger['load']))
- \Base::instance()->call($mapper->trigger['load'],$mapper);
- return $mapper;
- }
- /**
- * Return fields of mapper object as an associative array
- * @return array
- * @param $obj object
- **/
- function cast($obj=NULL) {
- if (!$obj)
- $obj=$this;
- return $obj->document;
- }
- /**
- * Build query and execute
- * @return static[]
- * @param $fields string
- * @param $filter array
- * @param $options array
- * @param $ttl int|array
- **/
- function select($fields=NULL,$filter=NULL,array $options=NULL,$ttl=0) {
- if (!$options)
- $options=[];
- $options+=[
- 'group'=>NULL,
- 'order'=>NULL,
- 'limit'=>0,
- 'offset'=>0
- ];
- $tag='';
- if (is_array($ttl))
- list($ttl,$tag)=$ttl;
- $fw=\Base::instance();
- $cache=\Cache::instance();
- if (!($cached=$cache->exists($hash=$fw->hash($this->db->dsn().
- $fw->stringify([$fields,$filter,$options])).($tag?'.'.$tag:'').'.mongo',
- $result)) || !$ttl || $cached[0]+$ttl<microtime(TRUE)) {
- if ($options['group']) {
- $grp=$this->collection->group(
- $options['group']['keys'],
- $options['group']['initial'],
- $options['group']['reduce'],
- [
- 'condition'=>$filter,
- 'finalize'=>$options['group']['finalize']
- ]
- );
- $tmp=$this->db->selectcollection(
- $fw->HOST.'.'.$fw->BASE.'.'.
- uniqid(NULL,TRUE).'.tmp'
- );
- $tmp->batchinsert($grp['retval'],['w'=>1]);
- $filter=[];
- $collection=$tmp;
- }
- else {
- $filter=$filter?:[];
- $collection=$this->collection;
- }
- if ($this->legacy) {
- $this->cursor=$collection->find($filter,$fields?:[]);
- if ($options['order'])
- $this->cursor=$this->cursor->sort($options['order']);
- if ($options['limit'])
- $this->cursor=$this->cursor->limit($options['limit']);
- if ($options['offset'])
- $this->cursor=$this->cursor->skip($options['offset']);
- $result=[];
- while ($this->cursor->hasnext())
- $result[]=$this->cursor->getnext();
- }
- else {
- $this->cursor=$collection->find($filter,[
- 'sort'=>$options['order'],
- 'limit'=>$options['limit'],
- 'skip'=>$options['offset']
- ]);
- $result=$this->cursor->toarray();
- }
- if ($options['group'])
- $tmp->drop();
- if ($fw->CACHE && $ttl)
- // Save to cache backend
- $cache->set($hash,$result,$ttl);
- }
- $out=[];
- foreach ($result as $doc)
- $out[]=$this->factory($doc);
- return $out;
- }
- /**
- * Return records that match criteria
- * @return static[]
- * @param $filter array
- * @param $options array
- * @param $ttl int|array
- **/
- function find($filter=NULL,array $options=NULL,$ttl=0) {
- if (!$options)
- $options=[];
- $options+=[
- 'group'=>NULL,
- 'order'=>NULL,
- 'limit'=>0,
- 'offset'=>0
- ];
- return $this->select($this->fields,$filter,$options,$ttl);
- }
- /**
- * Count records that match criteria
- * @return int
- * @param $filter array
- * @param $options array
- * @param $ttl int|array
- **/
- function count($filter=NULL,array $options=NULL,$ttl=0) {
- $fw=\Base::instance();
- $cache=\Cache::instance();
- $tag='';
- if (is_array($ttl))
- list($ttl,$tag)=$ttl;
- if (!($cached=$cache->exists($hash=$fw->hash($fw->stringify(
- [$filter])).($tag?'.'.$tag:'').'.mongo',$result)) || !$ttl ||
- $cached[0]+$ttl<microtime(TRUE)) {
- $result=$this->collection->count($filter?:[]);
- if ($fw->CACHE && $ttl)
- // Save to cache backend
- $cache->set($hash,$result,$ttl);
- }
- return $result;
- }
- /**
- * Return record at specified offset using criteria of previous
- * load() call and make it active
- * @return array
- * @param $ofs int
- **/
- function skip($ofs=1) {
- $this->document=($out=parent::skip($ofs))?$out->document:[];
- if ($this->document && isset($this->trigger['load']))
- \Base::instance()->call($this->trigger['load'],$this);
- return $out;
- }
- /**
- * Insert new record
- * @return array
- **/
- function insert() {
- if (isset($this->document['_id']))
- return $this->update();
- if (isset($this->trigger['beforeinsert']) &&
- \Base::instance()->call($this->trigger['beforeinsert'],
- [$this,['_id'=>$this->document['_id']]])===FALSE)
- return $this->document;
- if ($this->legacy) {
- $this->collection->insert($this->document);
- $pkey=['_id'=>$this->document['_id']];
- }
- else {
- $result=$this->collection->insertone($this->document);
- $pkey=['_id'=>$result->getinsertedid()];
- }
- if (isset($this->trigger['afterinsert']))
- \Base::instance()->call($this->trigger['afterinsert'],
- [$this,$pkey]);
- $this->load($pkey);
- return $this->document;
- }
- /**
- * Update current record
- * @return array
- **/
- function update() {
- $pkey=['_id'=>$this->document['_id']];
- if (isset($this->trigger['beforeupdate']) &&
- \Base::instance()->call($this->trigger['beforeupdate'],
- [$this,$pkey])===FALSE)
- return $this->document;
- $upsert=['upsert'=>TRUE];
- if ($this->legacy)
- $this->collection->update($pkey,$this->document,$upsert);
- else
- $this->collection->replaceone($pkey,$this->document,$upsert);
- if (isset($this->trigger['afterupdate']))
- \Base::instance()->call($this->trigger['afterupdate'],
- [$this,$pkey]);
- return $this->document;
- }
- /**
- * Delete current record
- * @return bool
- * @param $quick bool
- * @param $filter array
- **/
- function erase($filter=NULL,$quick=TRUE) {
- if ($filter) {
- if (!$quick) {
- foreach ($this->find($filter) as $mapper)
- if (!$mapper->erase())
- return FALSE;
- return TRUE;
- }
- return $this->legacy?
- $this->collection->remove($filter):
- $this->collection->deletemany($filter);
- }
- $pkey=['_id'=>$this->document['_id']];
- if (isset($this->trigger['beforeerase']) &&
- \Base::instance()->call($this->trigger['beforeerase'],
- [$this,$pkey])===FALSE)
- return FALSE;
- $result=$this->legacy?
- $this->collection->remove(['_id'=>$this->document['_id']]):
- $this->collection->deleteone(['_id'=>$this->document['_id']]);
- parent::erase();
- if (isset($this->trigger['aftererase']))
- \Base::instance()->call($this->trigger['aftererase'],
- [$this,$pkey]);
- return $result;
- }
- /**
- * Reset cursor
- * @return NULL
- **/
- function reset() {
- $this->document=[];
- parent::reset();
- }
- /**
- * Hydrate mapper object using hive array variable
- * @return NULL
- * @param $var array|string
- * @param $func callback
- **/
- function copyfrom($var,$func=NULL) {
- if (is_string($var))
- $var=\Base::instance()->$var;
- if ($func)
- $var=call_user_func($func,$var);
- foreach ($var as $key=>$val)
- $this->set($key,$val);
- }
- /**
- * Populate hive array variable with mapper fields
- * @return NULL
- * @param $key string
- **/
- function copyto($key) {
- $var=&\Base::instance()->ref($key);
- foreach ($this->document as $key=>$field)
- $var[$key]=$field;
- }
- /**
- * Return field names
- * @return array
- **/
- function fields() {
- return array_keys($this->document);
- }
- /**
- * Return the cursor from last query
- * @return object|NULL
- **/
- function cursor() {
- return $this->cursor;
- }
- /**
- * Retrieve external iterator for fields
- * @return object
- **/
- function getiterator() {
- return new \ArrayIterator($this->cast());
- }
- /**
- * Instantiate class
- * @return void
- * @param $db object
- * @param $collection string
- * @param $fields array
- **/
- function __construct(\DB\Mongo $db,$collection,$fields=NULL) {
- $this->db=$db;
- $this->legacy=$db->legacy();
- $this->collection=$db->selectcollection($collection);
- $this->fields=$fields;
- $this->reset();
- }
- }
|