Symfony2: inject security context into model classes - symfony

I have propel classes that implement the preSave method. This is a hook where some fields can be automatically updated at each saving operation. This is needed in order to save the date of last update and the user of the last update.
The problem is that the model classes have no access to the service container, where I can get the user id (to set into the last update user field). Model classes cannot (at my knownledge) be declared as service, as these are kind of entities, instancied by propel itself and not by the service container.
The only solution I see is to have a "real" singleton (with a static instance) holding the user object, that I would instanciate during the bootstrap of the application, then any model class could access it.
Any better idea?

For anyone having the same propel, the given bundle only adds the EventDispatchor behavior to Propel, which means that you can manage propel events in the same as Symfony does, but it is separated from the Symfony container (it seams it is using it own container).
But glorpen/propel-bundle is doing this job very well, you can really define service that listen to Propel events, using simple tags.

Related

How to use EventSubscriber in TYPO3 e.g. for symfony/workflow events?

How is it possible to use Symfony\Component\EventDispatcher\EventSubscriberInterface to implement a subscriber-class, listening for events dispatched by TYPO3s PSR-14 EventDispatcher?
Let's see an example by using symfony/workflow for a TYPO3 extension, which works great until it comes to events. Because of typo3/symfony-psr-event-dispatcher-adapter, the TYPO3 default EventDispatcher can be smoothly added to the Workflow class. So far so good.
Now I've several problems:
Problem 1: The event-names such as 'workflow.myname.leave'
The events dispatched by Workflow using a string name, instead of a FQCN like all other events dispatched in the TYPO3 life-cycle. This makes it impossible to use the common way of EventListeners registered inside the services.yaml, because the configuration requires a FQCN of the event-class.
# this will not work because the "event" needs to be a FQCN
Vendor\MyExt\EventListener\MyWorkflowEventListener:
tags:
- name: event.listener
identifier: 'vendor-myext/MyWorkflowEventListener'
event: 'workflow.myname.leave'
method: 'onLeave'
Problem 2: Trying to use an EventSubscriber
The doc recomments an EventSubscriber. IMO using an EventSubscriber (Symfony\Component\EventDispatcher\EventSubscriberInterface) would also solve problem #1, because the configuration of events is defined as key-value array inside getSubscribedEvents(). (BTW this seems to be also much easier for lots of events like in this case of workflow-events, because one class can be responsible handling multiple "similar" events and will not mess-up the services.yaml).
Also the Symfony doc says, that implementing this interface while autowire and autoconfigure is set to true will be enough; the EventSubscriber should be available and listening. Maybe this is true in a plain Symfony environment, but it seems not in a context of TYPO3. Unfortunately I can't figure out why (the subscriber classes doesn't show up inside EventDispatcher->ListenerProvider->listeners array).
How to continue here?
The TYPO3 core EventDispatcher is not able to handle or register Subscribers (yet). So for now I ended up using the Symfony\Component\EventDispatcher\EventDispatcher in parallel to the TYPO3 default one. The Symfony EventDispatcher handles only the workflow-events in this case. It feels not as clean as I'd like to, but it works.

Symfony event vs service

Hi I have a question about symfony application architecture,
In my application I create different user, but when a user is created, updated, deleted, or his picture change, I need to do some action.
What is the best way to do this ? I excluded to do this on a controller action. There is 2 others solutions :
Create differents events like user.created, user.updated, ... And dispatch it on the controller action and make different listener to do the different action like MailListener (for user.created) TaskListener (for user.created) for add a task.
Use a service like UserManager and on this service have a method like userCreated() and on this method call differents actions like sendMailOnCreated, addTaskOnCreated for example.
For you what is the best method ?
For me, your first solution is the best one. It's clearly a use case for the Event component. It will be easier to maintain and more readable.
Moreover, if you need to add more listener you just need to create another one and bind it to your event. You don't need to modify your controller anymore.

Accessing Symfony2 global parameter in entity class

I have a value stored in my parameters.ini file, and I need to access it during the prepersist method of my model.
Normally I use $this->container->getParameter('value');, but the container is not available in the entity.
Is there a way to get parameters within an entity class?
P.S. The value is an API key for a service I am pulling info from during prepersist. Best practice is to keep keys/passwords in parameters.ini
Best practice is to use a service to persist your entity. This one would inject the container and set your parameter when you call your updateMyEntity() service method.
Inside your controller (or whatever you want):
$user = new User('foo');
$user->setSomeProperty('bar');
$userService->update($user);
Inside the UserService:
public function update(User $user) {
$user->setSomeParameter($this->container->getParameter('value'));
$this->em->persist($user);
}
In addition to Florent's answer, Entities are meant to be purely data objects. They should not know about any other variables or services within your application. I'm more curious about why your entity needs to know anything about an API key that is system-wide. With very little background information, I'd say you should rethink what you are trying to do.
You need a service to interact with the API, ideally configured through the container. I don't see what that has to do with an entity.

Where should I instantiate the Entity Framework's ObjectContext in a 3-tier applicaiton

I have a 3-tier web application wit ha bunch of simple forms. One to list records, one to edit a single record, etc. The works.
I have a DataLayer where my EDMX is.
I have an App Layer where my POCOs are.
I haev a BusinessLayer with all my controller classes, etc. (not MVC!)
I have a UI layer where my web UI is.
The EDMX has many, many tables wit ha lot of navigation properties.
Of course, when I fetch the data in one of my controllers, e.g. GetCustomerById(int id), I create the Object context and close it when I'm done.
However, the ObjectContext is out of scope when I try to access the navigation properties in the UI layer.
Should I do (using MyContext = new MyContext()) {... } in the web layer?? that does not seem right.
Should I create another set of POCOs that I populate from the entities' data from the BizLayer?
What happens when I want to save data entered in a web form? Would I call a BizLayer controller e.g. SaveCustomer()?
My question is, how do you design the web UI layer if I want to be able to properly access the navigation properties of an entity?
Note:
EDMX is set to LazyLoading.
You want to use lazy loading in UI but it means that UI defines lifetime of your ObjectContext. There are many ways to achieve this without exposing the context to UI. You can for example use this simple approach:
You mentioned some controller which uses context and disposes it. So make your controller disposable and instead of disposing context in every method use single context for whole lifetime of the controller. Dispose the context in controller's Dispose method.
Instantiate your controller per request. So for example you can create instance of controller in Page.Load and dispose it in Page.Unload.
Use your controller and entities as you want. Whole processing of the request (between Load and Unload) will be in scope of single living context.
Anyway you should not need lazy loading in Web application too much. In your form you usually know exactly what entities you need so you should request them directly with eager loading.

Does Prism/Unity have a "service preloader"?

I've got a number of modules in a Prism application which load data that takes 3-8 seconds to get from a service.
I would like to be able to say in my bootstrapper something like this:
PSEUDO-CODE:
Customers allCustomers = Preloader(Models.GetAllCustomers);
And this would run in a background thread and when the user actually needs the variable "allCustomers" it would be fully loaded.
Is there an automatic service in Prism/Unity which does this type of preloading?
No, there is not.
However...
What you can consider is adding your ViewModel with a ContainerControlledLifetime to the container in your ConfigureContainer method that the views can use. You'd kickoff your threaded request in the constructor of your ViewModel and allow Views to pull this ViewModel out of the Container.
Even if they grab the ViewModel out of the container before the GetAllCustomers method is done firing, they will be notified correctly if the property you store the customers in implements INotifyPropertyChanged correctly.
If it was more appropriate, you could also do this from the Modules (in the Initialize method), rather than in the bootstrapper (for instance, if your Module was what actually knew about your Customer's Model).

Resources