Doctrine createQueryBuilder - How get data from foreign key - symfony

I have two database tables which were created with make:entity
participant (id, firstname, lastname, age, gender, school*, group*, ...)
school (id, name)
Participant has a field "school" which stores an id that is also a foreign key which points to an entry in school table.
In my frontend I want to show just a subset of the fields of the participant table.
An easy solution would be to skip the irrelevant fields, but the participant_table.twig template is used multiple times in my application.
There should be different views which show more or less participant data depending who's using the view.
This approach would lead to too much logic in the template in order control what's going to be shown/hidden.
So I need to build a custom query in the ParticipantRepository.php class which passes the data to the template.
Example:
$query = "participant.Firstname, participant.Lastname, participant.Age, participant.Gender ..."
And now the tricky part: how do I fetch the school's name by it's foreign key?
In the end I want to have an array with the following structure:
[
0 => [
"Firstname" => "Jon"
"Lastname" => "Doe"
"Age" => 6
"Gender" => "m"
"School" => "School X"
]
1 => [
"Firstname" => "Mike"
"Lastname" => "Doe"
"Age" => 10
"Gender" => "m"
"School" => "School Y"
]
...
]
Searched in Symfony, Docrtine docs, Stackoverflow..

You can achieve this by using a join in your custom query in the ParticipantRepository.php class. The join will allow you to fetch the school name from the school table based on the foreign key in the participant table. Here's an example:
$query = $this->createQueryBuilder('p')
->select('p.Firstname', 'p.Lastname', 'p.Age', 'p.Gender', 's.name as School')
->join('p.school', 's')
->getQuery();
$result = $query->getArrayResult();

Related

How search in repository by IDENTITY in Doctrine?

I have some table in Symfony app
id
user_id
test_id
type_id
points
I need search by different pairs: user_id and test_id, user_id and type_id, test_id and type_id.
I can write methods in repository, like this for all pairs:
$hints = $this->createQueryBuilder('points')
->andWhere('IDENTITY(points.user) = :user_id')
->andWhere('IDENTITY(points.test) = :test_id')
->setParameters([
'user_id' => $user->getId(),
'test_id' => $test->getId(),
])
->getQuery()
->getResult();
But I want not to add each time new function in repository for new combination and execute searching by standard methods like $repository->findBy(['IDENTITY(points.user)' => 1]) or $repository->matching($creteria).
But in this way I get error Unrecognized field: IDENTITY(points.user)
How search by standard functions with IDENTITY?
As Skyd said in comments it could be executed by $pointsRep->findBy(['user' => 1]); or by $pointsRep->findBy(['user' => $user]);

Database design to store values and arguments of functions

I'm facing the following problem, where I need to design a filter engine with nested conditional logic.
I'm representing the logic as a tree where each branch first value is "OR" or "AND"; the second value can either be
a name of a function
another branch with further conditional structure
For example:
$tree = [
'nodetype' => 'ruleset',
'conditional' => 'OR',
'children' => [
[
'nodetype' => 'method',
'methodName' => 'startsWith'
'arguments' => [
'startsWithThis' => 'john',
'subject' => 'john doe'
]
],
[
'nodetype' => 'ruleset'
'conditional' => 'AND',
'children' => [
...more nesting
]
]
]
];
This tree is then recursively evaluated using Symfony's Expression language component (I've registered custom expressions for methods like startsWith etc).
The issue is that methods will differ from one another in their number of arguments they accept and the order of those arguments. I'm not sure how to store this in a relational database, without serialising the whole tree to a json string; which I'd like to avoid.
What I came up with so far is the following database structure:
filters:
id
name
filter_arguments:
id
filter_id
name
filter_usecases:
id
filter_id
filter_usecase_values
id
filter_usecase_id
filter_argument_id
value
However this table design does not address the issue of storing the "OR" / "AND" nature of a branch; and it also cannot represent nested filters (e.g. parent-child relation of branches).
How do I go about this? Is there a specific term that describes what I'm trying to achieve here? I'd gladly read more about this but I don't even know what to google.
To take a quick stab at it, going just from the data:
node
id
nodetype
conditional
method_name
children
id
parent_node_id
child_node_id
arguments
id
node_id
key
value
Note that the relationships (children) and argument data are not in the node table, but rather are specified by cross reference tables you will have to join with when you retrieve nodes. I would expect that it is the "children" table which will become the central actor in your recursing the tree, while "node" and "arguments" will be the joined tables.
Please let us know the solution you end up using successfully.

DynamoDB - UpdateItem where X <= Y

I have a DynamoDb table defined with a composite key of
$response = $this->dynamoDb->createTable([
...
'KeySchema' => [
[
'AttributeName' => 'product_code',
'KeyType' => 'HASH'
],
[
'AttributeName' => 'token',
'KeyType' => 'RANGE'
]
]
...
]);
I want to be able to update all records where "product_code" = "X" and "created_at" <= "Y". I assume it must be possible but I am a bit stumped. The updateItem method requires the full key but I want a conditional update without specifying a key. My latest stub reads as
$response = $this->dynamoDb->updateItem([
'TableName' => 'products',
'ExpressionAttributeValues' => [
':val1' => ['N' => (string)$this->input['product_code']]
':val2' => ['N' => (string)$this->product['created_at']['N']],
':val3' => ['N' => (string)strtotime("now")],
],
'ConditionExpression' => 'product_code = :val1 AND processed_at <= :val2',
'UpdateExpression' => 'set processed_at = :val3'
]);
But the generated error message reads as follows:
[Key] is missing and is a required parameter
Which command should I be using? Any help building my query is greatly appreciated.
The following is taken from AWS DynamoDB API reference for UpdateItem:
For the primary key, you must provide all of the attributes. For example, with a simple primary key, you only need to provide a value for the partition key. For a composite primary key, you must provide values for both the partition key and the sort key.
In your code (the update item part) you provide only hash key (product_code). You have to provide the range key (token) as well in your ConditionExpression property, because you defined a composite key.
EDIT:
(regarding the comment)
The following describes the parameters for UpdateItem:
Request Parameters
...
Key
The primary key of the item to be updated. Each element consists of an
attribute name and a value for that attribute.
For the primary key, you must provide all of the attributes. For
example, with a simple primary key, you only need to provide a value
for the partition key. For a composite primary key, you must provide
values for both the partition key and the sort key.
Type: String to AttributeValue object map
Required: Yes
...
As you can see, the primary key is required for an UpdateItem operation.
So you cannot use a secondary index to point UpdateItem to a collection of items to update.
However, you can query the table by a secondary index, and collect the primary keys of the resulted items, say in an array keysToUpdate.
Then you can update the desired items, whose keys are in keyToUpdate.

How to query all related items in a many to many relationship using Pods API?

I have two Pods:
course
participant
The pod course has a PICK field to the pod participant. The field is a multiple relationship field. So, each course item has multiple participants.
I want to find all the course items where a certain participant is related.
So, I guess a SQL query such as the following would do what I want:
SELECT DISTINCT `t`.* FROM `wp_pods_course` AS `t` WHERE t.id IN
(SELECT DISTINCT r.item_id FROM wp_podsrel AS r WHERE r.related_item_id = '42')
42 is the id of a participant.
I am trying to figure out how to write such a SQL query using Pods API:
$pod = pods('course');
$participant_id = $participant->field('id');
$params['where'] = "t.id in (SELECT r.id FROM ??? WHERE ???)";
$pod->find($params);
Is this the correct way to write such a query?
You're overcomplicating things, Pods does all of the joins for you automatically with one of it's most powerful features, field traversal.
Try this:
$pod = pods( 'course' );
// I use ->id() because it's always the right ID field, no matter what pod type
$participant_id = $participant->id();
$params = array(
'where' => 'participants.id = ' . (int) $participant_id
);
$pod->find( $params );
Where particpants is your relationship field name, id is the field id on that related object.

Symfony - Get Entity Repository with multiple ID's

I have an entity that has multiple keys, how would I go about finding the proper object based on multiple ids?
$product = $em->getRepository('AcmeStoreBundle:Product')->find($id);
It's a little confusing what you're asking here. It sounds as though you have an entity with a compound key (primary key relates to multiple columns) and want to find it based on it's primary key values, yes?
If so, the find method will require an array containing values for each of the fields that make up the key:
$product = $em->getRepository('AcmeStoreBundle:Product')->find(array(
'key1' => 'value1',
'key2' => 'value2'
));
Alternatively, you could use findOneBy method. This would be useful for when the combination of the provided fields are not unique as you're able to provide a second argument to define the ordering.
$product = $em->getRepository('AcmeStoreBundle:Product')->findOneBy(array(
'key1' => 'value1',
'key2' => 'value2'
), array('updated_at' => 'DESC'));
See http://symfony.com/doc/2.0/book/doctrine.html#fetching-objects-from-the-database
$product = $em->getRepository('AcmeStoreBundle:Product')->findBy(
array('key1' => 'value1', 'key2'=>'value2')
);

Resources