Location: PHPKode > projects > MongoDB Object Document Mapper > lib/Doctrine/ODM/MongoDB/MongoCollection.php
<?php
/*
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * This software consists of voluntary contributions made by many individuals
 * and is licensed under the LGPL. For more information, see
 * <http://www.doctrine-project.org>.
 */

namespace Doctrine\ODM\MongoDB;

use Doctrine\ODM\MongoDB\Mapping\ClassMetadata,
    Doctrine\ODM\MongoDB\Mapping\Types\Type,
    Doctrine\ODM\MongoDB\Event\CollectionEventArgs,
    Doctrine\ODM\MongoDB\Event\CollectionUpdateEventArgs;

/**
 * Wrapper for the PHP MongoCollection class.
 *
 * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
 * @link        www.doctrine-project.org
 * @since       1.0
 * @author      Jonathan H. Wage <hide@address.com>
 */
class MongoCollection
{
    /** The PHP MongoCollection being wrapped. */
    private $mongoCollection;

    /** The ClassMetadata instance for this collection. */
    private $class;

    /** A callable for logging statements. */
    private $loggerCallable;

    /**
     * The event manager that is the central point of the event system.
     *
     * @var Doctrine\Common\EventManager
     */
    private $eventManager;

    /**
     * Mongo command prefix
     * @var string
     */
    private $cmd;

    /**
     * Create a new MongoCollection instance that wraps a PHP MongoCollection instance
     * for a given ClassMetadata instance.
     *
     * @param MongoCollection $mongoColleciton The MongoCollection instance.
     * @param ClassMetadata $class The ClassMetadata instance.
     * @param DocumentManager $dm The DocumentManager instance.
     */
    public function __construct(\MongoCollection $mongoCollection, ClassMetadata $class, DocumentManager $dm)
    {
        $this->mongoCollection = $mongoCollection;
        $this->class = $class;
        $this->loggerCallable = $dm->getConfiguration()->getLoggerCallable();
        $this->cmd = $dm->getConfiguration()->getMongoCmd();
        $this->eventManager = $dm->getEventManager();
    }

    /**
     * Log something using the configured logger callable.
     *
     * @param array $log The array of data to log.
     */
    public function log(array $log)
    {
        if ( ! $this->loggerCallable) {
            return;
        }
        $log['class'] = $this->class->name;
        $log['db'] = $this->class->db;
        $log['collection'] = $this->class->collection;
        call_user_func_array($this->loggerCallable, array($log));
    }

    /**
     * Returns teh ClassMetadata instance for this collection.
     *
     * @return Doctrine\ODM\MongoDB\MongoCollection
     */
    public function getMongoCollection()
    {
        return $this->mongoCollection;
    }

    /** @override */
    public function batchInsert(array &$a, array $options = array())
    {
        if ($this->eventManager->hasListeners(CollectionEvents::preBatchInsert)) {
            $this->eventManager->dispatchEvent(CollectionEvents::preBatchInsert, new CollectionEventArgs($this, $a));
        }

        if ($this->mongoCollection instanceof \MongoGridFS) {
            foreach ($a as $key => $array) {
                $this->saveFile($array);
                $a[$key] = $array;
            }
            return $a;
        }
        if ($this->loggerCallable) {
            $this->log(array(
                'batchInsert' => true,
                'num' => count($a),
                'data' => $a
            ));
        }
        $result = $this->mongoCollection->batchInsert($a, $options);

        if ($this->eventManager->hasListeners(CollectionEvents::postBatchInsert)) {
            $this->eventManager->dispatchEvent(CollectionEvents::postBatchInsert, new CollectionEventArgs($this, $result));
        }

        return $result;
    }

    /**
     * Save a file whether it exists or not already. Deletes previous file 
     * contents before trying to store new file contents.
     *
     * @param array $a Array to store
     * @return array $a
     */
    public function saveFile(array &$a)
    {
        if ($this->eventManager->hasListeners(CollectionEvents::preSaveFile)) {
            $this->eventManager->dispatchEvent(CollectionEvents::preSaveFile, new CollectionEventArgs($this, $a));
        }

        $fileName = $this->class->fieldMappings[$this->class->file]['fieldName'];
        $file = $a[$fileName];
        unset($a[$fileName]);
        if ($file instanceof \MongoGridFSFile) {
            $id = $a['_id'];
            unset($a['_id']);
            $set = array($this->cmd . 'set' => $a);

            if ($this->loggerCallable) {
                $this->log(array(
                    'updating' => true,
                    'file' => true,
                    'id' => $id,
                    'set' => $set
                ));
            }

            $this->mongoCollection->update(array('_id' => $id), $set);
        } else {
            if (isset($a['_id'])) {
                $this->mongoCollection->chunks->remove(array('files_id' => $a['_id']));
            }
            if (file_exists($file)) {
                if ($this->loggerCallable) {
                    $this->log(array(
                        'storing' => true,
                        'file' => $file,
                        'document' => $a
                    ));
                }

                $id = $this->mongoCollection->storeFile($file, $a);
            } elseif (is_string($file)) {
                if ($this->loggerCallable) {
                    $this->log(array(
                        'storing' => true,
                        'bytes' => true,
                        'document' => $a
                    ));
                }

                $id = $this->mongoCollection->storeBytes($file, $a);
            }

            $file = $this->mongoCollection->findOne(array('_id' => $id));
        }

        if ($this->eventManager->hasListeners(CollectionEvents::postSaveFile)) {
            $this->eventManager->dispatchEvent(CollectionEvents::postSaveFile, new CollectionEventArgs($this, $file));
        }

        $a = $file->file;
        $a[$this->class->file] = $file;
        return $a;
    }

    /** @override */
    public function getDBRef(array $reference)
    {
        if ($this->eventManager->hasListeners(CollectionEvents::preGetDBRef)) {
            $this->eventManager->dispatchEvent(CollectionEvents::preGetDBRef, new CollectionEventArgs($this, $reference));
        }

        if ($this->loggerCallable) {
            $this->log(array(
                'get' => true,
                'reference' => $reference,
            ));
        }

        if ($this->class->isFile()) {
            $ref = $this->mongoCollection->getDBRef($reference);
            $file = $this->mongoCollection->findOne(array('_id' => $ref['_id']));
            $data = $file->file;
            $data[$this->class->file] = $file;
            return $data;
        }
        $dbRef = $this->mongoCollection->getDBRef($reference);

        if ($this->eventManager->hasListeners(CollectionEvents::postGetDBRef)) {
            $this->eventManager->dispatchEvent(CollectionEvents::postGetDBRef, new CollectionEventArgs($this, $dbRef));
        }

        return $dbRef;
    }

    /** @override */
    public function save(array &$a, array $options = array())
    {
        if ($this->eventManager->hasListeners(CollectionEvents::preSave)) {
            $this->eventManager->dispatchEvent(CollectionEvents::preSave, new CollectionEventArgs($this, $a));
        }

        if ($this->loggerCallable) {
            $this->log(array(
                'save' => true,
                'document' => $a,
                'options' => $options
            ));
        }
        if ($this->class->isFile()) {
            $result = $this->saveFile($a);
        } else {
            $result = $this->mongoCollection->save($a, $options);
        }

        if ($this->eventManager->hasListeners(CollectionEvents::postSave)) {
            $this->eventManager->dispatchEvent(CollectionEvents::postSave, new CollectionEventArgs($this, $result));
        }

        return $result;
    }

    /** @override */
    public function update(array $criteria, array $newObj, array $options = array())
    {
        if ($this->eventManager->hasListeners(CollectionEvents::preUpdate)) {
            $this->eventManager->dispatchEvent(CollectionEvents::preUpdate, new CollectionUpdateEventArgs($this, $criteria, $newObj, $options));
        }

        if ($this->loggerCallable) {
            $this->log(array(
                'update' => true,
                'criteria' => $criteria,
                'newObj' => $newObj,
                'options' => $options
            ));
        }
        $result = $this->mongoCollection->update($criteria, $newObj, $options);

        if ($this->eventManager->hasListeners(CollectionEvents::postUpdate)) {
            $this->eventManager->dispatchEvent(CollectionEvents::postUpdate, new CollectionEventArgs($this, $result));
        }

        return $result;
    }

    /** @override */
    public function find(array $query = array(), array $fields = array())
    {
        if ($this->class->hasDiscriminator() && ! isset($query[$this->class->discriminatorField['name']])) {
            $discriminatorValues = $this->getClassDiscriminatorValues($this->class);
            $query[$this->class->discriminatorField['name']] = array('$in' => $discriminatorValues);
        }

        $query = $this->prepareQuery($query);

        if ($this->eventManager->hasListeners(CollectionEvents::preFind)) {
            $this->eventManager->dispatchEvent(CollectionEvents::preFind, new CollectionEventArgs($this, $query));
        }

        if ($this->loggerCallable) {
            $this->log(array(
                'find' => true,
                'query' => $query,
                'fields' => $fields
            ));
        }
        $result = $this->mongoCollection->find($query, $fields);

        if ($this->eventManager->hasListeners(CollectionEvents::postFind)) {
            $this->eventManager->dispatchEvent(CollectionEvents::postFind, new CollectionEventArgs($this, $result));
        }

        return $result;
    }

    /** @override */
    public function findOne(array $query = array(), array $fields = array())
    {
        if ($this->class->hasDiscriminator() && ! isset($query[$this->class->discriminatorField['name']])) {
            $discriminatorValues = $this->getClassDiscriminatorValues($this->class);
            $query[$this->class->discriminatorField['name']] = array('$in' => $discriminatorValues);
        }

        $query = $this->prepareQuery($query);

        if ($this->eventManager->hasListeners(CollectionEvents::preFindOne)) {
            $this->eventManager->dispatchEvent(CollectionEvents::preFindOne, new CollectionEventArgs($this, $query));
        }

        if ($this->loggerCallable) {
            $this->log(array(
                'findOne' => true,
                'query' => $query,
                'fields' => $fields
            ));
        }

        if ($this->mongoCollection instanceof \MongoGridFS) {
            if (($file = $this->mongoCollection->findOne($query)) === null) {
                return null;
            }
            $data = $file->file;
            $data[$this->class->file] = $file;
            return $data;
        }
        $result = $this->mongoCollection->findOne($query, $fields);

        if ($this->eventManager->hasListeners(CollectionEvents::postFindOne)) {
            $this->eventManager->dispatchEvent(CollectionEvents::postFindOne, new CollectionEventArgs($this, $result));
        }

        return $result;
    }

    private function getClassDiscriminatorValues(ClassMetadata $metadata)
    {
        $discriminatorValues = array($metadata->discriminatorValue);
        foreach ($metadata->subClasses as $className) {
            if ($key = array_search($className, $metadata->discriminatorMap)) {
                $discriminatorValues[] = $key;
            }
        }
        return $discriminatorValues;
    }

    private function prepareQuery(array $query)
    {
        foreach ($query as $key => $value) {
            if ($this->class->hasField($key)) {
                if ($this->class->fieldMappings[$key]['name'] !== $key) {
                    $query[$this->class->fieldMappings[$key]['name']] = $value;
                    unset($query[$key]);
                }
            }
        }
        return $query;
    }

    /** @proxy */
    public function __call($method, $arguments)
    {
        if (method_exists($this->mongoCollection, $method)) {
            return call_user_func_array(array($this->mongoCollection, $method), $arguments);
        }
        throw new \BadMethodCallException(sprintf('Method %s does not exist on %s', $method, get_class($this)));
    }
}
Return current item: MongoDB Object Document Mapper