# Troubleshooting

A compilation of common problems and ways to work around them.

# Recording does not work

You followed all the steps in the documentation and still, Ledger records are not being created?

# Query Builder vs. Eloquent

Bear in mind that this package relies on Eloquent events (opens new window) and if they don't fire, a Ledger won't be created.

The most common mistake is performing an update or delete operation using a Builder instance, instead of an Eloquent Model.

Using the Builder won't create a Ledger:

Article::where('id', $id)->update($data);

But using Eloquent will:

Article::find($id)->update($data);

# Testing and Command Line Interface

By default, Eloquent events fired from a CLI or Testing context, will not be recorded.

Refer to the Recording Contexts section for more details.

# Return value of Altek\Accountant\Resolvers\UserResolver::resolve() must be an instance of Altek\Accountant\Contracts\Identifiable or null

This means the User model being returned by the resolve() method doesn't implement the Identifiable interface.

Refer to the UserResolver documentation for more details.

# Ledgers without modified values are being recorded

A Ledger is more than just the modified property value.

There's other metadata like user_*, recordable_*, context, event, properties, extra, url, ip_address, user_agent, signature and pivot, which should be more than enough for accountability purposes.

Nevertheless, if such information isn't of use to retain, just register the following observer in the boot() method of the Ledger model:

static::creating(function (Ledger $model) {
    if (empty($model->modified)) {
        return false;
    }
});

CAVEAT

Keep in mind that the modified column of a retrieved and pivot events (toggled, synced, existingPivotUpdated,attached and detached), will always be empty!

# PHP Fatal error: Maximum function nesting level of '512' reached, aborting!

This might happen when a User model has the retrieved Eloquent event set as recordable and a retrieval happens.

It boils down to the following:

  1. A User record is retrieved from the database;
  2. Given the retrieved event is recordable, the recording process kicks in;
  3. During the data gathering phase for the new Ledger, the current user must be resolved for accountability purposes;
  4. The current User record is retrieved after being resolved;
  5. The previous step starts the process all over again from step 2, leading to an infinite cycle;

# Solution #1

The simplest way to avoid this, is to disable the retrieved event from being recordable on a User model:

<?php

declare(strict_types=1);

namespace App\Models;

use Altek\Accountant\Contracts\Identifiable;
use Altek\Accountant\Contracts\Recordable;
use Illuminate\Database\Eloquent\Model;

class User extends Model implements Identifiable, Recordable
{
    use \Altek\Accountant\Recordable;

    protected $recordableEvents = [
        'created',
        'updated',
        'restored',
        'deleted',
        'forceDeleted',
    ];

    /**
     * {@inheritdoc}
     */
    public function getIdentifier()
    {
        return $this->getKey();
    }

    // ...
}

# Solution #2

Another way to work around this, is to implement a UserResolver where the logic to fetch a User relies on the Illuminate\Database\Query\Builder, which doesn't fire events.

# IpAddressResolver incorrectly resolving IP addresses

This usually happens to applications running behind a load balancer (or proxy), in which the IP address of the load balancer/proxy is being returned, instead.

Refer to the IP Address Resolver section for a workaround.

# Unable to encode attribute [properties] for model [Altek\Accountant\Models\Ledger]

This error will happen when creating a Ledger with one or more binary properties.

In order to solve this, you should use the Base64 cipher.