(I deleted previous similar subject, because there was too many changed in the code).
I use Symfony\Component\HttpFoundation\Session\Session and Symfony\Component\HttpFoundation\Request but without all framework.
I have simple index
$request = Request::createFromGlobals();
$session = new Session();
if(!$session->isStarted()){
$session->start();
}
$request->setSession($session);
$kernel = new Kernel(new AppContainer());
$response = $kernel->handle($request);
$response->send();
it works well when I use just twig templates.
When I use any class what implements FormRendererInterface it throw me an error.
I expect that by CsrfTokenManager.
This problem doesn't exists when I use $session = new Session(new PhpBridgeSessionStorage()); in index.php. Unfortunately in such case sessions in the next request are empty (this is logic, because I sessions auto start in php.inii is disabled).
Bellow is code what I use in the controller to use form builder.
...
$form = (new LoginForm($this->formBuilder))->getForm($this->generateUrl('login'));
$form->handleRequest($request);
Match::val($form->isSubmitted() && $form->isValid())
->of(
When::equals(true, function($item) use ($form){
$this->commandBus->dispatch(new UserLogin($form->getData()));
}),
When::other(false)
);
...
Thanks for any hints.
SOLUTION
The issues was because to build form I use class FormBuilder what is abstract for others forms and it was provided as service.
There is creating csrf token and to do it I need to session instance.
I could not fond sessions in this class because it was configured in AppContainer.
So finally I had session what was start in the index.php and next try to start in the SessionTokenStorage. It has been throwed an error.
Now session is create in the AppContainer as public service.
I can set the same instance as parameter for others services and also add to the request by $appContainer->get('sessions').
Little bit of code
services.yaml
...
sessions:
class: Symfony\Component\HttpFoundation\Session\Session
arguments: []
public: true
form.builder:
class: Iaso\Web\Component\Form\FormBuilder
arguments: ['#twig','#config.loader', '#sessions']
public: true
index.php
<?php
...
$request = Request::createFromGlobals();
$appContainer = new AppContainer();
$session = $appContainer->get('sessions');
if(!$session->isStarted()){
$session->start();
}
$request->setSession($session);
$kernel = new Kernel($appContainer);
$response = $kernel->handle($request);
$response->send();
Related
First off, I am building using Symfony components. I am using 3.4. I was following the form tutorial https://symfony.com/doc/3.4/components/form.html which lead me to this page
https://symfony.com/doc/current/forms.html#usage
I noticed that Symfony added a Form directory to my application.
This was great! I thought I was on my way. So, in my controller, I added this line.
$form = Forms::createFormFactory();
When I tried loading the page, everything went well with no error messages until I added the next two lines.
->addExtension(new HttpFoundationExtension())
->getForm();
I removed the ->addExtension(new HttpFoundationExtension()) line and left the ->getForm() thinking it would process without the add method call. It did not. So, I backed up to see if the IDE would type hint for me.
In the IDE PHPStorm, these are the methods that I have access to but not getForm per the tutorial
Every tutorial I have tried ends with not being able to find some method that does not exist. What do I need to install in order to have access to the ->getForm() method?
UPDATE:
I have made a couple of steps forward.
$form = Forms::createFormFactory()
->createBuilder(TaskType::class);
The code above loads with no errors. (Why is still fuzzy). But next stop is the createView(). None existant also. I only get hinted with create().
Reading between the lines in this video help with the last two steps. https://symfonycasts.com/screencast/symfony3-forms/render-form-bootstrap#play
UPDATE 2:
This is what I have now.
$session = new Session();
$csrfManager = new CsrfTokenManager();
$help = new \Twig_ExtensionInterface();
$formFactory = Forms::createFormFactoryBuilder()
->getFormFactory();
$form = $formFactory->createBuilder(TaskType::class)
->getForm();
//$form->handleRequest();
$loader = new FilesystemLoader('../../templates/billing');
$twig = new Environment($loader, [
'debug' => true,
]);
$twig->addExtension(new HeaderExtension());
$twig->addExtension(new DebugExtension());
$twig->addExtension($help, FormRendererEngineInterface::class);
return $twig->render('requeueCharge.html.twig', [
'payments' => 'Charge',
'reportForm' => $form->createView()
]);
Does anyone know of an update standalone for example? The one that everyone keeps pointing two is 6 years old. There have been many things deprecated in that time period. So, it is not an example to follow.
Your Form class and method createFormFactory must return object that implement FormBuilderInterface then getForm method will be available. You need create formBuilder object.
But this can't be called from static method because formBuilder object need dependency from DI container. Look at controller.
If you want you need register your own class in DI and create formBuilder object with dependencies and return that instance of object.
EDIT
You don't need to use abstract controller. You can create your own class which is registered in DI for geting dependencies. In that class you create method which create new FormBuilder(..dependencies from DI from your class ...) and return instance of that FormBuilder. Then you can inject your class in controller via DI.
Example (not tested)
// class registered in DI
class CustomFormFactory
{
private $_factory;
private $_dispatcher;
public CustomFormFactory(EventDispatcherInterface $dispatcher, FormFactoryInterface $factory)
{
$_dispatcher = $dispatcher;
$_factory = $factory;
}
public function createForm(?string $name, ?string $dataClass, array $options = []): FormBuilderInterface
{
// create instance in combination with DI dependencies (factory..) and your parameters
return new FormBuilder($name, $dataClass, $_dispatcher, $_factory, $options);
}
}
Usage
$factory = $this->container->get('CustomFormFactory');
$fb = $factory->createForm();
$form = $fb->getForm();
I created a php file in \web folder (that's mean outside of the application right?), I set a variable in a session within the application (in a controller action), but I can't get that session outside the application (in the external php file). I got always empty session.
this is the controller's action where I set the session
*/
public function questionnaireConfigAction($id,Request $request)
{
$em=$this->getDoctrine()->getManager();
$questionTypes=$em->getRepository(QuestionType::class)->findAll();
$questionnaire = $em->getRepository(Questionnaire::class)->find($id);
$session = new Session();
$session->set('fileContext',['questionTypes'=>$questionTypes,'questionnaire'=>$questionnaire]);
return $this->render('questionnaires/questionnaireConfig/config.html.twig',
['questionTypes'=>$questionTypes,
'questionnaire'=>$questionnaire]);
}
and here is the external file
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Response;
use AppBundle\twigExtentions\filesLoader;
use Symfony\Component\HttpFoundation\Session\Storage\PhpBridgeSessionStorage;
$loader = require __DIR__.'/../app/autoload.php';
$request = Request::createFromGlobals();
$session = new Session();
$session->start();
dump($session->get('fileContext')); /*get nothing here */
[SOLVED]
i find the solution . by using PhpBridgeSessionStorage class
ini_set('session.save_handler', 'files');
ini_set('session.save_path', 'path/to/save file');
session_start();
$session = new Session(new PhpBridgeSessionStorage());
$session->start();
dump($session->get('fileContext'));
here the symfony doc
I'm writing my own PHP framework built on top of Symfony components as a learning exercise. I followed the tutorial found at http://symfony.com/doc/current/create_framework/index.html to create my framework.
I'd now like to wire up my routes against my controllers using annotations. I currently have the following code to setup the routing:
// Create the route collection
$routes = new RouteCollection();
$routes->add('home', new Route('/{slug}', [
'slug' => '',
'_controller' => 'Controllers\HomeController::index',
]));
// Create a context using the current request
$context = new RequestContext();
$context->fromRequest($request);
// Create the url matcher
$matcher = new UrlMatcher($routes, $context);
// Try to get a matching route for the request
$request->attributes->add($matcher->match($request->getPathInfo()));
I have come across the following class to load the annotations but I'm not sure how to use it:
https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Routing/Loader/AnnotationDirectoryLoader.php
I'd appreciate it if someone could help.
Thanks
I've finally managed to get this working. First I changed where I included the autoload.php file to the following:
use Doctrine\Common\Annotations\AnnotationRegistry;
$loader = require __DIR__ . '/../vendor/autoload.php';
AnnotationRegistry::registerLoader([$loader, 'loadClass']);
Then I changed the routes collection bit (in the question) to:
$reader = new AnnotationReader();
$locator = new FileLocator();
$annotationLoader = new AnnotatedRouteControllerLoader($reader);
$loader = new AnnotationDirectoryLoader($locator, $annotationLoader);
$routes = $loader->load(__DIR__ . '/../Controllers'); // Path to the app's controllers
Here's the code for the AnnotatedRouteControllerLoader:
class AnnotatedRouteControllerLoader extends AnnotationClassLoader {
protected function configureRoute(Route $route, ReflectionClass $class, ReflectionMethod $method, $annot) {
$route->setDefault('_controller', $class->getName() . '::' . $method->getName());
}
}
This has been taken from https://github.com/sensiolabs/SensioFrameworkExtraBundle/blob/master/Routing/AnnotatedRouteControllerLoader.php. You may wish to modify it to support additional annotations.
I hope this helps.
I'm using the Symfony Routing components standalone, i.e. not with the Symfony framework. Here's my bare-bones code I'm playing with:
<?php
$router = new Symfony\Component\Routing\RouteCollection();
$router->add('name', new Symfony\Component\Routing\Route(/*uri*/));
// more routes added here
$context = new Symfony\Component\Routing\RequestContext();
$context->setMethod(/*method*/);
$matcher = new Symfony\Component\Routing\Matcher\UrlMatcher($router, $context);
$result = $matcher->match(/*requested path*/);
Is there a way to cache the routes, so I don't need to run all the add() calls on every page load? (See for example FastRoute.) I believe there is caching when using the full Symfony framework, can that be implemented easily here?
The Symfony Routing Component documentation contains an example of how to easily enable the cache: The all-in-one Router
Basically your example can be reworked like the following:
// RouteProvider.php
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;
$collection = new RouteCollection();
$collection->add('name', new Route(/*uri*/));
// more routes added here
return $collection;
// Router.php
use Symfony\Component\Config\FileLocator;
use Symfony\Component\Routing\RequestContext
use Symfony\Component\Routing\Loader\PhpFileLoader;
$context = new RequestContext();
$context->setMethod(/*method*/);
$locator = new FileLocator(array(__DIR__));
$router = new Router(
new PhpFileLoader($locator),
'RouteProvider.php',
array('cache_dir' => __DIR__.'/cache'), // must be writeable
$context
);
$result = $router->match(/*requested path*/);
I want to use a standalone Symfony2 Routing component in my small site. I've created this according to documentation and some examples:
$request = Request::createFromGlobals();
$routeTest = new Symfony\Component\Routing\Route('/route-test', array('controller' => 'test'));
$routes = new Symfony\Component\Routing\RouteCollection();
$routes->add('test', $routeTest);
$context = new Symfony\Component\Routing\RequestContext();
$context->fromRequest($request);
$matcher = new Symfony\Component\Routing\Matcher\UrlMatcher($routes, $context);
$matcher->match($request->getPathInfo());
I don't understand how I should call my controller test, that I've passed to the Route constructor. As a result I want to get something like Silex Route matching:
$app->get('/hello/{name}', function($name) use($app) {
return 'Hello '.$app->escape($name);
});
And sorry for my english...
$matcher->match() returns[1] the attributes of the matching route[2] (including a special _route attribute containing the route name [3]).
The controller default is included in the attributes too, so you can easily access it and then use something like call_user_func to call the controller:
// ...
$attributes = $match->match($request->getPathInfo());
$controllerResult = call_user_func($attributes['controller']);