From f89350afe340360bfa93ca36873906c688791d1b Mon Sep 17 00:00:00 2001 From: Mike Russell Date: Fri, 30 Jun 2017 10:57:46 -0400 Subject: [PATCH 1/3] Count Endpoints + Filter Changes FilterData object is better coupled with Filter parameter on the Endpoint objects. If you set a default filter on the Endpoint via Data Properties, it will push to the Filter Object on initialize, and when you build on top of the Filter object it merges with the default applied. It also will reset the parameter when it gets reset on the Endpoint. Added count endpoints to FilterRelated/GetRelated and ModuleFilter Endpoints. --- examples/FilterAPI.php | 2 +- examples/FilterRelated.php | 10 +- .../AbstractSugarBeanCollectionEndpoint.php | 8 +- .../Abstracts/AbstractSugarBeanEndpoint.php | 53 +++++++--- src/Endpoint/Data/FilterData.php | 17 +++- src/Endpoint/ModuleFilter.php | 73 +++++++++----- src/Helpers/Helper.php | 1 + ...bstractSugarBeanCollectionEndpointTest.php | 3 +- .../AbstractSugarBeanEndpointTest.php | 11 +++ tests/Endpoint/Data/FilterDataTest.php | 25 ++--- tests/Endpoint/ModuleFilterTest.php | 97 ++++++++++++++++--- 11 files changed, 221 insertions(+), 79 deletions(-) diff --git a/examples/FilterAPI.php b/examples/FilterAPI.php index f045320..c0c7e8e 100644 --- a/examples/FilterAPI.php +++ b/examples/FilterAPI.php @@ -16,7 +16,7 @@ ->endOr() ->equals('assigned_user_id','seed_max_id') ->endAnd(); - echo "
 Filter Accounts that are assigned to User Max, and that either start with an S or contain 'test' in the name: ".var_dump($Accounts->filter()->compile())."

"; + echo "
 Filter Accounts that are assigned to User Max, and that either start with an S or contain 'test' in the name: ".print_r($Accounts->filter()->compile(),true)."

"; $Accounts->filter()->execute(); echo "
 Response:".print_r($Accounts->getResponse()->getBody(),true)."

"; }catch (Exception $ex){ diff --git a/examples/FilterRelated.php b/examples/FilterRelated.php index 8b674bc..15b46f7 100644 --- a/examples/FilterRelated.php +++ b/examples/FilterRelated.php @@ -13,12 +13,14 @@ echo ""; $Accounts = $SugarAPI->list('Accounts'); $Accounts->fetch(); - $account = current($Accounts->asArray()); - $Account = $Accounts->get($account['id']); + $Account = $Accounts->at(1); + $Account->getRelated('contacts',true); + echo $Account->getRequest()->getURL()."
"; + echo "
 Response:".print_r($Account->getResponse()->getBody(),true)."

"; $Filter = $Account->filterRelated('contacts')->contains('first_name','s'); - echo "
 Filter Contacts related to Account {$account['id']} where first_name contains an 's': ".var_dump($Filter->compile())."

"; + echo "
 Filter Contacts related to Account {$account['id']} where first_name contains an 's': ".print_r($Filter->compile(),true)."

"; $Filter->execute(); - echo "
 Response:".print_r($Account->getRequest(),true)."

"; + echo "
 Response:".print_r($Account->getResponse()->getBody(),true)."

"; }catch (Exception $ex){ echo "
";
     //print_r($SugarAPI);
diff --git a/src/Endpoint/Abstracts/AbstractSugarBeanCollectionEndpoint.php b/src/Endpoint/Abstracts/AbstractSugarBeanCollectionEndpoint.php
index 3727f25..10bb7c0 100644
--- a/src/Endpoint/Abstracts/AbstractSugarBeanCollectionEndpoint.php
+++ b/src/Endpoint/Abstracts/AbstractSugarBeanCollectionEndpoint.php
@@ -37,12 +37,12 @@ abstract class AbstractSugarBeanCollectionEndpoint extends AbstractSugarCollecti
 
     public function setOptions(array $options)
     {
-        $opts = array();
         if (isset($options[0])) {
-            $this->setModule($options[0]);
-            $opts['module'] = $this->module;
+            $options['module'] = $options[0];
+            $this->setModule($options['module']);
+            unset($options[0]);
         }
-        return parent::setOptions($opts);
+        return parent::setOptions($options);
     }
 
     /**
diff --git a/src/Endpoint/Abstracts/AbstractSugarBeanEndpoint.php b/src/Endpoint/Abstracts/AbstractSugarBeanEndpoint.php
index 0e2346a..6b43952 100644
--- a/src/Endpoint/Abstracts/AbstractSugarBeanEndpoint.php
+++ b/src/Endpoint/Abstracts/AbstractSugarBeanEndpoint.php
@@ -40,6 +40,14 @@ abstract class AbstractSugarBeanEndpoint extends ModelEndpoint implements SugarE
 
     const BEAN_ACTION_ATTACH_FILE = 'attachFile';
 
+    const BEAN_ACTION_ARG1_VAR = 'actionArg1';
+
+    const BEAN_ACTION_ARG2_VAR = 'actionArg2';
+
+    const BEAN_ACTION_ARG3_VAR = 'actionArg3';
+
+    const BEAN_MODULE_VAR = 'module';
+
     /**
      * @inheritdoc
      */
@@ -94,7 +102,6 @@ public function __construct(array $options = array(), array $properties = array(
      * @inheritdoc
      */
     public function compileRequest(){
-        $this->configureAction($this->getCurrentAction());
         return $this->configureRequest($this->getRequest());
     }
 
@@ -106,7 +113,7 @@ public function compileRequest(){
     public function setOptions(array $options) {
         if (isset($options[0])){
             $this->setModule($options[0]);
-            $options['module'] = $this->module;
+            $options[self::BEAN_MODULE_VAR] = $this->module;
             unset($options[0]);
         }
         if (isset($options[1])){
@@ -140,8 +147,8 @@ public function getModule(){
      * @inheritdoc
      */
     protected function configureURL(array $options) {
-        $action = $this->action;
-        switch($this->action){
+        $action = $this->getCurrentAction();
+        switch($action){
             case self::BEAN_ACTION_CREATE_RELATED:
             case self::BEAN_ACTION_MASS_RELATE:
             case self::BEAN_ACTION_UNLINK:
@@ -173,6 +180,11 @@ protected function configureURL(array $options) {
      * @inheritdoc
      */
     protected function configureAction($action,array $arguments = array()) {
+        $options = $this->getOptions();
+        $options[self::BEAN_MODULE_VAR] = $this->module;
+        if (isset($options[self::BEAN_ACTION_ARG1_VAR])) unset($options[self::BEAN_ACTION_ARG1_VAR]);
+        if (isset($options[self::BEAN_ACTION_ARG2_VAR])) unset($options[self::BEAN_ACTION_ARG2_VAR]);
+        if (isset($options[self::BEAN_ACTION_ARG3_VAR])) unset($options[self::BEAN_ACTION_ARG3_VAR]);
         if (!empty($arguments)){
             switch($action){
                 case self::BEAN_ACTION_RELATE:
@@ -182,18 +194,18 @@ protected function configureAction($action,array $arguments = array()) {
                 case self::BEAN_ACTION_CREATE_RELATED:
                 case self::BEAN_ACTION_FILTER_RELATED:
                     if (isset($arguments[0])){
-                        $this->options['actionArg1'] = $arguments[0];
-                    }
-                    if (isset($arguments[1])){
-                        $this->options['actionArg2'] = $arguments[1];
-                    }
-                    if (isset($arguments[2])){
-                        $this->options['actionArg3'] = $arguments[2];
+                        $options[self::BEAN_ACTION_ARG1_VAR] = $arguments[0];
+                        if (isset($arguments[1])){
+                            $options[self::BEAN_ACTION_ARG2_VAR] = $arguments[1];
+                            if (isset($arguments[2])){
+                                $options[self::BEAN_ACTION_ARG3_VAR] = $arguments[2];
+                            }
+                        }
                     }
             }
         }
-        $this->options['module'] = $this->module;
-        parent::configureAction($action);
+        $this->setOptions($options);
+        parent::configureAction($action,$arguments);
     }
 
     /**
@@ -245,21 +257,30 @@ public function getFile($field){
     /**
      * Human friendly overload for filterLink action
      * @param $linkName - Name of Relationship Link
+     * @param bool $count
      * @return self
      */
-    public function getRelated($linkName){
+    public function getRelated($linkName,$count = false){
+        if ($count){
+            return $this->filterLink($linkName,'count');
+        }
         return $this->filterLink($linkName);
     }
 
     /**
      * Filter generator for Related Links
      * @param $linkName - Name of Relationship Link
+     * @param bool $count - Whether or not to just do a count request
      * @return FilterData
      */
-    public function filterRelated($linkName){
+    public function filterRelated($linkName,$count = false){
         $Filter = new FilterData($this);
         $this->setCurrentAction(self::BEAN_ACTION_FILTER_RELATED);
-        $this->configureAction($this->action,array($linkName));
+        $args = array($linkName);
+        if ($count){
+            $args[] = 'count';
+        }
+        $this->configureAction($this->action,$args);
         return $Filter;
     }
 
diff --git a/src/Endpoint/Data/FilterData.php b/src/Endpoint/Data/FilterData.php
index c80dcfe..bec86b8 100644
--- a/src/Endpoint/Data/FilterData.php
+++ b/src/Endpoint/Data/FilterData.php
@@ -17,6 +17,8 @@
  */
 class FilterData extends AbstractExpression implements DataInterface
 {
+    const FILTER_PARAM = 'filter';
+
     /**
      * @var AbstractSmartEndpoint
      */
@@ -96,7 +98,7 @@ public function offsetGet($offset) {
     public function asArray($compile = TRUE){
         if ($compile){
             $data = $this->compile();
-            $this->data[ModuleFilter::FILTER_PARAM] = $data;
+            $this->data = array_replace_recursive($this->data,$data);
         }
         return $this->data;
     }
@@ -148,6 +150,7 @@ public function update(array $data){
     }
 
     /**
+     * Set the Endpoint using the Filter Data
      * @param AbstractSmartEndpoint $Endpoint
      * @return self
      */
@@ -156,13 +159,23 @@ public function setEndpoint(AbstractSmartEndpoint $Endpoint){
         return $this;
     }
 
+    /**
+     * Return the Endpoint being used with the Filter Data
+     * @return AbstractSmartEndpoint
+     * @codeCoverageIgnore
+     */
+    public function getEndpoint(){
+        return $this->Endpoint;
+    }
+
     /**
      * @return AbstractSmartEndpoint|false
      * @throws \MRussell\REST\Exception\Endpoint\InvalidRequest
      */
     public function execute(){
         if (isset($this->Endpoint)){
-            $this->Endpoint->getData()->update($this->asArray());
+            $filter = $this->asArray();
+            $this->Endpoint->getData()->update(array(self::FILTER_PARAM => $filter));
             return $this->Endpoint->execute();
         }
         return false;
diff --git a/src/Endpoint/ModuleFilter.php b/src/Endpoint/ModuleFilter.php
index d430d93..c9067f9 100644
--- a/src/Endpoint/ModuleFilter.php
+++ b/src/Endpoint/ModuleFilter.php
@@ -16,9 +16,9 @@
  */
 class ModuleFilter extends AbstractSugarBeanCollectionEndpoint
 {
-    const FILTER_PARAM = 'filter';
+    const COUNT_OPTION = 'count';
 
-    protected static $_ENDPOINT_URL = '$module/$:filter';
+    protected static $_ENDPOINT_URL = '$module/filter/$:count';
 
     /**
      * @var FilterData
@@ -30,14 +30,30 @@ class ModuleFilter extends AbstractSugarBeanCollectionEndpoint
      */
     protected $data;
 
+    /**
+     * @var
+     */
+    protected $totalCount;
+
+    /**
+     * Sanitize passed in options
+     * @param array $options
+     * @return $this|mixed
+     */
+    public function setOptions(array $options)
+    {
+        if (isset($options[1])){
+            unset($options[1]);
+            $options[self::COUNT_OPTION] = self::COUNT_OPTION;
+        }
+        return parent::setOptions($options);
+    }
+
     /**
      * @inheritdoc
      */
     public function fetch(){
-        if (isset($this->options[self::FILTER_PARAM])){
-            unset($this->options[self::FILTER_PARAM]);
-        }
-        $this->setProperty('httpMethod',JSON::HTTP_GET);
+        $this->setProperty(self::PROPERTY_HTTP_METHOD,JSON::HTTP_GET);
         return parent::fetch();
     }
 
@@ -47,42 +63,49 @@ public function fetch(){
      */
     protected function configureData($data)
     {
-        if (isset($this->options[self::FILTER_PARAM]) && is_object($this->Filter)){
-            $data->update($this->Filter->asArray());
+        if (is_object($this->Filter)){
+            $compiledFilter = $this->Filter->asArray();
+            if (!empty($compiledFilter)){
+                $data->update(array(FilterData::FILTER_PARAM => $this->Filter->asArray()));
+            }
         }
         return parent::configureData($data);
     }
 
-    /**
-     * Check for httpMethod setting, and if configured for POST make sure to add Filter to URL
-     * @param array $options
-     * @return string
-     */
-    protected function configureURL(array $options)
-    {
-        $properties = $this->getProperties();
-        if (!isset($options[self::FILTER_PARAM]) && $properties['httpMethod'] == JSON::HTTP_POST){
-            $options[self::FILTER_PARAM] = self::FILTER_PARAM;
-        }
-        return parent::configureURL($options);
-    }
-
     /**
      * Configure the Filter Parameters for the Filter API
      * @param bool $reset
      * @return FilterData
      */
-    public function filter($reset = FALSE){
-        $this->options[self::FILTER_PARAM] = self::FILTER_PARAM;
-        $this->setProperty('httpMethod',JSON::HTTP_POST);
+    public function filter($reset = FALSE)
+    {
+        $this->setProperty(self::PROPERTY_HTTP_METHOD,JSON::HTTP_POST);
         if (empty($this->Filter)){
             $this->Filter = new FilterData();
             $this->Filter->setEndpoint($this);
+            $data = $this->getData();
+            if (isset($data[FilterData::FILTER_PARAM]) && !empty($data[FilterData::FILTER_PARAM])){
+                $this->Filter->update($data[FilterData::FILTER_PARAM]);
+            }
         }
         if ($reset){
             $this->Filter->reset();
+            $data = $this->getData();
+            if (isset($data[FilterData::FILTER_PARAM]) && !empty($data[FilterData::FILTER_PARAM])){
+                unset($data[FilterData::FILTER_PARAM]);
+                $this->setData($data);
+            }
         }
         return $this->Filter;
     }
 
+    /**
+     * Configure the Request to use Count Endpoint
+     */
+    public function count()
+    {
+        $this->setOptions(array($this->getModule(),self::COUNT_OPTION));
+        return $this->execute();
+    }
+
 }
\ No newline at end of file
diff --git a/src/Helpers/Helper.php b/src/Helpers/Helper.php
index 27818c7..26fa31e 100644
--- a/src/Helpers/Helper.php
+++ b/src/Helpers/Helper.php
@@ -8,6 +8,7 @@
 class Helper
 {
     const API_VERSION = 10;
+
     const API_URL = '/rest/v%d/';
 
     /**
diff --git a/tests/Endpoint/AbstractSugarBeanCollectionEndpointTest.php b/tests/Endpoint/AbstractSugarBeanCollectionEndpointTest.php
index cd419af..892d706 100644
--- a/tests/Endpoint/AbstractSugarBeanCollectionEndpointTest.php
+++ b/tests/Endpoint/AbstractSugarBeanCollectionEndpointTest.php
@@ -57,7 +57,8 @@ public function testSetOptions()
             'foo'
         )));
         $this->assertEquals(array(
-            'module' => 'Accounts'
+            'module' => 'Accounts',
+            1 => 'foo'
         ),$Endpoint->getOptions());
     }
 
diff --git a/tests/Endpoint/AbstractSugarBeanEndpointTest.php b/tests/Endpoint/AbstractSugarBeanEndpointTest.php
index 35d0da0..00b7afb 100644
--- a/tests/Endpoint/AbstractSugarBeanEndpointTest.php
+++ b/tests/Endpoint/AbstractSugarBeanEndpointTest.php
@@ -161,6 +161,10 @@ public function testGetRelated(){
         $this->assertEquals($Bean,$Bean->getRelated('test'));
         $this->assertEquals('http://localhost/rest/v10/Foo/bar/link/test',$Bean->getRequest()->getURL());
         $this->assertEquals('GET',$Bean->getRequest()->getMethod());
+
+        $this->assertEquals($Bean,$Bean->getRelated('test',true));
+        $this->assertEquals('http://localhost/rest/v10/Foo/bar/link/test/count',$Bean->getRequest()->getURL());
+        $this->assertEquals('GET',$Bean->getRequest()->getMethod());
     }
 
     /**
@@ -177,6 +181,13 @@ public function testFilterRelated(){
         $this->assertEquals('http://localhost/rest/v10/Foo/bar/link/test',$Bean->getRequest()->getURL());
         $this->assertEquals('GET',$Bean->getRequest()->getMethod());
         $this->assertArrayHasKey('filter',$Bean->getRequest()->getBody());
+
+        $Filter = $Bean->filterRelated('test',true);
+        $this->assertInstanceOf('Sugarcrm\\REST\\Endpoint\\Data\\FilterData',$Filter);
+        $this->assertEquals($Bean,$Filter->execute());
+        $this->assertEquals('http://localhost/rest/v10/Foo/bar/link/test/count',$Bean->getRequest()->getURL());
+        $this->assertEquals('GET',$Bean->getRequest()->getMethod());
+        $this->assertArrayHasKey('filter',$Bean->getRequest()->getBody());
     }
 
     /**
diff --git a/tests/Endpoint/Data/FilterDataTest.php b/tests/Endpoint/Data/FilterDataTest.php
index 0771fd8..3269626 100644
--- a/tests/Endpoint/Data/FilterDataTest.php
+++ b/tests/Endpoint/Data/FilterDataTest.php
@@ -116,26 +116,21 @@ public function testConstructor(){
     public function testDataAccess(){
         $Filter = new ModuleFilter();
         $Data = new FilterData($Filter);
-        $Data['filter'] = $this->data_simple;
-        $this->assertEquals($this->data_simple,$Data['filter']);
-        $this->assertEquals(TRUE,isset($Data['filter']));
+        $Data->update($this->data_simple);
+        $this->assertEquals($this->data_simple,$Data->asArray(false));
         $Data->clear();
-        $this->assertEquals(array('filter' => array()),$Data->asArray());
+        $this->assertEquals(array(),$Data->asArray());
         $Data->starts('name','s')->equals('status','foo')->gte('date_entered','2017-01-01');
-        $this->assertEquals(array(
-            'filter' => $this->data_simple
-        ),$Data->asArray(TRUE));
-        $Data->update(array(
-            'filter' => $this->data_simple
-        ));
-        $this->assertEquals(array(
-            'filter' => $this->data_simple
-        ),$Data->asArray(TRUE));
-        unset($Data['filter']);
+        $this->assertEquals($this->data_simple,$Data->asArray());
+        $Data->update($this->data_simple);
+        $this->assertEquals($this->data_simple,$Data->asArray());
+        $Data->reset();
         $this->assertEmpty($Data->asArray(FALSE));
         $Data[] = 'foo';
         $this->assertEquals('foo',$Data[0]);
-
+        unset($Data[0]);
+        $this->assertEquals(array(),$Data->asArray(FALSE));
+        $Data['$foo'] = 'bar';
         $Data->reset();
         $this->assertEmpty($Data->asArray(FALSE));
 
diff --git a/tests/Endpoint/ModuleFilterTest.php b/tests/Endpoint/ModuleFilterTest.php
index 19df048..4394506 100644
--- a/tests/Endpoint/ModuleFilterTest.php
+++ b/tests/Endpoint/ModuleFilterTest.php
@@ -6,7 +6,9 @@
 namespace Sugarcrm\REST\Tests\Endpoint;
 
 use MRussell\Http\Request\Curl;
+use MRussell\Http\Request\JSON;
 use MRussell\REST\Endpoint\Data\EndpointData;
+use Sugarcrm\REST\Endpoint\Data\FilterData;
 use Sugarcrm\REST\Endpoint\ModuleFilter;
 
 
@@ -39,6 +41,43 @@ public function tearDown()
         parent::tearDown();
     }
 
+    /**
+     * @covers ::setOptions
+     */
+    public function testSetOptions(){
+        $ModuleFilter = new ModuleFilter();
+        $this->assertEquals($ModuleFilter,$ModuleFilter->setOptions(array(
+            'Accounts',
+            'count'
+        )));
+        $this->assertEquals(array(
+            'module' => 'Accounts',
+            'count' => 'count'
+        ),$ModuleFilter->getOptions());
+        $this->assertEquals($ModuleFilter,$ModuleFilter->setOptions(array(
+            'Accounts',
+            true
+        )));
+        $this->assertEquals(array(
+            'module' => 'Accounts',
+            'count' => 'count'
+        ),$ModuleFilter->getOptions());
+        $this->assertEquals($ModuleFilter,$ModuleFilter->setOptions(array(
+            'Accounts',
+            0
+        )));
+        $this->assertEquals(array(
+            'module' => 'Accounts',
+            'count' => 'count'
+        ),$ModuleFilter->getOptions());
+        $this->assertEquals($ModuleFilter,$ModuleFilter->setOptions(array(
+            'Accounts'
+        )));
+        $this->assertEquals(array(
+            'module' => 'Accounts'
+        ),$ModuleFilter->getOptions());
+    }
+
     /**
      * @covers ::fetch
      */
@@ -47,12 +86,12 @@ public function testFetch(){
         $ModuleFilter->setBaseUrl('http://localhost/rest/v10');
         $ModuleFilter->setModule('Accounts');
         $ModuleFilter->fetch();
-        $this->assertEquals('http://localhost/rest/v10/Accounts',$ModuleFilter->getRequest()->getURL());
+        $this->assertEquals('http://localhost/rest/v10/Accounts/filter',$ModuleFilter->getRequest()->getURL());
+        $this->assertEquals(JSON::HTTP_GET,$ModuleFilter->getProperties()[$ModuleFilter::PROPERTY_HTTP_METHOD]);
         $ModuleFilter->filter();
-        $this->assertArrayHasKey('filter',$ModuleFilter->getOptions());
+        $this->assertEquals(JSON::HTTP_POST,$ModuleFilter->getProperties()[$ModuleFilter::PROPERTY_HTTP_METHOD]);
         $ModuleFilter->fetch();
-        $this->assertArrayNotHasKey('filter',$ModuleFilter->getOptions());
-        $this->assertEquals('http://localhost/rest/v10/Accounts',$ModuleFilter->getRequest()->getURL());
+        $this->assertEquals(JSON::HTTP_GET,$ModuleFilter->getProperties()[$ModuleFilter::PROPERTY_HTTP_METHOD]);
     }
 
     /**
@@ -66,21 +105,16 @@ public function testConfigureData(){
 
         $ModuleFilter->setBaseUrl('http://localhost/rest/v10');
         $ModuleFilter->setModule('Accounts');
-        $ModuleFilter->setOptions(array(ModuleFilter::FILTER_PARAM => array()));
-        $data = $configureData->invoke($ModuleFilter,new EndpointData());
-        $this->assertArrayNotHasKey('filter',$data);
-
         $ModuleFilter->filter();
         $data = $configureData->invoke($ModuleFilter,new EndpointData());
-        $this->assertArrayHasKey('filter',$data);
+        $this->assertArrayNotHasKey('filter',$data);
 
         $ModuleFilter = new ModuleFilter();
         $ModuleFilter->setBaseUrl('http://localhost/rest/v10');
         $ModuleFilter->setModule('Accounts');
-        $ModuleFilter->filter();
+        $ModuleFilter->filter()->contains('foo','bar');
         $data = $configureData->invoke($ModuleFilter,new EndpointData());
         $this->assertArrayHasKey('filter',$data);
-        $this->assertArrayHasKey('filter',$ModuleFilter->getOptions());
     }
 
     /**
@@ -111,6 +145,47 @@ public function testFilter(){
         $Filter->equals('foo','bar');
         $this->assertEquals($Filter,$ModuleFilter->filter(TRUE));
         $this->assertEquals(array(),$Filter->asArray(FALSE));
+        $ModuleFilter->setData(array(
+            'filter' => array(
+                array(
+                    '$equals' => array(
+                        'bar' => 'foo'
+                    )
+                )
+            )
+        ));
+        $Filter = $ModuleFilter->filter(TRUE);
+        $this->assertEmpty($ModuleFilter->getData()['filter']);
+
+        $ModuleFilter = new ModuleFilter();
+        $ModuleFilter->setData(array(
+            'filter' => array(
+                array(
+                    '$equals' => array(
+                        'bar' => 'foo'
+                    )
+                )
+            )
+        ));
+        $Filter = $ModuleFilter->filter();
+        $this->assertEquals(array(
+            array(
+                '$equals' => array(
+                    'bar' => 'foo'
+                )
+            )
+        ),$Filter->asArray(FALSE));
+    }
+
+    /**
+     * @covers ::count
+     */
+    public function testCount(){
+        $ModuleFilter = new ModuleFilter();
+        $ModuleFilter->setModule('Accounts');
+        $ModuleFilter->setBaseUrl('http://localhost/rest/v10/');
+        $this->assertEquals($ModuleFilter,$ModuleFilter->count());
+        $this->assertEquals('http://localhost/rest/v10/Accounts/filter/count',$ModuleFilter->getRequest()->getURL());
     }
 
 }

From af054c448c6f00c8f217037dba37aec6f97c016b Mon Sep 17 00:00:00 2001
From: Mike Russell 
Date: Fri, 30 Jun 2017 11:03:43 -0400
Subject: [PATCH 2/3] Fix PHP 5.3 CI Failures

---
 tests/Endpoint/ModuleFilterTest.php | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/tests/Endpoint/ModuleFilterTest.php b/tests/Endpoint/ModuleFilterTest.php
index 4394506..049bf76 100644
--- a/tests/Endpoint/ModuleFilterTest.php
+++ b/tests/Endpoint/ModuleFilterTest.php
@@ -87,11 +87,14 @@ public function testFetch(){
         $ModuleFilter->setModule('Accounts');
         $ModuleFilter->fetch();
         $this->assertEquals('http://localhost/rest/v10/Accounts/filter',$ModuleFilter->getRequest()->getURL());
-        $this->assertEquals(JSON::HTTP_GET,$ModuleFilter->getProperties()[$ModuleFilter::PROPERTY_HTTP_METHOD]);
+        $properties = $ModuleFilter->getProperties();
+        $this->assertEquals(JSON::HTTP_GET,$properties[$ModuleFilter::PROPERTY_HTTP_METHOD]);
         $ModuleFilter->filter();
-        $this->assertEquals(JSON::HTTP_POST,$ModuleFilter->getProperties()[$ModuleFilter::PROPERTY_HTTP_METHOD]);
+        $properties = $ModuleFilter->getProperties();
+        $this->assertEquals(JSON::HTTP_POST,$properties[$ModuleFilter::PROPERTY_HTTP_METHOD]);
         $ModuleFilter->fetch();
-        $this->assertEquals(JSON::HTTP_GET,$ModuleFilter->getProperties()[$ModuleFilter::PROPERTY_HTTP_METHOD]);
+        $properties = $ModuleFilter->getProperties();
+        $this->assertEquals(JSON::HTTP_GET,$properties[$ModuleFilter::PROPERTY_HTTP_METHOD]);
     }
 
     /**

From 317c358a829785fccd4e5271dcb91e2f8deeee7e Mon Sep 17 00:00:00 2001
From: Mike Russell 
Date: Fri, 30 Jun 2017 11:06:46 -0400
Subject: [PATCH 3/3] More PHP 5.3 CI Fixes

---
 tests/Endpoint/ModuleFilterTest.php | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/tests/Endpoint/ModuleFilterTest.php b/tests/Endpoint/ModuleFilterTest.php
index 049bf76..4988f15 100644
--- a/tests/Endpoint/ModuleFilterTest.php
+++ b/tests/Endpoint/ModuleFilterTest.php
@@ -158,7 +158,8 @@ public function testFilter(){
             )
         ));
         $Filter = $ModuleFilter->filter(TRUE);
-        $this->assertEmpty($ModuleFilter->getData()['filter']);
+        $data = $ModuleFilter->getData();
+        $this->assertEmpty($data['filter']);
 
         $ModuleFilter = new ModuleFilter();
         $ModuleFilter->setData(array(