Symfony2, Sonata, UserBundle : Send email when user is enable on update - symfony

I would like to be able to send an email to the user when the admin enable the user in Sonata admin panel.
I have to idea which file i should override or extend.
I suppose it is similar to this subject or this stack-overflow subject:
/**
* {#inheritdoc}
*/
public function create($object)
{
parent::create($object);
// send welcome email to new user
}
I found the create function in the admin bundle but i suppose it would not be overridden only for the UserBundle. If it is indeed the way to go, how could i specify for the UserBundle only?
For the information I can't find any create or update function in UserBundle. Only in the AdminBundle.

I will relate to contract event from my gist:
https://gist.github.com/webdevilopers/4eea317ade72a119a72e
Adapt it to your needs. Guess you can simply rename "Contract" to "User".
Then add the event somewhere in your admin class:
$event = new ContractEvent($contract);
$dispatcher = $this->get('event_dispatcher');
$dispatcher->dispatch(
ContractEvents::CONTRACT_CREATED,
$event
);
See the gist for details how to inject SwiftMailer.
Instead of creating your own event you can choose from the events Sonata Admin offers you:
Admin's documentation - Reference - Events (master)
Pick up the one that suits your needs.

Related

how to make a dynamic roles in Symfony

I am a begginer, I would like to know if is possible to transform a roles in dynamic role like the #Route model.
/**
* #IsGranted("ROLE_{dance}_{level}")
* #Route("/{dance}/{level}", name="danceLevel")
*/
I have a project to make a website with some restrictions to accees to the content and I would like to throught by a interface like "easy Admin" to create a new category of dance and level that will be transform in role automaticaly
thanks by advance for your help
The security annotations would be for statically named roles and other permissions (checked by Voters).
You would be able to do more dynamic checks with:
$this->denyAccessUnlessGranted("ROLE_{$dance}_{$level}", $user, 'No access');
It's possible that a Security voter would be able to simplify the checks to what would be a static name and so used in #IsGranted (Or, it could for example, get the current $request, via the RequestStack service, to get dance and level parameters, if required).

Symfony Login form with existing user class

I'm trying to use (and understand) how Security works in Symfony. I've created a login form and it works with hard-coded users.
Now I want to use an existing user table in my database. The table has all the requiered fields but with different column names. The entity also exists, also with different names (for example "customUserId" instead of "id").
Something like (with "MAGIC_MAPPING"):
/**
* #ORM\Table(name="custom_user_table")
* #ORM\Entity
*/
class User implements UserInterface, \Serializable
{
/**
* #ORM\Column(name="customUserId", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
* #MAGIC_MAPPING so it links this to the mandatory "id" field
*/
private $customUserId;
...
}
Is there a way to map my existing fields so Symfony uses them for login purpose? Or at least can I make it work without changing my database structure (only the entity class)?
I've tried seleveral actions, from this forum and from Symfony documentation, but it always ends with ugly error I can't fix.
Any idea or lead? Thanks a lot for your help, I've been struggling on this for several hours now...
You have to change the providers configuration inside the security.yml file
here is an example, i use the email field from my administrator entity, I think you can do the same with your entity
providers:
administrator:
entity: { class: Entity:Administrator, property: email }
Try changing the ORM file of that table.
create an ORM file using Command promt.
then edit the orm file .
<mapped-superclass name="FOS\UserBundle\Entity\User" table="your_table_name">
/.../
</mapped>
BenoƮt 's answer help me figure it out. I gave too much attention to Symfony documentation's creation process that I forgot the essential: the UserInterface. No need to map anything, just implement this interface and defined methods like:
public function getUsername() {
return $this->customLogin;
}
Then update the provider configuration (thanks Benoit):
providers:
db_sam_provider:
entity:
class: AppBundle:User
property: customLogin
The other parts are conform to Symfony documentation: here and here

Create an Admin User with FosUserBundle

I try to create an Admin User with FOsUserBundle from command windows with the following command:
php app/console fos:user:create
In my project the Admin User extends other user with mandatory propriety. So, when I choose my username, mail and password, it tells me:
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'latitude' cannot be null
How can I set the value "latitude" in my AdminUser? I also use PUGXMultiUserBundle.
Only possibile way to reach that to me is
1 - override the cli command of FOSUserBundle placed into Command/CreateUserCommand.php
2 - override the user create method of FOSUserBundle placed into Util/UserManipulator.php
// Command/CreateUserCommand.php
protected function execute(InputInterface $input, OutputInterface $output)
{
$username = $input->getArgument('username');
$email = $input->getArgument('email');
$password = $input->getArgument('password');
$inactive = $input->getOption('inactive');
$superadmin = $input->getOption('super-admin');
$latitude = $input->getOption('latitude'); //this will be your own logic add
$manipulator = $this->getContainer()->get('fos_user.util.user_manipulator');
$manipulator->create($username, $password, $email, $latitude, !$inactive, $superadmin);
$output->writeln(sprintf('Created user <comment>%s</comment>', $username));
}
and
// Util/UserManipulator.php
public function create($username, $password, $email, $latitude, $active, $superadmin)
{
$user = $this->userManager->createUser();
$user->setUsername($username);
$user->setEmail($email);
$user->setPlainPassword($password);
$user->setEnabled((Boolean) $active);
$user->setSuperAdmin((Boolean) $superadmin);
$user->setLatitude($latitude);
$this->userManager->updateUser($user);
return $user;
}
Of course when I say override i mean ... override :P So you haven't to modify FOSUserBundle original files (you know, it's dangerous for many reasons) but make your own files by making your bundle extended by FOSUserBundle
Are you wondering how to make your bundle extended by FOSUserBundle?
Into your bundle "mainfile" - is the one you use to register your bundle - just add this lines
public function getParent()
{
return 'FOSUserBundle';
}
Then you simply recreate the tree structure where your ovverride files lives into original bundle, into your custom bundle's Resources/ directory (same position, same file name, same annotations if any) and .... the magic can start :) (this is valid only for views, please pay attention!)
What "override" means?
Override means that you take an existent function, "shadow" it by redefining elsewhere (declare a function with the same name, no matter how many parameters it accept, no matter the type of paramenters since php doesn't support method overloading [except if you do some "hack"]) and then you can use it instead of the original one. This is a common technique for add extra functionalities to a function or to change the function itself.
Say that we have two classes, A and B with B that is a child class of A. Say also that A have a method called myMethod().
In B we can do something like
public function myMethod() {
parent::myMethod();
//add extra functionalities here
}
in that way we're adding extra functionalities as we're calling the parent ("original") method and then execute some extra functionalities
Whereas if in B we make something like
public function myMethod() {
//some code here, but not calling parent method
}
we're redefining the behaviour of myMethod()
How Symfony2 let me override methods?
As I said previously in my answer, you have to make your bundle a child of the bundle that containts the function(s) you're trying to override (in that case FOSUserBundle). Once you did it, use the Resources directory of your bundle to accomplish what you need. reproduce the "tree-folder-structure" of the original bundle (ie.: same names of the folders) until you reach the class that contains the function you need to override.
Follow your real example: you need to override execute() function contained in Command/CreateUserCommand.php. You have to create, into your bundle folder that path:
PathTo/YourCostumBundle/Command/
and place inside the file CreateUserCommand.php with the content I show you above.
If you don't understand where I find that path, please take a look to FOSUserBundle code and it will be absolutely clear!
Why is dangerous to modify the FOSUserBundle code directly?
Well, there's a lot of answer an critic point that I can show you. Choosing the main (not ordered for importance):
What if you need to update FOSUserBundle? You'll use composer and lost every modify that you made to FOSUserBundle code
What if you have more than one bundle into your project that need to use FOSUserBundle? Maybe the custom behaviour makes sense for a bundle but not for the other one. Costumizing the behaviour at local bundle level helps you to keep FOSUserBundle logic intact
What if you're developing a bundle that you want to share with other user? You need to force them to "take" your own costumized FOSUserBundle version and warn them about updating it
Finally: I perfeclty know that your entity isn't into FOSUserBundle, but I can bet that they extend FOSUserBundle base user so what I told above is applicable to your case.
Hope it's less fuzzy now :)
Documentation: http://symfony.com/doc/current/cookbook/bundles/inheritance.html#overriding-controllers
I always follow the pattern I learned in the symfony documentation itself:
php bin/console fos:user:create usertest mail#domain.com password
and sometimes I need change the "roles" on the table "fos_user"
then
a:0:{}
to
a:1:{i:0;s:10:"ROLE_ADMIN";}
After creating a user with:
bash-5.1# bin/console fos:user:create admin admin#mydomain.com password123
Promote the user with the ROLE_ADMIN role:
bash-5.1# bin/console fos:user:promote
Please choose a username:admin
Please choose a role:ROLE_ADMIN
Role "ROLE_ADMIN" has been added to user "admin". This change will not
apply until the user logs out and back in again.

Sonata admin bundle, how to use entity repository classes

Using this code in PropertyAdmin extends Admin :
public function createQuery($context = 'list')
{
$user = $this->getConfigurationPool()->getContainer()->get('security.context')->getToken()->getUser();
$query = $this->getModelManager()->createQuery($this->getClass(), 'o');
$query->where('o.Creator=:creator')->setParameter("creator", $user);
return $query;
}
I was able to limit "list" results to those who "belong" to logged admin ie. only Properties (that is an entity) created by logged admin.
The problem:
By manually changing the URL (id value like 1, 2...), I can edit Property that belongs to other user. For edit action, above query is not called at all. How to change that behavior?
2.Instead of putting query in controllers, can I fetch it from PropertyRepository class? That would keep logic in models for which I could write unit tests.
3.I am trying:
ProductAdmin extends AdminHelper {....}
AdminHelper extends Admin { .... }
But it fails saying "Cannot import resource "D:_development\rent2\app/config." from "D:_development\rent2\app/config\routing.yml".
AdminHelper is abstract class but Sonata still reads it. Any solution?
1.a) Use ACL for your objects, CRUD controller has permission checking.
1.b) Redefine edit action, make sure that user tries to edit property that belongs to him, something similar to Page Admin Controller, there create action is redefined
2) In controller $this->getConfigurationPool()->getContainer()->get('doctrine')->getRepository($this->getClass()); gives you access to repository registered for this model. Probably there are few other ways to get service container and entity manager from it.
3) To create your admin class you should extend Sonata Admin: docs for this, this problem does not seems to be related to sonata as for me. Can you please provide content for D:_development\rent2\app/config\routing.yml ?

Extend Symfony2 White October Admin Bundle Form Fields?

This question is quite specific.
I'm using Symfony2 White October Admin Bundle for generating administration for my application.
I wonder if anyone has experience with this bundle and knows how to modify specific fields added to Admin class. The bundle is not documented very well and I'd like to know, if there are methods for doing this, or does the bundle core need to be extended.
For example I've got a Speaker entity with a field storing the path to one's avatar:
/**
* #var string $picturePath
*
* #ORM\Column(name="picture_path", type="string", length=128, nullable=false)
*/
private $picturePath;
Then in the Admin class I'm adding the field:
protected function configure()
{
...
...
->addFields(array(
...
...
'picturePath'=> array("label" => "Avatar"),
));
}
Is there an easy way to tell the bundle that I'd like this field to be an upload field instead of a text field, and define extra methods to call after submitting the form? (e.g. resize the image, store it, and then just store the image path in the DB)
As I haven't found any solution yet, I had to rape my entities to do that. So I modified the basic setter methods to call other methods inside the entity that do the dirty job. This is not a solution, and I'll still be happy if I could find better answers here.

Resources