symfony create database index with lower function - php

How can I declare in Doctrine an index for postgresql like:
CREATE INDEX index_name_city_hotel ON booking_hotels(lower(name) text_pattern_ops, city_hotel, cc1)
I already tried but it seems impossible to use lower() function.
This doesn't work because of the lower function:
indexes={
#ORM\Index(name="index_name_city_hotel", columns={"lower(name) text_pattern_ops", "city_hotel", "cc1"})
thanks in advance for your help.

Try to use https://github.com/intaro/custom-index-bundle
<?php
namespace Acme\MyBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Intaro\CustomIndexBundle\Annotations as CustomIndexAnnotation
/**
* #ORM\Table(name="my_entity")
* #ORM\Entity()
* #CustomIndexAnnotation\CustomIndexes(indexes={
* #CustomIndexAnnotation\CustomIndex(columns="my_property1"),
* #CustomIndexAnnotation\CustomIndex(columns={"lower(my_property1)", "lower(my_property2)"})
* })
*/
class MyEntity
{
/**
* #ORM\Column(type="string", length=256)
*/
protected $myProperty1;
/**
* #ORM\Column(type="string", length=256)
*/
protected $myProperty2;
}

Related

Doctrine always filter rows with certain column values

I am using Symfony 5.1 with doctrine. I would like to know how to put a filter on a field/column for all doctrine queries that do a search on an entity. For example, with the entity Sejour I would like to make sure all queries that search for this entity have the where by clause on the field/column: "sejAnnule != 'Y'". Here is the Sejour entity:
<?php
namespace App\Entity;
use DateTime;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* Sejour.
*
* #ORM\Table(name="Sejour")})
* #ORM\Entity(repositoryClass="App\Repository\SejourRepository")
*/
class Sejour
{
/**
* #ORM\Column(name="SEJ_NO", type="integer", nullable=false)
* #ORM\Id
*/
private int $sejNo;
/**
* #var string|null
*
* #ORM\Column(name="SEJ_ANNULE", type="string", length=1, nullable=true)
*/
private string $sejAnnule;
public function getSejAnnule(): ?string
{
return $this->sejAnnule;
}
public function setSejAnnule(?string $sejAnnule): void
{
$this->sejAnnule = $sejAnnule;
}
public function getSejNo(): int
{
return $this->sejNo;
}
public function setSejNo(int $sejNo): void
{
$this->sejNo = $sejNo;
}
}
I think this is possible with doctrine filters but I was wondering if anyone knows a quicker way to do this (e.g. an annotation on the field or a bundle)?
The easiest way to this I think is to use a doctrine filter. No need to create an event listener (as i first thought). Create the filter:
<?php
namespace App\Filter;
use App\Entity\Sejour;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Query\Filter\SQLFilter;
class SoftDeleteFilter extends SQLFilter
{
/**
* {#inheritdoc}
*/
public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias)
{
if (Sejour::class == $targetEntity->getReflectionClass()->name) {
return sprintf(' %s.SEJ_ANNULE != \'Y\'', $targetTableAlias);
}
return '';
}
}
Then enable the filter in doctrine.yaml:
orm:
filters:
soft_delete_filter:
class: AppBundle\Doctrine\SoftDeleteFilter
enabled: true
Symfony documentation: https://symfony.com/doc/current/bundles/DoctrineBundle/configuration.html#filters-configuration
The Symfony Casts documentation (although this is with an event listener) https://symfonycasts.com/screencast/doctrine-queries/filters

ODM inheritance document with type SINGLE_COLLECTION schema create error

I have inheritance document with type SINGLE_COLLECTION configured in my Symfony 4.4 app.
When i run command bin/console doctrine:mongodb:schema:create, then error occurs a collection 'db.Person' already exists.
Everything was done according to the documentation: https://www.doctrine-project.org/projects/doctrine-mongodb-odm/en/2.0/reference/inheritance-mapping.html#single-collection-inheritance
src/Document/Person.php
<?php
namespace App\Document;
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
/**
* #MongoDB\Document
* #MongoDB\InheritanceType("SINGLE_COLLECTION")
* #MongoDB\DiscriminatorField("type")
* #MongoDB\DiscriminatorMap({"person"=Person::class, "employee"=Employee::class})
*/
class Person
{
/**
* #var integer|null
*
* #MongoDB\Id
*/
protected $id;
/**
* #var string|null
*
* #MongoDB\Field(type="string")
*/
protected $name;
}
src/Document/Employee.php
<?php
namespace App\Document;
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
/**
* #MongoDB\Document
*/
class Employee extends Person
{
/**
* #var string|null
*
* #MongoDB\Field(type="string")
*/
protected $grade;
}
It looks like command is trying to create DB collection for every Document class, ignoring declaration of SINGLE_COLLECTION type.
How to fix it?
ODM's odm:schema:create is iterating through all metadatas and tries to create a collection without considering possible relations between them. A proper fix would be in the ODM's SchemaManager to either check whether a collection exists prior to creating or catching exception and ignoring it in case of existing collection.
I have created https://github.com/doctrine/mongodb-odm/issues/2182 to track this issue. If you have some time to spare we will appreciate a PR!

API Platform immutable property

I'm using API Platform on a Symfony 4.3 project and I just want to have an immutable property (userId in this case) which can be set on POST but cannot be changed with PUT. So far, the only way to accomplish this was to drop the userId setter and use the constructor to initially set the value.
This setup still shows the property in Swagger for PUT (image below), but more troublesome is that it accepts that property without modifying the record. It's a silenced ignore and I would prefer a 400 Bad Request return code to let the client know his request was not processed as expected.
Is there any other way I could accomplish a similar behavior with API Platform? Already tried serialization groups, maybe with the wrong settings though.
<?php
declare(strict_types = 1);
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiFilter;
use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\NumericFilter;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="App\Repository\SubscriptionRepository")
*
* #UniqueEntity("userId")
*
* #ApiResource()
*/
class Subscription
{
/**
* #var int
*
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #var int
*
* #ORM\Column(type="integer")
*
* #ApiFilter(NumericFilter::class)
*/
private $userId;
/**
* Subscription constructor.
*
* #param int $userId
*/
public function __construct(int $userId)
{
$this->userId = $userId;
}
...
?>
I think you will need to explicitly set normalization_context.groups for PUT request to {"read"} (or something else, depending on your configuration).
See Operations documentation

Doctrine Association Mapping OneToMany Bidirectional do not work

i use doctrine ORM for generate a association one-to-many bidirectional, but when i execute the orm:validation-scheme command, this shows me the mesaje below:
"C:\xampp\htdocs\Gestor\vendor\bin>doctrine-module orm:validate-schema
[Mapping] FAIL - The entity-class 'Empleados\Entity\TipoDocumento' mapping is i
nvalid:
* The association Empleados\Entity\TipoDocumento#empleados refers to the owning
side field Empleados\Entity\Empleado#tipodocumento which does not exist.
[Database] FAIL - The database schema is not in sync with the current mapping fi
le."
The code:
Empleado class (many to one side)
<?php
namespace Empleados\Entity;
use Doctrine\Common\Collections\ArrayCollection as Collection;
use Empresas\Entity\Empresa;
use Empleados\Entity\TipoDocumento;
use Doctrine\ORM\Mapping as ORM;
use Documentos\Entity\Documentacion_Empleado;
/**
* #ORM\Entity
* #ORM\Table(name="empleado")
*
*/
class Empleado
{
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string",length=30,nullable=false,unique=true)
*/
private $nro_documento;
/*
* #ORM\ManyToOne(targetEntity="Empleados\Entity\TipoDocumento",inversedBy="empleados")
* #ORM\JoinColumn(name="tipodocumento_id", referencedColumnName="id")
*/
private $tipodocumento;
//...
}
The TipoDocumento class (one to many side):
<?php
// yes, the class are in the same namespace "Empleados"
namespace Empleados\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Empleados\Entity\Empleado;
/**
* #ORM\Entity
* #ORM\Table(name="tipo_documento")
*/
class TipoDocumento
{
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\OneToMany(targetEntity="Empleados\Entity\Empleado", mappedBy="tipodocumento"))
*/
private $empleados;
//.....
public function __construct()
{
$this->empleados = new ArrayCollection();
}
}
I'm based on the Doctrine documentation example in http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/association-mapping.html
In class TipoDocumento, private $empleados; should be private $empleado;.
Edit
Sorry that's right, I was looking at the wrong place in the documentation.
The Many-to-one has the plural there. It also contains something like:
public function __construct() {
$this->empleados = new ArrayCollection();
}
I can't tell if your class contains this function.
jmarkmurphy thanks for your help.
The problem was in the camelcase of the "TipoDocumento" class, for some reason Doctrine does not like the camelcase ... What I did was rename the class to Tipo_documento and with that change everything started to work fine.

Symfony3 The identifier id is missing for a query of AppBundle\Entity\

I am new to symfony and I am trying to pass a object from a list to a new page using:
Update
The list ({% for item in list %}) of Foo objects is fine, the objects are fully loaded from the database, but the link does not work because of this Doctrine error:
The identifier id is missing for a query of AppBundle\Entity\Foo
Here is the Foo class:
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="foo")
*/
class Foo {
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue
*/
private $id;
/**
* #ORM\Column(type="string")
*/
private $description;
//getters and setters
And here is the controller method:
/**
* #Route("/foo/fooUpdate/", name="fooUpdate")
*/
public function updateAction($id, Request $request) {
$foo = $this->getDoctrine()->getRepository('AppBundle:Foo')->find($id);
return $this->render('/foo/fooUpdate.html.twig', array(
'foo' => $foo
));
}
The link itself looks like it is working, because the URL of the error is:
http://127.0.0.1:8000/foo/fooUpdate/?id=1
So what am I missing?
Also, is there any way of doing this using POST, so the id will not appear in the URL?
You are missing the id in the route:
#Route("/foo/fooUpdate/{id}", name="fooUpdate")
Actually, you should also set defaults:
/**
* #Route("/foo/fooUpdate/{id}",
* defaults={"id" = 0},
* name="fooUpdate")
*/
The defaults are used in case you don't pass in a parameter.
As far as not setting the id in the URL, look into sessions:
https://symfony.com/doc/current/components/http_foundation/sessions.html
You should be able to do that, but it's more work (coding).

Categories