Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: Implement PSR-6 compliant caching mechanism #288

Open
Xesau opened this issue Sep 19, 2023 · 0 comments
Open

Feature request: Implement PSR-6 compliant caching mechanism #288

Xesau opened this issue Sep 19, 2023 · 0 comments

Comments

@Xesau
Copy link
Contributor

Xesau commented Sep 19, 2023

Results from the Moneybird API are easily cacheable because of the synchronization API and because most (all?) entities have a version attribute. It would therefore make sense to integrate support for a PSR-6 compatible cache into this package to speed up queries and prevent users from making too many requests to the API.

Preferable, the user could specify a prefix for the cache key.

This would require the following work to be done:

  • Adding version to the attribute list of all entities that support synchronization.
  • Checking if all entities that support synchronization actally use the Synchronize trait.
  • Updating the getAll() method to load items from and save items to the cache if the entity supports synchronization.

Currently, it is possible to implement something similar using the following code. However, this requires modifying the output of the ->attributes() method, which does not return raw data that can cached and used with ->collectionFromResult(...) later.

<?php

namespace App\Service;

use Picqer\Financials\Moneybird\Moneybird;
use Psr\Cache\CacheItemPoolInterface;

class MoneybirdCache
{

    public function __construct(
        private readonly Moneybird $moneybird,
        private readonly CacheItemPoolInterface $cache
    ) {}

    public function getAll(string $type, array $filters): array
    {
        $results = [];

        $repository = $this->moneybird->$type();
        $versions = $repository->listVersions($filters);
        $idsToFetch = [];
        foreach ($versions as $version)
        {
            $versionCacheItem = $this->cache->getItem('moneybird.'. $type .'.'. $version->id);
            if ($versionCacheItem->isHit())
            {
                $cacheResult = $versionCacheItem->get();
                if ($cacheResult['version'] == $version->version)
                {
                    $results[] = $cacheResult;
                    continue;
                }
            }
            $idsToFetch[] = $version->id;
        }

        $results = $repository->collectionFromResult($results);

        for ($i = 0; $i < count($idsToFetch); $i += 100)
        {
            $fetchedObjects = $repository->getVersions(array_slice($idsToFetch, $i, 100, false));

            foreach ($fetchedObjects as $object)
            {
                $results[] = $object;
                $versionCacheItem = $this->cache->getItem('moneybird.'. $type .'.'. $object->id);

                $attributes = self::normalizeAttributes($object->attributes());

                $versionCacheItem->set($attributes);
                $this->cache->save($versionCacheItem);
            }
        }

        return $results;
    }

    private static function normalizeAttributes(array $attributes): array
    {
        $normalizedAttributes = [];

        foreach ($attributes as $key => $value)
        {
            if (is_scalar($value))
            {
                $normalizedAttributes[$key] = $value;
            }
            elseif (is_array($value))
            {
                $normalizedAttributes[$key] = self::normalizeAttributes($value);
            }
            elseif ($value instanceof Model)
            {
                $normalizedAttributes[$key] = $value->attributes();
            }
        }

        return $normalizedAttributes;
    }

}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

1 participant