troydavisson / PHRETS

PHP client library for interacting with a RETS server to pull real estate listings, photos and other data made available from an MLS system
http://troda.com
MIT License
451 stars 236 forks source link

Call to a member function toArray() on null #180

Closed minhtranite closed 6 years ago

minhtranite commented 6 years ago

I created a symfony command to get RETS data but got exception: Here is log:

22:51:01 DEBUG     [app] Sending HTTP Request for http://connectmls-rets.mredllc.com:80/rets/server/search (Search)
[
  "auth" => [
    "*******",
    "*******",
    "digest"
  ],
  "headers" => [
    "User-Agent" => "PHRETS/2.0",
    "RETS-Version" => "RETS/1.5",
    "Accept-Encoding" => "gzip",
    "Accept" => "*/*"
  ],
  "curl" => [
    10031 => "/tmp/phrets7GIaRS"
  ],
  "query" => [
    "SearchType" => "Property",
    "Class" => "ResidentialProperty",
    "Query" => "(STATE=IL),(ST=ACTV,BOMK,NEW,PCHG,RACT,AUCT,CLSD,PEND,CTG),(LD=2017-01-01+)",
    "QueryType" => "DMQL2",
    "Count" => 1,
    "Format" => "COMPACT-DECODED",
    "Limit" => 99999999,
    "StandardNames" => 0
  ]
]
[]
22:54:56 DEBUG     [app] Response: HTTP 200
[]
[]
22:54:56 DEBUG     [app] 454 column headers/fields given
[]
[]
22:54:57 DEBUG     [app] 146535 total results found
[]
[]
22:54:57 DEBUG     [app] 2000 results given
[]
[]
22:54:57 DEBUG     [app] Maximum rows returned in response
[]
[]
22:54:57 DEBUG     [app] Continuing pagination...
[]
[]
22:54:57 DEBUG     [app] Current count collected already: 2000
[]
[]
22:54:57 DEBUG     [app] Sending HTTP Request for http://connectmls-rets.mredllc.com:80/rets/server/search (Search)
[
  "auth" => [
    "*******",
    "*******",
    "digest"
  ],
  "headers" => [
    "User-Agent" => "PHRETS/2.0",
    "RETS-Version" => "RETS/1.5",
    "Accept-Encoding" => "gzip",
    "Accept" => "*/*"
  ],
  "curl" => [
    10031 => "/tmp/phretsXXl5pz"
  ],
  "query" => [
    "SearchType" => "Property",
    "Class" => "ResidentialProperty",
    "Query" => "(STATE=IL),(ST=ACTV,BOMK,NEW,PCHG,RACT,AUCT,CLSD,PEND,CTG),(LD=2017-01-01+)",
    "QueryType" => "DMQL2",
    "Count" => 1,
    "Format" => "COMPACT-DECODED",
    "Limit" => 99999999,
    "StandardNames" => 0,
    "Offset" => 2001
  ]
]
[]
22:54:57 DEBUG     [app] Response: HTTP 200
[]
[]
22:54:57 DEBUG     [app] Assuming TAB delimiter since none specified in response
[]
[]
22:54:57 DEBUG     [app] 1 column headers/fields given
[]
[]
22:54:57 DEBUG     [app] 0 results given
[]
[]
22:54:57 ERROR     [console] Error thrown while running command "rets:import --env=prod -vvv". Message: "Call to a member function toArray() on null"
[
  "error" => Error {
    #message: "Call to a member function toArray() on null"
    #code: 0
    #file: "/path/to/project/vendor/troydavisson/phrets/src/Parsers/Search/RecursiveOneX.php"
    #line: 81
    trace: {
      /path/to/project/vendor/troydavisson/phrets/src/Parsers/Search/RecursiveOneX.php:81: {
        : {
        :     return $big->first()->toArray() == $small->first()->toArray();
        : }
      }
      /path/to/project/vendor/troydavisson/phrets/src/Parsers/Search/RecursiveOneX.php:40: {
        : // test if we're actually paginating
        : if ($this->isPaginationBroken($rs, $inner_rs)) {
        :     throw new AutomaticPaginationError("Automatic pagination doesn't not appear to be supported by the server");
        arguments: {
          $big: PHRETS\Models\Search\Results { …}
          $small: PHRETS\Models\Search\Results { …}
        }
      }
      /path/to/project/vendor/troydavisson/phrets/src/Session.php:287: {
        :     }
        :     return $parser->parse($this, $response, $parameters);
        : }
        arguments: {
          $rets: PHRETS\Session { …}
          $response: PHRETS\Http\Response { …}
          $parameters: [ …8]
        }
      }
      /path/to/project/src/RetsBundle/Helper/RetsHelper.php:50: {
        :     $options,
        :     true
        : );
        arguments: {
          $resource_id: "Property"
          $class_id: "ResidentialProperty"
          $dmql_query: "(STATE=IL),(ST=ACTV,BOMK,NEW,PCHG,RACT,AUCT,CLSD,PEND,CTG),(LD=2017-01-01+)"
          $optional_parameters: []
          $recursive: true
        }
      }
      /path/to/project/src/RetsBundle/Command/RetsImportCommand.php:55: {
        : $this->logger->info('Fetching Residential Properties...');
        : $results = $this->rets->getResidentialProperties();
        : $this->logger->info('Found '.$results->count().' Residential Properties');
      }
      /path/to/project/vendor/symfony/symfony/src/Symfony/Component/Console/Command/Command.php:240: {
        : } else {
        :     $statusCode = $this->execute($input, $output);
        : }
        arguments: {
          $input: Symfony\Component\Console\Input\ArgvInput {#1 …}
          $output: Symfony\Component\Console\Output\ConsoleOutput {#2 …}
        }
      }
      /path/to/project/vendor/symfony/symfony/src/Symfony/Component/Console/Application.php:876: {
        : if ($event->commandShouldRun()) {
        :     $exitCode = $command->run($input, $output);
        : } else {
        arguments: {
          $input: Symfony\Component\Console\Input\ArgvInput {#1 …}
          $output: Symfony\Component\Console\Output\ConsoleOutput {#2 …}
        }
      }
      /path/to/project/vendor/symfony/symfony/src/Symfony/Component/Console/Application.php:216: {
        : $this->runningCommand = $command;
        : $exitCode = $this->doRunCommand($command, $input, $output);
        : $this->runningCommand = null;
        arguments: {
          $command: RetsBundle\Command\RetsImportCommand { …}
          $input: Symfony\Component\Console\Input\ArgvInput {#1 …}
          $output: Symfony\Component\Console\Output\ConsoleOutput {#2 …}
        }
      }
      /path/to/project/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Console/Application.php:71: {
        : 
        :     return parent::doRun($input, $output);
        : }
        arguments: {
          $input: Symfony\Component\Console\Input\ArgvInput {#1 …}
          $output: Symfony\Component\Console\Output\ConsoleOutput {#2 …}
        }
      }
      /path/to/project/vendor/symfony/symfony/src/Symfony/Component/Console/Application.php:122: {
        :     $e = null;
        :     $exitCode = $this->doRun($input, $output);
        : } catch (\Exception $e) {
        arguments: {
          $input: Symfony\Component\Console\Input\ArgvInput {#1 …}
          $output: Symfony\Component\Console\Output\ConsoleOutput {#2 …}
        }
      }
      /path/to/project/bin/console:27: {
        : $application = new Application($kernel);
        : $application->run($input);
        : 
        arguments: {
          $input: Symfony\Component\Console\Input\ArgvInput {#1 …}
        }
      }
    }
  },
  "command" => "rets:import --env=prod -vvv",
  "message" => "Call to a member function toArray() on null"
]
[]
22:55:04 DEBUG     [console] Command "rets:import --env=prod -vvv" exited with code "1"
[
  "command" => "rets:import --env=prod -vvv",
  "code" => 1
]
[]

  [Symfony\Component\Debug\Exception\FatalThrowableError]  
  Call to a member function toArray() on null              

Exception trace:
 () at /path/to/project/vendor/troydavisson/phrets/src/Parsers/Search/RecursiveOneX.php:81
 PHRETS\Parsers\Search\RecursiveOneX->isPaginationBroken() at /path/to/project/vendor/troydavisson/phrets/src/Parsers/Search/RecursiveOneX.php:40
 PHRETS\Parsers\Search\RecursiveOneX->parse() at /path/to/project/vendor/troydavisson/phrets/src/Session.php:287
 PHRETS\Session->Search() at /path/to/project/src/RetsBundle/Helper/RetsHelper.php:50
 RetsBundle\Helper\RetsHelper->getResidentialProperties() at /path/to/project/src/RetsBundle/Command/RetsImportCommand.php:55
 RetsBundle\Command\RetsImportCommand->execute() at /path/to/project/vendor/symfony/symfony/src/Symfony/Component/Console/Command/Command.php:240
 Symfony\Component\Console\Command\Command->run() at /path/to/project/vendor/symfony/symfony/src/Symfony/Component/Console/Application.php:876
 Symfony\Component\Console\Application->doRunCommand() at /path/to/project/vendor/symfony/symfony/src/Symfony/Component/Console/Application.php:216
 Symfony\Component\Console\Application->doRun() at /path/to/project/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Console/Application.php:71
 Symfony\Bundle\FrameworkBundle\Console\Application->doRun() at /path/to/project/vendor/symfony/symfony/src/Symfony/Component/Console/Application.php:122
 Symfony\Component\Console\Application->run() at /path/to/project/bin/console:27
steveheinsch commented 6 years ago

Can you try running as RETS 1.7.2 client (you're using 1.5)?

It looks like the server isn't capable of returning paginated results (at least using version 1.5). It retrieves the first "page" fine (22:54:57 DEBUG [app] 2000 results given), but when it tries to retrieve the next "page" of results (22:54:57 DEBUG [app] Continuing pagination...), it receives 0 (22:54:57 DEBUG [app] 0 results given). So then you try to run ->toArray() on an empty collection.

You're not showing any code so hard to see what's going on, but I'd check to see if you actually received results before running toArray() or any further processing.

minhtranite commented 6 years ago

@steveheinsch, I have tried but still got the error.

09:44:31 DEBUG     [app] Sending HTTP Request for http://connectmls-rets.mredllc.com:80/rets/server/search (Search)
[
  "auth" => [
    "*****",
    "*****",
    "digest"
  ],
  "headers" => [
    "User-Agent" => "PHRETS/2.0",
    "RETS-Version" => "RETS/1.7.2",
    "Accept-Encoding" => "gzip",
    "Accept" => "*/*"
  ],
  "curl" => [
    10031 => "/tmp/phretsC6vVSN"
  ],
  "query" => [
    "SearchType" => "Property",
    "Class" => "ResidentialProperty",
    "Query" => "(STATE=IL),(ST=ACTV,BOMK,NEW,PCHG,RACT,AUCT,CLSD,PEND,CTG),(LD=2017-01-01+)",
    "QueryType" => "DMQL2",
    "Count" => 1,
    "Format" => "COMPACT-DECODED",
    "Limit" => 99999999,
    "StandardNames" => 0,
    "Offset" => 28001
  ]
]
[]
09:44:32 DEBUG     [app] Response: HTTP 200
[]
[]
09:44:32 DEBUG     [app] Assuming TAB delimiter since none specified in response
[]
[]
09:44:32 DEBUG     [app] 1 column headers/fields given
[]
[]
09:44:32 DEBUG     [app] 0 results given

In my command I just call $results = $this->rets->getResidentialProperties();. and here is my helper class:

<?php

namespace RetsBundle\Helper;

use Monolog\Logger;
use PHRETS\Configuration;
use PHRETS\Session;
use RetsBundle\Entity\ResidentialProperty;

class RetsHelper
{
    private $url;

    private $username;

    private $password;

    private $logger;

    private $rets;

    public function __construct(string $url, string $username, string $password, Logger $logger)
    {
        $this->url = $url;
        $this->username = $username;
        $this->password = $password;
        $this->logger = $logger;
        $config = new Configuration();
        $config->setRetsVersion('1.7.2');
        $config->setLoginUrl($this->url);
        $config->setUsername($this->username);
        $config->setPassword($this->password);
        $this->rets = new Session($config);
        $this->rets->setLogger($this->logger);
        $this->rets->Login();
    }

    public function getResidentialProperties(int $offset = 0)
    {
        $status = implode(',', ResidentialProperty::ALLOW_STATUS);
        $options = [];
        if ($offset > 0) {
            $options['Offset'] = $offset;
        }

        return $this->rets->Search(
            'Property',
            'ResidentialProperty',
            '(STATE=IL),(ST='.$status.'),(LD=2017-01-01+)',
            $options,
            true
        );
    }

    public function getPropertyStates()
    {
        $results = [];
        $lookUpValues = $this->rets->GetLookupValues('Property', 'STATE');
        /** @var \PHRETS\Models\Metadata\LookupType $item */
        foreach ($lookUpValues as $item) {
            $results[$item->getValue()] = $item->getLongValue();
        }

        return $results;
    }

    public function getPropertyStatus()
    {
        $results = [];
        $lookUpValues = $this->rets->GetLookupValues('Property', 'ST');
        /** @var \PHRETS\Models\Metadata\LookupType $item */
        foreach ($lookUpValues as $item) {
            $results[$item->getValue()] = $item->getLongValue();
        }

        return $results;
    }

    public function getPropertyPhotos($ids)
    {
        return $this->rets->GetObject('Property', 'HrPhoto', $ids);
    }
}
minhtranite commented 6 years ago

I have tried dump the response when error like that:

if($response->getHeader('Content-Type') !== 'text/xml;charset=utf-8'){
            dump($response->getBody()->getContents());
        }

and got this message

<RETS ReplyCode="20036" ReplyText="Duplicate login detected - this session is invalid" >\n
</RETS>\r\n

Seems it isn't problem of PHRETS so I will close this issue.