How to go directly in the edit section in Backpack-Laravel? - laravel-5.3

I need that when you to click on an item in the Backpack sidebar (For ex. Profile),
I immediately can edit the information in this page (For ex. the user who is writing, then the name, surname, date of birth etc.) without going through the table, typical visual of backpack.
In a simple manner:
The user should have the ability to change their profile information whith one click.
How can I do this in Backpack-laravel?
Anyone have any ideas?
Starting code:
ProfileCrudController.php
public function __construct()
{
parent::__construct();
}
public function edit($id)
{
return parent::edit($id);
}

If you mean clicking on the user name in the sidebar should go to editing that user, you can do that by placing the link on it in your /resources/views/vendor/backpack/base/inc/sidebar.blade.php.

I do not know if it might be the correct way. But it's the only way I've found to accomplish what I had in mind.
public function index()
{
$this->crud->addFields([
[
'name' => 'name',
'label' => 'Name',
'type' => 'Text'
],
[
'name' => 'surname',
'label' => 'Surname',
'type' => 'Text'
]
]);
return parent::edit(Auth::id());
}

Related

How can I set a value in Twig when the select is built using EntityType?

In a Form say I have a builder option like this:
->add('choice', ChoiceType::class, [
'choices' => [
'Cheese' => 'cheese',
'Plain' => 'plain
]
])
And let's say we are editing this option, in the database they've already selected plain. With twig we can write the widget like this:
{{ form_widget(BurgerForm.choice, {
'value': burger.type
}) }}
This will make the value in the database the pre-selected value for the select. But if you do the same thing with EntityType:
->add('choice', EntityType::class, [
'class' => 'AppBundle:BurgersTypes',
'choice_label' => 'type'
])
And you use the same twig it doesn't pre-select the option from the database. How can I get the value from the database to show as the pre-selected value of the widget?
Pre-selecting a value for this form means setting a value on the underlying data. In your case, the controller ought to look something like:
// src/AppBundle/Controller/MyController.php
namespace AppBundle\Controller\MyController;
use AppBundle\Entity\Order;
use AppBundle\Entity\BurgersTypes;
use AppBundle\Form\Type\FormType;
use Symfony\Component\HttpFoundation\Request;
public function formAction(Request $request)
{
$obj = new Order();
$defaultBurgerChoice = new BurgersTypes('cheese');
$ob->setChoice($defaultBurgerChoice);
$form = $this->create(FormType::class, $obj);
$form->handleRequest($request);
...
// Now, if the form needs to render a value for `choice`,
// it will have the value of BurgerForm.choice determined
// intentionally - by your default, or overridden and
// handled in the request!
return [
'BurgerForm' => $form->createView()
]
}

Use the category node name as a label in Zikula

I do use Zikula 1.5.2dev
My module is generated with modulestudio
I have made two entries in the Category registry. One is showing at the node "Global" and one at the node "Type"
In Global are several entries I can select. Some other entries are inside Type.
The selection is working in my template like expected. But how can I use the node names as a label?
I can not figure out in which template I have to place to label (have to do more searching). But more important, I do not know the right twig syntax to catch the categories label.
if you assign a category to the template, the properties are accessible like normal class properties.
{{ category.name }}
if you need the display name, this is stored as an array with lang codes as keys
{{ category.display_name['de'] }}
Hope that helps.
That sounds good. But now I have recognized this label seem not to be placed in a pure template. There is a form type defined:
class ShowRoomItemType extends AbstractShowRoomItemType
{
/**
* #inheritDoc
*/
public function addCategoriesField(FormBuilderInterface $builder, array $options)
{
$builder->add('categories', CategoriesType::class, [
'label' => $this->__('Category') . ':',
'empty_data' => null,
'attr' => [
'class' => 'category-selector'
],
'required' => false,
'multiple' => false,
'module' => 'RKShowRoomModule',
'entity' => 'ShowRoomItemEntity',
'entityCategoryClass' => 'RK\ShowRoomModule\Entity\ShowRoomItemCategoryEntity',
// added:
'includeGrandChildren' => true
]);
}
}
In my template it is called like this:
{{ form_row(quickNavForm.categories) }}
For this my skills are very limmited. I will write a feature request at modulestudio. (https://github.com/Guite/MostGenerator/issues/1147)
But big thanks for your reply!
This has been fixed for core 1.5.4 / 2.0.4 in https://github.com/zikula/core/pull/3846

Symfony2 dynamically assign attr to form field

I'm in a situation where I want to be able to dynamically set the required=true/false option or the array(...other stuff..., 'class' => ' hidden') of a form field.
The context is the following: there is a "Project" entity with some fields. When I create other entities with forms I want to check some attributes of the Project entity and make decisions on the visibility/requiredness of certain fields of the entity I'm creating.
For example if a Project is with attribute "timePressure=high" then a field of a given entity is not required (but is visible). If there are other conditions it becomes invisible etc...
So basically I was hoping to call a function inside each ->add() of the form builder to spit out the relevant portions (e.g. that function would return a string with "required=true" or the other related to the hidden class). The thing is that the function should take as arguments: the projectID (ok, this can be passed as options of the form builder), the class and the field we are talking about to decide. I was envisioning something like:
->add('background', 'textarea', array('attr' => array('rows' => 4, functionToDecideIfInvisible($projectId)), functionToDecideRequiredness($projectId)))
The two function would return the string 'class' => ' hidden' and required=true (or false)
I'd like to avoid to having to specify the field name (in this case background) to avoid code repetition.
Can this be done?
Other suggestions on how to solve the thing?
Thank you!
SN
What you need are Form Events: http://symfony.com/doc/current/cookbook/form/dynamic_form_modification.html#cookbook-form-events-underlying-data
They allow you to modify your form based on your data.
You create you project form in the controller:
$form = $this->createForm(new ProjectType(), $project, array(
'action' => $this->generateUrl('project.edit'),
'method' => 'POST',
));
Then you add the FormEvents::PRE_SET_DATA listener:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
$project = $event->getData();
$form = $event->getForm();
// check timePressure on the Project object
if ('high' === $project->timePressure) {
$form->add('timePressure', 'text', array(
'required' => false
);
}
});
}
I found a way to do it.
My add would be like:
->add('background', 'textarea', array_merge($this->vr->fieldReq(get_class($this),
'background', $projectID), array('attr' => array_merge(array('rows' => 4, ),
$this->vr->fieldCssClass(get_class($this), 'background', $projectID) ) )))
To do that I had to define the form as service, plus I created another class as service (the one which holds the two methods I need).
This is the class:
class FieldReqAndCssClass
{
public function fieldReq($parentEntity, $field, $projectID)
{
$required = array();
$required['required'] = false; //do stuff on the database instead of setting it to false hardcoded
return $required;
}
public function fieldCssClass($parentEntity, $field, $projectID)
{
$cssClass= array();
//do stuff on the database instead of setting the class as hidden hardcoded
//$cssClass['class'] = ' hidden';
$cssClass['class'] = '';
return $cssClass;
}
}
Of course in my form I had to:
public function __construct(\AppBundle\Util\FieldReqAndCssClass $fieldReqAndCssClass)
{
$this->vr = $fieldReqAndCssClass; // vr stands for visibility and requiredness
}
And these are the two services:
app_bundle.field_req_and_css_class:
class: AppBundle\Util\FieldReqAndCssClass
arguments: []
app_bundle.form.type.projectdetail:
class: AppBundle\Form\Type\ProjectDetailFormType
arguments: [#app_bundle.field_req_and_css_class]
tags:
- { name: form.type, alias: ProjectDetail }
Of course here in the first service I'll need to inject the entity manager and add it to the construct, and probably also in the form service, but the basic skeleton is working :)
I'm a happy man :)
EDIT
The only problem of the above is that it makes hidden the widget but not the label. To fix it:
->add('background', 'textarea', array_merge($vr->fieldReq($myClass,
'background', $project), array('label_attr' => $vr->fieldCssClass($myClass,
'background', $project),'attr' => array_merge(array('rows' => 4, ),
$vr->fieldCssClass($myClass, 'background', $project) ) )))
Obviously before I have to declare:
$myClass = get_class($this);
$vr = $this->vr;

datagrid filter for relation object as text field (insted of dropdown) in sonata admin in symfony 2.4

I have entity 'Action' with relation to 'User'. Created Admin CRUD controller in SonataAdminBundle. Everything works fine except user filter is rendered as dropdown list. I have 8k user count and growing so you must see why this is a problem.
I want user filter to be text input and on submit to search with LIKE %username%
Right now I add user filter like this - $datagridMapper->add('user').
I know I can add filter type and field type but I am not able to find the right combination and options. Found information on http://sonata-project.org/bundles/doctrine-orm-admin/master/doc/reference/filter_field_definition.html but still no success.
Final solution
Following Alex Togo answer I used this code:
$datagridMapper->add('user', 'doctrine_orm_callback', array(
'callback' => function($queryBuilder, $alias, $field, $value) {
if (empty($value['value'])) {
return;
}
$queryBuilder->leftJoin(sprintf('%s.user', $alias), 'u');
$queryBuilder->where('u.username LIKE :username');
$queryBuilder->setParameter('username', '%'.$value['value'].'%');
return true;
},
'field_type' => 'text'
))
I needed something like this on a project. I implemented this feature using this. You can try to set the 'field_type' option to 'text' (I used 'choice' in the project I worked at) and add the querybuilder actions you need to filter.
Use doctrine_orm_choice option.
protected function configureDatagridFilters(DatagridMapper $datagridMapper)
{
$datagridMapper->add(
'module',
'doctrine_orm_choice',
[],
'choice',
[
'choices' => $this->filterModuleList
]
)
....

Create menu link to view with argument

I'm trying to use hook_menu to create a link to a view which takes an argument. However if I use the path (in $items[view-path/%dest]) that I've already set as the path in the view then the link doesn't appear. I'm guessing there's a path conflict somewhere. Is there a way round this? Or can I use another method to return the view?
I'm using the following code:
/**
* implementation of hook_menu().
*/
function sign_custom_menu() {
$items['view-path/%dest'] = array(
'title' => 'Link to view',
'page callback' => 'sign_custom_hello',
'page arguments' => array(1), //(corrected typo from 'page arguements')
'access callback' => TRUE,
'type' => MENU_NORMAL_ITEM,
'menu_name' => 'menu-student-links',
);
return $items;
}
function dest_to_arg() {
// would normally be dynamic to get view with correct argument
$arg = 73;
return $arg;
}
Thanks in advance.
Addition
function sign_custom_hello() {
//return t('Hello!');
}
I managed to answer my problem. Basically I used a different path to the one I had set in the view and then used views_page() as my "page callback". I passed it the arguments for the view, the page ID and it's own additional arguments to make the view work. I was able to use a wildcard in the menu item to pass to views_page() by using the to_arg() function that works with hook_menu() to pass in wildcards. The 'page arguments' pass in the three arguments. The last argument, "1" is a reference to which position in the path the argument appears (starting from 0).
The working code is:
<?php
/**
* implementation of hook_menu().
*/
function sign_custom_menu() {
$items['view-path/%dest'] = array(
'title' => 'link to view',
'page callback' => 'views_page',
'page arguments' => array('view_name', 'page_1', 1),
'access callback' => TRUE,
'type' => MENU_NORMAL_ITEM,
'menu_name' => 'menu-student-links',
);
return $items;
}
//this function is needed from the "%dest" argument in hook_menu above
function dest_to_arg() {
// would normally be dynamic to get view with correct argument
$arg = 73;
return $arg;
}
?>
I don't have much experience with wildcard URLs in my custom modules much, but I researched the issue in the Pro Drupal Development book. From what I read in the "Wildcards and Parameter Replacement" section on page 77, I think you may want to use $items['view-path/%'] instead. Using %dest apparently makes drupal look for a dest_load function.
Items that appear in menus can't be created by a wildcard router item: each menu item corresponds to exactly one path. That is, if you have a router item that is foo/%bar and %bar can have 10 different values, Drupal's menu system isn't going to create 10 new menu items off of one router item definition.
So what you're going to need to do is create a router item for each possible argument ahead of time. Otherwise, you're going to have to look outside Drupal's menu system and think about creating a separate Views block that looks like a menu but is really a Views unordered list of the available options.
To do the former, you need to implement hook_menu_alter() to add your custom router item after everything else, including the wildcard router item you're trying to override. Your custom router item will be more or less the same as the wildcard router item, but with some defaults set that would normally be derived from the wildcard.
For example, if I wanted to create a new router item for user/1/edit which overrides the built-in user/%user_category/edit, I'd implement hook_menu_alter() as so:
function mymodule_menu_alter(&$items) {
// user_edit and user_edit_access expect a user object
$account = user_load(array('uid' => 1));
$items['user/1/edit'] = array(
'type' => MENU_CALLBACK,
'page arguments' => array($account),
'access arguments' => array($account),
) + $items['user/%user_category/edit'];
}
In this example, user/%user_category/edit calls user_edit() and user_edit_access() for the page and access callbacks, respectively, and they both attempt to use the wildcard. Since there is no wildcard in your router item, you need override the arguments to say "check user 1".
You'll do this for each and every possible value of the wildcard.
But this isn't enough: notice I used MENU_CALLBACK instead of MENU_NORMAL_ITEM. If you use MENU_NORMAL_ITEM, your router item is going to show up in the Navigation menu, not in your custom menu, even if you set menu_name (I don't know why this is: it should work). But you can get around this by using menu_link_save().
Consider this implementation of hook_init():
function mymodule_init() {
$router_path = 'user/1/edit';
// Check to see if the custom router item has been added to menu_links.
// This is to ensure the menu has already been rebuilt.
$router_item = db_fetch_object(db_query("SELECT * FROM {menu_links} WHERE router_path = '%s'", $router_path));
// Only create a new menu item if the router item exists and it
// hasn't already been created (it's hidden until created).
if ($router_item && $router_item->hidden) {
$item = array(
'link_title' => 'Edit Administrator',
'link_path' => $router_path,
'menu_name' => 'primary-links',
'router_path' => $router_path,
'mlid' => $router_item->mlid,
);
// Save the menu item.
menu_link_save($item);
}
}
In this implementation, it checks to see if the custom router has already been created and hasn't been otherwise modified. If this is true, it creates a menu link in the primary links menu that references your custom router item.
Obviously, since this is in hook_init(), it'll perform the check on every page: this is to ensure it fires after the menu is rebuilt. It shouldn't be much of a performance hit, but it's something to keep in mind.
As you can see, it's a long and drawn out process to do this: if you're not going to go the Views fake-menu route, it might be better to just manually create the links yourself.

Resources