I am new to symfony2. I started it with some tutorials and then started building SYMBLOG. I have understood it and i am able to add or change the functionality. I have a bit confusion in the workflow, I mean How the files work together to render a page or to produce an output. Can anyone explain me in detail from the beginning how this flow goes on in symfony2. starting from the user request say user enters a url till the symfony2 displays results. please include the routing.yml in the flow. ?
You should check out this link. Symfony - the big picture
It explains in detail all the steps involved from the time you enter the URL in the browser to the page getting rendered.
Basically all requests go to a Front Controller. Its job is to route the requests to the appropriate controller code. It does this with the help of the routes defined in the app/config/routing.yml file. The controllers which are defined in src/<BundleName>/Controller/<name> perform some business logic, like getting data from the Model (Repository) and send that information to the View (Templates). The views are simply HTML code. Symfony uses a templating engine called Twig. Instead of including <?php ... ?> blocks in the HTML code, Symfony passes the data from the controller and it can be easily used inside the view within Twig {% %} or {{ }} blocks.
Simply put, here is the workflow:
Browser sends Request
Request received in front controller web/app_dev.php or web/app.php
Front controller checks the routes defined in app/config/routing.yml and sends the request to the appropriate
controller defined in src/<BundleName>/Controller/<controller_name>
Controller prepares the content that is needed in the HTML (Example - query the database from src/<BundleName>/Repository) and sends the information to the View - src/Resources/views/<twig file name>
The view creates the HTML and sends it back to the controller
The controller creates an HTTP response and sends it back to the browser
There are things like the app/AppKernel that come in between but I have skipped it.
Here are the useful excerpts from the link provided above:
URL:
http://localhost/Symfony/web/app_dev.php/demo/hello/Fabien
What's going on here? Let's dissect the URL:
app_dev.php: This is a front controller. It is the unique entry point of the application and it responds to all user requests;
/demo/hello/Fabien: This is the virtual path to the resource the user wants to access.
Your responsibility as a developer is to write the code that maps the user's request (/demo/hello/Fabien) to the resource associated with it (the Hello Fabien! HTML page).
Routing:
Symfony2 routes the request to the code that handles it by trying to match the requested URL against some configured patterns. By default, these patterns (called routes) are defined in the app/config/routing.yml configuration file. When you're in the dev environment - indicated by the app_dev.php front controller - the app/config/routing_dev.yml configuration file is also loaded. In the Standard Edition, the routes to these "demo" pages are placed in that file:
_welcome:
pattern: /
defaults: { _controller: AcmeDemoBundle:Welcome:index }
Controller:
Symfony2 chooses the controller based on the _controller value from the routing configuration: AcmeDemoBundle:Welcome:index. This string is the controller logical name, and it references the indexAction method from the Acme\DemoBundle\Controller\WelcomeController class:
class WelcomeController extends Controller
{
public function indexAction()
{
return $this->render('AcmeDemoBundle:Welcome:index.html.twig');
}
}
View:
The controller renders the src/Acme/DemoBundle/Resources/views/Demo/hello.html.twig template
{% extends "AcmeDemoBundle::layout.html.twig" %}
{% block title "Hello " ~ name %}
{% block content %}
<h1>Hello {{ name }}!</h1>
{% endblock %}
You may also want to check out the Symfony2 architecture
Related
I have this Behat setup:
default:
extensions:
Behat\Symfony2Extension: ~
Behat\MinkExtension:
sessions:
default:
symfony2: ~
And this scenarion:
Scenario: Event list for authenticated user
Given I am authenticated
Then I should see pagination control
And I should be able to change list page
I check if the user is authenticated and if so show him pagination control in Twig:
{% if is_granted('IS_AUTHENTICATED_FULLY') %}
...
Related Behat context:
/**
* #Given I am authenticated
*/
public function iAmAuthenticated()
{
$user = new User('test', null, ['ROLE_USER']);
$token = new UsernamePasswordToken($user, null, 'test', $user->getRoles());
$this->getTokenStorage()->setToken($token);
}
/**
* #Then I should see pagination control
*/
public function iShouldSeePaginationControl()
{
$this->assertSession()->elementExists('css', 'ul.pagination');
}
I get true for
$this->kernel
->geContainer()
->get('security.authorization_checker')
->isGranted('IS_AUTHENTICATED_FULLY')
in my iShouldSeePaginationControl() but it is false in rendered content.
What am I missing?
My guess is that you're using a different instance of the container in your behat step and in your template.
AFAIR, the symfony2 driver uses BrowserKit under the hood to navigate through your website. The container which will be used in your web page will then be instanciated by the PHP Engine of your Web server (and not by Behat). If so, it is absolutely impossible to operate modifications in the container at runtime in a step and expect that the web server will be aware of them.
Easy solution would be to actually log in in the behat step (through the web interface) instead of setting the token manually.
Another harder way, if you absolutely want to login programatically, would be to serialize the created token on HDD and register some kind of logic (a kernel.request listener for example) that will check if this file is available and inject the unserialized token in the security context. If you do so, MAKE SURE that you enable this logic in TEST environment only, as it potentially is a security breach.
The problem is you have running 2 instances of Symfony:
One core for Behat, that was initialized.
Second, initialized by apache/nginx that was triggered by Mink connection to the server.
Solution
For that, we had a solution in another project (with Zend).
We created service, that created an additional configuration to authorization:
if a file exists and the project was in DEV mode, then it was loaded in the initialization step.
Then in hook/step we could call service that generates a file like that and after scenario, delete it. This way, you could have any logged user in your project.
Another way is to call steps that will log you into your project via a standard form.
So I use Pubnub for WebRTC in my Symfony 2 application, and all works well, apart from the showing of videos of other users. What happens is that when a user connects, an url gets generated like this one:
mediastream:http://www.domain.com/cd024a62-02fa-42eb-8f52-621074ea887e
These url's are temporary, and the only purpose is to serve as a way to connect video streams. After the WebRTC session the do not exist anymore and they are impossible to predict.
Since the Symfony router cannot find a route to 'http://www.domain.com/cd024a62-02fa-42eb-8f52-621074ea887e', the stream is never showed (www.domain.com is the url to the symfony application in this example).
What I could do is adapt the exisiting scripts so that all video streams look like 'http://www.domain.com/video/cd024a62-02fa-42eb-8f52-621074ea887e', but in that case any route with prefix /video/ should be left alone by Symfony.
Any ideas?
In the end I found a solution. As a last routing rule I added:
display_blob:
defaults: { _controller: Bundlename:Main:blob }
path: /{blob}
Then I created a function in the Main controller:
public function blobAction(Request $request)
{
$path = $request->getUri();
return $this->render($path);
}
Of course I need to do some filtering of the URL itself and check if it really is a stream, but for now I am happy it works.
Trying to implement an optional routing prefix and running into some issues. Here is my route definition:
[RoutePrefix("{tenant:range(10,12)?}")]
[Route("{action=Index}")]
public class HomeController : Controller {
Routes are:
{tenant}/Index
{tenant}/Search
Loading the site with a tenant works fine, such as:
https://localhost:44300/10/
Using #Url.Action("Search", "Home") generates a correct link to the Search Action.
Without tenant, the site loads:
https://localhost:44300/
But I am unable to load the "non-default" action such as "Search", returns a 404. Also, the Url Helper generates a link such as: https://search
The range condition is temporary. I will have to further develop a custom constraint to actually verify the value.
I want my custom error pages to use my main application base template. By base template uses KnpMenu to build a menu. Parts of the meny are only rendered for privileged users, and do to do that I inject the security component and do checks like this:
if ($security->isGranted('ROLE_COURSES')) {
However, when there's a 404 an exception is thrown in the routing component which is executed before the firewall component is run.
I'm not entirely sure what is actually injected into the menu builder since the security component has not yet run, but regardless, I'm getting another exception when I try to go to a non-existent page in production when that if statement is executed.
What's the recommended approach here? If I have to abandon rendering the menu for my 404's, I guess that's ok, but I was hoping I could still render the menu in its complete form.
I know this is an old issue, but facing this problem myself I fixed it by creating an extra route which matches everything and is the last thing to match of my routes:
pageNotFound:
pattern: /{path}
defaults: { _controller: MyContentBundle:PageNotFound:pageNotFound, path: '' }
requirements:
path: .*
The action is simply:
public function pageNotFoundAction()
{
throw new NotFoundHttpException();
}
Since you are throwing the NotFound exception from a controller, the firewall has already been run and you now have app.user in your custom 404 error page.
There are tonnes about this around the internet, it's related to the routing being loaded before the security context so when the route isn't found the user isn't even created.
A way to use it in your template is to use {% if app.user is not null and is_granted() %} as stated in https://github.com/symfony/symfony-docs/issues/2078.
I assume that could be translated to
if (null !== $securityContext->getToken() && $securityContext->isGranted())
but I haven't tried it so I'm not sure.
I'm trying to learn learn how routing works in Symfony2, and so far everything I've read has examples like this:
blog:
path: /blog/{page}
defaults: { _controller: AcmeBlogBundle:Blog:index, page: 1 }
This routes requests to /blog/123 to the AcmeBlogBundle Blog controller's "index" action, and passes the 123 parameter as the "page" parameter to that controller action. If no page parameter is passed, then the page defaults to 1.
That's all well and good, but what if you want to simply have a convention based routing system that passes things through like this:
/{bundle}/{controller}/{action}
So, for a URL like this:
/acme/blog/index
It would then call AcmeBlogBundle Blog controller's "index" action.
No specific routing configuration is necessary, it simply infers the bundle, controller, and action from the URL. So you can continue adding bundles, controllers, and actions, and you don't need to modify the routing configuration. It just works.
If this isn't possible, can you at least infer the controller and action from the URL? E.g., perhaps you need a route that specifically identifies the bundle, but can we get the controller and action from the URL?
I read through the Symfony "The Book" page about routing, and I couldn't figure out a way to do this.
No way. This was considered as bad practice and so it was removed from symfony.
But you should take a look at the #Route annotation, as it simplifies configuring routes in such a nice way. Directly attached to the action, there is no lack between config and code.