Event logging in Symfony2 - symfony

We would like to keep track of all user specific actions regarding the database, e.g. changing the username, getting assigned to a company and so on.
Is there any Symfony bundle that supports this kind of history logging?

doctrine offers some extensions like timestampable, blameable....
look here : http://symfony.com/en/doc/current/cookbook/doctrine/common_extensions.html
Every time an entity changes, it must have 'updatedBy' 'updatedAt' field....
(edit : excuse, i changed , first link was in french)

Related

Dynamic Access Control for entities in symfony 4

I try to manage the access rights for users to edit or view different articles.
Articles can be created dynamically and the rights should be editable for every article.
In my case, I have a User object and multiple other objects (Article, and more...).
I need to check if a User can read or write any kind of object.
I actually see there is a method Voters, but they only can manage User groups?
Can somebody help me?
A Voter can decide almost anything - usually it's based on a user's permission, but it doesn't have to be - I've used one as a 'feature flag' check, with a value fetched from a configuration, or database entry to show something - or not, as an example.
The page on voters has an example on viewing, or editing a database record (a Post entity, via a $this->denyAccessUnlessGranted('edit', $post);.
In your instance, the voter would be passed the 'attribute', the object (Article, etc) you want to check on, and gets the current user from a service. If that user has the appropriate permission to read/edit/delete the Article or other object, it returns true.

Keep two different versions of an entity in Doctrine ORM

I'm working on a Symfony4/Doctrine/MySQL project with the following requirement:
Users can create entities (say posts) that are visible in the public frontend only after approval by an admin
When a user edits his post after approval/publication, the changed post needs to be approved again before the changes will become visible in the frontend. But while approval is pending the old approved version of the post must remain visible in the frontend.
This means I have to keep two versions of every "Post" entity: the approved version for the frontend and the work-in-progress version for the backend.
In past projects with similar requirements I tried different approaches to this problem:
Using "Versionable behavior" (this was in the Symfony1/Propel days using sfPropelVersionableBehaviorPlugin). For display in the frontend, if an entity was not approved I had to fetch the previous versions until the latest approved version was found.
Using a second entity/database table "ApprovedPost" with the same field definition as the main "Post" entity. When a post is approved by the admin, it will be copied to the ApprovedPost table. The frontend operates on the ApprovedPost table only.
What is the current best practice to implement such a behavior?
Because I am chellenging this problem right now, I want to share my approach.
The entity is a request for something. Everytime something changes, the changes should be preserved.
The approach:
On every edit action, a new entity row is created.
The entity has an "approved" flag and a createdAt Date field.
A request has a nullable one-to-one self relation (to point to the root/parent entity).
A custom repository is used fo accessing the database.
The typical find and findAll methods are modified: they search for the most recent version (by the createdAt field) that is approved.
Search is done via custom SQL/DQL: (WHERE id = ?1 OR WHERE parent-id = ?1) AND WHERE approved = true SORT BY created_at DESC LIMIT 1
More features can be added like enabled/disabled, deletion and so on ...
If you want to render the page server side and show the changed or old versions, I would recommend writing e.g. a Twig extension. You could implement different search functions in the repo and handle the representaion via the extension (sorting, referencing ...).
I created an API, which is able to do both: return the newest version and return all versions (with or without root or newest), but I use the latter one in the frontend only if necessary.
Like dbrumann stated, this is a opinionated approach (I like custom repos, because I can create them type safe and I can decouple application from persistence logic).

symfony dynamically add translation based on condition

I'm searching for a way to add a translation to an existing translation catalogue during runtime.
I have a working symfony 2.3 application which uses translations in de/en/fr/it and fetches all available translation keys from /Resources/translations/messages..yml.
Now if a user logs in I want to have the possibility to override some of the already loaded labels based on setting for that user (e.g. textfield in DB which holds key-value-pairs).
E.g.
messages.en.yml
company.name.short: Company profile
Usersetting:
company.name.short: Profile for company
I found no way to add/override keys to the existing catalogue or to make them available in twig. Is there a Bundle or a setting or some Symfony magic to get this to work?
You'll probably want to extend Symfony's own translation class for this. This article explains how to do that:
http://www.webtipblog.com/extend-symfony-2-translator-to-log-untranslated-messages-to-a-database/
The key point is to override the "translator.class" parameter in your config, and then point it to your own class that first checks for database overrules and will defer to the symfony default implementation if it cannot find one.

FOSUserBundle: Update entity after registration

In order to register, users have to select a their account name created by my moderators. That means that a moderators have to create an account name before the user registers.
To do so, I made a first entity, let's call it "Member", that has a field "account". Then I added to this entity the boolean field "bound" that is set to false by default.
What I want to do is to set this field "bound" to true when someone registers after he selected his account name and fill the FOSUserBundle required fields (username, passwords, email...).
I tried to follow the documentation of "overriding controllers", but I'm getting an error (You have requested a non-existent service "fos_user.registration.form".) and this is where I'm stucked.
Using controller events can maybe help me, but I do not know which is the best solution.
If anyone has a solution to my problem, I'll be really grateful.
You should used the controller event to hook after the registration process, and more specifically the
REGISTRATION_COMPLETED event (if I remember correctly).

Access Session from EntityRepository

I'm using Symfony2 with Doctrine2. I want to achieve the following:
$place = $this->getDoctrine()->getRepository('TETestBundle:Place')->find($id);
And on that place will be the info of the place (common data + texts) on the user language (in session). As I am going to do that hundreds of times, I want to pass it behind the scenes, not as a second parameter. So an English user will view the place info in English and a Spanish user in Spanish.
One possibility is to access the locale of the app from an EntityRepository. I know it's done with services and DI but I can't figure it out!
// PlaceRepository
class PlaceRepository extends EntityRepository
{
public function find($id)
{
// get locale somehow
$locale = $this->get('session')->getLocale();
// do a query with the locale in session
return $this->_em->createQuery(...);
}
}
How would you do it? Could you explain with a bit of detail the steps and new classes I have to create & extend? I plan on releasing this Translation Bundle once it's ready :)
Thanks!
I don't believe that Doctrine is a good approach for accessing session data. There's just too much overhead in the ORM to just pull session data.
Check out the Symfony 2 Cookbook for configuration of PDO-backed sessions.
Rather than setting up a service, I'd consider an approach that used a Doctrine event listener. Just before each lookup, the listener would pick out the correct locale from somewhere (session, config, or any other place you like in the future), inject it into the query, and like magic, your model doesn't have to know those details. Keeps your model's scope clean.
You don't want your model or Repository crossing over into the sessions directly. What if you decide in the future that you want a command-line tool with that Repository? With all that session cruft in there, you'll have a mess.
Doctrine event listeners are magically delicious. They take some experimentation, but they wind up being a very configurable, out-of-the-way solution to this kind of query manipulation.
UPDATE: It looks like what you'd benefit from most is the Doctrine Translatable Extension. It has done all the work for you in terms of registering listeners, providing hooks for how to pass in the appropriate locale (from wherever you're keeping it), and so on. I've used the Gedmo extensions myself (though not this particular one), and have found them all to be of high quality.

Resources