Muhammad Omer Aslam
Muhammad Omer Aslam

Reputation: 23778

include(Throwable.php): failed to open stream: No such file or directory

Q A
Yii version 1.1.14
PHP version 5.6.4
Guzzle version 6.*
Operating system Ubuntu

I am facing an issue and the problem is not related to the corrupt install of php or the php-fpm as the same code runs properly outside Yii framework.

Interestingly this happens when i create a pool of requests to be executed inside the Yii framework but if i dont use GuzzleHttp\Pool and just send a single request and try to use the promise everything works fine.

Here are the classes used and the code, I am using a custom written php client for dejavoo IPOSTransact Gateway and use it inside a console job to open batch and settle the payments.

Below is the code when sending a single request from the console command

class DejavooSettlementCommand extends CConsoleCommand
{
    public function run($args)
    {
         Yii::import("application.components.PaymentHelper");
        Yii::import("application.modules.dejavoo.models.*");

        //get all the merchants from the database
        $merchants = DejavooMerchants::getMerchantsArray();

        $iposTransact = new IposTransact();
        $iposTransact->setAuthToken($merchants[0]['ipos_transact_token']);
        $iposTransact->setTpn($merchants[0]['merchant_id']);
        $iposTransact->initClient(Transact::class);
        $promise = $iposTransact->getOpenBatch();

        $promise->then(function ($response) {
            echo "here";
            Yii::log("Resolved the promise :" . $response->getBody(), CLogger::LEVEL_TRACE);
        })->wait();
    }
}

The above code runs and returns the response correctly.


Below is the code that i use for sending the concurrent requests in console command file

class DejavooSettlementCommand extends CConsoleCommand
{
    public function run($args)
    {
         Yii::import("application.components.PaymentHelper");
        Yii::import("application.modules.dejavoo.models.*");

        //get all the merchants from the database
        $merchants = DejavooMerchants::getMerchantsArray();

        $iposTransact = new IposTransact();
        $iposTransact->setAuthToken($merchants[0]['ipos_transact_token']);
        $iposTransact->initClient(Transact::class);
        $iposTransact->sendOpenBatchRequest($merchants);
    }
}

The above code throws the following exception

PHP Error[2]: include(Throwable.php): failed to open stream: No such file or directory
    in file /var/www/html/Bottle360/yii/framework/YiiBase.php at line 427
#0 /var/www/html/Bottle360/yii/framework/YiiBase.php(427): autoload()
#1 unknown(0): autoload()
#2 unknown(0): spl_autoload_call()
#3 /var/www/html/Bottle360/vendor/guzzlehttp/guzzle/src/Exception/GuzzleException.php(6): interface_exists()
#4 /var/www/html/Bottle360/vendor/composer/ClassLoader.php(571): include()
#5 /var/www/html/Bottle360/vendor/composer/ClassLoader.php(428): Composer\Autoload\includeFile()
#6 unknown(0): Composer\Autoload\ClassLoader->loadClass()
#7 /var/www/html/Bottle360/vendor/guzzlehttp/guzzle/src/Exception/TransferException.php(5): spl_autoload_call()
#8 /var/www/html/Bottle360/vendor/composer/ClassLoader.php(571): include()
#9 /var/www/html/Bottle360/vendor/composer/ClassLoader.php(428): Composer\Autoload\includeFile()
#10 unknown(0): Composer\Autoload\ClassLoader->loadClass()
#11 /var/www/html/Bottle360/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php(13): spl_autoload_call()
#12 /var/www/html/Bottle360/vendor/composer/ClassLoader.php(571): include()
#13 /var/www/html/Bottle360/vendor/composer/ClassLoader.php(428): Composer\Autoload\includeFile()
#14 unknown(0): Composer\Autoload\ClassLoader->loadClass()
#15 /var/www/html/Bottle360/vendor/guzzlehttp/guzzle/src/Exception/ConnectException.php(12): spl_autoload_call()
#16 /var/www/html/Bottle360/vendor/composer/ClassLoader.php(571): include()
#17 /var/www/html/Bottle360/vendor/composer/ClassLoader.php(428): Composer\Autoload\includeFile()
#18 unknown(0): Composer\Autoload\ClassLoader->loadClass()
#19 /var/www/html/Bottle360/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php(200): spl_autoload_call()
#20 /var/www/html/Bottle360/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php(155): createRejection()
#21 /var/www/html/Bottle360/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php(105): finishError()
#22 /var/www/html/Bottle360/vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php(202): finish()
#23 /var/www/html/Bottle360/vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php(130): GuzzleHttp\Handler\CurlMultiHandler->processMessages()
#24 /var/www/html/Bottle360/vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php(145): GuzzleHttp\Handler\CurlMultiHandler->tick()
#25 /var/www/html/Bottle360/vendor/guzzlehttp/promises/src/Promise.php(248): GuzzleHttp\Handler\CurlMultiHandler->execute()
#26 /var/www/html/Bottle360/vendor/guzzlehttp/promises/src/Promise.php(224): GuzzleHttp\Promise\Promise->invokeWaitFn()
#27 /var/www/html/Bottle360/vendor/guzzlehttp/promises/src/Promise.php(269): GuzzleHttp\Promise\Promise->waitIfPending()
#28 /var/www/html/Bottle360/vendor/guzzlehttp/promises/src/Promise.php(226): GuzzleHttp\Promise\Promise->invokeWaitList()
#29 /var/www/html/Bottle360/vendor/guzzlehttp/promises/src/Promise.php(62): GuzzleHttp\Promise\Promise->waitIfPending()
#30 /var/www/html/Bottle360/vendor/guzzlehttp/promises/src/EachPromise.php(108): GuzzleHttp\Promise\Promise->wait()
#31 /var/www/html/Bottle360/vendor/guzzlehttp/promises/src/Promise.php(248): GuzzleHttp\Promise\EachPromise->GuzzleHttp\Promise\{closure}()
#32 /var/www/html/Bottle360/vendor/guzzlehttp/promises/src/Promise.php(224): GuzzleHttp\Promise\Promise->invokeWaitFn()
#33 /var/www/html/Bottle360/vendor/guzzlehttp/promises/src/Promise.php(269): GuzzleHttp\Promise\Promise->waitIfPending()
#34 /var/www/html/Bottle360/vendor/guzzlehttp/promises/src/Promise.php(226): GuzzleHttp\Promise\Promise->invokeWaitList()
#35 /var/www/html/Bottle360/vendor/guzzlehttp/promises/src/Promise.php(62): GuzzleHttp\Promise\Promise->waitIfPending()
#36 /var/www/html/Bottle360/protected/commands/DejavooSettlementCommand.php(88): GuzzleHttp\Promise\Promise->wait()
#37 /var/www/html/Bottle360/protected/commands/DejavooSettlementCommand.php(15): DejavooSettlementCommand->test()
#38 /var/www/html/Bottle360/yii/framework/console/CConsoleCommandRunner.php(71): DejavooSettlementCommand->run()
#39 /var/www/html/Bottle360/yii/framework/console/CConsoleApplication.php(92): CConsoleCommandRunner->run()
#40 /var/www/html/Bottle360/yii/framework/base/CApplication.php(180): CConsoleApplication->processRequest()
#41 /var/www/html/Bottle360/cronjob.php(11): CConsoleApplication->run()

Yii component IposTransact.php that extends the base component Transact class stripping off extra code from the class

<?php

namespace application\components;

use GuzzleHttp\Pool;
use GuzzleHttp\Psr7\Response;
use b360\paymentgateways\dejavoo\Transact;
use GuzzleHttp\Exception\RequestException;
use application\modules\dejavoo\models\DejavooOpenBatchLogs;
use b360\dejavoo\finals\TransactParams;
use b360\dejavoo\Transact as DejavooTransact;
use CLogger;
use Exception;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Promise\Promise;
use Psr\Http\Message\ResponseInterface;
use Yii;

class IposTransact extends Transact
{
    /**
     * @return Promise
     */
    public function getOpenBatch()
    {
        \Yii::log("sending openbatch from IposTransact ", CLogger::LEVEL_TRACE);
        //sends request to the spin proxy sale endpoint
        return $this->getClient()->openBatch();
    }

    public function sendOpenBatchRequest($batches)
    {
        //call parent implementation
        $pool = parent::sendOpenBatchRequest($batches);
        $pool->promise()->wait();
        // print_r($pool->each);
        print_r($pool);
    }
}

Base Yii component Transact.php that is extended by IposTransact.php class above

<?php

namespace b360\paymentgateways\dejavoo;

use CApplicationComponent;
use GuzzleHttp\Psr7\Response;
use b360\dejavoo\finals\TransactParams;
use b360\dejavoo\Transact as DejavooTransact;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Pool;
use Psr\Http\Message\ResponseInterface;

class Transact extends CApplicationComponent
{
    //holds the auth token
    /**
     * @var mixed
     */
    protected $authToken;

    //holds the merchant ID
    /**
     * @var mixed
     */
    protected $tpn;

    //hold the environment sandbox/live
    /**
     * @var mixed
     */
    protected $env;

    //guzzel HTTP client
    /**
     * @var mixed
     */
    private $client;

    //holds the current request response
    /**
     * @var mixed
     */
    public $response;

    //saves the request params
    /**
     * @var mixed
     */
    public $request;

    /**
     * Initializes the client for the Dejavoo gate way.
     */
    public function initClient($clientType)
    {
        //initilize the client
        $client = new $clientType(
            $this->getTpn(),
            $this->getAuthToken(),
            $this->getEnv()
        );

        //set the client
        $this->setClient($client);
    }

    /**
     * Sends open batch requests to the IPOS Transact API
     *
     * @param array $merchants the array of the merchants
     *                         to open the batches for settlement
     *
     */
    public function sendOpenBatchRequest($merchants)
    {
        //prepare default options
        $defaultOptions = [
            'merchantAuthentication' => [
                TransactParams::MERCHANT_ID => $this->getTPN(),
            ],
            'transactionRequest' => [
                TransactParams::TRANSACTION_TYPE => DejavooTransact::TRANSACTION_TYPE_OPEN_BATCH,
            ],
        ];

        $requests = function ($merchants) use (&$defaultOptions) {
            foreach ($merchants as $merchant) {
                yield function () use (&$merchant, &$defaultOptions) {
                    $this->setTpn($merchant['merchant_id']);
                    $this->initClient(DejavooTransact::class);

                    //set the request property for the logs usage
                    $this->setRequest($defaultOptions);
                    return $this->getClient()->openBatch();
                };
            }
        };

        //pool the requests to make concurrent requests and get the responses via promise
        $pool = new Pool(
            $this->getClient()->getHttpClient(),
            $requests($merchants),
            [
                "concurrency" => 2,
                "fulfilled" => function (ResponseInterface $response) {
                    //set the reesponse property
                    $this->setResponse($response);
                    $res=$response->getBody();
                    \Yii::log("Response: {$res}");
                    //save the open batch logs to db
                    // $this->saveOpenBatchLogs();
                },
                "rejected" => function (RequestException $response) {
                    echo "rejected";
                },
            ]
        );
        return $pool;
    }

Dejavoo php client class Transact.php

<?php

namespace b360\dejavoo;

use b360\dejavoo\finals\TransactParams;
use CLogger;
use GuzzleHttp\Client;
use GuzzleHttp\Pool;
use GuzzleHttp\Psr7\Request;

class Transact
{
    //holds the auth token
    protected $authToken;

    //holds the merchant ID
    protected $tpn;

    //guzzel HTTP client
    private $client;

    //holds the current request response
    public $response;

    //base urls for sandbox and live
    const BASE_URL_SANDBOX = 'https://payment.ipospays.tech/';
    const BASE_URL = ''; //note: need to ask for live url once live

    //sandbox and live mode
    const MODE_SANDBOX = 'sandbox';
    const MODE_LIVE = 'live';

    //request types
    const REQUEST_POST = 'POST';
    const REQUEST_GET = 'GET';

      /**
     * Sets the GuzzleHttp\Client object
     *
     * @param string $mode the sasndbox or the live moe to be used for the request
     *
     * @return void
     */
    public function setHttpClient($mode)
    {
        $baseUrl = $mode === self::MODE_LIVE ? self::BASE_URL : self::BASE_URL_SANDBOX;

        $this->client = new Client(
            [
                // Base URI is used with relative requests
                'base_uri' => $baseUrl,
                // You can set any number of default request options.
                'timeout'  => 0,
            ]
        );
    }

    /**
     * Sends a request to the given url.
     *
     * @param string $type    the type of the request
     * @param array  $options the array for payload or custom headers
     *
     * @return $response|PromiseInterface
     */
    public function sendRequest($type, $options = [])
    {
        //set the headers request
        $headers = [
            'Content-Type' => 'application/json',
            'token' => $this->getAuthToken()
        ];

        if ($type == self::REQUEST_POST) {
            //json encode the body params for the payload
            $body = json_encode($options);

            //initialize the request
            $request = new Request($type, self::TRANSACT_URL, $headers, $body);
        } else {
            //initialize the request
            $request = new Request($type, self::TRANSACT_URL, $headers);
        }
        //send request
        return $this->getHttpClient()->sendAsync($request);
    }


    /**
     * Sends the Refund request to the Transact API
     *
     * @return Request the guzzel requests object
     */
    public function openBatch()
    {
        
        $defaultOptions = array_merge(
            $this->getAuthenticationParams(),
            [
                "transactionRequest" => [
                    TransactParams::TRANSACTION_TYPE => self::TRANSACTION_TYPE_OPEN_BATCH
                ]
            ]
        );
        
        return $this->sendRequest(self::REQUEST_POST, $defaultOptions);
    }
}

Now the same code i.e using the GuzzelHttp\Pool that throws the listed exception above inside Yii1.1.14 if I extract that code in a simple .php file, that code works like a charm.

Note: this rules out the Yii extended component (IposTransact.php) and base component (Transact.php) and only involves the dejvoo-php client class Transact.php

<?php
require dirname(__FILE__) . DIRECTORY_SEPARATOR . 'vendor/autoload.php';

use b360\dejavoo\Transact;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Pool;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Response;
use Psr\Http\Message\ResponseInterface;

$merchants = [
    [
        "merchant_id" => "125852036987",
        "ipos_transact_token" => "THE_TOKEN"
    ],
    [
        "merchant_id" => "214523698741",
        "ipos_transact_token" => "THE_TOKEN"
    ]
];

$pool = sendOpenBatchRequest($merchants);
$pool->promise()->wait();

function sendOpenBatchRequest($merchants)
{
    $tpn = "124521452112";
    $token = "THE_TOKEN";

    $transact = new Transact($tpn, $token);
    

    $requests = function ($merchants) use (&$transact) {
        foreach ($merchants as $merchant) {
            yield function () use (&$merchant, &$transact) {
                return $transact->openBatch();
            };
        }
    };

    //pool the requests to make concurrent requests and get the responses via promise
    $pool = new Pool(
        $transact->getHttpClient(),
        $requests($merchants),
        [
            "concurrency" => 2,
            "fulfilled" => function (ResponseInterface $response) {
                //set the reesponse property
                
                $res = $response->getBody();
                echo $res;
            },
            "rejected" => function (RequestException $response) {
                echo "rejected";
            },
        ]
    );
    return $pool;
}

Any help or suggestions are welcome.

Regards,

Muhammad Omer Aslam

Upvotes: 0

Views: 18

Answers (0)

Related Questions