Categories
Software Development Web Development

Symfony 5+ Twig templates don’t forget to call the parent

Twig templates use inheritance and allows you to create named sections like this.


<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <link rel='icon' href="{{ asset('images/favicon.ico') }}" type='image/x-icon' >
    {% block head_extra %}{% endblock %}
    <title>{% block title %}{{ title }}{% endblock %}</title>
    {% block stylesheets %}
        {# 'app' must match the first argument to addEntry() in webpack.config.js #}
        {{ encore_entry_link_tags('app') }}
    {% endblock %}
</head>
<body>

<main>
    <div class="container">
       {% block navbar %}{{ include('_nav_bar.html.twig') }}{% endblock %}
        {% block body %}{% endblock %}
        {% block javascripts %}
            {# these files are needed for getting url routes in javascript  #}
            <script src="{{ asset('bundles/fosjsrouting/js/router.js') }}"></script>
            <script src="{{ path('fos_js_routing_js', { callback: 'fos.Router.setData' }) }}"></script>
            {# 'app' must match the first argument to addEntry() in webpack.config.js #}
            {{ encore_entry_script_tags('app') }}
        {% endblock %}

        {% block javascript_extra %}{% endblock %}
    </div>
</main>
</body>
</html>

And then you can reuse/inherit this template in another template like this.

{% extends 'base.html.twig' %}
{% block title %}Register{% endblock %}

{% block stylesheets %}
{{ parent() }}

{% endblock %}
{% block body %}

{{ 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.agreeTerms) }}

{{ form_end(registrationForm) }}

{% endblock %}
{% block javascript_extra %}

{{ encore_entry_script_tags('registration') }}

{% endblock %}

Notice the extends keyword and notice this section

{% block stylesheets %}
{{ parent() }}

{% endblock %}

Notice the use of the “parent” keyword here.

{% block stylesheets %} {{ parent() }} {% endblock %}

Any other css code you want included must come after the parent call like this.


{% block stylesheets %}
    {# 'app' must match the first argument to addEntry() in webpack.config.js #}
    {{ parent() }}
    {{ encore_entry_link_tags('editAboutUser') }}
    {{ encore_entry_link_tags('sogiDraw') }}
{% endblock %}

If I didn’t call “parent()” above then only the CSs for editAboutUser and sogiDraw would be included app would not be included. The CSS for app which is called in the base template in the stylesheets section would not be included without the call to parent().

So if some of your CSS is not working, then the reason is you probably forgot to call parent. This call to parent is saying “Include what was in the parent stylesheet section”. Otherwise without the call you will be missing Styles and be saying WTF?

Don’t forget to call parent
Categories
Software Development

How to list all stopped and running Docker containers

I often need to do this but forget exactly how to do this. I don’t know if this has changed. I could swear it has changed.

You will probably find crap all over the internet telling you to use

docker ps

But that only lists running containers. Same story for

docker container ls

So how do you get docker to list all the damn containers?

docker ps -a
homer simpson meme
You got to strangle docker for the truth about containers
Categories
Software Development Web Development

How to create 100+ Symfony 5+ Doctrine 2 or 3 Repositories

Scroll to the bottom to view a video of this Repository maker in action. I make about 100 Repositories in less than 2 minutes. You can go faster by just hitting enter really fast. LOL

NOTE – repository in the sense of this article means a Doctrine Repository Object. This object is used to interact with the database.

So you need to make a lot of basic Doctrine repositories for your Symfony 5 app? I needed to do the same thing. That is why I created a Doctrine Repository maker for Symfony 5+ or any version that contains the Maker Bundle and uses the src/Repository and src/Entity directory structure.

What happened is I was not very familiar with Doctrine and and the exact syntax it requires for everything in order to work properly. I don’t have the time to learn everything either. I often solve problems by finding the shortest solution time wise.

I know exactly how to design a database, I’ve studied that deeply. But I didn’t feel like wasting time to learn everything about Doctrine ORM just to be able to make queries and use migrations.

Plus I code in so many languages, I don’t have time to learn everything about every ORM… and that is why SQL was invented.

too many words meme
Not enough time to read it all.

So I have this seriously complex app I am building. It needs several hundred tables. I had well over 100 tables already created via MySQL Workbench. I love workbench because it is a nice UI that makes creating tables and making changes super fast and easy. Much faster than typing all of that mess into an Entity directly.

So what I did is I used Doctrine to reverse engineer my database and create the mapping to the Entity Annotations. That was a pain, but still faster than learning EVERYTHING about Doctrine and typing all that stuff in.

too fast meme
As a lazy programmer I like to go fast. LOL

The main problems with reverse engineering with  Doctrine is it doesn’t create the repositories for the entities. And in order to use Doctrine with Symfony you need a Repository for each Entity, especially if you need custom queries/methods.

Another issue I had is if you do reverse engineer your database like this and you do create the repositories, you must then go into each Entity and add the Repository imports.

In order to create the Repositories for my new Entities, I created a maker. The maker gets a list of all of the Entities and existing Repositories. It then loops through each of the Entities that does not have a Repository and asks you if you would like to create one.

If you go with the naming path of the Repository maker it can overwrite files so be careful.

I also created an Entity clone maker, which I’ll talk about and share soon. Many of my Database tables were very similar, so I created an Entity cloner which can be used with Doctrine migrations and the Repository Maker to quickly finish building my app.

The Entity cloner also loops through entities and asks if you want to clone it. Very helpful.

wow dog meme
Entity Cloner is very helpful too…

Repository Maker in action

 

 

Categories
Software Development Web Development

How to install Redis with Docker for local testing

In another article I suggest installing Redis with docker but do not tell how. In this article I cover how to get a Redis Image up and running with Docker locally.

First you need to install Docker for your system.  After you have Docker installed, next you need to download a Redis image. Here is a list of official redis images.

To get the image you can use the pull method.
To view all of the current images you have on your system type

docker image ls -a

You should see something like this if you have any redis downloaded.

docker image ls outpu
output of docker image ls -a

Next create and run a new container with this command:

docker run --name redis-5 -dp 127.0.0.1:6379:6379 redis

–name is how you tell it the name you want for the container mine is redis-3
-dp the -d starts in detached mode, the p is for port and mine maps 6379 to 6379 127.0.0.1:6379:6379 tells docker to start the container with an ipv4 of 127.0.0.1 and network the systems port 6379 to the containers port 6379 without the ipv4 part Docker starts with an ipv4 of 0.0.0.0 127.0.0.1 is localhost some systems may map 0.0.0.0 to localhost in the hosts file too. You an add almost any conforming IP you want here and that will be the IP for the container docker run creates.
Here is a link to the docker docs about networking. Here is a link to Learning Ocean about docker networking.
redis is the name of the image I want to use to create the container.

That command will output something like this.

output of docker run
docker run output

Notice in the image, I did not specify an IP so it starts with an ipv4 of 0.0.0.0 not very helpful.

Once you have created the container you can start and stop it with the docker stop and start commands.

You will need to install the redis-cli if you want to quickly test your redis docker container is working. I am using ubuntu so I just install the redis-tools package. If you are using something else you are in for a world of hurt, see this stack question.  Ubuntu makes programming easier for most things.

Now to test if your docker redis is working just type the following into your command line to interact with redis via cli

redis-cli

You should see the following output, just the ip and port means your redis is working

your redis is working if you see this

To learn more about how to configure your symfony app to use this redis connection read this article.

Links

Here is a nice article about how to remove old images and containers and clean docker up.

Remove multiple docker images at once. This is good for when you have a bunch of unused images. Use this command to view all images currently on your system

Learning Ocean Docker tutorials – some of the best information you can find on Docker



		
Categories
Software Development Web Development

Tips and tricks to reverse engineer your existing database with Doctrine for Symfony

So in the Symfony documentation there is a page that describes how to reverse engineer an existing database using Doctrine.

borat not meme
Symfony doctrine NOT Joke with Borat

Rule #1 No DB Vendor custom types

The only problem is this technique will only work with databases that are  generically designed. Meaning you can’t use some of the DB vendor specific types etc.

This means if your database uses tinyint or enum for example you should undo that before trying to reverse engineer it with the link above. And god bless you if you have used tiny ints as foreign keys. You must delete all foreign keys first, then recreate them.

Seriously trying to figure out how to work around TinyInts and Enums is a real pain in the ass, I’d advise against it. This documentation page is written poorly it leaves lots of questions to be asked.

symfony documentation meme
Doctrine is all like WTF do you need docs for?

Like WTF does this line even mean?

In this case however Schema-Tool update will have a hard time not to request changes for this column on each call.

Anyone want to have a stab at translating  WTF that means?

details meme
I need more details than that please. LOL

Use a backup

the office meme
Step 1 use a backup

Don’t just backup your database. Start by dumping your current database structure, no data. Save this to your repository so you can restore if you need to. Next import that into a new Schema. You can do that with one of the doctrine migration commands see this article.

Once you have the database structure imported. Open a terminal and do a quick doctrine migration diff as talked about here. Once you have the diff look over the migration to see what doctrine is wanting to change in your database schema. For me, It is easier to make those changes in something like MySQL Workbench with the added bonus that it can create an Entity Relationship diagram as part of my documentation.

Working with a backup of the data-structure lets you see what needs to be changed in your real database first. Follow the techniques in this article about reverse engineering the database.

Do the doctrine orm mapping import after you do the first diff. The purpose of the first diff is just to see the changes. You will see stuff like problems with TinyInts, Enums etc. Any vendor specific column type will generally be more trouble than it is worth.

Delete Migrations

system32 meme
Delete time

In the process of doing the diff and creating the mapping and doing the diff again and again, you end up with lots of migrations. Delete all of the migrations except for the very last diff migration.

You do the final diff after making final changes to the entity, mapping annotations. This way Doctrine can view your entities and compare them to your actual Schema. When you run this migration it will sync your database to the Entities.

No TinyInts

Sorry database designers you are not allowed to have these in your database design as they are mostly MySQL specific the Doctrine code does not allow them.

angry cat not going to happen
Doctrine is all like… NOPE
The Answer

Convert your tinyint columns to smallint. Doctrine understands those. Sure you are using like, a little more space each row now, but you really need Doctrine. LOL You can create a custom tinyint type, but wiring it in and using it is more of a pain than it is worth unless you really need it.

NO ENUMS

no enums meme
Remove Enums from your database design first

And the docs are wrong on this one and need updating. MySQL no longer requires an entire table rebuild costing hours.However Enums are not very useful because NULL and an empty string can be acceptable values under normal MySql configuration. Also with enums users can choose multiple values, so Doctrine uses php array type. You can use Enums, but it is more of a pain. See the doctrine docs here. You have to create a custom type and wire it in.

The Answer

Just use varchar or string as doctrine calls it. Make a check in your code (entity methods) to restrict values that are able to be accepted or make a table that holds the values. I personally use a table when there will be 10 or more values or I don’t know for certain how many there will be. If you use a table use a foreign link id to it in your main tables.

Forget your foreign key names

There is no solution for this. I have no idea why but Doctrine will absolutely rename,or suggest to rename every last foreign key.

why can't i have my foreign key names?
Why can’t I have my foreign key names?

I think it tries to make sure each is unique or maybe it needs it in a specific format. I usually like to put the table name in it to be a hint in error output. But it also seems to rename keys it has previously renamed too.

The Answer

Like the leg humping dog in National Lampoon… “it’s best to let him finish”

I’ll post more as I find it.

Your Entities have no repositories

It is awesome that doctrine can reverse engineer a database and even create the repositories too. What I don’t understand is why it does not link the damn repository  to the Entity. When you use the Entity maker it does this. When you reverse engineer with Doctrine it only creates the Entity mappings.

Answer

Use this Doctrine/Symfony maker I created. It can loop through your Entities and create Repositories for them.

There is still one catch though. You will have much fun like I did, opening 100+ Entity files and adding the proper annotations for the matching Repository to it. I still have another maker to put on github that fixes some issues with entity/repository mapping.

This part is so tedious and fun

For example my app has a PageUrls Entity and it uses… PageUrlsRepository so to fix PageUrls so that I can use custom Repository methods I must now add this in the annotations.

/**
 * PageUrls
 *
 * @ORM\Table(name="page_urls", indexes={@ORM\Index(name="userOwnerId", columns={"owner_user_id"})})
 * @ORM\Entity(repositoryClass=PageUrlsRepository::class)
 */

So I must do this 100+ times now. I hope you have less tables in your database schema

hide the pain meme
Repetitive stuff is fun

I could add more code to the RepositoryMaker to update the Entities with the proper Repository tag. But then it is doing more than one thing. Maybe I should make a maker that updates the Entities Repository definition line to match. I’ve done this I just need to create the github repo add some stuff and publish it.

FullText ignored

I found that Doctrine ignored several things, fulltext indexes is one of them. It seems to me it doesn’t do cascading updates/deletes either, this may have changed by now or maybe I wasn’t paying close attention.

Anyways this isn’t documented yet I think it is a new feature to cover this issue. You must manually add the fulltext info to each index definition inside your Entity with a flags=fulltext section like so.

, flags={"fulltext"}

This goes in your Table indexes section like this

/**
 * ImageCollections
 *
 * @ORM\Table(name="image_collections",
 * uniqueConstraints={@ORM\UniqueConstraint(name="uniqueCollection",
 *     columns={"collection_name", "owner_user_id"})},
 *      indexes={@ORM\Index(name="collection", columns={"collection_name"}, flags={"fulltext"}),
 *     @ORM\Index(name="ownerIndex", columns={"owner_user_id"})})
 * @ORM\Entity(repositoryClass=ImageCollectionsRepository::class)
 */

Imagine having to go through all of this typing to create 100+ Entities! Yeah for me it was just easier to create my entire database in a GUI like MySQLWorkbench then reverse engineer with Doctrine. Otherwise I’d have to spend months becoming a doctrine wizard before I could dare to create a database design.

Categories
Software Development Web Development

How to fix Unknown database type enum requested, Doctrine\DBAL\Platforms\MySQL80Platform may not support it.

So you got this lovely error when trying to reverse engineer a database with doctrine. This error means that your database uses ENUM and is probably running on MySQL.

MySQL also contains SET which is about the same as ENUM except enum allows only 1 value from the list( or empty string or NULL) and set allows multiple values from the list. Doctrine doesn’t barf when it sees a SET but it sure does when it sees an ENUM.

baby threw up meme
Doctrine no ENUMs very well

Enums are ok when you know in advance that your app will only ever require a small number of options and you will allow empty strings or NULL. I usually go with a table when the number of options will be like 10+ , or I don’t know for sure how many items there could be.

However, working with Enums is a little difficult with Doctrine. Especially if you are trying to reverse engineer an existing database, you will get the following error :

doctrine enum barf
Doctrine barfs when it encounters an ENUM

The easiest way to reverse engineer a database that exists already is to redesign it the Doctrine way. Remove all Enums and TinyInts. And if those tinyints were used in foreign key ids then, you must hunt down each one and remove it then you can add it again.

Then after you reverse engineer the database you can go into each and every single Entity that should be using an Enum and add the Enum to the Entity like so. Then you can rerun migrations:diff and update the database.

are you kidding me
So do you really want those Enums that bad?

Do you really need enums that bad?

Here is an article about tips and tricks to reverse engineer your existing database.

Categories
Software Development Web Development

How to reverse engineer a database for a symfony project with doctrine… aka t_

TLDR

This is a parody about how I learned to Reverse engineer a Database for a Symfony App with Doctrine.

Here is a short article including tips and tricks I discovered I learned while writing this.

This article jokes about some of what I ran into and what I was thinking while I learned Doctrine. It does give some details and useful information. t_ is how you tell Doctrine to ignore a table in migrations. I was going to just tell Doctrine to ignore all my tables. LOL

To understand why DATA is the most important to me. Watch this video and read the subtitles. Warning you will laugh your ass off.

@2:14 you will understand why us older guys put the database and database design before any other part of the app. You can have 100000000000000000000 interfaces to a database, but if your data is fubar you are fucked. “We can reverse the code right? Sure thing, the database is still fucked though, of course you had bad code running on it” LMFAO Best part of the video.

The same thing happens when you let an ORM design a database and you don’t fully understand the ORM and how it sees data. Get the wrong Entity design and you get lots of redundant fields in your database, or NULLS or just a big mess. Your app might work… until it sees actual traffic. You don’t want to flop on your big day, trust me I’ve done it.

Plus if you design your system by entities then move to a different frame work or want to run two versions of your app using two different frameworks… WELL…

When you learn to do something with one tool and then that tool is taken away.
This does show an interesting way to learn doctrine.

The story

I’ve been designing databases for more than 10 years now. I studied the subject in depth and still own many books on it. I only started using frameworks in the last few years.

I think in terms of data and data manipulation needs while designing apps in order to design the best system. First I read the specifications closely and start designing the database based on those. I try to imagine what data needs to be collected in order to cover the specifications properly.

I decided to try to get doctrine to import the mapping.

The Symfony docs say it should work about 80% and you will need to fill in the rest. It doesn’t really say what the rest is, or give any tips. It kind of assumes you are a doctrine Wizard.

look a wizard meme
Yes I am now a doctrine wizard, because I don’t have to know it first LOL

The issue is, you must damn near be a  Doctrine Wizard in order to understand exactly how the Entities should be modeled in order to match a database design. Otherwise you are like me and have to do this by trial and error wasting lots of time or spend months doing courses and tutorials. Nah, I’ll stick with designing my database the old way thanks.

I am a Wizard

If you have a sloppy Entity you have a sloppy database design. I had to learn how Doctrine would like an entity to be designed to match my database design.

i am wizard meme
So I became a doctrine wizard… sort of LMFAO

Well the first issue I ran into was using foreign keys as a composite primary key.

Doctrine was all like

kitten frew up meme
doctrine no like primary foreign key

Ok so I changed my design so that every table had a unique ID instead of a unique foreign key primary key etc. I deleted most of my entities.

Then I run the command to rebuild the entities aka map them.

php bin/console doctrine:mapping:import "App\Entity" annotation --path=src/Entity

Doctrine creates all my entities. I look them over, not really knowing what all the hell I am really looking at with the annotations and such.

makes sense to me meme
Yes this all looks good to me. LMFAO

Next I decided to diff the database to see what all would need changing.

Ok now Doctrine doesn’t like my tinyint values I used in my MySql database design.

tiny paper meme
Doctrine is all like Tinyint WTF?

So I go through and change every tinyint to smallint. Delete most of the entities.  Run the commands again. You can define your own types for Doctrine more on that in another post.

Lets Change the foreign keys

Now doctrine is not trying to change tinyint to smallint… but it wants to rename ALL of my foreign keys. WTF.

Lets rename the foreign keys for no F***ing reason

Ok that isn’t so bad, maybe it needs them named a specific way. I didn’t google that mess.

Lets get Cryptic with it.

I can live with cryptic foreign key names like…

FK_CA093F7E83172943

Not like I have to see them often. Other than when there is a DB error, now… instead of my beautiful Foreign key scheme which included the table name as a hint I get some cryptic bullshit in my messages and no way to track down WTF key it was.

borat great job meme
It is the little things in programming.

Lets be Null together

But then I look closer and now the diff command wants to change all of my foreign keys to default null.

are you kidding me
Freaking seriously
The purpose of a foreign key is to make the database make sure a value exists in one table before inserting a value that links to it in another table. This is known as referential integrity.

This is where I draw the line with Doctrine

draw the line meme
Sorry doctrine. No I will not ruin my database design just to use you.

Allowing nulls on a foreign key is STUPID. This means that now your application code must make sure a value is not null before inserting it and it must exist in the other table first… GO HOME YOU ARE DRUNK, TAKE SISTER NULL BACK TO JAVALAND FFS.

Which means you can’t use some of symfony’s validation techniques because they rely on the same Entity class annotations. Sure you can add to the form validation, but you still need to make sure a value exists in the linked table before you can insert it or else you insert a null value, which destroys referential integrity.

Null values on foreign keys just make no sense to me.

makes no sense meme
That makes no damn logical sense!

So in order to use Doctrine it looks to me like I must ruin my beautiful table design. I only wanted to use it for the migrations and some ease of use deals. But I do not want to destroy my database to do so.

For example if I have a hashtagged_images table and that table contains a hashtag_id and an image_id . A table like the following

hashtagged_images

  • id
  • hashtag_id
  • image_id

Why would I ever want either of those to be null? That is like dividing by zero. You never ever, want either of those null, that will make your database a flaming hot mess.

Yay lets have nulls in the database

Now your code must check whether anything contains a null before your app can use it. It must also make sure that before you insert a hashtag for an image that you must first hit the hashtags table to make sure a hashtag with a specific id exists. Then you must hit the images table too, to make sure an image with such an ID exists. Then you can finally insert your images hashtag.

That is a ton of work when a simple “not null foreign key” constraint would do all of that for you. It would also shift the query work from the app to the database like it should be.

A new team member may not know your system and forget to check for null for example. Here is more info about nulls in the database.

Null is only useful when you have a table with columns that don’t need a value when the record is initially inserted. Something like a collection ID for an image a user uploads. It very well may not belong to a collection, therefore you would need to allow for a NULL field value or have a default value.

These days I try to just create default values for everything. I try to have as few Nulls in the database as possible. The longer you program, the more you hate NULL.

Nope, Not gonna do it…

So that is how I came to prefixing all tables with t_ so that Doctrine would leave them alone.

nothing works meme
I kept trying and trying to make changes
But I have this disorder that makes me INSANELY persistent.

I refused to leave this alone.  So I kept making changes and running this command

php bin/console doctrine:mapping:import "App\Entity" annotation --path=src/Entity

Then running a migration diff and viewing the changes that doctrine wanted to make in the migration up.

Then I got this idea.

smiley bright idea meme
Then I got an idea!!!

What if I try adding nullable=false to the join column definitions? I didn’t bother googling it or trying to find it in the damn docs. I just did it.

just do it meme
Let me just try this.

So after I added that and reran the diff, not the entity mapping, and BOOM Doctrine was no longer suggesting in the migration up that it should change the foreign key to default to null.

detecting much win meme
Boom I won.

So when you want your foreign keys which are an ID in another linked table to not be null like they should be. You should have a definition like this in your Entity

/**
     * @var \ImageHashtags
     *
     * @ORM\ManyToOne(targetEntity="ImageHashtags")
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="image_hashtag_id", referencedColumnName="id", nullable=false)
     * })
     */

This tiny little line nullable=false changes everything. It tells Doctrine you do not want that field to be nullable.

I don’t know why the Doctrine mapping code can’t get this right. This information is provided to it by the DB query. Maybe I could help find this code and update it so that it includes this tiny line if the DB query returns it.

The story must go on…

but there is still more stuff to do

You also need to fix EVERY LAST ENTITY NOW. Yes for each and every entity you must now open the file and list the damn repository for it. For some reason the Doctrine code can’t do this either, even though the Repository is just the Entity name with Repository added to it.

now I do more work.

So open up every last single Entity and create a line like this above the class definition in  a comment (I also created another maker to fix this, I still need to create a repo etc. for it)

* @ORM\Entity(repositoryClass=PageUrlsRepository::class)

Otherwise you will get Errors every time you try to use a Repository with a custom method name.

Now I am a wizard

i am a wizard meme
Now I am a Doctrine Wizard

Here is an article about tips and tricks to reverse engineer your database with Doctrine.

Categories
Software Development Web Development

How to quickly create a complete Symfony 5+ app with login and password reset

If you follow this quick guide you should be able to have a simple, yet complete Symfony 5.xx ( or 6 soon ) . There are lots and lots of baby steps. If you want to know how all of this works and much more I suggest reading this excellent article.

This is meant to be more of a cheatsheet. If you are totally new to Symfony, try this Free to read symfonycast as an introduction, or the article above.

If you want to know more about Symfony authentication read this symfonycast, some things have changed in version 5.xx.

I may eventually take the time to write Linux Shell scripts to automate all of this. The permissions are the most painful part of all of it.

I thought about setting up a simple app and saving it to a repository on github to make it even faster and easier. But the truth is the base code is moving so fast, it would be better to just create new apps with the latest Symfony version so you get the latest updates.

So step 1 is decide if you want to use pure composer or the Symfony binary. I like using plain old composer, but with the Symfony Binary you get the added benefit of a local server, security checks.

The local server setup is nice because it saves you time from having to create virtual servers. You will still need to decide how you want to run the other parts of your app like Mysql/Postgre, Redis, Memcache, RabbitMq etc. I’ve been using docker for some of these and installing others. Soon I will be experimenting with running Symfony Locally with MiniKube, which lets  you run Kubernetes locally.  I’ll have to figure that workflow out and share in another article.

Step 1 create the app

Move to the directory you want your app to exist in and type the following replacing with your project name.

 symfony new my_project_name --full

Step 2 fix permissions

Now that the app has been created you need to fix the permissions on the var folder. Change directories to your app directory. This is the one that contains bin, config, public, src, var etc. Then copy and paste this command into the command line ( ctrl + shift + v ) got to add the shift.

HTTPDUSER=$(ps axo user,comm | grep -E '[a]pache|[h]ttpd|[_]www|[w]ww-data|[n]ginx' | grep -v root | head -1 | cut -d\  -f1)

You must also set permissions for future files and folders in this directory.

 sudo setfacl -dR -m u:"$HTTPDUSER":rwX -m u:$(whoami):rwX var

Almost there…

hide the pain meme
Many steps

Now you must set permissions for existing files.

sudo setfacl -R -m u:"$HTTPDUSER":rwX -m u:$(whoami):rwX var

I have to admit I don’t fully understand what is meant by the next permission step of setting the ”
Use the same User for the CLI and the Web Server

I think what it means, and how I got this working is, find the name of the server you are using, mine is www-data.  More info on setting the server name here and create a group for it

To find the user name your server is running as use the following command

ps -aux

Which will list out all of the processes that are running and lots of info about them. Below is an example. As you can see my nginx is running as www-data

nginx name is www-data

What I did is create a group named server-group and I added www-data to that group. I then set that group “server-group” as the group for the file. Here is a link on how to create a group in linux.

Once you have created the group and added your server user name. You now need to change group permissions on the var folder.

Make sure you are in the app directory of your app still, the one with var, src, public etc. then issue this command( change it for your name and group name)

sudo chown -R akashicseer:server-group var

Then you must make sure the new group can read and write to that directory or else you get an error. So you also need to issue this command.

sudo chmod -R 775 var

Now that all of that is out of the way. You can finally add the useful bits.

Install & Configure Doctrine

Before doing anything else you need to install and configure Doctrine as some of the other commands require it.

I like to put the database and other info in env.local instead of .env so the values are not stored in my repository. So first create .env.local For more information about the many configuration files and how they work in Symfony view this.

I prefer listing the database parts instead of a long connection string, it is easier to substitute later. I can use system variables for DATABASE_USER and DATABASE_PASSWORD.  I have also set the app environment variables like this and here too.  And you will want to see what environmental variables your symfony app is using too. I also set the configuration for things like Redis in .env.local

DATABASE_USER=dingleberryFarmer
DATABASE_PASSWORD=aBigPassword

Now you will also need to make some changes to config/packages/doctrine.yaml

dbal:
  dbname: sogi-test
  host: localhost
  port: 3306
  user: '%env(resolve:DATABASE_USER)%'
  password: '%env(resolve:DATABASE_PASSWORD)%'
  driver: pdo_mysql
  server_version: '8.0.21'
  schema_filter: ~^(?!t_)~
    # IMPORTANT: You MUST configure your server version,
    # either here or in the DATABASE_URL env var (see .env file)
    #server_version: '5.7'

Here I add the database name, user name, password (from the .env.local file) the driver etc. The Schema filter is so that doctrine doesn’t mess with my custom tables which have to start with t_ .

To learn more about Doctrine 2 with Symfony 5 I suggest this free to read symfonycast on doctrine.

Creating the User classes

For this you need to use makers. First install the maker bundle with this command.

composer require --dev symfony/maker-bundle

Now list all of the available makers with this command.

php bin/console list make

You will see one named “make:user”. Now type this command and it will ask some questions.

php bin/console make:user

After you answer the questions, it will create a user table, entity and repository class for you.

cool stuff meme
Cool stuff man.

Here I went with the default settings.

symfony make user image
How to create the users

Experiment to find out what the others do.

Create the Authentication system

I learned this the hard way by creating the registration before the authentication. This creates the login/logout forms and supporting classes. Use the following command to create the authentication system.

php bin/console make:auth

This will ask you some questions. I named everything “Loginxxx” So it would match. I first had the defaults but it was too confusing with the name mismatches.

symfony make authentication image
make:auth asks some questions

Create the registration system

Next create the registration system with this command :

php bin/console make:registration-form

This command will ask questions I mostly went with the defaults except for requiring an email to be sent to verify the email.

symfony make registration image
Questions symfony maker asks while creating the registration system

The options for redirect after registration suck because there are no other routes yet. This will be changed later.

kitten stay strong meme
See lots of baby steps

Password reset time

What good is an app if users can’t reset their passwords? Lucky for us Symfony makes this easy too, with another Maker. LOL

Before you can use this maker you must install a bundle with this command.

composer require --dev symfonycasts/reset-password-bundle

Now use this command to create the password reset classes.

 php bin/console make:reset-password

This command will ask you some questions like so

symfony reset password image
Symfony maker will ask these questions

Below where it says next it shows that you should create a migration. In order to do that next we must setup some configs.

symfony reset password image 2
Options after reset password is created

Now follow the advice in the last screenshot and do some doctrine migrations to create the needed tables for all of the Entities you now have.

You can now add more contollers and build your app. After you get another controller and some routes you can change the route to direct users to after they register. I redirect mine to the last page they viewed or to their home page. I’ll have to write an article about that too.

Categories
Software Development Web Development

Symfony 5+ how to create a Maker

The docs do not mention how to create your own maker bundle. It gives a link to some of the Github code of the existing maker bundles for you to view as an example.

you need to figure it out meme
Here is a link, you figure it out. LOL

So when I dug deeper into the subject, I figured out what you are actually doing with a maker is creating a console app. You will know these “Makers” from typing commands on the command line like the following:

php bin/console cache:clear  or 
php bin/console list make

So step 1 is to create a new class in a directory in your “src” directory. I call mine… “Makers”

Then inside your class you need to add some use statements for the classes you intend to use like so.


use Symfony\Bundle\MakerBundle\ConsoleStyle;
use Symfony\Bundle\MakerBundle\DependencyBuilder;
use Symfony\Bundle\MakerBundle\Generator;
use Symfony\Bundle\MakerBundle\InputConfiguration;
use Symfony\Bundle\MakerBundle\Maker\AbstractMaker;
use Symfony\Bundle\MakerBundle\Validator;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;

Here is a link to the Console classes so you can find out what is available.
For the other classes you see e.g. “Symfony\Bundle\MakerBundle\ConsoleStyle  It appears these are located in “maker-bundle/src/class-name/ now. Here is a link to the related classes source code.

Once you have decided what classes you will need, via trial and error based on your project idea, you next need to extend the AbstractMaker interface and add the methods like this.

Below is an example of a maker that extracts table information from a database and creates classes with it. I use these classes for creating custom queries. It is easier than remembering all the fields of a table and what values they can contain etc. The only downside is when changes to a table are made and the column name you used no longer exists, you have to find it in your code. But a good IDE will help you find this. I might add this code to a repo or maybe Symfony one day. This is useful for writing custom queries where you need to know the column names and types etc. You can use this with Doctrine CRUD classes or your own etc.

I made notes on what I think the methods do since there is absolutely 0 documentation that I can find.


<?php


namespace App\Maker;


use App\DbUtils\MysqlConnection;
use App\Schema\SchemaMaker;
use Symfony\Bundle\MakerBundle\ConsoleStyle;
use Symfony\Bundle\MakerBundle\DependencyBuilder;
use Symfony\Bundle\MakerBundle\Generator;
use Symfony\Bundle\MakerBundle\InputConfiguration;
use Symfony\Bundle\MakerBundle\Maker\AbstractMaker;
use Symfony\Bundle\MakerBundle\Validator;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;

class TableMetaMaker extends AbstractMaker
{

    /**
     * Return the command name for your maker (e.g. make:report).
     */
    public static function getCommandName(): string
    {
        return 'make:table-meta';
    }

    /**
     * Configure the command: set description, input arguments, options, etc.
     *
     * By default, all arguments will be asked interactively. If you want
     * to avoid that, use the §inputConfig->setArgumentAsNonInteractive() method.
     * @param Command §command
     * @param InputConfiguration §inputConfig
     */
    public function configureCommand(Command §command, InputConfiguration §inputConfig)
    {
        §command->setDescription('Creates classes with table data')
            ->addArgument('schema', InputArgument::REQUIRED, sprintf('The name of database schema to model '));
    }

    /**
     * Configure any library dependencies that your maker requires.
     * @param DependencyBuilder §dependencies
     */
    public function configureDependencies(DependencyBuilder §dependencies)
    {
        // TODO: Implement configureDependencies() method.
    }

    /**
     * Called after normal code generation: allows you to do anything.
     * @param InputInterface §input
     * @param ConsoleStyle §io
     * @param Generator §generator
     */
    public function generate(InputInterface §input, ConsoleStyle §io, Generator §generator)
    {
        §schema = §input->getArgument('schema');
        §io->success("Now generating Table classes for schema " . §schema);
        §userName = §_SERVER['DATABASE_USER'];
        §pass = §_SERVER['DATABASE_PASSWORD'];

        §mysql = new MysqlConnection(§userName,§pass, §schema);
        §schemaMaker = new SchemaMaker(§mysql,§schema);
        §schemaMaker->setSchemaTableList();
        §schemaMaker->createAllSchemaClasses();

        foreach (§schemaMaker->getTablesList() as §table){
            §io->success("Created Class for table " . implode('-', §table));
        }

    }

    public function interact(InputInterface §input, ConsoleStyle §io, Command §command)
    {
        §io->title('Create the database table classes...');
        §value = '';

        if (null === §input->getArgument('schema')) {
            §argument = §command->getDefinition()->getArgument('schema');
            §question = new Question(§argument->getDescription());
            §value = §io->askQuestion(§question);
            §input->setArgument('schema', §value);

        }
        §value = §input->getArgument('schema');
        §io->success("Table classes were made from schema " . §value);

        /*§input->setArgument('schema', §io->ask(
            'What is the name of the database schema',
            null,
            [Validator::class, 'notBlank']
        )
        );*/
    }
}

As you can see there are some custom classes I am using too. I don’t have the time right now to cleanup and publish all the code. Maybe one day though. I have several other Makers I use. One clones Entities, another creates Repositories based on Entities. Those two I may publish sooner as they are the most useful and would require the least effort to share.

Since all you are doing with a Maker is creating a console app. I’d recommend reading all the links below about that. When you extend

AbstractMaker

Here is an absolute basic class with the basic methods you must have for your maker to work.


<?php

namespace App\Maker;

use Symfony\Bundle\MakerBundle\ConsoleStyle;
use Symfony\Bundle\MakerBundle\DependencyBuilder;
use Symfony\Bundle\MakerBundle\Generator;
use Symfony\Bundle\MakerBundle\InputConfiguration;
use Symfony\Bundle\MakerBundle\Maker\AbstractMaker;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;

/**
 * @method string getCommandDescription()
 */
class TestMaker extends AbstractMaker
{

    public static function getCommandName(): string
    {
        // TODO: Implement getCommandName() method.
    }

    public function configureCommand(Command $command, InputConfiguration $inputConfig)
    {
        // TODO: Implement configureCommand() method.
    }

    public function configureDependencies(DependencyBuilder $dependencies)
    {
        // TODO: Implement configureDependencies() method.
    }

    public function generate(InputInterface $input, ConsoleStyle $io, Generator $generator)
    {
        // TODO: Implement generate() method.
    }

    public function __call($name, $arguments)
    {
        // TODO: Implement @method string getCommandDescription()
    }
}

I don’t work on Symfony core and there is no documentation so I can’t tell you what these methods do. However, you can look at all of the code for the makers and see what is done in them.

I do most of my work in the generate method. For getCommandDescription() method I do this

public static function getCommandDescription(): string
{
    return 'Clones a Doctrine Entity class.';
}

Additional info and links

I had to google and dig to find this  which explains the console command arguments and options.

Here is another link to the docs for the console commands you can use with Makers.

Here is yet another link to more information about the console and how to use it. This is to the console component itself. This link has most of the other helpful console related links to the bottom of the article. There looks to be about 20 links at this time. These are the most helpful links so I won’t repost every one of them here.

Here is yet another link about the console arguments and options.

And here is a link that explains the QuestionHelper class you use to ask questions.

Here is a link explaining the FormatHelper class used to format console output. This one is useful if you want to print messages in blocks with background colors.  If you want to change the color of the actual text you need to read this.

You can even display a clickable link to the user in the command line.

Categories
Software Development Web Development

Php how to use array_map with an anonymous function

In PHP you can use array_map() and the other array related methods like array_filter() with either a named function, an anonymous function, or an arrow function.
I didn’t see any examples in the PHP docs( they can be updated any day ) about how to use an anonymous function, so I tried it and here is how to do it. It does show how to use an arrow function which is a shorter way to accomplish this, but looks different. It is a preference thing, both work the same under the hood.

Below is the array_map function definition from the PHP docs.
array_map(?callable $callback, array $array, array ...$arrays): array
As you can see it takes a callable/callback function. This means you could create a function and supply it to this method. And that is a great way to do this… unless what you need to do in the function is very small.
For example I needed to remove the word “Repository” from every file name. I globbed the file names from the directory then I use this function


private function getRepositoryNames(): array{
$values = array_map(function ($val){
return str_replace('Repository', '', $val);
}, $this->_repositoryNames);

dump($values);
return $values;
}

Look closely and you will see the anonymous function. It is the first argument to the array_map() method. The second argument is the actual array I want to work on here. As you can see this would quickly become hard to read if the function were more than a few lines of code. You see this a lot more often in languages like Javascript and Scala.

As you can see I am simply using str_replace() If I needed to do much more it would be better to have a separate named function instead of an anonymous one for several reasons. The #1 reason to separate out the function is for readability purposes. The #2 I can think of relates to #1, maintaining or changing how the function works. But mostly if it is long separate it out so it is easier to read the code.

How does it work?

Basically the way array_map works is the second value you supply, an array, is looped over and supplied to your function one at a time and your function operates on it and returns it to array_map. When array_map is done looping over all the values it returns the new array. You can read more in the PHP docs here.

Links

A very good in depth article about using Php Arrow functions.

Php Anonymous Functions, what are they and why use them. – a very good in depth article about php anonymous functions. It is 10 years old, but still up to date and relevant.

Anonymous and Arrow functions in PHP – a very good article that covers both.