No value(s) from doctrine query - symfony

I am not retrieving any values with a simple Doctrine PHPCR query I am executing.
In this piece of code I get all the values from field 'name':
public function getPagesAction()
{
$dm = $this->get('doctrine_phpcr.odm.default_document_manager');
$qb = $dm->createQueryBuilder();
$qb->from()->document('Foo\BarBundle\Document\StandardPage', 'p');
return $this->render(
'FooBarBundle:Toolbar:navigation.html.twig',
array('names' => $qb->getQuery()->execute())
);
}
output: home, mypage, testpage, foo
And with this code I get nothing in return:
public function getPagesAction()
{
$dm = $this->get('doctrine_phpcr.odm.default_document_manager');
$qb = $dm->createQueryBuilder();
$qb->from()->document('Foo\BarBundle\Document\StandardPage', 'p');
$qb->where()->like()->field('p.name')->literal('mypage');
return $this->render(
'FooBarBundle:Toolbar:navigation.html.twig',
array('names' => $qb->getQuery()->execute())
);
}
I am also not receiving any errors. My HTML is plain empty. The query does work when I replace 'p.name' with 'p.title'.
Here is my StandardPage.php on Gist

Related

How to configure the Symfony serializer to link relational fields when deserialising?

Objective:
I'm importing a bunch of JSON files data into the database. Keeping the id fields the same as in the json files and link the relational id's to existing rows.
Problem:
When deserialising relational fields, the serialiser is inserting new empty records rather than linking them to existing rows.
Context:
I'm deserialising the files into respective entity objects.
Let's focus on one called Region.json which has an entity called Region and has a ManyToOne relation to Country.
Here is a snippet from Region.json the fields are the same as the entity properties.
[
{
"id": 1,
"name": "Aera",
"code": AR",
"country": 1, // relational field
"isActive": true,
},
{
"id": 2,
"name": "Mauw",
"code": "MW",
"country": 8, // relational field
"isActive": true,
}
]
The deserialisation process is as follows:
public function getDeserializeData(): mixed
{
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
$normalizers = [new ObjectNormalizer( classMetadataFactory: $classMetadataFactory,propertyTypeExtractor: new ReflectionExtractor()), new GetSetMethodNormalizer(), new ArrayDenormalizer()];
$encoders = [new JsonEncoder(), new XmlEncoder(), new CsvEncoder()];
$serializer = new Serializer(
normalizers: $normalizers,
encoders: $encoders
);
return $serializer->deserialize(
$this->staticDataFile->getContents(),
$this->getEntityNamespace() . '[]',
$this->staticDataFile->getExtension()
);
}
I'm using the ReflectionExtractor because are you can see the json data files have pre-defined ids and this can not be changed.
If I try to change the generated value strategy from 'IDENTITY' to 'NONE' I get the following error:
Entity of type App\Entity\Country is missing an assigned ID for field 'id'. The identifier generation strategy for this
entity requires the ID field to be populated before EntityManager#persist() is called. If you want automatically genera
ted identifiers instead you need to adjust the metadata mapping accordingly.
You will likely need a custom (De-)Normalizer for this, designed for each specific entity, e.g. for Region. Then you know, which fields contain associated data like country and how to search for that data. Your normalizer will take the id from the input, get the country from the database and add it in place of the number. It could look roughly like this:
class RegionDenormalizer implements DenormalizerInterface
{
public function __construct(
private CountryRepository $countryRepository,
) {}
public functionsupportsDenormalization(mixed $data, string $type, string $format = null /* , array $context = [] */)
{
return $type === Region::class;
}
public function denormalize(mixed $data, string $type, string $format = null, array $context = [])
{
$country = $this->countryRepository->find($data[’country’];
if (!$country instanceof Country)
{
// throw an Exception probably
}
$region = $context[AbstractNormalizer::OBJECT_TO_POPULATE];
$region->setCountry($country);
// Probably also set the other fields
}
}
You can also use $context to prevent your Denormalizer from being called twice, replace the id with the country in data and then use the original ObjectNormalizer. This is a bit more complicated, but I prefer this:
class RegionDenormalizer implements DenormalizerInterface, DenormalizerAwareInterface
{
use DenormalizerAwareTrait;
public function __construct(
private CountryRepository $countryRepository,
) {}
public functionsupportsDenormalization(mixed $data, string $type, string $format = null /* , array $context = [] */)
{
return $type === Region::class
&& !in_array($data[‘id’], $context[‘visited_regions’] ?? []);
}
public function denormalize(mixed $data, string $type, string $format = null, array $context = [])
{
$innerContext = $context;
$innerContext[‘visited_regions’][] = $data[‘id’];
$country = $this->countryRepository->find($data[’country’];
if (!$country instanceof Country)
{
// throw an Exception probably
}
$innerContext = $context;
// By setting this inner context, we prevent this listener from being called again for this region
$innerContext[‘visited_regions’][] = $data[‘id’];
// By replacing the country in data, we now have the expected country instead of the id or a new entity
$data[‘country’] = $country;
return $this->denormalizer->denormalize($data, $type, $innerContext);
}
}
I prefer this, because I don’t have to care about how to deserialize the region itself, only about replacing the country-id with the actual instance, but handling the context is more difficult.
Note: the single quotes in the code samples are wrong, because I am typing this on an iPad. You will have to replace them.

Or on symfony findOneBy

Is possible to make a request by one filed or another using the orm on symfony
$user_test = $em->getRepository("AppBundle:UserTest")->findOneBy([
'hash' => $data->user_data->hash,
'code' => $data->user_data->hash],
);
to get something like WHERE hash = 'foo' OR code = 'foo'
you have to define the method in the entity UserTest repository
// UserTestRepository.php
public function getUserTestByHashOrCode($hash, $code){
return $this->createQueryBuilder('u')
->where('hash = :hash')
->orWhere('code = :code')
->setParameter('hash', $hash)
->setParameter('code', $code)
->getQuery()
->getOneOrNullResult();
and then
$user_test = $em->getRepository("AppBundle:UserTest")->getUserTestByHashOrCode($data->user_data->hash, $data->user_data->hash);

Magento 2 get product collection by price range

How can I create a production collection based on pricerange in Magento 2.
This is what i have so far:
<?php namespace Qxs\Related\Block;
class Related extends \Magento\Framework\View\Element\Template
{
protected $_productCollectionFactory;
public function __construct(
\Magento\Backend\Block\Template\Context $context,
\Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $productCollectionFactory,
\Magento\Catalog\Model\Product\Attribute\Source\Status $productStatus,
\Magento\Catalog\Model\Product\Visibility $productVisibility,
array $data = []
)
{
$this->_productCollectionFactory = $productCollectionFactory;
$this->productStatus = $productStatus;
$this->productVisibility = $productVisibility;
parent::__construct($context, $data);
}
public function getProductCollection()
{
//var_dump($this->currentProduct());
$collection = $this->_productCollectionFactory->create();
$collection->addAttributeToSelect('*')
->addAttributeToFilter('special_price', ['from' => 0, 'to' => 1000])
->addAttributeToFilter('status', ['in' => $this->productStatus->getVisibleStatusIds()])
->setVisibility($this->productVisibility->getVisibleInSiteIds())
->setPageSize(5);
return $collection;
}
public function currentProduct()
{
return $this->_coreRegistry->registry('product');
}
}
?>
However, the code does not return a result including a price range. The result is totally empty but should return some products, how can I filter on price-range?
Thanks,
Range filters, to me work in this way, with addFieldToFilter. Have you tried it?
$orders = $this->_orderCollectionFactory->create()
->addAttributeToSelect('*')
->addFieldToFilter( 'created_at' , array('from' => $dateFrom, 'to' => $dateTo) )
->setOrder('created_at', 'desc' );
->setPageSize(200);

How to sum the contents of a document field with symfony query builder?

I am just trying to get the total value of one of the fields of my documents but it's not working. What am I missing?
#ProductRepository
public function countTotalValue()
{
return $this->createQueryBuilder('a')
->select('SUM(a.price)')
->getQuery()
->getSingleScalarResult()
;
}
I discovered it!
public function countTotalValue()
{
$array = $this->createQueryBuilder()
->select('price')
->hydrate(false)
->getQuery()
->execute()
->toArray()
;
$array = array_column($array, 'price');
return (array_sum($array));
}
It was returning a complex array, I had to stripe it before make the sum.

Doctrine 2: Separate chain calls in QueryBuilder

What is the approach to separate the querybuilder if I have some condition that I want to check.
What I want to get is something like this:
public function getProfilePhotoByUserId($userId, $checkApproved = false)
{
$profile = $this->createQueryBuilder('p')
->where('p.user = :userId')
->andWhere('p.profile = 1')
->setParameter('userId', $userId);
if($checkApproved) $profile->andWhere('p.approved = 1');
$profile->getQuery();
return $profile->getOneOrNullResult(Query::HYDRATE_ARRAY);
}
However this shows error on getOneOrNullResult:
"Method not found in querybuilder"
getQuery() return a Doctrine\ORM\Query object.
$query = $profile->getQuery();
return query->getOneOrNullResult(Query::HYDRATE_ARRAY);
or
return $profile->getQuery()->getOneOrNullResult(Query::HYDRATE_ARRAY);

Resources