I have a list view in sonata admin. I want to add a column that will allow me to click on a link to send an email. The link action will know variables from that row in the table so that it can fill in the email. I was able to add the column and can visualize a twig template. I've added the following function to the Admin Class:
public function sendEmail( \Swift_Mailer $mailer)
{
$message = (new \Swift_Message('some email'))
->setFrom('contact#example.com')
->setTo('contact#example.com')
->setBody(
$this->renderView(
'emails/response.html.twig',
array('manufacturer' => $manuvalue, 'modelnum' => $modelnumvalue, 'email' => $email)
),
'text/html');
$mailer->send($message);
}
I'm stuck on how to connect these pieces together so that when I click on the link the email is sent and includes the params from the row. I have email working on form submit in other areas of the site, but need help figuring out the way to do this manually.
As you mentioned in the comments, what you want to do is typically a Custom Action
In order to ensure that this action can not be accessed via direct request and can only be performed by admin, you could do use a template like this for your customAction :
...
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
...
//AuthorizationCheckerInterface injected as authorizationChecker
public function customAction($id){
$object = $this->admin->getSubject();
if (!$object) {
throw new NotFoundHttpException(sprintf('unable to find the object with id: %s', $id));
}
// Check access with role of your choice
$access = $this->authorizationChecker->isGranted('ROLE_ADMIN');
if($access){
//Do your action
} else {
throw $this->createAccessDeniedException("You don't have the rights to do that!");
}
}
I ended up doing a custom route and protected it with security settings that #dirk mentioned.
Related
I have a form that I use both for registration and edition of the user informations. This form contains a profile picture property on which I put #Assert\Image.
I succeed in creating a new user through my registration form but when I try to edit the user informations (with a PATCH method, just to update what need to be updated) I encounter an error with a 'File could not be found' message.
I suppose it's because the path stored in the database is a string and my #Assert\Image want an image.
I'm not sure about how I should manage this kind of update.
When I dd() the $user right after the submission, I see that the profilePicture property still contains the path saved in the database.
Here is my function regarding the form handling:
public function myProfile(Request $request)
{
$user = $this->getUser();
$form = $this->createForm(UserFormType::class, $user, ['method' => 'PATCH']);
if ($request->isMethod('PATCH')){
$form->submit($request->request->get($form->getName()), false);
if ($form->isSubmitted() && $form->isValid()) {
//...
}
}
//if no request just display the page
return $this->render('connected/myProfile.html.twig', [
'user' => $user,
'userProfileForm' => $form->createView()
]);
}
The Validator will check if your object contains a image and that seems not the case when you’re updating your object.
A workaround is to use group validation you define a specific group to the property that have the assert Image and in the method getGroupSequence you return the group if you’re in creation (id == null) or if the property is setted.
I have two (2) Admins, UserAdmin and CarAdmin. From the list view of UserAdmin, I want to have a custom action that redirects to CarAdmin create view with the user already selected.
So far I have managed to create a custom action with its controller. My challenge is to redirect to CarAdmin create/new form passing some parameters for data persistence.
Any points of reference will be much appreciated.
Thanks
Sonata Admin allows to resolve such task pretty easy, no need to make a custom action. One of the solutions could be:
Define a custom template for one column in UserAdmin list view, render a special button(link) in it. A link should lead to CarAdmin create action with some get parameter.
In CarAdmin in method getNewInstance() check that if there is a special get parameter - set user with that ID. This step can also be done in methods getFormFields(), prePersist(), etc.
Some code samples:
In UserAdmin
protected function configureListFields(ListMapper $listMapper)
{
$listMapper
->add('actions', 'string', array(
'template' => 'your_template_name.html.twig',
'mapped' => false,
)
);
}
In your_template_name.html.twig
Create Car for this user
In CarAdmin
public function getNewInstance()
{
$car= parent::getNewInstance();
$userId = $this->getRequest()->query->get('user');
if ($userId) {
$em = $this->modelManager->getEntityManager(User::class);
$user = $em->getRepository(User::class)->find($id);
$car->setUser($user);
}
return $car;
}
I have a Sonata admin for an entity with many elements that naturally spans multiple pages in the list view.
What I'd like to do is make it so after editing, or creating a new entity, redirect the user to the appropriate page which displays the edited entity (as opposed to going back to the list's first page which is the default behavior of the sonata admin). The dafult behavior is ok when there are only 1 or 2 pages but when you have tens or even hundreds of pages, navigating back to the correct page becomes quite tedious.
So my question is what is the appropriate way to make this happen?
I'm thinking that it would involve customizing the admin controller for the entity but I'm not sure what the right extension points are. And also, how to utilize the paginator to obtain the correct page to navigate back to.
Another potential hack would be to capture the query parameters state when navigating from the list view to the edit, and then returning the user to the same URL. This won't work correctly for creating new items.
There's also the matter of the state of filters when navigating from the list view (if the user had sorted and/or filtered the list before navigating to the edit page).
I know I'm late but this can be useful for someone else...
Here is the way I've made it, by overriding AdminBundle CRUDController:
<?php
namespace MyProject\AdminBundle\Controller;
use Sonata\AdminBundle\Controller\CRUDController as BaseController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse;
class CRUDController extends BaseController
{
protected function redirectTo($object, Request $request = null)
{
$response = parent::redirectTo($object, $request);
if (null !== $request->get('btn_update_and_list') || null !== $request->get('btn_create_and_list')) {
$url = $this->admin->generateUrl('list');
$last_list = $this->get('session')->get('last_list');
if(strstr($last_list['uri'], $url) && !empty($last_list['filters'])) {
$response = new RedirectResponse($this->admin->generateUrl(
'list',
array('filter' => $last_list['filters'])
));
}
}
return $response;
}
public function listAction(Request $request = null)
{
$uri_parts = explode('?', $request->getUri(), 2);
$filters = $this->admin->getFilterParameters();
$this->get('session')->set('last_list', array('uri' => $uri_parts[0], 'filters' => $filters));
$response = parent::listAction($request);
return $response;
}
}
I am having the same problem, I was thinking of passing a variable in the route to the edit page, thus giving you where the request for the edit originated from, then you could redirect to the originating page given the variable.
I need some additional functionality added to user_pass_submit. This must be added without changing the core. What is the hook I would use to do this?
Thanks.
You should be able to use hook_form_FORM_ID_alter() to replace the submit handler for the user_pass form with your own module's copy of user_pass_submit, altered as necessary.
Something like this...
function MODULE_form_user_pass_alter(&$form, &$form_state) {
$form['#submit'] = array('MODULE_user_pass_submit');
}
function MODULE_user_pass_submit($form, &$form_state) {
global $language;
$account = $form_state['values']['account'];
// Mail one time login URL and instructions using current language.
_user_mail_notify('password_reset', $account, $language);
watchdog('user', 'Password reset instructions mailed to %name at %email.', array('%name' => $account->name, '%email' => $account->mail));
drupal_set_message(t('Further instructions have been sent to your e-mail address.'));
$form_state['redirect'] = 'user';
return;
}
Of course, this falls down if you have multiple modules trying to do
I have a site where some users will be registered by our staff, and won't have emails associated with them. I would like to keep the email field a required field, so I devised a random email generator.
function generateRandomEmail() {
$email = 'noemail'. rand(0,1000000) . '#noemail.com';
return $email;
}
So, I attached that to the user register form alter, and it worked nicely, effectively generating an email for these users.
However, in the process, all the other fields associated with the main account section (password, username, notify, etc.) disappeared. My question, is there a quick way to populate the rest of the fields that I don't want to alter? I've used drupal_render($form); in a tpl.php, but it didn't work in the form alter.
Here is where I'm altering the form:
function accountselect_user($op, &$edit, &$account, $category) {
if ($op == 'register') {
$fields['account']['mail'] = array(
'#type' => 'textfield',
'#default_value' => generateRandomEmail(),
);
You are currently using hook_user for your manipulation, but that is the wrong place. On $op 'registration', you can return additional fields you want to inject to the registration process, but not alter existing fields. Use hook_form_alter() or hook_form_FORM_ID_alter() for that, e.g.:
function yourModule_form_user_register_alter(&$form, &$form_state) {
$form['account']['mail']['#default_value'] = generateRandomEmail();
}
You probably want to add a check that the request is in fact coming from the staff, since the above code would prepopulate the email field for the normal registration form also!
Also, please do not generate 'random' mail addresses using existing third party domains (like 'nomail.com'). Use the reserved 'example.com', or better yet, one that you own yourself!