mneuhaus / Famelo.Features

3 stars 2 forks source link

Enable features based on third-party objects #2

Closed andreaswolf closed 10 years ago

andreaswolf commented 11 years ago

I need to enable features based on one of my domain objects, namely a "Contract" object. Each user has a contract object assigned (through another relation, but that doesn't matter here). These contracts have some features which can be enabled/disabled, based on e.g. what the client pays for the contract.

Integrating these third-party objects would in my eyes require a pluggable feature definition in the feature service - it should query several "feature sources" when trying to find a feature with a matching name. Therefore, the definition of a feature should be extended a bit and probably be provided as an interface one can implement in their package. In fact, the code that was removed in the "big refactoring" a few days ago probably already came quite close to what I want.

mneuhaus commented 11 years ago

i think you can do this now already:

  1. Create a new ConditionMatcher extending from \Famelo\Features\Core\ConditionMatcher
<?php
namespace My\Package\Features;

class ConditionMatcher extends \Famelo\Features\Core\ConditionMatcher {

        /**
         * The securityContext
         *
         * @var \TYPO3\Flow\Security\Context
         * @Flow\Inject
         */
        protected $securityContext;

        /**
         * @return boolean
         * @api
         */
        public function hasSomeContractFeatureEnabled() {
                return $this->securityContext->getParty()->getContract->hasSomeFeatureEnabled();
        }

}
?>
  1. Tell the FeatureService to use your ConditionMatcher instead of the default:
Famelo:
  Features:
    # You can change this setting to use your own ConditionMatcher with more specific functions
    # you might need
    conditionMatcher: \My\Package\Features\ConditionMatcher

I think this should cover that usecase. i am a bit hesitant to increase the complexity of the featureService because of performance reason.

andreaswolf commented 11 years ago

Yeah, it will cover the usecase for extending with one package. But having custom matchers in different packages will not work.

I would not be too worried about performance, the information could easily be cached for multiple requests on a per-user base, so it has to be calculated only once.

mneuhaus commented 11 years ago

then we should go for an getAllImplementationClassNames based implementation that lazyInstanciates those on request:

basic interface

interface ConditionMatcher {
    /**
      * returns a short name for this matcher used for reference in the eel expression
      */
    public function getShortName();
}

example implementation

class FooMatcher implements ConditionMatcher {
    public function getShortName() { return 'foo'; }

    public function isSomeConditionTrue($bar) {...}
}

example usage

condition: foo.isSomeConditionTrue('asd')

the variable "foo" in the condition is lazily instanciated by the default ConditionMatcher and is simply an instance of the FooMatcher

what do you think about this implementation?

simonschaufi commented 10 years ago

I am also interested in a nice solution here!

mneuhaus commented 10 years ago

ok. will try to implement this sometime this/next week :)

mneuhaus commented 10 years ago

hey, sorry, didn't get to it yet :( loaded with works as always :/

mneuhaus commented 10 years ago

finally came around to it :)

See: https://github.com/mneuhaus/Famelo.Features#additional-conditionmatchers for info on how to use it :)