Categories
Web Development

How to quickly create a Symfony 5+ controller

A Symfony 5 controller is just a class. You could just use your IDE to create a new class  for you, but you would need  to add some boiler plate code like the namespace and then extend AbstractController and add some use statements etc.

Symfony 5+ has a better way though. With just one command you can have a new controller created with the basic boiler plate already created. How do you ask? With a simple Symfony maker command.

php bin/console make:controller NewControllerName

IT is that easy. Now you can go to the new Controller and start adding methods. Here is a deeper explanation.

This also creates a template. You can delete the template if you don’t need it or leave it. I got the following output when creating UserImageController


created: src/Controller/UserImageController.php
created: templates/user_image/index.html.twig
Categories
rants

Ubuntu 20 slow and freezes often

I’ve used Ubuntu since version 8 or about 2009/2010ish. It used to be super fast. You used to be able to run it on ANYTHING. It was easy to use.

These days Ubuntu is SLOWER THAN MOLASSES IN THE WINTER IN SIBERIA. So slow I am HONESTLY thinking about switching back to Windows just so I can work. I rather not spend my time working than investigating and typing utter bullshit cryptic commands into the command line.

nothing works meme
Ubuntu 20

Booting is extra slow, 3 to 5 minutes on an i7 with 16Gb ram. That is purely insane. Opening any program is slower than hell, whether it is a browser or an IDE, Slow. Drivers?

CONSTANT CRASHES AND FREEZES.

Linux has a special trick called freeze…

And once this MOFO freezes, you can’t do shit. Nothing works.  No combination of keys on the keyboard will give any result. Your only option with Ubuntu/Linux desktop is to un-plug your PC. ISN’T THAT JUST SUPER….

I don’t feel like digging into any files to figure out WTF this pile of bile is doing. I am guessing Ubuntu/Mint (this all happens on another PC I am running mint on) TOTALLY SUCKS at memory management, as the freezes almost always happen when I am using a browser. Honestly I use my computer to get shit done not to screw around playing with the command line trying to get everything working so I can feel extra smart.

That shit is for kids. In adultland we need our PC to turn on and run programs and function and shit like that.

sarcastic kid meme
DERP

But the slowness and freezing really sucks and is pushing me to move back to Windows for web development and programming. Plus most of the image editing, video editing, etc. etc. etc. software for Linux desktop is not worth the shit. Hell most of the software for linux desktop is chock full o bugs.

I sent someone my resume I created with LibreOffice they sent me an email back saying they couldn’t open it. Yay, we still have that old ass issue in 2021???

homer simpson meme
My first encounter with an app using an ORM

Then you got the damn issues with print drivers and video drivers and drivers in general. In reality you are lucky if you get a PC to run Linux desktop properly. And don’t give me this shit about flavor xxx is better. They are all built from the same damn kernel, which is what most functionality is built on.

Right now I need my computer to work. I have too much to do to stop and investigate why Linux is not working and dig through logs and google and go forum after forum for 2 damn days. Screw that and soon screw Linux desktop too. I am over the sluggishness. Over the super hard freezes. Over the slow startups. Over the slow everything and piss poor memory management. Probably doesn’t even use all 8 cores either. And to think you used to be able to run Ubuntu on tiny devices.
I bet the Linux Fanboys are having some hyperventilating butthurt right now, gonna leave me lots of comments. They never read the article, then leave the dumbest comments.

I love you guys too and I want to help you heal that butthurt.

Categories
rants

What the world was like before Corporate greed set in

What were the good ole days like?

I am not super old, just 42 years old. But yet I am old enough to remember the good ole days. The days when Employers paid better. The days when employers cared about the product they produced or service they provided. The days when employers didn’t have a hard time finding employees because they were not so damn insanely greedy.

Why does CEO pay increase but not the workers?

Can you believe that back in the day( like before the year 2000), that companies would seek out people with an interest in their field that they could train? They would look for people that had an aptitude or interest in their given field and they would hire that person. I remember as a kid they would come around to high schools and interview Seniors and many got jobs before graduating and the companies would pay for their college.

Can you believe they would even pay to move that person? Want your mind blown further????? They even used pay for your training, certifications and college and give you a book stipend and much more. I have a friend who is a CPA, he earned his CPA that very way. He signed a contract to promise to work for 2 years after getting the CPA or he had to pay them back. He stayed for the 2 years.
They used to offer medical and dental coverage…. And to further blow your mind, did you know they used to offer pensions and retirement plans???? Not just the kind where you put into. No, like they used to fully fund those things and you could add to it too if you wanted, but it was an option!!!

Todays employers are much different than they used to be.

These were the days of our parents and grandparents. The days where you worked for a company your entire life, instead of job hopping. The days when companies cared at least a tiny bit about their employees. Hell the days when a company was around more than 4 to 6 years. The days before UBER GREEED.

Employers now encourage Job hopping

These greedy companies decided they could save more money to pay the precious investors by stealing trained employees from their competitors. This in turn leads to job hopping as companies offer more and more to steal the employee.

So they switched up the paradigm. Now instead of finding good people and training them, they use recruiters to steal them from other companies. But they claim they don’t want to hire job hoppers?

The deal gets more sour


Now we as potential employees are expected to go into deep debt getting an education so that some rich CEO and investors can get their pockets padded more?
So now we get paid less(due to inflation) and we have to pay for our education too? And jobs and companies are totally not stable anymore. To make it worse we are expected to work long hours and sometimes weekends. What a wonderful deal.

If you do the math you might not be making much more than minimum wage with that expensive degree. I’ll write another article about declining college attendance. Maybe another about the lie flat movement happening now due to this realization too.

The great resignation

We employees have finally in mass received the message loud and clear from you employers. “YOU ARE VALUELESS AND REPLACEABLE, LOOK HOW RICH AND IMPORTANT I AM

It just took the Covid 19 shutdowns for people to finally realize just how sour of a deal they were getting.

Covid awakened the sleepy employees while they were laid off at home.

Many started their own small businesses or started freelancing or trading stocks or crypto currencies. Suddenly people realized that we were being used and abused and that the money was not worth it.

We realized that maybe we can work less hours and make about the same amount of money or maybe more. Which in turn gives us more time for our family life, hobbies and living in general.

Money is only one part of the story. The way employers have been treating employees has declined since globalism and recruiting started. Back in the good ole days companies wanted to hang on to their valuable trained employees so they treated them like HUMANS. Imagine that???? Being treated like a human by your employer.

Now they treat you like a paycheck, and when that check grows too big they replace you in a heart beat. Yet you are still supposed to be loyal to the company? GTFO with that is what many of us are finally saying to the GREED MONGERERS.

The great resignation

Gone are the days of employers paying employees what they are worth. Gone are the days of employers paying to train their new employees. Gone are the days an employer will help move an employee. Gone are the days of retirement plans. Gone are the days of being treated like a human by your employer.

Now employers expect you to live in the city their home office is in or you get to pay to move. Now employers don’t offer pay increases. Now employers don’t offer retirement plans. Now employers don’t pay for college.  Now employers expect you to work more than 40 hours a week and say it is part of the salary.

Maybe now you understand why employers whine and cry they can’t find any employees.

The application process sucks

How many of you have gone through the application process lately? I’ve read many similar horror stories of people sending out their resume 300 times to get like 30 interviews, 3 job offers and 1 job. I’ve read about people having to do 6 to 10 interviews with the same company. People having to do side projects to prove their abilities etc. etc.

All in a time when employers are whining and crying and bitching and moaning that they can’t find anyone?????? REALLY???WTF?

are you kidding me
Today’s employers are cheap and picky too. WTF?

If employers want good employees again, then employers are going to have to change.

US corporations are the absolute worst on the planet too. This is why no one wants to work for them anymore if they can find a way around it. There is literally a term for it “turn and burn” where they suck the life out of their employees then replace them. The TECH/STEM industry is the most horrible about this. So bad they even make you retrain your foreign h1b replacements.

 

Categories
Web Development Web Security

Faking Enumerations with Vanilla javascript

What is an Enumeration?

An Enumeration is a way to create a limited list of options to choose from.This is useful for keeping a list of field names for a form so you can use javascript to animate something for example.

Having a limited list of options is helpful so that you can eliminate bugs due to misspellings (very common in Javascript UI programming).

A limited list also helps so that you can just type and your IDE gives you suggestions to jog your memory of the available options so you don’t have to dive into code.

Javascript has no Enums yet

Javascript has no such concept as an enumerated class… yet( the keyword enum is reserved so maybe in the future). Heck it is 2021 and PHP just got Enum classes.  While it does allow class level variables they are defined in the most funky way inside the constructor with this keyword.

Uhm, wait… what?

I say funky because with most other languages you define variables at the class level, then instantiate ( give them a starting value ) them inside the constructor for example. Just be glad you don’t have to use the old syntax What does prototypical Javascript look like?

So to define class level variables in Javascript you need to do so inside the constructor using the this keyword. The reason for this is how the Javascript prototype system works.

class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
}
Before Javascript classes… remembering this

Now anywhere inside the class you can get or set the value by this.height or this.width. You can’t set any constants like this though. Constants have to be defined outside the class if you want to use them inside a class, in all methods/functions. You can define a constant inside a function ( aka constructor ) but it is limited to the function in scope just like the let keyword.

But what if you want something like a list of constants or values that can be used? For example I like to keep my form field id’s inside an Enum to be able to easily refer to the field I need, but how can I do this with Javascript?

The answer

The easiest way I have come up with is to NOT USE a class at all. Instead I just use a simple file with a constant set to an object with a list of values. Sure you could just make a list of constants, but there are downsides to that. For one you would need to export them in order to import and use them.

I prefer to create a constant set to a literal object value inside of a single file, like this.

const MEDIA_FORM_FIELDS_ENUM = {
    ALLOW_COMMENTS: 'allow_comments',
    COLLECTION: 'collection',
    CONTENT_RATING: 'content_rating',
    DESCRIPTION: 'description',
    HASHTAGS: 'hashtags',
    PUBLISHED: 'published',
    REUSE_TYPE: 'reuse_type',
    TITLE: 'title'
};

export {MEDIA_FORM_FIELDS_ENUM}

Note the export.

Then I use it like this in my form or form fragment in this case.

Note the import.

import {MEDIA_FORM_FIELDS_ENUM as fields} from "../enums/MediaFormFieldsEnum";

class MediaOptions {
    static getMediaOptions(mediaType) {
        let collection = fields.COLLECTION;
        let comments = fields.ALLOW_COMMENTS;
        let description = fields.DESCRIPTION;
        let hashtags = fields.HASHTAGS;
        let published = fields.PUBLISHED;
        let reuse = fields.REUSE_TYPE;
        let title = fields.TITLE;

        return `
        <div id="media-options" class="container">
            
            <div class="form-group">
             <label for="content-rating" >${mediaType} rating</label>
               <select name="content-rating" id="content-rating" class="form-control" >
                  <option selected value="rating-everyone" id="rating-everyone" >Everyone</option>
                  <option  value="rating-mature" id="rating-mature">Mature</option>
                  <option value="rating-xrated" id="rating-xrated" >Adult rated-x</option>
               </select>
            </div>
         
          <div class="form-group">
            <label for="${title}">${mediaType} Title</label>
            <input type="text" class="form-control" id="${title}" name="${title}">
          </div>
          
          <div class="form-group">
            <label for="${description}" >${mediaType} Description</label>
            <textarea rows="5" id="${description}" name="${description}" 
            placeholder="describe the image in 200 characters" class="form-control" ></textarea>
          </div>
          
          <div class="form-group">
                <label for="${hashtags}" >${mediaType} Hashtags</label>
                <textarea rows="2" id="${hashtags}" name="${hashtags}"
                 placeholder="separate hashtags with space" class="form-control" ></textarea>
          </div>
             
          <div class="form-group">
            <label for="${collection}">${mediaType} Collection</label>
            <input type="text" class="form-control" id="${collection}" name="${collection}">
          </div>
          
          <div class="form-row">Published/visible status</div>
          <div class="form-check">
            <input class="form-check-input" type="radio" name="${published}"
             id="${published}" value="published" checked>
            <label class="form-check-label" for="${published}">
             Published ( visible to others )
            </label>
          </div>
          <div class="form-check">
            <input class="form-check-input" type="radio" name="${published}"
             id="unpublished" value="unpublished">
            <label class="form-check-label" for="unpublished">
             Un-Published ( visible to only you )
            </label>
          </div>
          
          <div class="form-group">
             <label for="${comments}">Allow comments</label>
               <select name="${comments}" id="${comments}" class="form-control" >
                  <option value="followers" >Buyers only/no one/private</option>
                  <option selected value="everyone" >Everyone & Buyers</option>
                  <option value="followers" >Followers & Buyers</option>
               </select>
           </div>
             
          <div class="form-group">
             <label for="${reuse}" >Allow reuse</label>
               <select name="${reuse}" id="${reuse}" class="form-control" >
                  <option selected value="none" id="reuse-none" >None/private (me only)</option>
                  <option  value="free" id="reuse-free">Free</option>
                  <option value="credits" id="reuse-credits" >Credits</option>
               </select>
            </div>
           
        </div>
        `;
    }
}

export {MediaOptions}

That is a lot of code. Note it is HTML inside of a Javascript Literal. I’ll write another article about creating templates with Javascript literals later. For now note how I imported it and used it. I could have just called the fields.OPTIONS but that is longer than a variable name.

I use the above code by importing it into yet another file that builds a whole form but only when called. Like I said I’ll have to write an article about the Javascript Literals, because wow they are handy.

Vanilla javascript might be a little more work, but in the end when something doesn’t work you know exactly why and exactly where to look. And if it is a bug… IT IS YOUR BUG and you can quickly fix it and move right along.

Links

Mozilla Developer Network Javascript class info

Mozilla Developer Network Javascript const info

Mozilla Developer Network javascript literal info

While working on this article I found this excellent article about using Enums in Javascript.

Categories
Software Development Web Development

Php Backed Enums don’t forget to call value

This is about the change from the old way of doing things to the new Enum classes.  I’m currently working to switch over from the old way to the new way, one file at a time.

This means in places where I refactor code I have to remember to call ->value. Hence the article title “Php Backed Enums don’t forget to call value”

Well thanks to my IDE PhpStorm, I caught this error before it happened to me… in most places.

I like the concept of having an Enum class as up until version PHP 8.1 you had to create class constants and pretend they were real Enums.

Old php enums

Old PHP Enums Example

Here is how we used to do PHP Enums for forever until version 8.1

class ImageDataEnum
{
    const HEIGHT = 'height';
    const SIZE_STRING = 'size';
    const IMAGE_URL = 'image_url';
    const WIDTH = 'width';
}

And to use that in any code you simply did the following where you needed a value.

$height = ImageDataEnum::HEIGHT;

And inside $height would be the string “height” you could use this to make sure a value exists without having to spell it out every time, reducing the likelihood of bugs. This is very straight forward and easy. You can still add constants to Enum classes and use them, but it feels better using case instead.

New Enums

A backed enum looks like this. Note const is now case, class is now enum, but the rest is about the same.

enum ImageDataEnum: string
{
    case HEIGHT = 'height';
    case SIZE_STRING = 'size';
    case IMAGE_URL = 'image_url';
    case WIDTH = 'width';
}

Notice the word “string” you can use int or string but not a combination of both. Backed Enums Docs here.

Now to use the new Enums like the code above you do like this

$height = ImageDataEnum::HEIGHT->value;

Otherwise $height will be an object, one that contains  handy built in methods try() and tryFrom(). See the doc links for more info on that. You can also define your own methods.

But if you fail to call ->value and you try to use this for a string comparison you will get oopsies. You can use the IDE to hunt down all cases of the old class type enums.

//this won't work
if('height' === ImageDataEnum::HEIGHT ){
 //code to do stuff in here
}

The above will result in an error telling you the comparison is not possible. You can’t compare a string to an object.

//this will work
if('height' === ImageDataEnum::HEIGHT->value ){
 //code to do stuff in here
}

You can also call ImageDataEnum::HEIGHT->name which will return HEIGHT. So you can get the name and value using those methods.

Another nice thing about the new Enum classes is they are full on classes, you can add methods to them if you want. Like checking if a value matches any of the case values or whatever your use case is.

Enums are really handy for limiting what values can be entered by users and checking against them. Another good use I have found is creating a list of options for a Database table column.

Here is an example of a column in one of my tables that stores a medias content rating type. The system later uses this in many places to make sure that the media is of this type or that the user wants to see this type of media.

enum ContentRatingsEnum: string
{
    case EVERYONE = 'everyone';
    case MATURE = 'mature';
    case RATED_X = 'rated-x';
}

This column in a media table can only contain these values and users can only select from these values as their content preference type. This is helpful because I don’t have to type those strings in 100,000 places and when I need to change one I simply refactor with my IDE features.

Categories
Web Development

Working with your apps local image assets in Symfony 5+

This article is mostly about managing your apps personal images and SVG files that it uses in your User Interface. It also explains how the Assets system works to the best of my abilities and discoveries.

This is the best info about assets, I have found in the docs about assets. It doesn’t mention some things that are handy to know. Like where is the configuration? There appears to be some sort of configuration in /config/packages/assets.yaml.

framework:
    assets:
        json_manifest_path: '%kernel.project_dir%/public/build/manifest.json'

It looks like this just points to the manifest.json file location.

I believe this is used when you call the template functions.

encore_entry_link_tags() and encore_entry_script_tags() functions

If you open that file you will you see a long list of all of your Javascript and CSS files that Webpack Encore manages.

{
  "build/app.css": "/build/app.css",
  "build/app.js": "/build/app.js",
  "build/app~registration~sogiDraw.js": "/build/app~registration~sogiDraw.js",
  "build/editAboutUser.js": "/build/editAboutUser.js",
  "build/featuredImage.js": "/build/featuredImage.js",
  "build/modalAction.js": "/build/modalAction.js",
  "build/registration.js": "/build/registration.js",
  "build/runtime.js": "/build/runtime.js",
  "build/sogiDraw.css": "/build/sogiDraw.css",
  "build/sogiDraw.js": "/build/sogiDraw.js",
  "build/vendors~app.js": "/build/vendors~app.js",
  "build/vendors~app~featuredImage~modalAction~registration.js": "/build/vendors~app~featuredImage~modalAction~registration.js",
  "build/vendors~app~featuredImage~modalAction~registration~sogiDraw.js": "/build/vendors~app~featuredImage~modalAction~registration~sogiDraw.js",
  "build/vendors~app~featuredImage~registration~sogiDraw.js": "/build/vendors~app~featuredImage~registration~sogiDraw.js",
  "build/vendors~app~registration.js": "/build/vendors~app~registration.js",
  "build/vendors~app~registration~sogiDraw.js": "/build/vendors~app~registration~sogiDraw.js",
  "build/vendors~editAboutUser.css": "/build/vendors~editAboutUser.css",
  "build/vendors~editAboutUser.js": "/build/vendors~editAboutUser.js",
  "build/vendors~editAboutUser~sogiDraw.js": "/build/vendors~editAboutUser~sogiDraw.js",
  "build/vendors~featuredImage~sogiDraw.js": "/build/vendors~featuredImage~sogiDraw.js",
  "build/vendors~sogiDraw.js": "/build/vendors~sogiDraw.js"
}

There is more than one way to work with assets in Symfony 5+. I use Webpack for my CSS and Javascript, so I use the related tags with those to import them into my templates.

Files that you let users upload are handled differently from files your app uses. Files your app uses will always be needed and won’t change, they are static in nature. Files your users upload will need to be edited, deleted etc. Also if you need assets like JS or CSS you should absolutely use Webpack and asset versioning it is way easier.

I won’t be using Webpack to handle my image and svg files. If I was doing a single page app, then that would maybe be my route.

What I need is access to some basic default images my app uses. Like an avatar for a user who hasn’t uploaded an image, or various SVG files used in the interfaces. These files can be stored in your apps public folder or in a CDN. If you are using something like Varnish cache or CloudFlare or both it doesn’t really matter if you keep them locally.

This article covers how I prefer to work with images and SVG’s my app will use. I’ll write another article about working with user uploaded images later.

You can display a SVG inside an img tag, which is what I do sometimes when I don’t need JS interaction with the SVG.

There might be more than one way to do this. I will cover what I  have found here so I can review it later if  I need to.

Using the Package class is easy. You do it like this.


 $package = new Package(new EmptyVersionStrategy());
 $defaultImage = '/images/app_art/click-edit.png';
        if(!empty($profileImageId)){
            //update this to get actual user image.
            $profileImageUrl = $package->getUrl($defaultImage);
        }

Here I have my images located in app/public/images/app_art/  This works if you know your files will never change. This lacks versioning(EmptyVersionStrategy()), so if you change the image, your users might never see it. This is because reverse proxy servers and other servers between your server and the users browser will cache the image and send the cached version. If you think you might make changes to the image in the future use the ( StaticVersionStrategy ) or else a large portion of your users will not see the new image.

Here is the Package class source code on github.

To say it another way it means that users who have downloaded the image before, their browsers will never download it again until the expires header or something similar. A new visitor or person who cleared their cache would get the new image. Versioning fixes this. This becomes a major PITA when working CSS and JS, so always use versioning with those or you will get magic errors due to the browser using cached versions.

homer simpson meme
don’t let your browser be a PITA

I should note here that this also works because I have the configuration set in my nginx to serve images from the public folder like this.

location /media/ {
	root /var/www/sogi/sogizmo/public;
	}

That opens the public folder to serve assets. When you use webpack encore to manage your JS and CSS it takes your files from the /assets/ folder and compiles them then stores them in the related folders inside the public folder usually inside the build folder.

As you can see above I have another folder within the public folder named images/ which I keep my app related images in. Inside the images folder I further break it down into the related images. Above you can see I am using an image from the app_art/ folder.

Also notice when I build the URI/URL for the image I don’t include the “/public/” part. The symfony template linking functions know where the file I need is located from the assets.yaml configuration file. All I need to do is include the subfolder “/image/” and the actual file name. I keep my assets in many subfolders named after the page or object that uses them.

 

Categories
Web Development

How to fix Symfony FosJsRoutingBundle outputs routes in browser

Yeah I got this problem once too. The routing bundle outputs the routes in your browser on a plain white background, giving the user no options to navigate etc. after they register or login.

A user needs to see a real page

So how do you fix this? Read the last step of this article I wrote How to get URL Routes in your Javascript in Symfony 5+

It is a long article but it explains everything. See the note about the Last Step. I don’t want to repeat it here because I don’t think many will view this article anyways.

Categories
Uncategorized

How to fix Symfony Compile Error: Cannot use Repository as Repository because the name is already in use

So you got this error? WTF does it even mean?

baby what does that even mean meme
What does this error mean?

Well my actual error was this.
Compile Error: Cannot use App\Repository\PageUrlsRepository as PageUrlsRepository because the name is already in use

I oopsied

You can see here what I did is accidentally add a second use statement. I remove that and BOOM all back to normal.

Categories
Web Development Web Security

How to secure individual Symfony AJAX api routes without using API Platform

Creating the Symfony route is easy. Checking if the request was sent by AJAX is again easy. But what stops a mischievous hacker from hitting that endpoint and trying to get a list of used emails or something else with a script?

What if you have routes that you want to access with AJAX without API Platform? With Symfony, standard forms created with the Form Component, your forms are CSRF protected. But, when you are sending an AJAX request to an endpoint without a form how do you protect it?

There is probably some Symfony approved way I am not aware of.

If you send the whole form you can use a different procedure and use the CSRF string stored in the form.

However, for simple situations where you need to randomly access a route you can do something similar to the CSRF form protection by generating a unique string and saving in a Session cookie and to the page/form.

Where you save the string in the page is up to you, but it should be a hidden element. This element needs a unique ID in the page so that you can access it with Javascript. A hidden input element in a form works great, otherwise use a hidden span element.(use css to hide the element).

When you need to make a request to the route you use javascript to get the value you hid in the element. Make sure it is just the unique string that you fetch not the entire element html or this wont work. Include this string with the data you are sending to the route.

Inside your route fetch the unique string that you sent in your AJAX. Then try to fetch the same unique string from your session cookies. If the string exists and matches process the request.

There are tricks you can try to use with the header like checking the users browser agent. But that is useless as it can be easily spoofed by a good hacker using something like Curl.

This unique string trick isn’t 100% hacker proof. But it makes it a hell of a lot harder.  More on CSRF attacks here.

NOTE

If you are using the Symfony forms with CSRF activated then you can use Javascript to fetch the value of the nonce hidden in the _token input element. However, if your code will make multiple ajax requests, then you might want to create the custom hidden field and generate a new unique string each time and replace it in the custom field.

Step #1 create the field

To create the field add it in the FormType definition like this. The entire class is too long so I’ll show just the add section.


->add('ajaxString', HiddenType::class, [
                'mapped' => false,
                'attr' => ['class' => 'hidden-field', 'value' => $secretString]
            ])

Notice mapped is false so that I don’t get errors.

Step #2 Build the form

Now you build the form inside the Template for the form. Mine looks like this.


{{ form_start(registrationForm) }}
        {{ form_errors(registrationForm) }}
        {{ form_row(registrationForm.email) }}
        {{ form_row(registrationForm.emailMatch) }}
        {{ form_row(registrationForm.plainPassword) }}
        {{ form_row(registrationForm.passwordMatch) }}
        {{ form_row(registrationForm.userAlias) }}
        {{ form_row(registrationForm.ajaxString, { 'id': 'ajaxString'}) }}
        {{ form_row(registrationForm.agreeTerms) }}

        <div class="d-flex justify-content-center">
            <button type="submit" class="btn btn-lg btn-success">Register</button>
        </div>

        {{ form_end(registrationForm) }}

Notice how I have the id : ajaxString line. This is currently the only way to change the ID of a form field in Symfony see How to change the id for a form input in Symfony 5+

Step #3 add initial value

Inside the controller you must add the initial value for the field and store it in a session cookie.

For this I am using a simple class which generates semi random/unique strings. This doesn’t need to be super top notch secure, it is just to make sure the request is coming from a form my app built.

To access the Session Cookie in Symfony 5.3+ you must now use RequestStack instead of Session or SessionInterface for some odd reason. It just makes it more obscure and harder to figure out how to get to sessions.


$session = $this->requestStack->getCurrentRequest()->getSession();
        $secretString = RandomStringGenerator::lowercaseUppercaseNumberString(32);
        $session->set('secretString', $secretString);

 

To check the value in the Controller route endpoint I do like this.


$secretString = $request->query->get('secretString');
        $secretString = DataSanitizer::sanitizeString($secretString);
        $string = $this->requestStack->getCurrentRequest()->get('secretString');

        if ($request->isXmlHttpRequest() && $secretString === $string) {

Note that secretString is the value sent by the AJAX request. This was the value I hid in the form field to use for this purpose.
The other line

$string=$this->requestStack->getCurrentRequest()->get(‘secretString’);

gets the value I stored in the Session Cookie. Then the if statement makes sure the two values match before processing the request. If the two strings match we know that my app built the form, added the string and my Javascript copied the string and sent it to my server. This prevents people from randomly hitting your route endpoints.

&& $secretString === $string

Links

Here is a good link to Symfony Casts about API Platform. There are many symfony casts here to learn more. I was going to post each but this link contains all of them with pretty pictures and descriptions. LOL

More about CSRF in symfony forms here in the documentation.

Categories
Web Development

Symfony 5.3+ how to use Sessions with RequestStack

So some changes happened in Symfony 5.3. Previously you could get to a session with either Session or SessionInterface. Some didn’t like how that worked so now it is moved to RequestStack. The docs or article are not correct here.

It shows you get to the session like this.


$session = $this->requestStack->getSession();

But that doesn’t work. You will be told that RequestStack doesn’t have a getSession() method. I had to open up the source code to figure out how this works.

You get to the session instead like this now.


 $session = $this->requestStack->getCurrentRequest()->getSession();

Note you have to call getCurrentRequest() then getSession. now you can use sessions like this.


$session = $this->requestStack->getCurrentRequest()->getSession();
        $session->set('key-name', $value);

You will now have access to all of the session methods via $session. Your IDE should now list all of the methods in the Session class that you can access.

How to get the RequestStack?

So how do you get the ReqeustStack? Autowiring.

You simply Autowire it into your Controller route method or the __constructor() method. I prefer the constructor method in my Controllers if more than one route needs it.  But in other services you have no choice, it has to be autowired via the constructor like this.



   private RequestStack $requestStack;

    public function __construct(MysqlConnection $mysqlConnection, RequestStack $requestStack)
    {
        $this->mysqlConnection = $mysqlConnection;
        $this->illegalRequest = 'Sorry. Your request to this API is not allowed';
        $this->requestStack = $requestStack;
    }

Now any method can access the requestStack and through the RequestStack you can access the Session. At least for now.

Here is a link to the actual Symfony Session docs.