Categories
Web Development

How to get the user id in a service in Symfony 5

I’m no Symfony expert, I write what I find as I find it. Nothing in the documentation really covers this subject, so I am not sure what the correct way is of if there even is one.

There are a few ways I have found to get a user id. None of the classes you can inject such as UserInterface, SessionInterface, TokenInterface, Security etc. contain an actual getUserId() method.

You can  get a user object from the Security class, as seen in the documentation here. To do so you type hint aka Dependency Inject your service constructor with Security but not just any Security will do there is also one by Sensio labs and another. You want this Security

use Symfony\Component\Security\Core\Security;

Then your ide wont show it or will warn something about a polymorphic call blah blah, but apparently there is a getId() method of the user returned from Security and you can get a user id like this.


/** @var User $user */
$user = $this->security->getUser()->getId();
if(!empty($user){
$userId = $user->getId();
}

This method may return null if the user is not logged in so you need to check for that. The @var syntax tells the IDE what is going on so it knows there is a getId() method, you will also need to import that class. The User object it refers to is your App/Entity/User class.

Forgive me if anything is wrong.
Link to a Symfony cast with a little more info but not much.

Categories
Resources Web Development

How does login and authentication work in Symfony 5.*

This is mostly for myself as a reminder. The most frustrating part of Symfony is Authentication because the information is scattered all over between articles, symfonycasts etc. just all over, like a unicorn farting out rainbow sprinkles.

There are two versions of authentication an old one and a new one. The old one uses Authentication providers the new one users just Authetincators. No one but the authors of Symfony know WTF the difference is though.

Note : to add confusion Symfony refers to what you usually call Sessions as Tokens FFS.

First off a list of files involved in the login process :

  1. The login form obviously app/templates/security/login.html.twig
  2. A security controller app/src/Controller/SecurityController.php
  3. A user Provider aka the User entity class app/src/Entity/User.php
  4. An Authenticator app/src/Security/LoginFormAuthenticator.php

When a user requests /login Symfony first calls LoginFormAuthenticator.php to check to see if the user is logged in/authenticated so the work is not done in the controller like most other actions. To change, add, remove anything from the authentication process you make changes in the LoginFormAuthenticator.php methods.

There is a new experimental Authentication system it still uses authenticators but a slightly different process.

This authenticator is listed in the app/config/packages/security.yaml file under firewalls:main:guard:athenticators as

- App\Security\LoginFormAuthenticator

symfony firewall authenticator section

Every time a request is made the firewall will use the authenticator listed to try to authenticate the user. If authentication fails Symfony secretly behind the scenes tries other ways to authenticate the user as you can see in the image below.

symfony guards
Secret guards attack

As you can see in the image above Symfony will try your guard you listed in the configuration file, but it also tries it’s own secret list of default authenticators.

For information about the login form see this article in the scatterdocs. A little more info about the login form and process from the Symfony Spaghetti docs.

Categories
Resources Web Development

Symfony Session resources list

Plain session docs – This is the symfony documentation page about Sessions alone. This link shows the basic configuration and use of Sessions in Symfony. This also mentions not starting a session for Anonymous users and has links to other info about sessions.

Configuring Sessions and Save handlers – Symfony documentation link. This covers more about how to configure sessions and their Save Handlers. This is some of the better information about Sessions and how they work in Symfony. It covers the save handlers and more of the configuration information.

Session proxy examples – Symfony Documentation link. This covers how to create your own session handler. It also discusses how to encrypt session data with an example.

Framework configuration – Symfony documentation link. This covers many of the options for the security component of Symfony.

Store sessions in a database – Symfony documentation link that describes how to store session data in a database or Redis.

Session Management – Symfony documentation link. Explains how sessions are managed in symfony. Gives a good overview and important information about how symfony functions. It covers the functions symfony uses to replace PHP session functions and how to use them. This also covers the ways to work with sessions in Symfony. Oddly this covers Flash messages too.

 

Categories
Resources Web Development

Symfony errors and exception handling resources

How to customize error pages – Documentation page about how to create custom error pages.
How to Customize Access Denied Responses – specifically about how to customize access denied responses. This is useful for when you use voters to authorize a users access to content.

Categories
Resources

Links and resources about Symfony firewall and authentication system

One thing you will want to do is view your current security settings to do so you use this command.
php bin/console debug:config security

Old symfony cookbook security entry – This is an ancient link to nearly the very beginning of symfony. This explains the mechanics of the Symfony security system if you are like me and just want to know how the hell this functions so you can feel confident in the system and be able to diagnose and fix issues.

More on Security – this is another ancient link like above, it explains the system.


Symfony cast covering
firewall and authentication and how it works. This has lots of info that should be directly in the documentation.

Security configuration reference -> not complete listing of some of the values you can set. If you run the debug:config command above you will see more values you can set, but good luck figuring out what they do.

How to restrict firewalls to a request -> symfony docs. This talks about using multiple firewalls and how the Symfony firewall system works like a waterfall trying one firewall after another until it finds one that works or uses the last  firewall listed. This also explains some of the options to the firewall. This basically shows how to use multiple firewalls.

Symfony cast about security – this covers the entire system. Some things have changed in version 5 but this is mostly correct and serves as a starting point.

Security user providers – Part of the Firewall/Authentication/Authorization system is something called security providers. User providers check the users identity from a session cookie to verify the user. This part of the documentation talks about how the firewall uses the User providers to authenticate the user after they have logged in.

Custom Authentication System with Guard (API Token Example) – talks about how to create a custom API token

Built-in Authentication Providers – documentation about the built in service providers.

Symfony Cast about gaurds – this is ancient from version 3, but it is helpful because it covers how the system is supposed to work or was supposed to.

The firewall and authorization – this covers how authorization works in the firewall system. It has a section at the bottom that explains how the firewall/authentication/authorization flow works.

Using the form_login Authentication Provider  – This explains how to create a login form and how the system processes it and authenticates the user.

Videos


A good video explaining how multiple authenticators work

Categories
Resources

Links and resources about Symfony Doctrine fixtures

Symfony cast page about fixtures.

Categories
Resources Web Development

Symfony caching resource list and information

Once I started digging into Symfony caching I found all kinds of information all over. I’ll use this page to catalog it all for myself and others. This way I can quickly find what I am looking for.

Cache – From the docs. This is the overall plain documentation about Symfony cache. It covers the following

Configuring Cache with FrameworkBundle
Creating Custom (Namespaced) Pools
Custom Provider Options
Creating a Cache Chain
Using Cache Tags
Clearing the Cache
Encrypting the Cache

The Symfony Cache component – This is the actual caching component documentation. It covers the following.

Installation
Cache Contracts versus PSR-6
Cache Contracts
Available Cache Adapters
Generic Caching (PSR-6)
Basic Usage (PSR-6)
Advanced Usage

Cache pools and Adapters – from the documentation. This covers cache adapters such as Redis and Memcached. It covers the following information.

Creating Cache Pools
Using the Cache Contracts
Using PSR-6
Looking for Cache Items
Saving Cache Items
Removing Cache Items
Pruning Cache Items

Cache items – from the documentation. You need ItemInterface and cache items in order to set expire information on cached items. This link covers the following :

Cache Item Keys and Values
Creating Cache Items
Cache Item Expiration
Cache Item Hits and Misses

Tagged Cache aka Tag Aware Caching – This article explains how tag aware caching works in Symfony. The article is old from version 3.2 when this feature was added.

Categories
Resources Web Development

Symfony 5+ check if user is logged in inside a twig template

Often you may need to know whether a user is logged in or not inside a template to show or not show something. For example you might want to show links to login or register if a user is not logged in but show a link to logout if the user is logged in.

To do this you use is_granted() within a template with one of the following.

IS_AUTHENTICATED_ANONYMOUSLY, IS_AUTHENTICATED_REMEMBERED, IS_AUTHENTICATED_FULLY

<div class="modal-body">
<ul class="nav flex-column">
{% if is_granted('ROLE_SUPER_ADMIN_1') %}
<a class="nav-link" href="{{ path('show_dash') }}">Dashboard</a>
{% endif %}
{% if is_granted('ROLE_USER') %}
<a class="nav-link" href="{{ path('app_logout') }}">Logout</a> {% else %}
<a class="nav-link" href="{{ path('app_login') }}">Login</a> or <a class="nav-link" href="{{ path('app_register') }}">Signup</a> {% endif %}
</ul>
</div>

Using ROLE_SUPER_ADMIN_1 which is something I made up for my own app to check what type of admin the user is. I don’t really like the IS_AUTHENTICATED_* methods, read more about them in the link below if you want.

Link to more information about IS_AUTHENTICATED_* here in  a really old symfony cast I found via google.

Categories
Resources Web Development

How to create a cookie in Symfony 5.0+ and render a template in a controller

First what I wanted to do was create a cookie in a Controller and display a template at the same time. Sort of like when a user visits a page you set a page count or something. The documentation doesn’t really show an example, you are expected to know it via “common sense” apparently according to one smartass.

There is more than one way I have discovered over time. Apparently you can use render the same way I show using renderView.

Below is the Symfony Cookie class create method comment/documentation. This is all of the values you can supply when creating a cookie.

 /**
     * @param string                        $name     The name of the cookie
     * @param string|null                   $value    The value of the cookie
     * @param int|string|\DateTimeInterface $expire   The time the cookie expires
     * @param string                        $path     The path on the server in which the cookie will be available on
     * @param string|null                   $domain   The domain that the cookie is available to
     * @param bool|null                     $secure   Whether the client should send back the cookie only over HTTPS or null to auto-enable this when the request is already using HTTPS
     * @param bool                          $httpOnly Whether the cookie will be made accessible only through the HTTP protocol
     * @param bool                          $raw      Whether the cookie value should be sent with no url encoding
     * @param string|null                   $sameSite Whether the cookie will be available for cross-site requests
     *
     * @throws \InvalidArgumentException
     */

If you create a cookie like this :

$response->headers->setCookie(Cookie::create('foo', 'bar'));

Then the cookie will only live/exist until the user closes their browser(unless your browser restores from your last session). You must supply an expires time to make it persist beyond closing the browser. Providing an expires time gives you better control over when the cookie expires due to the above mentioned browser restore issue which will restore cookies that should have died on browser close.

You can also create the cookie then pass it to setCookie() like this.

 $response = new Response();
        $expires = time() + 36000;
        $cookie = Cookie::create($cookieName, $cookieValue,  $expires);
        //$cookie = $response->headers->setCookie(Cookie::create('foo', 'bar'));
        $response->headers->setCookie($cookie);

        $content = "<html><body><h1>Learning symfony cookie creation techniques?</h1></body></html>";
        $response->setContent($content);
        $response->headers->set('Content-Type', 'text/html');
        return $response;

Here I set the expires to a number,  time() returns a linux/unix timestamp and I added 36000 seconds or 10 hours to it. This cookie will exist until the user refreshes their page or clicks a link in 10 hours from creation. However long you want it to live you add that many seconds. Or you could create a date using PHP DateTime as you can pass a DateTime object to the expires position. You then use the methods of DateTime to increase the time to a period in the future and pass the DateTime object after calling the methods to do so.

Side Note : in the above code, you can create a cookie without the $response->setContent() call. I do that with the body tag so that the profiler will show up at the bottom of the page for debugging.

That code goes inside a controller method for the requested route by the way. Usually you use the render() method inside a controller to send a response, which renders the template and sends it in a response. You can also use renderView to do the same thing and capture the value in a variable then use setContent or just make the renderView call right in setContent. I know that works. You can also store the returned value from render the same way.  But no matter how you do it, you must return the response object, the very last line. You can find all the methods of the Response class here in the source code.

If you wanted to render a view which requires variables to be sent you do it like this and capture the output of renderView().


 $content = $this->renderView('blog/display_article.html.twig', [
            'title' => $title,
            'article' => $article,
            'tags' => implode(', ', $tags),
            'tagLinks' => $links,
            'edit' => $editLink,
            'affiliateUrl' => $affiliateUrl,
            'backButton' => $backButton
        ]);

Note : do not just use php setcookie or setrawcookie. The reason is they start sending output headers to the browser, which may interfere with how symfony works. You probably won’t notice in a browser, but you may get errors when testing your controllers with functional tests etc.

Personally I created a huge class which extends DateTime which has all kinds of methods for adding days, hours, removing them and doing other math. I’d share it on github but it has bugs since I wrote it way back in version 5 of php in 2012. Some changes were made to DateTime and I haven’t had time to review them all and hunt down the changes that need to be made yet. I’ll probably do it and add it to github eventually.  But for now I use time() + seconds. It’s not the best solution but it works and I only need this one cookie.

And another person found me more hidden docs about cookies, I wish I had this days ago.

As another note. Any values you put in a cookie you must sanitize before trying to use them in any way since users can access and change regular cookie values.

Categories
Resources Web Development

Symfony 5 how to clear the cache

I can never ever remember where I see anything ever I read entirely too much about entirely too many subjects. I mostly use this site as my own personal google.

To clear all caches
php bin/console cache:pool:clear cache.global_clearer

Symfony docs link to more info.