Document
********

.. php:namespace:: PHPOnCouch

.. php:class:: CouchClient


:hidden:`getAllDocs`
""""""""""""""""""""

    .. php:method:: getAllDocs()

        Retrieve all documents from the database. In fact it only retrieve document IDs, unless you specify the server to include the documents using the View query parameters syntax.

        :returns: An object with the total_rows number, the rows returned and other informations.

        Example :

        .. code-block:: php

            $all_docs = $client->getAllDocs();
            echo "Database got ".$all_docs->total_rows." documents.<BR>\n";
            foreach ( $all_docs->rows as $row ) {
                echo "Document ".$row->id."<BR>\n";
            }

:hidden:`getDoc`
""""""""""""""""

    .. php:method:: getDoc($id)

        Gives back the document that got ID $id, if it exists. Note that if the document does not exist, the method will throw an error.

        :params string $id: The id of the document to fetch
        :returns: The document if found. Otherwise, a CouchNotFoundException is throw.

        The document is sent back as an HTTP object of class `stdClass <http://fr3.php.net/manual/en/reserved.classes.php/>`_.

        Example :

        .. code-block:: php

            try {
                $doc = $client->getDoc("some_doc_id");
            } catch ( Exception $e ) {
                if ( $e->getCode() == 404 ) {
                   echo "Document some_doc_id does not exist !";
                    }
                exit(1);
            }
            echo $doc->_id.' revision '.$doc->_rev;

Chainable methods to use with getDoc()
======================================

:hidden:`rev`
"""""""""""""

    .. php:method:: rev($value)

        The chainable **rev($value)** method specify the document revision to fetch.

        :params mixed $value: The specific revision to fetch of a document.
        :returns: The CouchClient instance.

        Example :

        .. code-block:: php

            try {
                $doc = $client->rev("1-849aff6ad4a38b1225c80a2119dc31cb")->getDoc("some_doc_id");
            } catch ( Exception $e ) {
                if ( $e->getCode() == 404 ) {
                   echo "Document some_doc_id or revision 1-849aff6ad4a38b1225c80a2119dc31cb does not exist !";
                }
                exit(1);
            }
            echo $doc->_rev ; // should echo 1-849aff6ad4a38b1225c80a2119dc31cb

:hidden:`asCouchDocuments`
""""""""""""""""""""""""""

    .. php:method:: asCouchDocuments()

        When the getDoc function will be called, it will return a :meth:`CouchDocument`. You can however get back the document as a CouchDocument object by calling the **asCouchDocuments()** method before the **getDoc($id)** method.

        :returns: The CouchClient instance.

        Example :

        .. code-block:: php

            try {
                $doc = $client->asCouchDocuments()->getDoc("some_doc_id");
            } catch ( Exception $e ) {
                if ( $e->getCode() == 404 ) {
                   echo "Document some_doc_id does not exist !";
                }
                exit(1);
            }
            echo get_class($doc); // should echo "CouchDocument"

:hidden:`conflicts`
"""""""""""""""""""

    .. php:method:: conflicts()

        The chainable method **conflicts()** asks CouchDB to add to the document a property *_conflicts* containing conflicting revisions on an object.

        :returns: The CouchClient instance.

        Example :

        .. code-block:: php

            try {
                $doc = $client->conflicts()->getDoc("some_doc_id");
            } catch ( Exception $e ) {
                if ( $e->getCode() == 404 ) {
                   echo "Document some_doc_id does not exist !";
                }
                exit(1);
            }
            if ( $doc->_conflicts ) {
                print_r($doc->_conflicts);
            }

:hidden:`revs`
""""""""""""""

    .. php:method:: revs()

        The chainable method **revs()** asks CouchDB to add to the document a property *_revisions* containing the list of revisions for an object.
    
        :returns: The CouchClient instance.

        Example :

        .. code-block:: php
            
            try {
                $doc = $client->revs()->getDoc("some_doc_id");
            } catch ( Exception $e ) {
                if ( $e->getCode() == 404 ) {
                   echo "Document some_doc_id does not exist !";
                }
                exit(1);
            }
            print_r($doc->_revisions);

:hidden:`revs_info`
"""""""""""""""""""

    .. php:method:: revs_info()
        
        The chainable method **revs_info()** asks CouchDB to add to the document a property *_revs_info* containing the avaibility of revisions for an object.
        
        :returns: The CouchClient instance.

        Example :

        .. code-block:: php

            try {
                $doc = $client->revs_info()->getDoc("some_doc_id");
            } catch ( Exception $e ) {
                if ( $e->getCode() == 404 ) {
                   echo "Document some_doc_id does not exist !";
                }
                exit(1);
            }
            print_r($doc->_revs_info);

:hidden:`open_revs`
"""""""""""""""""""

    .. php:method:: open_revs($value)
        
        Using the **open_revs($value)** method, CouchDB returns an array of objects.
        
        :params array|string $value: Should be an array of revision ids or the special keyword all (to fetch all revisions of a document)
        :returns: The CouchClient instance.

        Example :

        .. code-block:: php
            
            try {
                $doc = $client->open_revs( array("1-fbd8a6da4d669ae4b909fcdb42bb2bfd", "2-5bc3c6319edf62d4c624277fdd0ae191") )->getDoc("some_doc_id");
            } catch ( Exception $e ) {
                if ( $e->getCode() == 404 ) {
                   echo "Document some_doc_id does not exist !";
                }
                exit(1);
            }
            print_r($doc->_revs_info);

        Which should return something similar to :

        .. code-block:: php

            array (
                stdClass(
                    "missing" => "1-fbd8a6da4d669ae4b909fcdb42bb2bfd"
                ),
                stdClass(
                    "ok" => stdClass(
                        "_id"  => "some_doc_id",
                        "_rev" => "2-5bc3c6319edf62d4c624277fdd0ae191",
                        "hello"=> "foo"
                    )
                )
            )

:hidden:`storeDoc`
""""""""""""""""""

    .. php:method:: storeDoc($doc)

        Store a document on the CouchDB server.
         
        :params stdClass $doc: $doc should be an object. If the property $doc->_rev is set, the method understand that it's
             an update, and as so requires the property $doc->\_id to be set. If the property $doc->\_rev is not set, the method checks for the existance of property $doc->\_id and initiate the appropriate request.
        :returns: The response of this method is the CouchDB server response. In other words if the request ends successfully the returned object should be :

        .. code-block:: php

            stdClass ( "ok" => true, "id" => "some_doc_id" , "rev" => "3-23423423476" )

        Example : creating a document without specifying id

        .. code-block:: php
            
            $new_doc = new stdClass();
            $new_doc->title = "Some content";
            try {
                $response = $client->storeDoc($new_doc);
            } catch (Exception $e) {
                echo "ERROR: ".$e->getMessage()." (".$e->getCode().")<br>\n";
            }
            echo "Doc recorded. id = ".$response->id." and revision = ".$response->rev."<br>\n";
            // Doc recorded. id = 0162ff06747761f6d868c05b7aa8500f and revision = 1-249007504

        Example : creating a document specifying the id

        .. code-block:: php

            $new_doc = new stdClass();
            $new_doc->title = "Some content";
            $new_doc->_id = "BlogPost6576";
            try {
                $response = $client->storeDoc($new_doc);
            } catch (Exception $e) {
                echo "ERROR: ".$e->getMessage()." (".$e->getCode().")<br>\n";
            }
            echo "Doc recorded. id = ".$response->id." and revision = ".$response->rev."<br>\n";
            // Doc recorded. id = BlogPost6576 and revision = 1-249004576


        Example : updating an existing document :

        .. code-block:: php

            // get the document
            try {
                $doc = $client->getDoc('BlogPost6576');
            } catch (Exception $e) {
                echo "ERROR: ".$e->getMessage()." (".$e->getCode().")<br>\n";
            }

            // make changes
            $doc->title = 'Some smart content';
            $doc->tags = array('twitter','facebook','msn');

            // update the document on CouchDB server
            try {
                $response = $client->storeDoc($doc);
            } catch (Exception $e) {
                echo "ERROR: ".$e->getMessage()." (".$e->getCode().")<br>\n";
            }
            echo "Doc recorded. id = ".$response->id." and revision = ".$response->rev."<br>\n";
            // Doc recorded. id = BlogPost6576 and revision = 2-456769086


Updating a document
===================

Using CouchDB `Update handlers <http://wiki.apache.org/couchdb/Document_Update_Handlers/>`_ , you can easily update any document part without having to send back the whole document.

:hidden:`updateDoc`
"""""""""""""""""""

    .. php:method:: updateDoc($ddoc_id, $handler_name, $params, $doc_id = null)

        Update document according to the code defined in the update handler.

        :params string $ddoc_id: The desing document id (suffix of _design/)
        :params string $handler_name: The update handler name
        :params array $params: to complete...
        :params string $doc_id: The document id to udpate

        Example : incrementing a document counter

        Let's say we have a design document _design/myapp containing :

        .. code-block:: json

            {
                "updates": {
                    "bump-counter" : "function(doc, req) {
                        if ( !doc ) return [null, {\"code\": 404, \"body\": \"Document not found / not specified\"}]
                        if (!doc.counter) doc.counter = 0;
                        doc.counter += 1;
                        var message = \"<h1>bumped it!</h1>\";
                        return [doc, message];
                    }"
                }
            }

        To bump the counter of the document "some_doc" , use :

        .. code-block:: php

            $client->updateDoc("myapp","bump-counter",array(),"some_doc");


:hidden:`updateDocFullAPI`
""""""""""""""""""""""""""

	 .. php:method:: updateDocFullAPI($ddoc_id, $handler_name, $options)

        Update document according to the code defined in the update handler.

        :params string $ddoc_id: The id of the design document (suffix of _design/)
        :params string $handler_name: Update handler name
        :params array $options:

                An array of optionnal query modifiers :

                - params      :   array|object of variable to pass in the URL ( /?foo=bar )
                - data        :   string|array|object data to set in the body of the request. If data is an array or an object it will be urlencoded using PHP http_build_query function and the request Content-Type header will be set to "application/x-www-form-urlencoded".
                - Content-Type:   string the Content-Type HTTP header to send to the couch server

        Example :

        .. code-block:: php

            $client->updateDocFullAPI("myapp","bump-counter",array( "data" => array("Something"=>"is set") ) );

:hidden:`deleteDoc`
"""""""""""""""""""

	 .. php:method:: deleteDoc($doc)

        Permanently removes $doc from the CouchDB server.

        :params stdClass $doc: An object containing at least \_id and \_rev properties.

        Example :

        .. code-block:: php

            // get the document
            try {
                $doc = $client->getDoc('BlogPost6576');
            } catch (Exception $e) {
                echo "ERROR: ".$e->getMessage()." (".$e->getCode().")<br>\n";
            }
            // permanently remove the document
            try {
                $client->deleteDoc($doc);
            } catch (Exception $e) {
                echo "ERROR: ".$e->getMessage()." (".$e->getCode().")<br>\n";
            }


:hidden:`copyDoc`
"""""""""""""""""

	 .. php:method:: copyDoc($id, $new_id)

        Provides an handy way to copy a document.

        :params string $id: The id of the document to copy.
        :params string $new_id: The id of the new document.

        :returns:

            The CouchDB server response, which has the main form than a document storage :

            .. code-block:: php

                stdClass ( "ok" => true, "id" => "new_id" , "rev" => "1-23423423476" )

        Example :

        .. code-block:: php

            try {
                $response = $client->copyDoc('BlogPost6576','CopyOfBlogPost6576');
            } catch (Exception $e) {
                echo "ERROR: ".$e->getMessage()." (".$e->getCode().")<br>\n";
            }


Attachments
===========

There is two methods handling attachments, it depends whether the file to send as attachment is on the harddrive, or if
it's contained in a PHP variable. The first one should be more reliable for large attachments.

:hidden:`storeAttachment`
"""""""""""""""""""""""""

	 .. php:method:: storeAttachment($doc, $file, $content_type = 'application/octet-stream', $filename = null)

        Handles the process of storing an attachment on a CouchDB document.

        :params stdClass $doc: A PHP object containing at least the properties \_id and \_rev
        :params string $file: The complete path to the file on disk
        :params string $content_type: The file's `content-type <http://en.wikipedia.org/wiki/MIME/>`_
        :params string $filename: The name of the attachment on CouchDB document, if the name is not the name of the file in $file
        :returns stdClass:
            An HTTP response object like this :

            .. code-block:: php

                stdClass ( "ok" => true, "id" => "BlogPost5676" , "rev" => "5-2342345476" )

        Example :

        .. code-block:: php

            $doc = $client->getDoc('BlogPost5676');
            $ok = $client->storeAttachment($doc,'/etc/resolv.conf','text/plain', 'my-resolv.conf');
            print_r($ok);
            // stdClass ( "ok" => true, "id" => "BlogPost5676" , "rev" => "5-2342345476" )

:hidden:`storeAsAttachment`
"""""""""""""""""""""""""""

	 .. php:method:: storeAsAttachment($doc,$data,$filename,$content_type = 'application/octet-stream')

        Records as a CouchDB document's attachment the content of a PHP variable.

        :params stdClass $doc: A PHP object containing at least the properties \_id and \_rev
        :params mixed $data: The data (the content of the attachment
        :params string $filename: The name of the attachment on CouchDB document
        :params string $content_type: The file's `content-type <http://en.wikipedia.org/wiki/MIME/>`_
        :returns: The HTTP response object.

        Example :

        .. code-block:: php

            $doc = $client->getDoc('BlogPost5676');
            $google_home=file_get_contents('http://www.google.com/');
            $ok = $client->storeAsAttachment($doc,$google_home,'GoogleHomepage.html','text/html');
            print_r($ok);
            // stdClass ( "ok" => true, "id" => "BlogPost5676" , "rev" => "5-2342345476" )


:hidden:`deleteAttachment`
""""""""""""""""""""""""""

	 .. php:method:: deleteAttachment($doc,$attachment_name)

        Delete an attachment from a CouchDB document.

        :params stdClass $doc: An object with, at least, \_id and \_rev properties,
        :params $attachment_name:  the name of the attachment to delete.
        :returns: An stdClass representing the HTTP response.

        Example :

        .. code-block:: php

            $doc = $client->getDoc('BlogPost5676');
            $ok = $client->deleteAttachment($doc,'GoogleHomepage.html');

:hidden:`getShow`
"""""""""""""""""

	 .. php:method:: getShow($design_id, $name, $doc_id = null, $additionnal_parameters = array())

        Request a show formatting of document *$doc_id* with show method *$name* stored in design document *design_id*.

        Example :

        .. code-block:: php

            $output = $client->getShow('blogs','html','BlogPost5676');


        More infos on CouchDB show formatting `here <http://wiki.apache.org/couchdb/Formatting_with_Show_and_List/>`_ .

Bulk operations
===============

A bulk operation is a unique query performing actions on several documents. CouchDB Bulk operations API are described in `this wiki page <http://docs.couchdb.org/en/2.0.0/api/database/bulk-api.html/>`_ .

:hidden:`keys`
""""""""""""""""""""

	 .. php:method:: keys($ids)->getAllDocs()

        To retrieve several documents in one go, knowing their IDs, select documents using the **keys($ids)** coupled with the method **getAllDocs()**. $ids is an array of documents IDs. This function acts like a view, so the output is the view output of CouchDB, and you should use "include_docs(true)" to have documents contents.

        Example :

        .. code-block:: php

            $view = $client->include_docs(true)->keys( array('BlogPost5676','BlogComments5676') )->getAllDocs();
            foreach ( $view->rows as $row ) {
              echo "doc id :".$row->doc->_id."\n";
            }


:hidden:`storeDocs`
""""""""""""""""""""

	 .. php:method:: storeDocs($docs, $new_edits)

        To store several documents in one go, use the method **storeDocs($docs, $new_edits)**. $docs is an array containing the documents to store (as CouchDocuments, PHP `stdClass <http://fr3.php.net/manual/en/reserved.classes.php/>`_ or PHP arrays). $new_edits is related to the updates of the revision. If set to true (which is the default), assign new revision id for each update. When set to false, it prevents the database from assigning them new reivision IDS.

        Example :

        .. code-block:: php

            $docs = array (
                array('type'=>'blogpost','title'=>'post'),
                array('type'=>'blogcomment','blogpost'=>'post','depth'=>1),
                array('type'=>'blogcomment','blogpost'=>'post','depth'=>2)
            );
            $response = $client->storeDocs( $docs );
            print_r($response);

        which should give you something like :

        .. code-block:: php

            Array
            (
                [0] => stdClass Object
                    (
                        [id] => 8d7bebddc9828ed2edd052773968826b
                        [rev] => 1-3988163576
                    )

                [1] => stdClass Object
                    (
                        [id] => 37bcfd7d9e94c67617982527c67efe44
                        [rev] => 1-1750264873
                    )

                [2] => stdClass Object
                    (
                        [id] => 704a51a0b6448326152f8ffb8c3ea6be
                        [rev] => 1-2477909627
                    )

            )


        This method also works to update documents.


:hidden:`deleteDocs`
""""""""""""""""""""

	 .. php:method:: deleteDocs($docs, $new_edits)

        To delete several documents in a single HTTP request, use the method **deleteDocs($docs, $new_edits)**. $docs is an array containing the documents to store (as couchDocuments, PHP `stdClass <http://fr3.php.net/manual/en/reserved.classes.php/>`_ or PHP arrays). $new_edits is related to the updates of the revision. If set to true (which is the default), assign new revision id for each update. When set to false, it prevents the database from assigning them new reivision IDS.


:hidden:`asArray`
"""""""""""""""""

	 .. php:method:: asArray()

        When converting a JSON object to PHP, we can choose the type of the value returned from a CouchClient query.

        Take for example the following JSON object :
            { 'blog' : true, 'comments' : { 'title' : 'cool' } }

        This can be converted into a PHP object :

        .. code-block:: php

            stdClass Object
            (
                [blog] => true
                [comments] => stdClass Object
                    (
                        [title] => "cool"
                    )
            )


        OR into a PHP array :

        .. code-block:: php

            Array
            (
                [blog] => true
                [comments] => Array
                    (
                        [title] => "cool"
                    )
            )


        Using the defaults, JSON objects are mapped to PHP objects. The **asArray()** method can be used to map JSON objects to PHP arrays.

        Example:

        .. code-block:: php

            $doc = $client->asArray()->getDoc('BlogPost5676');
            print_r($doc);


        should print :

        .. code-block:: php

            Array (
                [id] => "BlogPost5676"
            )


