API-Platform 2.6 when doing GET request with UUID it convert to binary in the Doctrine Query - symfony

I am using API-Platform 2.6 and I have an entity declared like this:
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: MyEntityRepository::class)]
class MyEntity {
#[ORM\Id]
#[ORM\Column(type: 'uuid', unique: true)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')]
private ?Uuid $id = null;
}
But when I try to fetch an entity using the UUID from the DB I get a 404 error.
In my DB, the entity table, has the UUID saved normally like that: 24306098-7e56-1ed9-8f48-db0c83a39071
Then when I try to fetch this using the url: http://my-local-server/api/my-entity/24306098-7e56-1ed9-8f48-db0c83a39071 I get the 404.
Finally, when I open the profiler, and checking the SQL Query I get this:
Just to let you know, I've tried lot's of different solutions I found on the internet, but none of them worked for me.
Any idea why I have this error or how can I solve this issue? Thank you in advance.

Finally found the solution.
The problem wasn't either the Symfony nore the API-Platform.
The issue was the PHP Storm itself. I place my answer here for other developers may using PHP Storm and have the same troubles as me.
When I listed the entity records inside the PHP Storm, the PHP Storm had activated the UUID Column formatter to be "UUID with time-low and time-high swapped" which made the UUIDs looks good but wasn't the original ones need it for the GET Operations in the Rest API.
By mistake I found that I can change the format in the table by using the context menu like that:
Thank you all for the time you took review my issue.

Related

PHP 7 and Doctrine Group Uses

I want to use some features of PHP 7 but I'm kinda struggling with it.
I have a Symfony-Project using Doctrine to map some Entities. New in PHP 7 are the GROUP USE-Statemens, which I wanted to try. But it seems I'm doing something wrong, since Symfony / Doctrine can't resolve the Annotations in the Entity-Object.
Use-Statement:
use Doctrine\ORM\Mapping\{Entity, Id, Table, Column, GeneratedValue, JoinColumn, OneToOne, ManyToMany, JoinTable};
Entity
/**
* #Entity
* #Table(name="expansion")
*/
class Expansion {
..
}
Exception
[Semantical Error] The annotation "#Entity" in class AppBundle\Entity\Expansion was never imported. Did you maybe forget to add a "use" statement for this annotation?
If I use the single USE-Statements, the import works perfectly...
What am I doing wrong? Versions are correct. Also PHPStorm is saying that 'Alias XY' is never used.
Thanks for your support!
I'm not 100% sure but I bet that the Doctrine\Common\Annotations component cannot handle PHP7 grouped use statements yet. I could not find any written statement that confirms this assumption but Doctrine\Common\Annotations\TokenParser::parseUseStatement does not seem to handle grouped namespaces at all.

Doctrine lifecycleCallbacks strange behaviour

I have defined lifecycleCallbacks in yaml as follows:
lifecycleCallbacks:
prePersist: [setCreatedAtValue]
preUpdate: [setUpdatedAtValue]
The above has generated entities with the respective functions as follows:
/**
* #ORM\PrePersist
*/
public function setCreatedAtValue()
{
if($this->created_at == null)
{
$this->created_at = new \DateTime();
}
}
Which looks all fine, right? However, when I try to open the sonata admin page, I get the following error
[Semantical Error] The annotation "#ORM\PrePersist" in method AppBundle\Entity\Article::setCreatedAtValue() was never imported. Did you maybe forget to add a "use" statement for this annotation?
I have never encountered this before and a bit confused about what to do. I am using symfony 2.7.6, Doctrine ORM version 2.5.1, Sonata Admin 2.3.7
Any help will be greatly appreciated
Since you defined your callbacks using yaml, you donĀ“t need to define them again using annotations. Just remove the comments with the #ORM\PrePersist block before the function and everything will be fine.
If you wanted to use annotations to define your doctrine properties, you would need to import them before you can use them. To do so you would need to add this line at the beginning of your file:
use Doctrine\ORM\Mapping as ORM;
Same issue came with me.
In my case everything worked well until I did not Serialize my object in JsonResponse.
So problem was that previously I was not using that entity class (which was giving error) for sending JsonResponse, as soon as I tried to prepare JsonResponse containing that class, JsonResponse failed to serialize my class as it hadn't implemented Serializable interface.
This will happen if you will fetch objects with methods like findAll or findBy which returns Entity objects instead of php array.
So I just skipped those native methods and write doctrine query for fetching data.
You can also implement Serializable interface.

Related Entities and their Repository - selectively loading entities

I have a few entities that have a few associations. They are loading up fine now. So I basically have a customer entity, that relates to an address entity. I also have a receipt transaction that relates to a customer.
When I retrieve a small set of customers I want to retrieve their related receipts but that set is huge. I want just the receipts from the last 2 weeks.
I thought that I could use a custom repository then use a function like customer->getRecentReceipts() but that doesn't work since the customer entity doesn't know about the repository. And from reading on this forum, people seem to say not to use the repository this way. How should I structure things to limit the loading of my receipt entities. I'm trying to avoid loading all then sorting them with a php routine.
i think you forgot to link your repository at the entity.
Exemple:
// src/AppBundle/Entity/Product.php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="AppBundle\Entity\ProductRepository")
*/
class Product
{
//...
}
that's when you can use your repository functions
There's nothing wrong with making a repository method to do this. You don't have to deal directly with the customer entity to get its receipts.
I'd just create a simple method in ReceiptRepository like (Syntax might be not quite right, I don't have an IDE handy right now)
getReceiptsForCustomerByDate(Customer $customer, \DateTime $createdAfter=null) {
if (!$createdAfter instanceof \DateTime) {
$createdAfter = new \DateTime('now -2 weeks');
}
$qb = $this->getEntityManager()->createQueryBuilder();
return $qb->select('c, r')
->from('YourBundle:Customer', 'c')
->join('c.receipt', 'r')
->where($qb->expr()->eq('c', ':customer')
->andWhere($qb->expr()->gt('r.createdAt', ':createdAfter')
->setParameter('createdAfter', $createdAfter)
->setParameter('customer', $customer)
->getQuery()->getResult();
}
The above means your fetched customer entities will only have the relevant receipts. Because we haven't lazy loaded the receipts, $customer->getReceipts() will only return the receipts we have specified by date.
No, you can't call this from your Customer entity, but there's no reason you can't call it in a controller method. This is a perfectly valid way to get things done in Symfony.
You could easily modify this to get many customer receipts by passing an array of customers.

With Symfony 2.2 and Doctrine 2.2.* I can't save manyToMany relations with cascade: persist

I try to use Doctrine casecade feature tu automagicaly save relations between two entities, and it does'nt seem to work.
I've made a demo here : https://github.com/asakurayoh/demo_bug_doctrine
So I use the doctrine fixture to make my demo.
you need to create de database (app/console doctrine:database:create), migrate the tables (app/console doctrine:migrations:migrate) and then, load the fixtures (app/console doctrine:fixtures:load). The third fixture (src/Demo/MyBundle/DataFixtures/ORM/TagsNewsFixtures.php) is adding all tags entities to all the news. And if you go to the database, you will see that no relation was save in the news_tag table... I think my relation are well defined in my mapping (Resources/config/doctrine/News.orm.yml and Tag.orm.yml) and the cascade property is set.
Someone can find the problem with this code? I search everywhere (stackoverflow too) and I've done everythings everyone said... it should work...
Thanks to save my life (and my entities relations, ha!)
AsakuraYoh
The problem is in fixtures loading order - TagNewsFixtures is loaded first, therefore no tag nor news are in database at that time. Try forcing load order using ordere
namespace Acme\HelloBundle\DataFixtures\ORM;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Common\Persistence\ObjectManager;
class LoadData extends AbstractFixture implements OrderedFixtureInterface
{
public function load(ObjectManager $manager)
{
// ...
}
public function getOrder()
{
return 1; // the order in which fixtures will be loaded
}
}
I found the problem.
The "joinTable" preperty need to be on the News side and news use the "inversedBy" property, no the MappedBy (that's the tag). So it work. And to add news to a tag (do the inverse, then), we need to specify in the Tag entity to add the tag to the news... I don't understand why Doctrine doesn't do that by default... weird...

Doctrine and Symfony: magic methods and caching

I'm currently implementing the doctrine result cache so I've set
result_cache_driver: apc
into my configuration.
Then I've correctly got query cache working inside the Repository, using for example
->setResultCacheId(sprintf('posts_for_user_%d', $userId))
First problem come when I used these things in doctrine:
$repository->findOneBy(array)
$repository->findBy(array)
which can maybe easily overridden in the repository.
The problem which I can't get past is to use the ParamConverter to use doctrine caching and also entities association.
For example, if I have a Team entity with a OneToMany relation to Player I usually do
$team->getPlayers()
I don't have the control over the caching of that query. Is that possible in some way?
When you run methods like find/findBy or process over PersistentCollection doing $team->getPlayers(), there is UoW which loads the data using EntityPersister and ObjectHydrator to hydrate an object. These objects have no support of result cache driver.
In the other hand, when you use DQL or QueryBuilder, your code products Query object that extends AbstractQuery. If you look inside AbstractQuery::execute you will see this pretty piece of code which makes using of result cache driver possible
$cache = $queryCacheProfile->getResultCacheDriver();
$result = $cache->fetch($cacheKey);
if (isset($result[$realCacheKey])) {
return $result[$realCacheKey];
}
So my suggestion - try load your entities using QueryBuilder and leftJoins on children Collections.
$this->createQueryBuilder('x')->select('x, p')->leftJoin('x.players', 'p')->....;
It'll create the possibility of using result cache driver.

Resources