gstreamer0.10-ffmpeg
gstreamer0.10-plugins-good
packages.
En nuestra entidad VinylMix
, olvidé añadir antes una propiedad: votes
. Vamos a llevar la cuenta del número de votos a favor o en contra que tiene una determinada mezcla.
Bien... ¿cómo podemos añadir una nueva propiedad a una entidad? Bueno, podemos hacerlo a mano: todo lo que tenemos que hacer es crear la propiedad y los métodos getter y setter. Pero, una forma mucho más fácil es volver a nuestro comando favorito make:entity
:
php bin/console make:entity
Éste se utiliza para crear entidades, pero también podemos utilizarlo para actualizarlas. Escribe VinylMix
como nombre de la clase y... ¡ve que existe! Añade una nueva propiedad: votes
... conviértela en integer
, di "no" a anulable... y pulsa "intro" para terminar.
¿El resultado final? Nuestra clase tiene una nueva propiedad... y métodos getter y setter a continuación.
... lines 1 - 9 | |
class VinylMix | |
{ | |
... lines 12 - 31 | |
#[ORM\Column] | |
private ?int $votes = null; | |
... lines 34 - 99 | |
public function getVotes(): ?int | |
{ | |
return $this->votes; | |
} | |
public function setVotes(int $votes): self | |
{ | |
$this->votes = $votes; | |
return $this; | |
} | |
} |
Bien, pensemos. Tenemos una tabla vinyl_mix
en la base de datos... pero aún no tiene la nueva columna votes
. Tenemos que modificar la tabla para añadirla. ¿Cómo podemos hacerlo? Exactamente igual que antes: ¡con una migración! En tu terminal, ejecuta:
symfony console make:migration
Luego ve a ver la nueva clase.
... lines 1 - 12 | |
final class Version20220718170741 extends AbstractMigration | |
{ | |
... lines 15 - 19 | |
public function up(Schema $schema): void | |
{ | |
// this up() migration is auto-generated, please modify it to your needs | |
$this->addSql('ALTER TABLE vinyl_mix ADD votes INT NOT NULL'); | |
} | |
... lines 25 - 31 | |
} |
¡Esto es increíble! Dentro del método up()
, dice
ALTER TABLE vinyl_mix ADD votes INT NOT NULL
Así que vio nuestra entidad VinylMix
, comprobó la tabla vinyl_mix
en la base de datos y generó una diferencia entre ellas. Se dio cuenta de que, para que la base de datos se pareciera a nuestra entidad, tenía que alterar la tabla y añadir esa columna votes
. Eso es simplemente increíble.
De vuelta al terminal, si ejecutas
symfony console doctrine:migrations:list
verás que reconoce ambas migraciones y sabe que no ha ejecutado la segunda. Para ello, ejecuta:
symfony console doctrine:migrations:migrate
Doctrine es lo suficientemente inteligente como para saltarse la primera y ejecutar la segunda. ¡Qué bien!
Cuando despliegues a producción, todo lo que tienes que hacer es ejecutar doctrine:migrations:migrate
cada vez. Se encargará de ejecutar todas y cada una de las migraciones que la base de datos de producción aún no haya ejecutado.
Bien, una cosa más rápida mientras estamos aquí. Dentro de VinylMix
, la nueva propiedad votes
tiene como valor por defecto null
. Pero cuando creamos un nuevo VinylMix
, tendría mucho sentido poner los votos por defecto a cero. Así que cambiemos esto a = 0
.
¡Genial! Y si hacemos eso, la propiedad en PHP ya no necesita permitir null
... así que elimina el ?
. Como estamos inicializando a un entero, esta propiedad siempre será un int
: nunca será nulo.
... lines 1 - 9 | |
class VinylMix | |
{ | |
... lines 12 - 32 | |
private int $votes = 0; | |
... lines 34 - 110 | |
} |
Pero... Me pregunto... porque he hecho este cambio, ¿tengo que modificar algo en mi base de datos? La respuesta es no. Puedo probarlo ejecutando un comando muy útil:
symfony console doctrine:schema:update --dump-sql
Es muy parecido al comando make:migration
... pero en lugar de generar un archivo con el SQL, sólo imprime el SQL necesario para actualizar tu base de datos. En este caso, muestra que nuestra base de datos ya está sincronizada con nuestra entidad.
La cuestión es: si inicializamos el valor de una propiedad en PHP... eso es sólo un cambio en PHP. No cambia la columna en la base de datos ni le da un valor por defecto, lo cual está totalmente bien.
Vamos a inicializar otro campo: $createdAt
. Sería increíble que algo estableciera automáticamente esta propiedad cada vez que creamos un nuevo objeto VinylMix
... en lugar de tener que establecerla nosotros manualmente.
Podemos hacerlo creando un método PHP __construct()
a la vieja usanza. Dentro, digamos $this->createdAt = new \DateTimeImmutable()
, que por defecto será ahora mismo.
... lines 1 - 9 | |
class VinylMix | |
{ | |
... lines 12 - 34 | |
public function __construct() | |
{ | |
$this->createdAt = new \DateTimeImmutable(); | |
} | |
... lines 39 - 115 | |
} |
Y ya está Y... ya no necesitamos el = null
ya que se inicializará aquí abajo... y tampoco necesitamos el ?
, porque siempre será un objetoDateTimeImmutable
.
... lines 1 - 9 | |
class VinylMix | |
{ | |
... lines 12 - 29 | |
private \DateTimeImmutable $createdAt; | |
... lines 31 - 115 | |
} |
¡Muy bien! Gracias a esto, la propiedad $createdAt
se establecerá automáticamente cada vez que instanciemos nuestro objeto. Y eso es sólo un cambio de PHP: no cambia la columna en la base de datos.
Muy bien, tenemos una entidad VinylMix
y la tabla correspondiente. A continuación, vamos a instanciar un objeto VinylMix
y guardarlo en la base de datos.
Hey @Dima
Yes, you're right. Since those fields are not nullable anymore, you can do that refactoring, but as you said, if you are using Symfony Forms to create new VinylMix
records, then you can't remove it from the $votes
property
Cheers!
concerning default values...
Am I right to understand that the way you've shown here (i.e. creating the entity > altering the code to insert defaults > not migrating the code changes), the table would still accept null
values, but no value would ever be null
because I changed the code?
If so, how could I make the table no longer accept null
values? Should I run the symfony console make:migration
command again? Or isn't there a way to do this once it's been set as nullable?
Hey!
Sorry we missed your original question somehow! Not cool!
the table would still accept null values, but no value would ever be null because I changed the code?
Not quite :). There are two totally independent systems going on:
A) By adding the defaults in PHP, it means that the properties on the PHP object will never been null
. So, you've got that correct.
B) But, whether or not the database will accept null
values is determined by something else: the nullable
: option on ORM\Column
. For example, you could have:
#[ORM\Column(nullable: true)
private $name = 'ryan';
In this case, in PHP, the name
property could never be null
. But, technically, you COULD insert a row into the database with a null
value (and yes, if you changed nullable: false
, you would need to run a database migration for that).
So, to answer this question:
how could I make the table no longer accept null values? Should I run the symfony console make:migration command again? Or isn't there a way to do this once it's been set as nullable?
The answer is: if you want a column in your table to NO accept null
values (i.e.to explode with an error if null
is sent), use nullable: false
on that property (or omit the nullable
option entirely, because false
is the default value for nullable
).
Let me know if that clears things up... or if I'm still being confusing :).
Cheers!
// composer.json
{
"require": {
"php": ">=8.1",
"ext-ctype": "*",
"ext-iconv": "*",
"babdev/pagerfanta-bundle": "^3.7", // v3.7.0
"doctrine/doctrine-bundle": "^2.7", // 2.7.0
"doctrine/doctrine-migrations-bundle": "^3.2", // 3.2.2
"doctrine/orm": "^2.12", // 2.12.3
"knplabs/knp-time-bundle": "^1.18", // v1.19.0
"pagerfanta/doctrine-orm-adapter": "^3.6", // v3.6.1
"pagerfanta/twig": "^3.6", // v3.6.1
"sensio/framework-extra-bundle": "^6.2", // v6.2.6
"stof/doctrine-extensions-bundle": "^1.7", // v1.7.0
"symfony/asset": "6.1.*", // v6.1.0
"symfony/console": "6.1.*", // v6.1.2
"symfony/dotenv": "6.1.*", // v6.1.0
"symfony/flex": "^2", // v2.2.2
"symfony/framework-bundle": "6.1.*", // v6.1.2
"symfony/http-client": "6.1.*", // v6.1.2
"symfony/monolog-bundle": "^3.0", // v3.8.0
"symfony/proxy-manager-bridge": "6.1.*", // v6.1.0
"symfony/runtime": "6.1.*", // v6.1.1
"symfony/twig-bundle": "6.1.*", // v6.1.1
"symfony/ux-turbo": "^2.0", // v2.3.0
"symfony/webpack-encore-bundle": "^1.13", // v1.15.1
"symfony/yaml": "6.1.*", // v6.1.2
"twig/extra-bundle": "^2.12|^3.0", // v3.4.0
"twig/twig": "^2.12|^3.0" // v3.4.1
},
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "^3.4", // 3.4.2
"symfony/debug-bundle": "6.1.*", // v6.1.0
"symfony/maker-bundle": "^1.41", // v1.44.0
"symfony/stopwatch": "6.1.*", // v6.1.0
"symfony/web-profiler-bundle": "6.1.*", // v6.1.2
"zenstruck/foundry": "^1.21" // v1.21.0
}
}
We changed $votes property never to be null. So can we remove "?" in getVotes method (or this will provide errors during for example form saving)? And the same question about getCreatedAt method