forrest icon indicating copy to clipboard operation
forrest copied to clipboard

"format => none" option doesn't work.

Open ShintaroNitta opened this issue 7 years ago • 7 comments
trafficstars

I was trying to get "Attachment.Body" as CSV file from Salesforce, but It returned NULL.

The following code is what I wrote then.

$url = 'https://foobar.salesforce.com/services/data/v43.0/sobjects/Attachment/00P5D000002UzJUUA0/body';
$res = Forrest::request($url, ['format' => 'none', 'method' => 'get']);
dd($res); // -> null

I think that the cause is "JsonFormatter" is used in default even though I specified format => none option.

ShintaroNitta avatar May 15 '18 01:05 ShintaroNitta

Hi Shintaro

Did you find a fix for this? i'm trying to download and store PDF's and are getting something very similiar

$response = \Forrest::sobjects('Attachment/00PD000001bxAz4MAE/Body', ['format'=> 'none']);
$content = (string) $response->getBody();

JoshReading avatar Jun 13 '18 08:06 JoshReading

I fixed it by overriding UserPassword and adding a method to get a Attachment.Body on Salesforce.

namespace App\Services\Forrest;

use GuzzleHttp\Exception\GuzzleException;
use Omniphx\Forrest\Authentications\UserPassword as BaseUserPassword;
use Psr\Http\Message\ResponseInterface;

/**
 * This class is to add a original method by overriding UserPassword class on Forrest.
 * @see https://github.com/omniphx/forrest
 */
class UserPassword extends BaseUserPassword
{

    /**
     * @param string $id Attachment.Id
     * @return ResponseInterface
     *
     * @throws GuzzleException
     */
    public function getAttachmentBody($id)
    {
        $url = $this->getBaseUrl() . sprintf('/sobjects/Attachment/%s/body', $id);

        $parameters = [
            'headers' => $this->formatter->setHeaders(),
        ];

        $response = $this->httpClient->request("get", $url, $parameters);

        $this->event->fire('forrest.response', json_encode([
            'url' => $url,
            'method' => 'get',
            'status_code' => $response->getStatusCode(),
            'body_size' => (string)$response->getBody()->getSize()
        ]));

        return $response;
    }

}

And overrode forrest in ServiceProvider.

<?php

namespace App\Providers;

use App\Services\Forrest\UserPassword;
use Omniphx\Forrest\Authentications\WebServer;
use Omniphx\Forrest\Formatters\JSONFormatter;
use Omniphx\Forrest\Providers\Laravel\ForrestServiceProvider as BaseServiceProvider;
use Omniphx\Forrest\Providers\Laravel\LaravelEncryptor;
use Omniphx\Forrest\Providers\Laravel\LaravelEvent;
use Omniphx\Forrest\Providers\Laravel\LaravelInput;
use Omniphx\Forrest\Repositories\InstanceURLRepository;
use Omniphx\Forrest\Repositories\RefreshTokenRepository;
use Omniphx\Forrest\Repositories\ResourceRepository;
use Omniphx\Forrest\Repositories\StateRepository;
use Omniphx\Forrest\Repositories\TokenRepository;
use Omniphx\Forrest\Repositories\VersionRepository;

class ForrestServiceProvider extends BaseServiceProvider
{

    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        $this->app->singleton('forrest', function ($app) {

            // Config options
            $settings           = config('forrest');
            $storageType        = config('forrest.storage.type');
            $authenticationType = config('forrest.authentication');

            // Dependencies
            $httpClient    = $this->getClient();
            $input     = new LaravelInput(app('request'));
            $event     = new LaravelEvent(app('events'));
            $encryptor = new LaravelEncryptor(app('encrypter'));
            $redirect  = $this->getRedirect();
            $storage   = $this->getStorage($storageType);

            $refreshTokenRepo = new RefreshTokenRepository($encryptor, $storage);
            $tokenRepo        = new TokenRepository($encryptor, $storage);
            $resourceRepo     = new ResourceRepository($storage);
            $versionRepo      = new VersionRepository($storage);
            $instanceURLRepo  = new InstanceURLRepository($tokenRepo, $settings);
            $stateRepo        = new StateRepository($storage);

            $formatter = new JSONFormatter($tokenRepo, $settings);

            switch ($authenticationType) {
                case 'WebServer':
                    $forrest = new WebServer(
                        $httpClient,
                        $encryptor,
                        $event,
                        $input,
                        $redirect,
                        $instanceURLRepo,
                        $refreshTokenRepo,
                        $resourceRepo,
                        $stateRepo,
                        $tokenRepo,
                        $versionRepo,
                        $formatter,
                        $settings);
                    break;
                case 'UserPassword':
                    $forrest = new UserPassword(
                        $httpClient,
                        $encryptor,
                        $event,
                        $input,
                        $redirect,
                        $instanceURLRepo,
                        $refreshTokenRepo,
                        $resourceRepo,
                        $stateRepo,
                        $tokenRepo,
                        $versionRepo,
                        $formatter,
                        $settings);
                    break;
                default:
                    $forrest = new WebServer(
                        $httpClient,
                        $encryptor,
                        $event,
                        $input,
                        $redirect,
                        $instanceURLRepo,
                        $refreshTokenRepo,
                        $resourceRepo,
                        $stateRepo,
                        $tokenRepo,
                        $versionRepo,
                        $formatter,
                        $settings);
                    break;
            }

            return $forrest;
        });
    }

}

You can get a Attachment.Body like this.

$body = Forrest::getAttachmentBody($attachment.Id);

ShintaroNitta avatar Jun 14 '18 04:06 ShintaroNitta

Thanks @ShintaroNitta

For anyone reading this the final steps are

Update your App.php to reference the new service provider

Omniphx\Forrest\Providers\Laravel\ForrestServiceProvider::class

To

App\Providers\ForrestServiceProvider::class

Then you can dump out raw data using

$content = \Forrest::getAttachmentBody('123123123123');
$content = $content->getBody();
dd($content);

JoshReading avatar Jun 14 '18 13:06 JoshReading

This seems to still be an issue @omniphx , the library doesn't seem to handle binary data coming back from a response.

jreeter avatar Sep 04 '19 22:09 jreeter

Hi @omniphx we're planning to dive into a fix for this on the latest version over the next couple of weeks.

If you or anyone else has preference for how it's addressed please let me know. Otherwise, we'll use our best judgement and circle back with a PR once we have something working.

kaypro4 avatar Jan 07 '20 21:01 kaypro4

@kaypro4 let me know if you have any questions/need help!

omniphx avatar Jan 08 '20 01:01 omniphx

The same approach works for ContentVersion as well for anyone stuck.


public function getContentVersionBody($id)
    {

        $url = $this->getBaseUrl() . sprintf('/sobjects/ContentVersion/%s/VersionData', $id);

        $parameters = [
            'headers' => $this->formatter->setHeaders(),
        ];

        $response = $this->httpClient->request("get", $url, $parameters);

        $this->event->fire('forrest.response', json_encode([
            'url' => $url,
            'method' => 'get',
            'status_code' => $response->getStatusCode(),
            'body_size' => (string)$response->getBody()->getSize()
        ]));

        return $response;
    }
    

zack-carlson avatar Jan 10 '23 17:01 zack-carlson