I use a service to get a basic search form on my website. I need to set the action form to a search result page. I can set the form action to be a specific url (/search) but can't use a "generateUrl"-like method in a yaml.
I want to be able to test my form in dev environment /app_dev.php as well as in prod environment. Any suggestion or idea?
services.yml
parameters:
form.search.default.value: "search for things"
services:
app_bundle.form.type.search:
class: AppBundle\Form\SearchType
arguments: [AppBundle\Entity\Search]
tags:
- { name: form.type, alias: tab_search }
app_bundle.form.search:
factory_method: create
factory_service: form.factory
class: Symfony\Component\Form\Form
arguments:
- tab_search
- #app_bundle.form.entity.search
- { action: /search } # I'd like something similar to $this->generateUrl("search")
app_bundle.form.entity.search:
class: AppBundle\Entity\Search
arguments: [%form.search.default.value%]
DefaultController.php
/**
* #Route("/", name="homepage")
* #Template()
*/
public function indexAction(Request $request)
{
$form = $this->get('app_bundle.form.search');
// [...]
return array('search' => $form->createView());
}
Untested, but I've done something like this before with this code:
protected $action;
public function setAction($action)
{
$this->action = $action;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
// rest of form configuration
$builder->setAction($this->action);
}
Then in your services.yml:
services:
app_bundle.form.type.search:
class: AppBundle\Form\SearchType
arguments: [AppBundle\Entity\Search]
calls:
- [setAction, ["%app_bundle.form.type.search.action%"]]
tags:
- { name: form.type, alias: tab_search }
And then set the app_bundle.form.type.search.action value in parameters somewhere.
If you want to allow the method to be overridden but set a default, set the action in setDefaultOptions and then override from the controller or a listener.
Related
I'm using sumfony 3.3.10, I have installed a fresh project of symfony and I added knpMenuBundle using this command,
composer require knplabs/knp-menu-bundle "^2.0"
Now I followed everything exactly as mentioned here http://symfony.com/doc/master/bundles/KnpMenuBundle/menu_builder_service.html
and added this line {{ knp_menu_render('main') }} in default/index.html.twig file.
Now when I execute the project, its showing me this error,
[InvalidArgumentException]
Menu builder services must be public but "app.menu_builder" is a private service.
config.yml
knp_menu:
# use "twig: false" to disable the Twig extension and the TwigRenderer
twig:
template: KnpMenuBundle::menu.html.twig
# if true, enables the helper for PHP templates
templating: false
# the renderer to use, list is also available by default
default_renderer: twig
MenuBuilder.php
<?php
namespace AppBundle\Menu;
use Knp\Menu\FactoryInterface;
class MenuBuilder
{
private $factory;
/**
* #param FactoryInterface $factory
*
* Add any other dependency you need
*/
public function __construct(FactoryInterface $factory)
{
$this->factory = $factory;
}
public function createMainMenu(array $options)
{
$menu = $this->factory->createItem('root');
$menu->addChild('Home', array('route' => 'homepage'));
// ... add more children
return $menu;
}
}
services.yml
app.menu_builder:
class: AppBundle\Menu\MenuBuilder
arguments: ["#knp_menu.factory"]
tags:
- { name: knp_menu.menu_builder, method: createMainMenu, alias: main } # The alias is what is used to retrieve the menu
How can I resolve it. Any help is much appreciated. Thanks
I added public: true to the app.menu_builder service in services.php,
app.menu_builder:
class: AppBundle\Menu\MenuBuilder
public: true
arguments: ["#knp_menu.factory"]
tags:
- { name: knp_menu.menu_builder, method: createMainMenu, alias: main } # The alias is what is used to retrieve the menu
And everything is working fine now.
Refer : https://symfony.com/doc/current/service_container/alias_private.html#marking-services-as-public-private
I have some variables in twig-templates, so think use global scope for it.
config.yml
twig:
globals:
varA: "#wf.autoload.getA"
varB: "#wf.autoload.getB"
In service yml I have:
services.yml
wf.autoload:
class: Scope\WfBundle\WfAutoloadService
arguments: ["#doctrine.orm.entity_manager"]
WfAutoloadService class have public function for getting variables
class WfAutloadService {
...
public function getA(){
return ...;
}
public function getB(){
return ...
}
...
}
My idea doesn't work. Method of #=service(wf.autoload).getA() also doesn't work.
Is it possible? Or it bad idea and bad practice?
Thanks
If getA() and getB() returns object, you can use a factory when configuring your service:
services:
wf.autoload:
class: Scope\WfBundle\WfAutoloadService
arguments: ["#doctrine.orm.entity_manager"]
wf.autoload.getA:
class: A
factory: ["#wf.autoload", getA]
And set the global twig:
twig:
globals:
varA: "#wf.autoload.getA"
I you want to use this functions in many twig templates you can create a twig extension
For example :
class MyExtensions extends \Twig_Extension
{
public function getFunctions()
{
return array(
'getA' => new \Twig_Function_Method($this, 'getA', array('is_safe' => array('html')))
);
}
public function getA() // you can if you want pass parameters
{
//your code
return ...
}
}
Declare it as service :
myextensions.twig_extension:
class: Project\YourBundle\Twig\MyExtensions
public: false
tags:
- { name: twig.extension }
And call it in yours twig template :
{{ getA() }}
I have a catch-all fallback route in Symfony2 that I couldn't get to work in Symfony3. I tried this exact syntax (a verbatim copy of my Symfony2 route) and that didn't work.
fallback:
path: /{req}
defaults: { _controller: MyBundle:Default:catchAll }
requirements:
req: ".+"
How can I get this working in Symfony3? (It's literally the only thing holding me back from using Symfony3 and keeping me at v2.8)
This should help you:
route1:
path: /{req}
defaults: { _controller: 'AppBundle:Default:index' }
requirements:
req: ".+"
Where, my controller is called "DefaultController", and I have a function called "indexAction()".
Here is my code for the DefaultController:
class DefaultController extends Controller
{
/**
* #Route("/", name="homepage")
*/
public function indexAction(Request $request)
...
I actually did try what you said in my environment, and it didn't work until I had the right controller settings specified.
EDIT:
For this to work, it was necessary to add the parameter Request $request (with the type hint) to the action's method signature.
I found the current accepted answer almost useful for Symfony 4, so I'm going to add my solution:
This is what I did to get it working in Symfony 4:
Open /src/Controller/DefaultController.php, make sure there is a function called index(){}
It's not required to add the Request $request as first param as some comment suggest.
This is the method that will handle all urls caught by the routes.yaml
Open /config/routes.yaml, add this:
yourRouteNameHere:
path: /{req}
defaults: { _controller: 'App\Controller\DefaultController::index' }
requirements: # the controller --^ the method --^
req: ".*"` # not ".+"
You can also override Exception controller.
# app/config/config.yml
twig:
exception_controller: app.exception_controller:showAction
# app/config/services.yml
services:
app.exception_controller:
class: AppBundle\Controller\ExceptionController
arguments: ['#twig', '%kernel.debug%']
namespace AppBundle\Controller;
use Symfony\Component\Debug\Exception\FlattenException;
use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class ExceptionController
{
protected $twig;
protected $debug;
public function __construct(\Twig_Environment $twig, $debug)
{
$this->twig = $twig;
$this->debug = $debug;
}
public function showAction(Request $request, FlattenException $exception, DebugLoggerInterface $logger = null)
{
// some action
return new Response($this->twig->render('error/template.html.twig', [
'status_code' => $exception->getStatusCode()
]
));
}
}
Error:
...ThemeValidator::__construct() must be of the type array, null given...
For some reason the Service is not being called, but the Class is being loaded directly.
validation.yml
theme:
- NotBlank: ~
- DashboardHub\Bundle\AppBundle\Validator\Constraints\ThemeValidator: ~
Validator Class
<?php
namespace DashboardHub\Bundle\AppBundle\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
class ThemeValidator extends ConstraintValidator
{
protected $config;
public function __construct(array $config)
{
$this->config = $config;
}
public function validatedBy()
{
return 'theme.validator';
}
public function validate($value, Constraint $constraint)
{
var_dump($this->config); exit;
}
// ...
service.yml
dashboardhub_app_main.validator.constraints.theme:
class: DashboardHub\Bundle\AppBundle\Validator\Constraints\ThemeValidator
arguments: ["%dashboard_hub_app%"]
tags:
- { name: validator.constraint_validator, alias: theme.validator }
Edit
parameters:
dashboard_hub_app:
themes:
Github: DashboardHubAppBundle:Template:Github.html.twig
GithubTravis: DashboardHubAppBundle:Template:GithubTravis.html.twig
Edit2
It works find when used in the Form Service
dashboardhub_app_main.form.type.dashboard:
class: DashboardHub\Bundle\AppBundle\Form\DashboardType
arguments: ["%dashboard_hub_app%"]
tags:
- { name: form.type, alias: dashboard }
parameters:
dashboard_hub_app: -- !!!!! IS NULL yes
funny :)
parameters follow one by one, so you need to be careful, paramenters && themes - are different.
to inject an array you need provide a value for this paramenter, but i guess you need to inject this one
themes:
Github: DashboardHubAppBundle:Template:Github.html.twig
GithubTravis: DashboardHubAppBundle:Template:GithubTravis.html.twig
arguments: ["%themes%"]
and result will be an array inside your Validator class
array (size=2)
'Github' => string 'DashboardHubAppBundle:Template:Github.html.twig' (length=47)
'GithubTravis' => string 'DashboardHubAppBundle:Template:GithubTravis.html.twig' (length=53)
I created my own form type at Me\MyBundle\Form\Type\UserFormRegistrationType:
namespace Me\MyBundle\Form\Type;
use FOS\UserBundle\Form\Type\RegistrationFormType as BaseType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class UserFormRegistrationType extends BaseType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
parent::buildForm($builder, $options);
// all my unique fields
}
public function getName()
{
return 'user_registration';
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array('data_class' => 'Me\MyBundle\Entity\User'));
}
}
I have the following in my services.yml:
services:
me_my.registration.form.type:
class: Me\MyBundle\Form\Type\UserFormRegistrationType
arguments: [%fos_user.model.user.class%]
tags:
- { name: form.type, alias: user_registration }
And the following added to my config.yml:
# other config stuff
fos_user:
# database stuff, general config
registration:
form:
type: user_registration
Yet, when I try to access my registration form/page, I get:
Could not load type "user_registration"
Any hint to what I'm obviously missing? It's not a firewall issue. I had one, but tweaking my security.yml fixed it. This is a pure not found error. Very annoying, as I believe I followed the docs to the letter.
You should not use aliases anymore
In your config file :
Before :
registration:
form:
type: user_registration
New :
registration:
form:
type: 'CoreBundle\Form\Type\RegistrationFormType'
In your src/CoreBundle/Form/Type/RegistrationFormType.php: getParent() function should be :
public function getParent()
{
return "FOS\UserBundle\Form\Type\RegistrationFormType";
}
Don't forget the use on the top of the file :
use FOS\UserBundle\Form\Type\RegistrationFormType;
Hi here is the explanation :
https://stackoverflow.com/a/53048060/7888453
Official :
https://github.com/symfony/symfony/blob/3.4/UPGRADE-3.0.md#form
Take a look at this guys problem and then the solution that he provides to his own question. I went off of his code and modified it to match the names within my files and it worked!
How to override register form FosUserBundle?
The docs declined to mention/remind that the service needs to be registered in config.yml.