stephpy/timeline-bundle

Create new driver services to be consumed by managers

Closed this issue · 13 comments

There is a bunch of redundancy between the ActionManager and the Provider with the new ORM provider.

I'm proposing creating a new service level to abstract the storage specific configuration & options called 'drivers'. This would require the following changes…

Remove:

  • Dynamic defintions of highco.timeline_action_manager.*
  • Provider classeshighco.timeline.provider.*

Add:

  • Drivers
    • highco.timeline.drivers.doctrine.orm with an object manager dependency (defaulting to doctrine.orm.entity_manager
    • highco.timeline.drivers.redis with a service dependency on snc_redis.default_client
  • Managers
    • highco.timeline.action_manager.orm
      • Depends on highco.timeline.driver.orm for persistence
    • highco.timeline.action_manager.redis
      • Depends on highco.timeline.driver.redis for persistence
    • highco.timeline.timeline_manager.orm
      • Depends on highco.timeline.driver.orm for persistence
    • highco.timeline.timeline_manager.redis
      • Depends on highco.timeline.driver.redis for persistence
  • Aliases
    • highco.timeline.timeline_manager as alias to chosen service from above

Redefine:

  • highco.timeline.action_manager as alias to chosen service from above
  • highco.timeline.spread.deployer to depend on highco.timeline.timeline_manager
  • highco.timeline.unread_notifications to depend on highco.timeline.timeline_manager

This would also support the introduction of a component manager as discussed in #35.

Another issue for 2.0

Possible configuration refactoring to support above:

highco_timeline:
  classes:
    timeline: 'Acme\YourBundle\Entity\Timeline'
    action: 'Acme\YourBundle\Entity\Action'
    component: 'Acme\YourBundle\Entity\Component'
    action_component: 'Acme\YourBundle\Entity\ActionComponent'  # bundle might not need to know this

  drivers:
    orm:
      object_manager: ~   # doctrine.orm.entity_manager
    redis:
      service: ~          # snc_redis.default_client

  action_manager: highco.timeline.action_manager.orm        # or user provided
  component_manager: highco.timeline.component_manager.orm  # or user provided
  timeline_manager: highco.timeline.timeline_manager.orm    # or user provided

  notifiers: [ highco.timeline.unread_notifications ]

  filters:
    - highco.timeline.filter.duplicate_key
    - highco.timeline.filter.data_hydrator

  spread:
    on_me: true               # Spread each action on subject too
    on_global_context: true   # Spread automatically on global context
    deployer: highco.timeline.spread.deployer
    delvery: immediate

  render:
      path:     'AcmeBundle:Timeline'
      fallback: 'AcmeBundle:Timeline:default.html.twig'
      i18n: #Do you want to use i18n when rendering ? if not, remove this node.
          fallback: en
      resources: []    # Always prepends 'HighcoTimelineBundle:Action:components.html.twig'

Mmmh issue here is than we cannot use Doctrine ORM/ODM to store Action, Component & co and store Timelines on Redis. In 1.x it's possible. I think to something like that:

highco_timeline:
  classes:
    timeline: 'Acme\YourBundle\Entity\Timeline'
    action: 'Acme\YourBundle\Entity\Action'
    component: 'Acme\YourBundle\Entity\Component'
    action_component: 'Acme\YourBundle\Entity\ActionComponent'  # bundle might not need to know this

  drivers: #define drivers
    orm:
      object_manager: ~   # doctrine.orm.entity_manager
    redis:
      service: ~          # snc_redis.default_client

  # ++++++++++++++
  storage:
    driver: orm
  # ++++++++++++++

  action_manager: highco.timeline.action_manager.orm        # or user provided
  component_manager: highco.timeline.component_manager.orm  # or user provided
  timeline_manager: highco.timeline.timeline_manager.orm    # or user provided

  notifiers: [ highco.timeline.unread_notifications ]

  filters:
    - highco.timeline.filter.duplicate_key
    - highco.timeline.filter.data_hydrator

  spread:
    # ++++++++++++++
    driver: orm
    on_subject: true               # on_subject instead of on_me.
    # ++++++++++++++
    on_global_context: true   # Spread automatically on global context
    deployer: highco.timeline.spread.deployer
    delvery: immediate

  render:
      path:     'AcmeBundle:Timeline'
      fallback: 'AcmeBundle:Timeline:default.html.twig'
      i18n: #Do you want to use i18n when rendering ? if not, remove this node.
          fallback: en
      resources: []    # Always prepends 'HighcoTimelineBundle:Action:components.html.twig'

One more thing, why don't use many bundles ?

  • TimelineBundle (root)
  • TimelineDoctrineORMDriverBundle
  • TimelineDoctrineODMDriverBundle
  • TimelineRedisDriverTimelineBundle
  • etc ...

It'll be easy to improve each drivers and user'll have to install only his needs.

And BTW, we could create an organisation, it'll be more convenient.

In my proposal, storing timeline on Redis would be implemented through:

highco_timeline:
    timeline_manager: highco.timeline.timeline_manager.redis

Which would essentially be a refactoring of highco.timeline.provider.redis. The spread deployer would be configured to use the highco.timeline.timeline_manager alias, and be ignorant of the storage mechanism.

Did I miss something?

Re: separate bundles:

Hmmm, It seems like an unnecessary level of abstraction & overhead. Once implemented will the drivers really change that often?

Re: In my proposal, ..etc...

You're right, we could set alias for our "core" manager, it would be easier

highco_timeline:
....
  drivers: #define drivers
    orm:
      object_manager: ~   # doctrine.orm.entity_manager
    redis:
      service: ~          # snc_redis.default_client

  action_manager: orm
  component_manager: orm
  timeline_manager: redis 
....

Re: separate bundles:

I took for example SonataAdmin, and yes, it's may be an unuseful layer, leave it as is.

I would recommend keeping the _manager keys as direct references to driver-specific managers (highco.timeline.action_manager.orm etc) to allow users to override/extend stock managers as they see fit.

Also, I'm not a huge fan of the Sonata way of doing things.

fixed on #54

I noticed you have chosen to go with distinct storage-specific managers Spy\Drivers\ORM\ActionManager, rather than abstracting the storage access into an abstract layer. Was it not possible to have generic managers working on a common driver api?

Yes, we should use Abstract ActionManager when we have support for ORM and ODM. ODM support will be implemented soon, we could add theses Abstract manager during this implementation ?

If you want to address it to an issue, i think we should create a new. :)

Perhaps I need to review the new code.