Jeremy
Jeremy

Reputation: 2536

PrestaShop API memory limit

I am using PrestaShop 1.5 and trying to make this API (webservice) call:

example.com/api/order_histories?schema=blank

However it returns the following error:

Fatal error: Allowed memory size of {some numbers} bytes exhausted (tried to allocate x bytes).

While invoking this URL:

http://example.com/api/categories?schema=blank

works just fine.

So I gradually increased my php.ini memory_limit parameter. Initially it was set to 32M, so I tried to bumped it up to 64M, 128M, until all the way up to 1024M. I also tried to set it up to 2048M, but since I only have 1GB RAM, 2048M will pretty much crash the server.

Before I am looking further into the code, I just want to know whether anyone else experience this kind of problem with PrestaShop (1.5.4), and if yes what was/is the solution?

Upvotes: 2

Views: 804

Answers (1)

Florian Lemaitre
Florian Lemaitre

Reputation: 5748

I had this problem before.

There's a bug in class WebserviceRequest which instantiate every object of this class to get a blank schema. So when calling a class like categories that contains a few entries there's no problem. But when calling a class like order_histories that contains thousands of entries it will load thousand objects in memory and crash.

But I can't remember which method was causing this bug. You should start debuging from method executeEntityGetAndHead and check if method getFilteredObjectList is called.


EDIT:

The method getFilteredObjectList has been updated on github:

public function getFilteredObjectList()
{
    $objects = array();
    $filters = $this->manageFilters();
    /* If we only need to display the synopsis, analyzing the first row is sufficient */
    if (isset($this->urlFragments['schema']) && in_array($this->urlFragments['schema'], array('blank', 'synopsis')))
        $filters = array('sql_join' => '', 'sql_filter' => '', 'sql_sort' => '', 'sql_limit' => ' LIMIT 1');

    $this->resourceConfiguration['retrieveData']['params'][] = $filters['sql_join'];
    $this->resourceConfiguration['retrieveData']['params'][] = $filters['sql_filter'];
    $this->resourceConfiguration['retrieveData']['params'][] = $filters['sql_sort'];
    $this->resourceConfiguration['retrieveData']['params'][] = $filters['sql_limit'];
    //list entities
    $tmp = new $this->resourceConfiguration['retrieveData']['className']();
    $sqlObjects = call_user_func_array(array($tmp, $this->resourceConfiguration['retrieveData']['retrieveMethod']), $this->resourceConfiguration['retrieveData']['params']);
    if ($sqlObjects)
    {
        foreach ($sqlObjects as $sqlObject)
        {
            if ($this->fieldsToDisplay == 'minimum')
            {
                $obj = new $this->resourceConfiguration['retrieveData']['className']();
                $obj->id = (int)$sqlObject[$this->resourceConfiguration['fields']['id']['sqlId']];
                $objects[] = $obj;
            }
            else
                $objects[] = new $this->resourceConfiguration['retrieveData']['className']((int)$sqlObject[$this->resourceConfiguration['fields']['id']['sqlId']]);
        }
        return $objects;
    }
}

With this modification, if we ask a blank schema a LIMIT 1 is added to the query so that only one object is loaded from database.

Upvotes: 2

Related Questions