Code Monkey home page Code Monkey logo

Comments (6)

SvenRtbg avatar SvenRtbg commented on June 3, 2024 1

I'm sorry for not replying earlier. Your suggestions do work nicely, but I wasn't able to look into the 3.0 release. Will come back with any issues if I encounter them.

from laminas-cache.

SvenRtbg avatar SvenRtbg commented on June 3, 2024 1

Just coming back reporting that 3.0 (or more precisely 3.1 now) behave exactly as stated above. Thanks again.

from laminas-cache.

boesing avatar boesing commented on June 3, 2024

@SvenRtbg You can always create all the instances by yourself using constructor injection.

As per design, v3 will and can never now which storage adapters are in upstream projects without populating them to the AdapterPluginManager. This will work automagically in laminas-mvc and mezzio projects.

Could you please provide more informations on how you are using StorageFactory or PatternFactory as of today so we can find a solution?

Happy to help here so you don't have to require plenty of dependencies you wont use otherwise.

from laminas-cache.

SvenRtbg avatar SvenRtbg commented on June 3, 2024

I'll add more details if necessary on Monday, but for the time being:

I am using the ObjectCache pattern in my libraries. The library defines an interface, I have an implementation for it, and then I have another implementation extends ObjectCache that implements all methods and simply does a forwarding to the call() method with method name and parameters. That way I can strictly separate concerns: One class does the real thing, the other only does caching.

This setup requires a bit of configuration, so I add the original class into the cache class to do the real work, and I have to add a storage adapter. I create that storage adapter effectively by the static call to StorageFactory in order to create either a file storage or a memcache storage - that's what my storage factory lib is doing: Pulling in configuration, calling the Laminas factory, returning the storage object.

The library factory is passing it into the caching instance together with additional config to get it into a use case specific state (that's where the real strength in Laminas Cache is: Ability to add about any custom code to influence the caching workflow if necessary - I liked it when it was called Zend Cache ;) ).

So the task I am facing right now: How would I instantiate a StorageAdapterFactory? I was looking at the 2.12.1 code base, btw.

Investigating with the 3.0.x branch:
public function __construct(\Laminas\ServiceManager\PluginManagerInterface $adapters, \Laminas\Cache\Service \StoragePluginFactoryInterface $pluginFactory)

Requires the StoragePluginFactory:
public function __construct(\Laminas\ServiceManager\PluginManagerInterface $plugins)

And both require the ServiceManagers PluginManagerInterface implementation, which is an abstract class, so there is a local implementation here: Laminas\Cache\Storage\PluginManager. No constructor, so am I fine? Unfortunately, not, because the Laminas\ServiceManager\AbstractPluginManager requires some very unspecific configuration arrays.
public function __construct($configInstanceOrParentLocator = null, array $config = [])

And that's where I am stuck. I will be perfectly able to "just" push all these instances into each other until this particular step.

And maybe I am already missing something until here, e.g. the two PluginManagerInterface instances not being the same object. If so, the configuration problem has just doubled (or maybe it exists as a whole from the start, and I'd just have to decide which parts go where).

Anyways: Happy to have your help here to understand things better! :)

from laminas-cache.

boesing avatar boesing commented on June 3, 2024

@SvenRtbg As far as I can see, laminas/laminas-servicemanager is a requirement of laminas/laminas-cache and thus, its already part of your application unless you are replacing it via composer.json to get rid of it.


And maybe I am already missing something until here, e.g. the two PluginManagerInterface instances not being the same object.

Exactly, in the laminas-servicemanager world, "plugin managers" are containers which only return instances of ONE specific type. So there is a plugin manager for storage adapters (AdapterPluginManager) and a plugin manager for storage plugins (PluginManager). Both plugin managers return different types of instances, e.g. StorageInterface or PluginInterface.


So one solution for you could be to replace the StorageFactory with a static factory created by yourself. Something like this might work out of the box if you only have Memory and Filesystem adapters.

class YourOwnStorageFactory
{
    /**
     * @var StorageAdapterFactoryInterface|null
     */
    private static $storageAdapterFactory;
    
    public static function factory(array $config): StorageInterface
    {
        $storageFactory = self::storageAdapterFactorySingleton();
        return $storageFactory->createFromArrayConfiguration($config);
    }

    /**
     * Singletons are considered bad, for more about this topic read this article
     * https://www.michaelsafyan.com/tech/design/patterns/singleton
     * But as you don't use dependency injection, thats actually a way to restore `StorageFactory` behavior as it was done
     * in laminas-cache v2.
     */
    private static function storageAdapterFactorySingleton(): StorageAdapterFactoryInterface
    {
        if (self::$storageAdapterFactory) {
            return self::$storageAdapterFactory;
        }
        
        $config = array_merge_recursive(
            (new \Laminas\Cache\ConfigProvider())(),
            // Starting with v3 you will have to uncomment these
            // (new \Laminas\Cache\Storage\Adapter\Memory\ConfigProvider())(),
            // (new \Laminas\Cache\Storage\Adapter\Filesystem\ConfigProvider())(),
        );
        
        $containerConfiguration = $config['dependencies'] ?? [];
        
        $container = new ServiceManager($containerConfiguration);
        return self::$storageAdapterFactory = $container->get(StorageAdapterFactoryInterface::class);
    }
}

The reason why YOU have to create this static factory is, that only YOU know what adapters your project requires and which not. Thats the main idea behind the changes regarding laminas-cache v3. There are plenty of upstream projects out there which do not use redis or memcached or apcu or mongo DB as a storage backend. And to not enforce them to install these (as done since v1 of this component), satellite packages were introduced.


If you only use the ObjectCache pattern, just instantiate it by yourself where necessary. The current PatternFactory does not work with the new requirements of v3 (e.g. require StorageInterface as constructor dependency) and thus, there is no way to have a generic factory around as some patterns require the StorageInterface while others dont.

So wherever you need the ObjectCache or your own implementation of ObjectCache (however you decide to either pick laminas pattern or your own), you just can manually instantiate it with new ObjectCache($storage) rather than PatternFactory::factory(ObjectCache::class, ['storage' => $storage|);.


If you have any other questions, feel free to drop them here. Please keep in mind that if you want to use StorageAdapterFactoryInterface, your configuration needs to be normalized as there were multiple configuration array structures allowed in the StorageFactory::factory.

https://docs.laminas.dev/laminas-cache/storage/adapter/#quick-start

from laminas-cache.

boesing avatar boesing commented on June 3, 2024

I am closing here as I think I've provided some examples which enable projects which do use laminas-cache standalone without any dependency injection. Directly instantiating cache adapters is still possible, dependency injection is only suggested if you want to use config-driven adapters. If you do use config-driven adapters, you can write your own adapter factory for that decorator you want to use.
Static factories will no longer be supported due to the reasons mentioned above.

If you have any problems during the migration to laminas-cache v3 (which was released last week), please let us know in a dedicated issue so we can see how to solve specific problems more accurately.

from laminas-cache.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.