stephpy/timeline-bundle

Spread only to array of users/groups

Closed this issue · 19 comments

Hi

Great bundle. Just wondering if it is possible to restrict which spread to use on deployment and if it is possible to parse parameters to a spread (e.g. an array of users to be notified about a specific action)?

Currently, I have a friend spread (i.e. everyone following the user) and a group spread (ie.e everyone the user shares a group with) so all user actions are visible to everyone they are friends with or in a group with.

However, sometimes we need to share information ONLY with certain individuals or select groups, not to everyone (e.g. an invitation to a private event).

Is it possible to create an action that only spreads to an array of users or groups?

I take this approach

public function supports(ActionInterface $action)
{

    $verbAllowed = in_array($action->getVerb(), $this->getAllowedVerbs());
    return ($verbAllowed && $action->getComponent('directComplement')) ? true : false;

}

public function getAllowedVerbs() {

    $allowedVerbs = array(
        "my_verb"
        );

    return $allowedVerbs;

}

Hi, thanks.

Yes, you can create as many spread as you want. As @thomask explained, you can create a Spread class for only ONE VERB (or action) and decide to have a different strategy than other verbs.

Imagine you have 100 verbs:

- private_call (deploy to X user)
- call (deploy to all)
- etc... (deploy to all)

You'll have to create 2 spreads class:

  • One which supports action with verb private_call
  • One which supports actions with other verbs ...

One more thing, if you have the same timeline for a group, you can deploy to a group, and then, get timeline by this way:

$subject  = $actionManager->findOrCreateComponent('Acme\Entity\Group', 1);
$timeline = $timelineManager->getTimeline($subject);

You aren't limited by the component ...

Do i answered correctly to your question ?

Thanks for your quick response but I'm not sure that I understand what you are proposing. Please bear with me!

Most of the time, I want actions to be deployed to all spreads (e.g. someone joins a group) but sometimes I want to be able to define specifically who an action is spread to (and no-one else).

For example, in my app a person can create a private group or event to which people are invited to attend. In such cases, I only want to spread the invitation to people who are specifically invited to the event. I don't want to spread to other people who are not invited (e.g. my generic Friends and Groups spreads).

Does that make sense? Is that possible? I don't see how I can associate verbs with arrays of people, which will change frequently.

Again, thanks for the quick response.

Sure, it's possible.

Verbs related to an event or private group must be recognizable, imagine we have:

$privateVerbs = array('event_comment', 'event_set_presence', 'accepts_event_invitation');
$publicVerbs  = array('accepts_friend_invitation');

You'll have TWO spreads class:

  • one which supports in_array($action->getVerb(), $privateVerbs) and will get all users of the event to spread to them.
  • one which supports !in_array($action->getVerb(), $privateVerbs) and will spread to everybody.

See documentation to create a spread

Via Dependency Injection, you can easily inject you Storage manager (doctrine.orm.entity_manager, doctrine.odm.entity_manager, etc...) and gets all users which have to be spread in each spread classes.

Thanks again for the quick responses. You've given me some great insight into how I can use this bundle better but I don't think this solves my specific issue, unless there is something I am missing??

Here's an overview of how our application works:

  • Groups and events are not predefined - many thousands of events and groups are created each day.
  • Users can create and join unlimited number of private or public groups
  • Users can create and join an unlimited number of private or public events
  • Currently, we only have a small number of verbs associated with actions (e.g. Join, follow, invite)

Here an example scenario:

  • User A has 10 friends - Friend1, Friend2, Friend3 etc
  • User A is in 3 groups - Group 1, Group2, Group 3
  • User 1 creates a number of different events each week and needs to invite different combinations of people and groups to each event.
  • On one day, User A creates a private event and invites Friend1, Friend3 and all members of Group2 - I need to spread the invitation to the timeline of only to Friend1, Friend3 and Group2 and not anyone else.
  • The next day, User A create another private event and invites Friend4 and Friend5 only - on this occasion I need to spread the invitation only to these two users.

So, the way our system works, we don't (and can't) limit people to joining predefined groups or events - each of the thousands of groups and events that are created would need a "distinct" verb and spread.

I guess the closest analogy, is that we need to spread private messages to individual users' timelines.

Is this possible with the bundle?

Again, many thanks for your help.

Hi, I didn't understand this point.

So, you can EASILY do this:

Creation of the action

$actionManager = $this->get('spy_timeline.action_manager');
$subject       = $actionManager->findOrCreateComponent('Acme\User', 1);

// note the $group here 
$action = $actionManager->create($subject, 'invite', array('user' => $secondUser, 'group' => $group));
$actionManager->updateAction($action);

Spread:

class PrivateGroupSpread implements SpreadInterface 
{
     public function supports(ActionInterface $action) 
     {
         // $action->getComponent('group') will return an instance of Spy\TimelineBundle\Entity\Component which has the entity injected in his `data` property.
         return $action->hasComponent('group') && $action->getComponent('group')->getData()->isPrivate();
     }

     public function process(ActionInterface $action, EntryCollection $coll)
     {
          // fetch all users associated to this group and deploy to them
     }
}

Then, you could create a spread for PrivateEvents and a “Public“ spread. :)

Do i answered correctly to your question ?

Ah yes, I believe you have clarified things. It's obvious now what I need to do,.

As you suggest:

  1. Create private spreads using private verbs or characteristics (e.g private groups group) that only spread to the $subjects
  2. Create public spreads for public actions or characteristics that spread to the $subjects graph.

Many thanks for you help!

Merci

Yep, that's it ! :)

You're welcome ;)

Thanks for your help. I've implemented this throughout my app and can send private notifications no problem. However, I have another quick question if you would be so kind. How can I access global twig variables (ie app.user) in the components.html.twig? For example, when the authenticated user is the subject or Direct complement I want to display "You" rather than "value.fullname" When I originally implemented the bundle I had a work around for this but I can no longer use it. Many thanks.

You can access to global twig variables on twig verbs files, i thought we can access them too into components.html.twig but i never tested it :\

It's weird ... i thought twig inject theses variables into each twig templates.

I'm sorry, i can't help you right now on this point, if i found time, i'll look at this asap.

I can confirm that I cannot access any global variables in components.html.twig.

I'll have a look at modifying the verbs but its messy.

Thanks.

Did you try to include components file manually in twig files instead of defined it in config ?

You'll be able to do this:

{% include "AcmeFooBundle:Bar:components.html.twig" with {"app": app } %}

I create a new issue to look at this point later, i guess we could inject theses global variables into the components files.

I ended up creating some override templates for each component that is rendered in the verb files. It works fine. Thanks.

👍

Hello stephpy
A great and very helpful bundle ;)

Hello mpclarkson,
I have the same problem as you, i need to acess some global variables in my components.html.twig, could you please tell me in details what is the solution that you have implemented to solve this problem please?
Thank you.

This will be fixed soon I hope ;)
#135

@abenmoussa As @stephpy said you should be able to inject the twig globals you need like this {% include "AcmeFooBundle:Bar:components.html.twig" with {"app": app } %} However, I ended up not using the templates. It was too complex to manage, as we have a lot of different ways of viewing the same components based on a range of conditions, so we just build the display in the individual verb files, where you can access all twig globals. It is indeed a great bundle, I would just love to be able to aggregate actions (e.g. User A and 2 others did XYZ) in timelines. :)

Thanks to @Miliooo, it's ok: #135

👏 👏