Doctrine 2.5 Embeddable: "Unknown Column" - doctrine-orm

I have a User class that looks like this:
/**
* #Entity #Table(name="users")
**/
class User {
/**
* #Id #Column(type="string")
**/
protected $id;
/**
* #var Password user's password
* #Embedded(class="Acme\Users\Password")
*/
private $password;
/**
* #var Email user's email address
* #Embedded(class="Acme\Users\Email")
*/
private $email;
/* .... More .... */
}
And a Password class that looks like this:
/**
* #Embeddable
*/
class Password {
/**
* #Column(type="string")
*/
private $password = NULL;
}
When I try to find a user with this:
$this->repository->findOneBy([
"email.email" => $email->toString()
]);
I'm getting errors like this:
Next exception 'Doctrine\DBAL\Exception\InvalidFieldNameException' with message 'An exception occurred while executing 'SELECT t0.id AS id_1, t0.password AS password_2, t0.email_email AS email_email_3 FROM users t0 WHERE t0.email_email = ? LIMIT 1' with params ["jason#email.com"]:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 't0.password' in 'field list'' in /Users/jason/Workspace/Personal/acme-bdd/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractMySQLDriver.php:71
Stack trace:
#0 /Users/jason/Workspace/Personal/acme-bdd/vendor/doctrine/dbal/lib/Doctrine/DBAL/DBALException.php(116): Doctrine\DBAL\Driver\AbstractMySQLDriver->convertException('An exception oc...', Object(Doctrine\DBAL\Driver\PDOException))
#1 /Users/jason/Workspace/Personal/acme-bdd/vendor/doctrine/dbal/lib/Doctrine/DBAL/Connection.php(836): Doctrine\DBAL\DBALException::driverExceptionDuringQuery(Object(Doctrine\DBAL\Driver\PDOMySql\Driver), Object(Doctrine\DBAL\Driver\PDOException), 'SELECT t0.id AS...', Array)
#2 /Users/jason/Workspace/Personal/acme-bdd/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php(715): Doctrine\DBAL\Connection->executeQuery('SELECT t0.id AS...', Array, Array)
#3 /Users/jason/Workspace/Personal/acme-bdd/vendor/doctrine/orm/lib/Doctrine/ORM/EntityRepository.php(196): Doctrine\ORM\Persisters\Entity\BasicEntityPersister->load(Array, NULL, NULL, Array, NULL, 1, NULL)
#4 /Users/jason/Workspace/Personal/acme-bdd/app/Acme/Users/DoctrineUserRepository.php(42): Doctrine\ORM\EntityRepository->findOneBy(Array)
#5 /Users/jason/Workspace/Personal/acme-bdd/app/Acme/Users/Commands/AttemptSignInCommandHandler.php(15): Acme\Users\DoctrineUserRepository->findByEmail(Object(Acme\Users\Email))
#6 /Users/jason/Workspace/Personal/acme-bdd/vendor/league/tactician/src/HandlerCommandBus.php(55): Acme\Users\Commands\AttemptSignInCommandHandler->handleAttemptSignInCommand(Object(Acme\Users\Commands\AttemptSignInCommand))
I have these packages installed:
$ composer show -i | grep doctrine
doctrine/annotations dev-master b5202eb Docblock Annotations Parser
doctrine/cache dev-master dbeacc7 Caching library offering an object-oriented API for many cache backends
doctrine/collections dev-master c63f2e6 Collections Abstraction library
doctrine/common dev-master 56360cc Common Library for Doctrine projects
doctrine/dbal 2.5.x-dev 67c4701 Database Abstraction Layer
doctrine/inflector dev-master e5eaf8c Common String Manipulations with regard to casing and singular/plural rules.
doctrine/instantiator dev-master 3d9669e A small, lightweight utility to instantiate objects in PHP without invoking their constructors
doctrine/lexer dev-master 83893c5 Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.
doctrine/migrations dev-master 1ac14fa Database Schema migrations using Doctrine DBAL
doctrine/orm dev-master 4a05e19 Object-Relational-Mapper for PHP
As far as I can tell, I'm doing everything right. Any help on what might be going wrong?

The problem turned out to be an incompatible version of PHP. I upgraded to the newest version and the problem went away.

Related

Persisting Doctrine Entity with Collection results in exception

Am working on a simple setup with two tables with a one to many (and inversed) relationship. The two corresponding entities are:
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass=ArticlesRepository::class)
* #ORM\Table(name="articles")
*/
class Article
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(name="unique_id", type="integer")
*/
protected int $idx;
/**
* The inverse side
* #ORM\OneToMany(targetEntity="Comment", mappedBy="article")
* #ORM\Column(name="uid", type="integer", nullable=true)
*/
protected $id;
public function __construct()
{
$this->id=new ArrayCollection();
}
}
and
use Doctrine\ORM\Mapping as ORM;
/**
* ORM\Entity(repositoryClass="CommentRepository::class")
* ORM\Table(name="comments")
*/
class Comment
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(name="uid", type="integer")
*/
protected $idx;
/**
* The owning side
* #ORM\ManyToOne(targetEntity="Article", inversedBy="uid")
* #ORM\JoinColumn(name="article", referencedColumnName="uid")
*/
protected $article;
protected $content;
}
Attempting to persist a new blank Article
$article=new Article();
$em->persist($article);
$em->flush();
results in the following exception
An exception occurred while executing 'INSERT INTO articles (uid) VALUES (?)' with params [{}]: PHP Warning: Object of class Doctrine\Common\Collections\ArrayCollection could not be converted to float in ...\vendor\doctrine\dbal\lib\Doctrine\DBAL\Driver\Mysqli\MysqliStatement.php line 164
I went searching for answers and came across suggestions close to but don't touch on this subject. One had to do with removing the type indication of the column. So I did and it gets stuck with the following exception
An exception occurred while executing 'INSERT INTO articles (uid) VALUES (?)' with params [{}]: Cannot add or update a child row: a foreign key constraint fails...
When type is removed, the field defaults to type string which makes no difference, since Doctrine still attempts to store an empty array in an integer field (see the values in the exception above).
Question: How can I get the setup to work properly and persist all objects correctly?
It turns out that the #ORM\OneToMany annotation in the Article entity should be used on a non-existent database field. In other words, property $id should not be an actual field in the database table of the entity.

The database schema is not in sync with the current mapping file (but it is !)

I just fixed some things in my code. I'm now trying to validate my schema
php bin/console doctrine:schema:validate
Doctrine tells me my mapping is correct but my database schema is not. So I'm doing a
schema:update --dump-sql
which results in the same ALTER again and again, that I already performed many times.
Here is the ALTER :
ALTER TABLE migration_versions CHANGE version version VARCHAR(14) NOT NULL;
I did it (with --force), the entity is reflecting the change already :
**
* MigrationVersions
*
* #ORM\Table(name="migration_versions")
* #ORM\Entity
*/
class MigrationVersions
{
/**
* #var string
*
* #ORM\Column(name="version", type="string", length=14, nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $version;
I am correct right ? its varchar, lenght 14...
And so is it in my database
I don't think Im making a mistake here but I may be missing something.
Have you already verified that the server_version in the doctrine config file is correct? (config/packages/doctrine.yaml in symfony5)
It happened to me that I was using MariaDB (version 10.4.11-MariaDB - Source distribution) and in the file doctrine.yaml the server_version parameter had the value 5.7.
After I corrected that, the error no longer occurred.
Also you can check this question

Must I sanitize my inputs when using setter methods to populate a Doctrine Entity?

I am under impression that ORM uses some kind of sanitation technique, but I am not sure. I looked at http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/security.html and was not clear on the issue.
Question
Will it be safe to use
$product = new Product();
$product->setModel($_POST['model']);
where POST is NOT sanitized previously, or must I always sanitize/validate my values first before sending them to Doctrine?
For reference
/**
* #Entity
*/
class Product
{
/**
* #var integer #Column(name="id", type="integer", nullable=false)
* #Id #GeneratedValue
*/
private $id;
/**
* #var string #Column(type="string")
*/
private $model;
}
You should always validate/sanitize user input. Even though Doctrine is using a prepared queries (which prevents SQL injections) you are not safe against other attacks.
Check this page, to see how to deal with inputs in Doctrine:
http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/security.html#user-input-and-doctrine-orm
Your are right, Doctrine ORM is doing all the sanitization automatically. Therefore, as long as you are using ORM, you are perfectly safe.
So in your example no additional sanitization is required.
I would only say that instead of using raw $_POST array you are supposed to use the Request object that is automatically injected in your controller:
$product = new Product();
$product->setModel($request->get('model'));

Symfony2 phpunit tests failed with the error invalid mapping file in orm.yml

I am new in an project and we want to resume the stand of working still yet.
I found testfiles in project. These were a good point for me to have an entry and find out the things.
So let before say, this is a Symfony 2.8 project which uses fosuserbundle.
Back to my matter: when I execute phpunit in terminal so I get MappingExceptions from doctrine:
PHPUnit 5.1.3 by Sebastian Bergmann and contributors.
WWWWWWWWWWWWWWWWWWWWWWWWWWEWWWWWWEWWWWWWWWWWWWWWWWWWW 53 / 53 (100%)
Time: 1.4 seconds, Memory: 36.50Mb
There were 2 errors:
1) ******\*****Bundle\Tests\Controller\******ControllerTest::testIndex
Doctrine\Common\Persistence\Mapping\MappingException: Invalid mapping file '******.UserBundle.Entity.User.orm.yml' for class '*******\UserBundle\Entity\User'.
/var/www/*****vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/MappingException.php:86
/var/www/********/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/FileDriver.php:117
/var/www/********/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php:56
/var/www/********/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/Driver/MappingDriverChain.php:102
/var/www/*******/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php:116
/var/www/*******/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/AbstractClassMetadataFactory.php:332
/var/www/*******/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/AbstractClassMetadataFactory.php:216
/var/www/********/vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php:265
/var/www/********/vendor/doctrine/orm/lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php:67
/var/www/********/vendor/doctrine/orm/lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php:50
/var/www/*******/vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php:665
/var/www/*******/vendor/friendsofsymfony/user-bundle/Doctrine/UserManager.php:40
It seems as something going wrong with User entity and related mapping file.
But these errors appear only when I execute phpunit. I deleted the user entity and orm file and run the commands generate entities and update schema. They work without any errors.
Here is the or.yml:
*****\UserBundle\Entity\User:
type: entity
table: fos_user
repositoryClass: ******\UserBundle\Entity\UserRepository
id:
id:
type: integer
id: true
generator:
strategy: AUTO
fields:
confirm:
type: bigint
and here the entity class which extends from fos superclass user
<?php
namespace *****\UserBundle\Entity;
use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
/**
*
*/
class User extends BaseUser
{
/**
* #var integer
*/
protected $confirm;
/**
* Set confirm
*
* #param integer $confirm
* #return User
*/
public function setConfirm($confirm)
{
$this->confirm = $confirm;
return $this;
}
/**
* Get confirm
*
* #return integer
*/
public function getConfirm()
{
return $this->confirm;
}
}
I am spending now the whole day with this issue but I can not figure out what is going wrong. It seems that for doctrine is the yml file invalid but why then it happens only with unittest?

Doctrine 2.0 vs 2.1 cascade remove OneToMany

Hello I have problem when trying to cascade remove entities in OneToMany relations.
After a few hours of debugging I tried to downgrade the doctrine from the latest 2.1.2 to 2.0.2 and It suddenly starts working.
Imagin two entities Company and Address in relation 1:N.
/**
* #Entity
*/
class Company extends Entity
{
/**
* #var integer
* #id #Column(type="integer")
* #generatedValue
*/
private $id;
/**
* #var Collection
* #OneToMany(targetEntity="Address",mappedBy="company", cascade={"persist","remove"})
*/
private $addresses;
}
/**
* #Entity
*/
class Address extends Entity
{
/**
* #var integer
* #id #Column(type="integer")
* #generatedValue
*/
private $id;
/**
* #var Company
* #ManyToOne(targetEntity="Company", inversedBy="addresses")
* #JoinColumn(name="company_id", referencedColumnName="id",nullable=false)
*/
private $company;
}
when I try to remove the entity Company, I would like the assigned addresses will be removed as well.
$em->remove($company);
$em->flush();
In doctrine 2.1.2 the deletion of addresses is not performed so the integrity constraint fails. In version 2.0.2 there it works perfectly. Wierd thing on it is, if I use EntityAudit extension https://github.com/simplethings/EntityAudit the LogRevisionListener is corretly versioning the addresses entities (set them revtype = DEL) in doctrine 2.1.2 (of course in 2.0.2 as well) but the UnitOfWork is not removing it.
Is there any difference how to handle cascade removing in 2.0.2 and in 2.1.2?
Thank you very much
Try using this on the addresses attribute of your Company Class
#OneToMany(targetEntity="Address",mappedBy="company",
cascade={"persist"}, orphanRemoval=true)
I had the same problem... Relations were added or updated, but not deleted, even if I had cascade: [persist, remove].
I found out that I didn't need the "remove" attribute in "cascade", but I had to add the orphanRemoval: true.
I was going crazy, you made my day!
I have met the same problem and i have solved him with that code :
$em->remove($object);
$em->flush();
$em->remove($user);
$em->flush();
Maybe you can use a findAll on your company for the addresses and remove this with a foreach like that :
// Return all the addresses of the company
$addresses = $em->getRepository(...)->findAllAddressesByCompany($company);
$em->remove($company);
foreach ($address in $addresses)
{
$em->remove($address);
}
That's not a very good method but for now, that's all I've found.