How to retrieve subject in Sonata configureListFields? - symfony

I use Sonata Admin Bundle in my Symfony project and created an ArticleAdmin class for my Article entity.
In the list page, I added some custom actions to quickly publish, unpublish, delete & preview each article.
What I want to do is to hide publish button when an article is already published & vice versa.
To do this, I need to have access to each object in method configureListFields(). I would do something like this:
protected function configureListFields(ListMapper $listMapper)
{
$listMapper->add('title');
// ...
/** #var Article article */
$article = $this->getSubject();
// Actions for all items.
$actions = array(
'delete' => array(),
'preview' => array(
'template' => 'AppBundle:ArticleAdmin:list__action_preview.html.twig',
),
);
// Manage actions depending on article's status.
if ($article->isPublished()) {
$actions['draft']['template'] = 'AppBundle:ArticleAdmin:list__action_draft.html.twig';
} else {
$actions['publish']['template'] = 'AppBundle:ArticleAdmin:list__action_preview.html.twig';
}
$listMapper->add('_actions', null, array('actions' => $actions));
}
But $this->getSubjet() always returns NULL. I also tried $listMapper->getAdmin()->getSubject() and many other getters but always the same result.
What am I doing wrong ?
Thanks for reading & have a good day :)

You can do the check directly in the _action template, as you can access the current subject.
protected function configureListFields(ListMapper $listMapper)
{
$listMapper
->add('title')
->add('_action', 'actions', array(
'actions' => array(
'delete' => array(),
'preview' => array(
'template' => 'AppBundle:ArticleAdmin:list__action_preview.html.twig',
),
'draft' => array(
'template' => 'AppBundle:ArticleAdmin:list__action_draft.html.twig',
),
'publish' => array(
'template' => 'AppBundle:ArticleAdmin:list__action_publish.html.twig',
),
))
;
}
And for example in AppBundle:ArticleAdmin:list__action_draft.html.twig, you can check your condition :
{% if object.isPublished %}
your html code
{% endif %}

Related

how to embed one to many sonata admin child views in ConfigeShowFields

I have a one to many relationship between account and contacts. I use sonata admin bundle
I want to display all contacts of an account in the view detail of an account ( ConfigureShowFields in AccountAdmin class)
in class AcountAdmin.php i have :
protected function configureShowFields(ShowMapper $showMapper)
{
$showMapper
# .......
->with('Liste des contacts', array('class' => 'col-md-12'))
->add('contacts')
->end()
;
}
I believe you can do this via sonata_type_collection.
->add('contacts', 'sonata_type_collection', array(
'associated_property' => 'email',
'route' => array(
'name' => 'show'
),
'admin_code' => 'app.admin.contacts',
))
The associated_property is the associated property found in the Contacts entity, and the admin_code is the contacts admin.

Use sonata_type_collection inside custom type

What I want to do is add sonata_type_collection to my custom formType.
Normal way is add sonata_collection_type to $formMaper inside AdminClass like:
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper->add('elements, 'sonata_type_collection', array(
'some_options' => 'options'
))
}
It work perfect, but i have my custom form type, and when i defined it like:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$formMapper->add('elements, 'sonata_type_collection', array(
'some_options' => 'options'
))
}
It doesn't work (it appear only label of filed). Problem is wrong template, so I tried to set formAdminTemplate
I made it by set template in view
{% form_theme formElement 'SonataDoctrineORMAdminBundle:Form:form_admin_fields.html.twig' %}
Problem is sonata_admin variable inside this 'formTheme'. This variable doesn't exist in my form.
Of course my form type is related to admin class but i don't know how could I I tell symfony about this relation
You need an admin class for your collection child :
$formMapper->add('customizations', 'sonata_type_collection',
array(
'required' => true,
'type_options' => array('delete' => true),
'by_reference' => false,
'mapped' => true
),
array(
'edit' => 'inline',
'inline' => 'table',
'sortable' => 'position',
'targetEntity' => '/path/to/Entity/Customization',
'admin_code' => 'my.service.customization_admin'
)
);
I find solution. Instead using my custom type, I defined form using admin class. I need this form outside admin so it was little difficult.
First of all in my controller i get admin class from service. Inside admin class I override 3 methods which are use to create form
public function getFormBuilder()
public function defineFormBuilder(FormBuilder $formBuilder)
public function buildForm()
then i had to save my entity by sonata admin way. using create method instead handleRequest.

Symfony2 - Give a default filter in a list of elements of Sonata Admin

I have a list of elements of type Vehicle and I show these elements with Sonata Admin. I allow to filter these elements by the "status" field, but I want that, when the list is showed, only the active vehicles are showed, and if somebody wants to see the inactive vehicles, uses the filter and select the inactive status. I would like to know if somebody Knows the way to apply filters by default for a list of elements using Sonata Admin.
Here is my code:
public function configureListFields(ListMapper $listMapper)
{
$listMapper
->addIdentifier('name')
->add('status')
;
}
protected function configureDatagridFilters(DatagridMapper $mapper)
{
$mapper
->add('name')
->add('status')
;
}
Is there any option that can be added to the status field in configureDatagridFilters() to achieve this goal? Other options?
Thanks in advance.
You have to override $datagridValues property as following (for status > 0 if it's an integer) :
/**
* Default Datagrid values
*
* #var array
*/
protected $datagridValues = array (
'status' => array ('type' => 2, 'value' => 0), // type 2 : >
'_page' => 1, // Display the first page (default = 1)
'_sort_order' => 'DESC', // Descendant ordering (default = 'ASC')
'_sort_by' => 'id' // name of the ordered field (default = the model id field, if any)
// the '_sort_by' key can be of the form 'mySubModel.mySubSubModel.myField'.
);
source: Configure the default page and ordering in the list view
You can also use this method
public function getFilterParameters()
{
$this->datagridValues = array_merge(
array(
'status' => array (
'type' => 1,
'value' => 0
),
// exemple with date range
'updatedAt' => array(
'type' => 1,
'value' => array(
'start' => array(
'day' => date('j'),
'month' => date('m'),
'year' => date('Y')
),
'end' => array(
'day' => date('j'),
'month' => date('m'),
'year' => date('Y')
)
),
)
),
$this->datagridValues
);
return parent::getFilterParameters();
}
Using both above suggested approaches will break the filters "reset" behaviour since we are always forcing the filter to filter by a default value. To me, i think the best approach is to use the getFilterParameters function (since we can add logic in there instead of statically add the value) and check if the user clicked the "Reset button"
/**
* {#inheritdoc}
*/
public function getFilterParameters()
{
// build the values array
if ($this->hasRequest()) {
$reset = $this->request->query->get('filters') === 'reset';
if (!$reset) {
$this->datagridValues = array_merge(array(
'status' => array (
'type' => 1,
'value' => 0
),
),
$this->datagridValues
);
}
}
return parent::getFilterParameters();
}
Since sonata-admin 4.0, the function getFilterParameters() is tagged as final and the $datagridValues doesn't exist anymore.
So you need to override the configureDefaultFilterValues() function
protected function configureDefaultFilterValues(array &$filterValues): void
{
$filterValues['foo'] = [
'type' => ContainsOperatorType::TYPE_CONTAINS,
'value' => 'bar',
];
}
More details: https://symfony.com/bundles/SonataAdminBundle/current/reference/action_list.html#default-filters
Another approach is to use createQuery and getPersistentParameters to enforce invisible filter. This approach is best to have fully customizable filters. See my articles here:
http://www.theodo.fr/blog/2016/09/sonata-for-symfony-hide-your-filters/

Drupal 7 - Confirm email address

I have added some extra fields to the standard 'create account' page; notably a 'confirm email' field.
How do hook into the validation so that I can add some custom validation rules of my own (e.g. to check the two emails match)?
I have found hook_user_presave, but am unsure on how to code it or where I should put it.
Any and all help appreciated.
I would advise installing the LoginToboggan module, it actually has the option for that exact functionality out of the box and has a bunch of other useful options as well.
If you want to do it yourself though you'd probably be better off implementing hook_form_FORM_ID_alter() and adding a validation function directly to the registration form:
function mymodule_form_user_register_form_alter(&$form, &$form_state, $form_id) {
$form['#validate'][] = 'mymodule_user_register_form_validate';
}
function mymodule_user_register_form_validate(&$form, &$form_state) {
if ($form_state['values']['first_email'] != $form_state['values']['second_email']) {
form_set_error('second_email', 'The email addresses much match.');
}
}
Make sure you clear Drupal's cache once you've implemented the form alter function so Drupal registers it correctly.
Hope that helps.
Here is the example solution for Drupal 7:
/**
* Implements hook_menu().
* Note: You can define your own menu callback optionally.
*/
function foo_menu() {
$items['foo-signup'] = array(
'title' => 'Create new account',
'page callback' => 'drupal_get_form',
'page arguments' => array('user_register_form'),
'access callback' => 'user_register_access',
'type' => MENU_CALLBACK,
);
return $items;
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function foo_form_user_register_form_alter(&$form, &$form_state, $form_id) {
$form['account']['mail_confirm'] = array(
'#type' => 'textfield',
'#title' => t('Confirm e-mail address'),
'#maxlength' => EMAIL_MAX_LENGTH,
'#description' => t('Please confirm your e-mail address.'),
'#required' => TRUE,
);
$form['#validate'][] = 'foo_user_register_form_validate';
}
/**
* Implements validation callback.
*/
function foo_user_register_form_validate(&$form, &$form_state) {
if ($form_state['values']['mail'] != $form_state['values']['mail_confirm']) {
form_set_error('mail_confirm', 'The email addresses must match.');
}
}

Can't create custom handler for Views2

Basically I want to create a custom handler to unserialize a db field called birthday.
I've managed to correctly output the field serialized using the default views_handler_field. Unfortunately When I try to create a custom handler, I get this message:
Error: handler for drappsprofiles > birthday doesn't exist!
Here's the file structure:
all/modules/drapps/drappsprofile/
|->drappsprofiles.views.inc
|->drappsprofiles.module
|->drappsprofiles.install
|->drappsprofiles.info
|->drappsprofiles.inc
|->drappsprofiles_handler_field_birthday.inc
here's drappsprofiles.module
/**
* VIEWS2 MODULE
* Implementation hook_views_api
**/
function drappsprofiles_views_api() {
$info['api'] = 2;
return $info;
}
/*****************************************************************************
* INCLUDES
**/
// Loads Google Apps Profile Integration
module_load_include('inc', 'drappsprofiles');
(...)
here's drappsprofiles.views.inc
/**
*
* Implementation of hook_views_handlers().
*
**/
function drappsprofiles_views_handlers() {
return array(
'handlers' => array(
'drappsprofiles_handler_field_birthday' => array(
'parent' => 'views_handler_field',
)
)
);
}
/**
* Implementation of hook_views_data().
*
* #return array
**/
function drappsprofiles_views_data() {
(...)
$data['drappsprofiles']['birthday'] = array(
'title' => t('Birthday'),
'help' => t('Users birthday'),
'field' => array(
'handler' => 'drappsprofiles_handler_field_birthday',
'click sortable' => FALSE,
),
);
return $data;
}
drappsprofiles_handler_field_birthday.inc
<?php
/**
*
* Custom views handler for Birthday
*
*/
class drappsprofiles_handler_field_birthday extends views_handler_field {
function render($values) {
$val = unserialize($values->{$this->field_alias});
return ($val);
}
}
It seems that drappsprofiles_handler_field_birthday.inc is not being read, although I can't figure out why.
Any help would be appreciated. (I've been around this for 2 weeks!)
Assuming your (...) in .views.inc conceals code like:
$data['drappsprofiles']['table']['group'] = t('drappsprofiles');
$data['drappsprofiles']['table']['base'] = array(
'field' => 'birthday',
);
$data['drappsprofiles']['table']['join'] = array(
'#global' => array(),
);
Which I am assuming it does since your field has a group from which to select it so that it can look for the missing handler..
Then the next thing to look at is still in .views.inc in module_views_handlers() { :
return array(
++ 'info' => array(
++ 'path' => drupal_get_path('module','drappsprofilse'),
++ ),
'handlers' => array(
And beyond that, I hate to say it, but uninstalling and reinstalling the module apparently refreshes recent code tweaks to the .views.inc .. I know I had to a bunch of times, you probably noticed this too.

Resources