gstreamer0.10-ffmpeg
gstreamer0.10-plugins-good
packages.
Lo bueno de la clase User
es que... ¡es nuestra clase! Mientras implementemosUserInterface
, podemos añadir lo que queramos:
... lines 1 - 7 | |
use Symfony\Component\Security\Core\User\UserInterface; | |
... lines 9 - 12 | |
class User implements UserInterface | |
{ | |
... lines 15 - 113 | |
} |
Por ejemplo, me gustaría almacenar el nombre de mis usuarios. Así que vamos a añadir una propiedad para eso. En tu terminal, ejecuta:
symfony console make:entity
Editaremos la entidad User
, añadiremos una propiedad firstName
, haremos que sea una cadena, de 255 de longitud... y diremos "sí" a anulable. Hagamos que esta propiedad sea opcional en la base de datos.
Ya está De vuelta a la clase User
, ¡no hay sorpresas! Tenemos una nueva propiedad... y nuevos métodos getter y setter:
... lines 1 - 12 | |
class User implements UserInterface | |
{ | |
... lines 15 - 31 | |
/** | |
* @ORM\Column(type="string", length=255, nullable=true) | |
*/ | |
private $firstName; | |
... lines 36 - 119 | |
public function getFirstName(): ?string | |
{ | |
return $this->firstName; | |
} | |
public function setFirstName(string $firstName): self | |
{ | |
$this->firstName = $firstName; | |
return $this; | |
} | |
} |
Ve a generar una migración para nuestro nuevo User
. En el terminal, ejecuta
symfony console make:migration
¡Genial! Gira y abre eso para asegurarte de que no esconde ninguna sorpresa:
... lines 1 - 2 | |
declare(strict_types=1); | |
namespace DoctrineMigrations; | |
use Doctrine\DBAL\Schema\Schema; | |
use Doctrine\Migrations\AbstractMigration; | |
/** | |
* Auto-generated Migration: Please modify to your needs! | |
*/ | |
final class Version20211001172813 extends AbstractMigration | |
{ | |
public function getDescription(): string | |
{ | |
return ''; | |
} | |
public function up(Schema $schema): void | |
{ | |
// this up() migration is auto-generated, please modify it to your needs | |
$this->addSql('CREATE TABLE user (id INT AUTO_INCREMENT NOT NULL, email VARCHAR(180) NOT NULL, roles JSON NOT NULL, first_name VARCHAR(255) DEFAULT NULL, UNIQUE INDEX UNIQ_8D93D649E7927C74 (email), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); | |
} | |
public function down(Schema $schema): void | |
{ | |
// this down() migration is auto-generated, please modify it to your needs | |
$this->addSql('DROP TABLE user'); | |
} | |
} |
Ejecuta: CREATE TABLE user
con las columnas id
, email
, roles
y first_name
. Cierra esto... y ejecútalo:
symfony console doctrine:migrations:migrate
¡Éxito!
Y como la entidad User
es... una entidad normal de Doctrine, también podemos añadir usuarios ficticios a nuestra base de datos utilizando el sistema de accesorios.
Abre src/DataFixtures/AppFixtures.php
. Vamos a utilizar Foundry para ayudarnos a cargar los datos. Así que vamos a crear una nueva fábrica de Foundry para User
. Como nos estamos divirtiendo tanto ejecutando comandos en este vídeo, vamos a colar uno... o tres más:
symfony console make:factory
¡Sí! Queremos una para User
. Ve a abrirlo: src/Factory/UserFactory.php
:
... lines 1 - 2 | |
namespace App\Factory; | |
use App\Entity\User; | |
use App\Repository\UserRepository; | |
use Zenstruck\Foundry\RepositoryProxy; | |
use Zenstruck\Foundry\ModelFactory; | |
use Zenstruck\Foundry\Proxy; | |
... lines 10 - 28 | |
final class UserFactory extends ModelFactory | |
{ | |
public function __construct() | |
{ | |
parent::__construct(); | |
// TODO inject services if required (https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#factories-as-services) | |
} | |
protected function getDefaults(): array | |
{ | |
return [ | |
// TODO add your default values here (https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#model-factories) | |
'email' => self::faker()->text(), | |
'roles' => [], | |
'firstName' => self::faker()->text(), | |
]; | |
} | |
protected function initialize(): self | |
{ | |
// see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#initialization | |
return $this | |
// ->afterInstantiate(function(User $user) {}) | |
; | |
} | |
protected static function getClass(): string | |
{ | |
return User::class; | |
} | |
} |
Nuestro trabajo en getDefaults()
es asegurarnos de que todas las propiedades necesarias tienen buenos valores por defecto. Establece email
en self::faker()->email()
, no estableceré ninguna función por ahora y establece firstName
en self::faker()->firstName()
:
... lines 1 - 28 | |
final class UserFactory extends ModelFactory | |
{ | |
... lines 31 - 37 | |
protected function getDefaults(): array | |
{ | |
return [ | |
'email' => self::faker()->email(), | |
'firstName' => self::faker()->firstName(), | |
]; | |
} | |
... lines 45 - 57 | |
} |
¡Genial! En AppFixtures
, en la parte inferior, crea un usuario: UserFactory::createOne()
. Pero utiliza un correo electrónico específico para que podamos iniciar sesión con él más tarde. Qué tal,abraca_admin@example.com
:
... lines 1 - 11 | |
use App\Factory\UserFactory; | |
... lines 13 - 15 | |
class AppFixtures extends Fixture | |
{ | |
public function load(ObjectManager $manager) | |
{ | |
... lines 20 - 41 | |
AnswerFactory::new(function() use ($questions) { | |
... lines 43 - 45 | |
})->needsApproval()->many(20)->create(); | |
UserFactory::createOne(['email' => 'abraca_admin@example.com']); | |
... lines 49 - 51 | |
} | |
} |
Luego, para rellenar un poco el sistema, añade UserFactory::createMany(10)
:
... lines 1 - 11 | |
use App\Factory\UserFactory; | |
... lines 13 - 15 | |
class AppFixtures extends Fixture | |
{ | |
public function load(ObjectManager $manager) | |
{ | |
... lines 20 - 47 | |
UserFactory::createOne(['email' => 'abraca_admin@example.com']); | |
UserFactory::createMany(10); | |
... lines 50 - 51 | |
} | |
} |
¡Vamos a probarlo! De vuelta al terminal, ejecuta:
symfony console doctrine:fixtures:load
¡No hay errores! Comprueba la nueva tabla:
symfony console doctrine:query:sql 'SELECT * FROM user'
Y... ¡ahí están! Ahora que tenemos usuarios en la base de datos, tenemos que añadir una o varias formas para que se autentiquen. ¡Es hora de construir un formulario de acceso!
Hey Ramon,
Yes, those files are already exist in this course. They come from past tutorials from the fundamental section: https://symfonycasts.com/tracks/symfony5#the-fundamentals - we base every new tutorial on the previous one.
Cheers!
Hi, the symfony console make:factroy command is not defined, I'm with symfony 6.3.x what can I replace it with ? Thanks
Hey @pasquale_pellicani ,
Yep, you need to install that bundle - that's how MakerBundle works, it does not have all possible dependencies and suggests you install specific ones on the go when you're trying to use more features. Good catch!
Cheers!
Hey,
Maybe silly question but I can't figure out how to display symfony console doctrine:query:sql 'SELECT * FROM user'<br />
in the same array format like in video? :)))
Hey Szymon,
It seems you can't anymore :) They output is displayed in a table now instead of a raw dump as it was before.
Cheers!
For some reason, the "doctrine:fixtures:load" command fails with my PostgresSQL container. I get the error
SQLSTATE[42601]: Syntax error: 7 ERROR: syntax error at or near "user" LINE 1: INSERT INTO user (id, name, email, roles, created_at, update...`
LINE 1: INSERT INTO user (id, name, email, roles, created_at, update...
Question: Is there a way I can tell Doctrine to use "user"
instead of user
for that Entity?
Or do I need to rename the Entity to something else?
I've tried to apply the quotes via an annotation #[ORM\Table(name: '"user"')]
but that caused a different error
SQLSTATE[42602]: Invalid name: 7 ERROR: invalid name syntax
LINE 1: SELECT NEXTVAL('"user"_id_seq')
Hey Philipp,
Yeah, most probably that's because of that table name, user
is a reserved word in PostgreSql. You need to rename that table to something, like app_user
.
Another trick, you might try to use ticks around the table name, i.e. use `, instead of ":
#[ORM\Table(name: '`user`')]
It might also work, though I've never tried it in PostgreSql, though in MySQL it worked. But safer would be not use reserved words at all, better use a unique name :)
Cheers!
Thanks for the clarification, Victor!
As you suggested, I could solve the issue by renaming the DB table via an annotation + recreating the DB schema
#[ORM\Table(name: 'app_user')]
class User implements UserInterface { ...
hey ! I have a error
***********
SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual
that corresponds to your MariaDB server version for the right syntax to use near 'INDEX idx_9474526c1e27f6bf
TO IDX_DADD4A251E27F6BF' at line 1
********
Column Already exist 'status'
Hey Anass,
It looks like you already have that "status" column. Please, try to validate your DB schema with:
$ symfony console doctrine:schema:validate
If it's not OK - try to apply the required changes, to know what queries you need to execute - see:
$ symfony console doctrine:schema:update --dump-sql
Of if you're working locally and don't worry about losing your data in the DB - instead you can run:
$ symfony console doctrine:schema:update --force
Cheers!
In case anyone else runs into an error trying to run the simple query at the end try using double quotes around the SQL statement instead of single quotes.
Hey Aaron,
Thanks for this tip! Are you talking about "symfony console doctrine:query:sql 'SELECT * FROM user'" command? It somehow does not work for you with single quotes around the SQL query? I wonder what OS do you use and what terminal?
Cheers!
Yes that's the command I'm talking about. When running it on the DOS console on Windows 10 using single quotes it throws an error but with double quotes it does not.
Ha! Windows likes to complicate things. Thanks for sharing your problem + solution with others
// composer.json
{
"require": {
"php": ">=8.1",
"ext-ctype": "*",
"ext-iconv": "*",
"babdev/pagerfanta-bundle": "^3.3", // v3.3.0
"composer/package-versions-deprecated": "^1.11", // 1.11.99.4
"doctrine/annotations": "^1.0", // 1.13.2
"doctrine/doctrine-bundle": "^2.1", // 2.6.3
"doctrine/doctrine-migrations-bundle": "^3.0", // 3.1.1
"doctrine/orm": "^2.7", // 2.10.1
"knplabs/knp-markdown-bundle": "^1.8", // 1.9.0
"knplabs/knp-time-bundle": "^1.11", // v1.16.1
"pagerfanta/doctrine-orm-adapter": "^3.3", // v3.3.0
"pagerfanta/twig": "^3.3", // v3.3.0
"phpdocumentor/reflection-docblock": "^5.2", // 5.2.2
"scheb/2fa-bundle": "^5.12", // v5.12.1
"scheb/2fa-qr-code": "^5.12", // v5.12.1
"scheb/2fa-totp": "^5.12", // v5.12.1
"sensio/framework-extra-bundle": "^6.0", // v6.2.0
"stof/doctrine-extensions-bundle": "^1.4", // v1.6.0
"symfony/asset": "5.3.*", // v5.3.4
"symfony/console": "5.3.*", // v5.3.7
"symfony/dotenv": "5.3.*", // v5.3.8
"symfony/flex": "^1.3.1", // v1.17.5
"symfony/form": "5.3.*", // v5.3.8
"symfony/framework-bundle": "5.3.*", // v5.3.8
"symfony/monolog-bundle": "^3.0", // v3.7.0
"symfony/property-access": "5.3.*", // v5.3.8
"symfony/property-info": "5.3.*", // v5.3.8
"symfony/rate-limiter": "5.3.*", // v5.3.4
"symfony/runtime": "5.3.*", // v5.3.4
"symfony/security-bundle": "5.3.*", // v5.3.8
"symfony/serializer": "5.3.*", // v5.3.8
"symfony/stopwatch": "5.3.*", // v5.3.4
"symfony/twig-bundle": "5.3.*", // v5.3.4
"symfony/ux-chartjs": "^1.3", // v1.3.0
"symfony/validator": "5.3.*", // v5.3.8
"symfony/webpack-encore-bundle": "^1.7", // v1.12.0
"symfony/yaml": "5.3.*", // v5.3.6
"symfonycasts/verify-email-bundle": "^1.5", // v1.5.0
"twig/extra-bundle": "^2.12|^3.0", // v3.3.3
"twig/string-extra": "^3.3", // v3.3.3
"twig/twig": "^2.12|^3.0" // v3.3.3
},
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "^3.3", // 3.4.0
"symfony/debug-bundle": "5.3.*", // v5.3.4
"symfony/maker-bundle": "^1.15", // v1.34.0
"symfony/var-dumper": "5.3.*", // v5.3.8
"symfony/web-profiler-bundle": "5.3.*", // v5.3.8
"zenstruck/foundry": "^1.1" // v1.13.3
}
}
Where are all these files coming from in the AppFixtures? Did you just create them? I can't find where they are coming from following your tutorials.. they just exist.