Doctrine Entity not being included inside the Doctrine Events callback - doctrine-orm

I have Entities with One-to-Many relationship
TransactionItem -- has many --> Payments
EDIT: included the mapping files
Payment.yml mapping file
Akademia\Institution\Sales\Domain\Model\Payment\Payment:
type: entity
table: payments
repositoryClass: Akademia\Institution\Sales\Infrastructure\Persistence\Doctrine\Payment\DoctrinePaymentRepository
id:
id:
type: string
length: 36
fields:
date:
type: datetime
amount:
type: decimal
precision: 11
scale: 2
manyToOne:
transactionItem:
targetEntity: Akademia\Institution\Sales\Domain\Model\TransactionItem
inversedBy: payments
joinColumn:
name: transaction_item_id
referencedColumnName: id
TransactionItem.yml mapping
Akademia\Institution\Sales\Domain\Model\TransactionItem:
type: entity
table: transaction_items
repositoryClass: Akademia\Institution\Sales\Infrastructure\Persistence\Doctrine\DoctrineTransactionItemRepository
id:
id:
type: string
length: 36
fields:
productId:
type: string
column: product_id
productType:
type: string
column: product_type
description:
type: string
quantity:
type: integer
price:
type: decimal
precision: 11
scale: 2
discount:
type: decimal
precision: 11
scale: 2
paid:
type: boolean
remarks:
type: string
nullable: true
manyToOne:
transaction:
targetEntity: Akademia\Institution\Sales\Domain\Model\Transaction
inversedBy: lineItems
joinColumn:
name: transaction_id
referencedColumnName: id
oneToMany:
payments:
targetEntity: Akademia\Institution\Sales\Domain\Model\Payment\Payment
mappedBy: transactionItem
cascade: ['persist']
fetch: EAGER
when Im calling
$transactionItem->pay($amount, $date);
$entityManager->persist($transactionItem);
$entityManager->flush();
TransactionItem.php
public function pay($amount, \DateTime $date = null)
{
$payment = new Payment(
Uuid::uuid4()->toString(),
$this,
$amount,
$date ?? new \DateTime());
$this->payments[] = $payment;
}
Im expecting that I can get the TransactionItem on doctrine callbacks here:
services.yml
services:
app.doctrine_event_listener:
class: AppBundle\Event\DomainEventListener
arguments: ["#app.domain_event_dispatcher"]
tags:
- { name: doctrine.event_listener, event: postPersist }
- { name: doctrine.event_listener, event: postUpdate }
- { name: doctrine.event_listener, event: postRemove }
- { name: doctrine.event_listener, event: postFlush }
app.domain_event_dispatcher:
class: AppBundle\Event\DefaultEventDispatcher
The listener:
class DomainEventListener
{
private $entities = array();
/** #var DomainEventDispatcher */
private $dispatcher;
public function __construct(DomainEventDispatcher $dispatcher)
{
$this->dispatcher = $dispatcher;
}
public function postPersist($event)
{
$this->keepAggregateRoots($event);
}
public function postUpdate($event)
{
$this->keepAggregateRoots($event);
}
public function postRemove($event)
{
$this->keepAggregateRoots($event);
}
public function postFlush($event)
{
/** #var AggregateRoot $entity */
VarDumper::dump($this->entities);die();
foreach ($this->entities as $entity) {
foreach ($entity->releaseEvents() as $anEvent) {
$this->dispatcher->dispatch($anEvent);
}
}
$this->entities = array();
}
private function keepAggregateRoots($event)
{
$entity = $event->getEntity();
if (!($entity instanceof AggregateRoot)) {
return;
}
$this->entities[] = $entity;
}
}
but when dumping the captured entities on the postFlush VarDumper::dump($this->entities);
Im just getting empty array result.
NOTE:
TransactionItem extends AggregateRoot but Payment does not
but at least Im expecting TransactionItem to be present.
Does just adding child relationships will not include it in the doctrine events?
How to manually tell doctrine that TransactionItem should be present in the postFlush event?
EDIT: Dumping inside postUpdate is not being called.
public function postUpdate($event)
{
$this->keepAggregateRoots($event);
VarDumper::dump('Inside postUpdate');
VarDumper::dump($this->entities);die();
}

Related

GraphQL save self relation in custom resolver in amplify

I have the following models:
type Field #model {
id: ID!
fieldID: ID #index(name: "byField", sortKeyFields: ["name"])
name: String!
type: String!
required: Boolean
fields: [Field] #hasMany(indexName: "byField", fields: ["id"])
}
type Mutation {
batchCreateField(fields: [BatchCreateField]): [Field]
}
input BatchCreateField {
id: ID
fieldID: ID
name: String!
type: String!
required: Boolean
fields: [BatchCreateField]
}
And wrote a custom resolver:
$util.log.info($util.toJson($context))
#set($isAuthorized = false)
#set( $createdAt = $util.time.nowISO8601() )
#set($fieldsArray = [])
#foreach($item in \${ctx.args.fields})
$util.qr($item.put("id", $util.defaultIfNullOrBlank($item.id, $util.autoId())))
$util.qr($item.put("createdAt", $util.defaultIfNull($item.createdAt, $createdAt)))
$util.qr($item.put("updatedAt", $util.defaultIfNull($item.updatedAt, $createdAt)))
$util.qr($item.put("__typename", "Field"))
$util.qr($fieldsArray.add($util.dynamodb.toMapValues($item)))
#end
## [End] Initialization default values. **
$util.toJson( {
"version": "2018-05-29",
"operation": "BatchPutItem",
"tables": {
"Field-INSERT_APIID-INSERT_PROJECT_ENV": $fieldsArray
}
} )
Saving in batch works fine, the self relation is not working. Is there any way i can save this self relation like below in a batch and the resolver autofilling the sub fields with the fieldID of the previously inserted field?
let fieldInput: CreateFieldInput = {
name: field.name,
type: field.type,
required: field.required,
fields: field.fields
};
batchFieldsInput.push(fieldInput)
API.graphql(graphqlOperation(batchCreateField, {fields: batchFieldsInput}))

AWS Amplify GraphQL Query For Null Connections

I have the following in my schema for my AWS Amplify project:
type DriveTime #model
#auth( rules: [
{allow: groups, groups: ["Admin", "Instructor"]},
{ allow: private, provider: iam }
]) {
id: ID!
start: AWSDateTime!
end: AWSDateTime!
openRegistration: AWSDateTime!
closeRegistration: AWSDateTime!
vehicle: Vehicle #connection(name: "VehicleDriveConnection")
instructor: Instructor #connection(name: "InstructorDriveConnection") #aws_cognito_user_pools #aws_iam
student: Student #connection(name: "StudentDriveConnection")
evaluation: DriveEvaluation #connection(name: "DriveEvaluationConnection")
}
I want to be able to list all drive times where the student connection is empty or null. I am able to get all driveTimes for a single student but not all driveTimes where there is no student.
Since I dont want students to be able to access drive times that are either not open for registration or already registered to another student I have added this to my schema:
type AvailableDriveTime {
id: ID!
start: AWSDateTime!
end: AWSDateTime!
openRegistration: AWSDateTime!
closeRegistration: AWSDateTime!
instructorFirstName: String!
instructorLastName: String!
}
type Query {
listAvailableDriveTimes(limit: Int, nextToken: String): AvailableDriveTimesConnection #function(name: "listAvailableDriveTimes-${env}") #aws_cognito_user_pools #aws_iam
}
And this is my current query in the Lambda resolver:
let currentDate = new Date();
const listDrives = `query ListDrives($limit: Int, $nextToken: String) {
listDriveTimes(limit: $limit, nextToken: $nextToken, filter: {and: {openRegistration: {le: "${currentDate.toISOString()}"}, closeRegistration: {ge: "${currentDate.toISOString()}"}}}) {
items {
id
start
end
openRegistration
closeRegistration
instructor {
firstName
lastName
}
student {
username
}
}
nextToken
}
}`
My current solution is sorting in the lambda resolver then returning the right data but it seems like there has to be a more efficient way.

mutation to create relations on AWS AppSync

I have been trying to run a mutation to create relations to two separate Types with not much success.
** SCHEMA **
(I have used "Create Resources" to create tables in DynamoDB)
type Comment {
eventId: ID!
commentId: String!
content: String
}
type CommentConnection {
items: [Comment]
nextToken: String
}
input CreateCommentInput {
eventId: ID!
commentId: String!
content: String
}
input CreateEventInput {
id: ID!
name: String
where: String
when: String
description: String
}
input DeleteCommentInput {
eventId: ID!
}
input DeleteEventInput {
id: ID!
}
type Event {
id: ID!
name: String
where: String
when: String
description: String
comments(limit: Int, nextToken: String): CommentConnection
}
type EventConnection {
items: [Event]
nextToken: String
}
type Mutation {
createEvent(input: CreateEventInput!): Event
updateEvent(input: UpdateEventInput!): Event
deleteEvent(input: DeleteEventInput!): Event
createComment(input: CreateCommentInput!): Comment
updateComment(input: UpdateCommentInput!): Comment
deleteComment(input: DeleteCommentInput!): Comment
commentOnEvent(input: commentOnEventInput!): Comment
}
type Query {
fetchEvent(id: ID!): Event
getEvent(id: ID!): Event
listEvents(first: Int, after: String): EventConnection
getComment(eventId: ID!): Comment
listComments(first: Int, after: String): CommentConnection
}
type Subscription {
onCreateEvent(
id: ID,
name: String,
where: String,
when: String,
description: String
): Event
#aws_subscribe(mutations: ["createEvent"])
onUpdateEvent(
id: ID,
name: String,
where: String,
when: String,
description: String
): Event
#aws_subscribe(mutations: ["updateEvent"])
onDeleteEvent(
id: ID,
name: String,
where: String,
when: String,
description: String
): Event
#aws_subscribe(mutations: ["deleteEvent"])
onCreateComment(eventId: ID, commentId: String, content: String): Comment
#aws_subscribe(mutations: ["createComment"])
onUpdateComment(eventId: ID, commentId: String, content: String): Comment
#aws_subscribe(mutations: ["updateComment"])
onDeleteComment(eventId: ID, commentId: String, content: String): Comment
#aws_subscribe(mutations: ["deleteComment"])
}
input UpdateCommentInput {
eventId: ID!
commentId: String
content: String
}
input UpdateEventInput {
id: ID!
name: String
where: String
when: String
description: String
}
input commentOnEventInput {
eventId: ID!
content: String
}
schema {
query: Query
mutation: Mutation
subscription: Subscription
}
** MUTATIONS **
mutation #1:
mutation {
createEvent(input: {
id: "id8888"
name: "some event"
where: "Tokyo"
when: "tomorrow"
description: "desc for event"
})
{
id
name
}
}
mutation #1 gives:
{
"data": {
"createEvent": {
"id": "id8888",
"name": "some event"
}
}
}
mutation #2:
mutation {
commentOnEvent(input : {
eventId: "id8888"
commentId: "id2222"
content: "some content"
})
{
commentId
content
}
}
mutation #2 gives:
{
"data": {
"commentOnEvent": null
}
}
In the React sample created by AWS AppSync creates commentId automatically but I can't recreate that in manually created schema and resource.
I would like to know how I can establish relations on separate types and query them. Has anybody successfully done this??
Starting from the console's “Create resources” functionality lets talk through how this works. Assume we have this schema.
type Comment {
eventId: ID!
commentId: String!
content: String
}
type CommentConnection {
items: [Comment]
nextToken: String
}
input CreateCommentInput {
eventId: ID!
commentId: String!
content: String
}
input CreateEventInput {
id: ID!
name: String
where: String
when: String
description: String
}
input DeleteCommentInput {
eventId: ID!
}
input DeleteEventInput {
id: ID!
}
type Event {
id: ID!
name: String
where: String
when: String
description: String
comments(limit: Int, nextToken: String): CommentConnection
}
type EventConnection {
items: [Event]
nextToken: String
}
type Mutation {
createEvent(input: CreateEventInput!): Event
updateEvent(input: UpdateEventInput!): Event
deleteEvent(input: DeleteEventInput!): Event
createComment(input: CreateCommentInput!): Comment
updateComment(input: UpdateCommentInput!): Comment
deleteComment(input: DeleteCommentInput!): Comment
}
type Query {
getEvent(id: ID!): Event
listEvents(first: Int, after: String): EventConnection
getComment(eventId: ID!): Comment
listComments(first: Int, after: String): CommentConnection
}
type Subscription {
onCreateEvent(
id: ID,
name: String,
where: String,
when: String,
description: String
): Event
#aws_subscribe(mutations: ["createEvent"])
onUpdateEvent(
id: ID,
name: String,
where: String,
when: String,
description: String
): Event
#aws_subscribe(mutations: ["updateEvent"])
onDeleteEvent(
id: ID,
name: String,
where: String,
when: String,
description: String
): Event
#aws_subscribe(mutations: ["deleteEvent"])
onCreateComment(eventId: ID, commentId: String, content: String): Comment
#aws_subscribe(mutations: ["createComment"])
onUpdateComment(eventId: ID, commentId: String, content: String): Comment
#aws_subscribe(mutations: ["updateComment"])
onDeleteComment(eventId: ID, commentId: String, content: String): Comment
#aws_subscribe(mutations: ["deleteComment"])
}
input UpdateCommentInput {
eventId: ID!
commentId: String
content: String
}
input UpdateEventInput {
id: ID!
name: String
where: String
when: String
description: String
}
schema {
query: Query
mutation: Mutation
subscription: Subscription
}
This is what the schema should look like after running Create Resources on the Event and Comment types. When going through the "Create Resources" flow with the Comment type you should choose the eventId as the table's hash key and the commentId as the sort key. For the Event type you can leave "id" as the single hash key. So what did that do for us?
First it created 2 DynamoDB tables to hold our objects of type Event and Comment. It then imported those tables as AppSync data sources and generated new schema parts including input objects, objects, and query and mutation fields and saved them to the schema. It also wired up resolvers specific to the new table you just defined and attached them to the newly generated query and mutation fields that implement common CRUD patterns. Unfortunately this does not yet understand relations so we have to add those ourselves. To do that let's first make the mutation to create relations as you have asked about and for completeness we will do a query as well.
As you have already done, you are going to need to add something like this to your schema
type Mutation {
commentOnEvent(input: CommentOnEventInput!): Comment
}
input CommentOnEventInput {
eventId: ID!
content: String
}
Save the schema and then click "Attach" on the Mutation.commentOnEvent field to add a resolver. Select the CommentTable data source we created earlier and from the mapping template put this:
{
"version" : "2017-02-28",
"operation" : "PutItem",
"key" : {
"eventId": $util.dynamodb.toDynamoDBJson($ctx.args.input.eventId),
"commentId": $util.dynamodb.toDynamoDBJson($util.autoId()),
},
"attributeValues" : $util.dynamodb.toMapValuesJson($ctx.args.input)
}
and for the response mapping template
$util.toJson($context.result)
Click save. Now you should be able to run a query like this:
mutation {
commentOnEvent(input: { eventId: "***", content: "A comment"}) {
eventId
content
}
}
Let's now add away to read data via a relation. E.G. I want to be able to run a query like this:
query {
getEvent(id: "***") {
id
comments(first: 5) {
items {
content
}
}
}
}
To do this lets first add the following parts to the schema.
type Event {
# add this to existing fields
comments(first: Int, after: String): CommentConnection
}
Click save then click "Attach" on the Event.comments field. Select the CommentTable data source again and then provide the following for the request mapping template.
# Event.comments.request.vtl
{
"version" : "2017-02-28",
"operation" : "Query",
"query" : {
"expression": "eventId = :eventId",
"expressionValues" : {
":eventId" : {
"S" : "${ctx.source.id}"
}
}
},
"limit": $util.defaultIfNull(${ctx.args.first}, 20),
"nextToken": $util.toJson($util.defaultIfNullOrBlank($ctx.args.after, null))
}
Notice the $ctx.source.id. Since we are resolving the Event.comments field, the $ctx.source is the instance of the Event type that we are resolving comments for. In effect this makes it so that anywhere we include { comments { ... } in a selection set on the Event type, only comments for the parent event will be fetched. And then you can return the paginated result object.
# Event.comments.response.vtl
# $ctx.result = { items: [...], nextToken: "..." }
$util.toJson($ctx.result)
This should do the trick. Now you can run both these queries and see the results.
mutation {
commentOnEvent(input: { eventId: "***", content: "A comment"}) {
eventId
content
}
}
query {
getEvent(id: "***") {
id
comments(first: 5) {
items {
content
}
}
}
}
Hope this helps.

Just the last one relationship in doctrine .orm file is working

I'm trying to make some relationships in Doctrine
LancamentoConf.orm.yml:
Amz\FinanceiroBundle\Entity\LancamentoConf:
type: entity
table: amz_financeiro_lancamento_conf
id:
id:
type: integer
generator: { strategy: AUTO }
fields:
active:
type: string
length: 1
...
manyToOne:
conta:
targetEntity: ContaConf
inversedBy: contajoinlancamentoconf
joinColumn:
name: amz_financeiro_conta_conf_id
referencedColumnName: id
manyToOne:
centrodecusto:
targetEntity: Amz\AmzBundle\Entity\CentroDeCustoConf
inversedBy: lancamentoconf
joinColumn:
name: amz_centro_de_custo_conf_id
referencedColumnName: id
ContaConf.orm.yml:
Amz\FinanceiroBundle\Entity\ContaConf:
type: entity
table: amz_financeiro_conta_conf
id:
id:
type: integer
generator: { strategy: AUTO }
fields:
active:
type: string
length: 1
...
oneToMany:
contajoinlancamentoconf:
targetEntity: LancamentoConf
mappedBy: lancamentoconf
But just "centrodecusto" relationship is working...
I noticed that just the last one relationship in LancamentoConf.orm.yml works. If I change the order ("centrodecusto" first and "conta" second), "centrodecusto" will work fine...
You're problem is duplicated manyToOne section, there should be only one definition and inside you could define several elements:
LancamentoConf.orm.yml:
Amz\FinanceiroBundle\Entity\LancamentoConf:
type: entity
table: amz_financeiro_lancamento_conf
id:
id:
type: integer
generator: { strategy: AUTO }
fields:
active:
type: string
length: 1
...
manyToOne:
conta:
targetEntity: ContaConf
inversedBy: contajoinlancamentoconf
joinColumn:
name: amz_financeiro_conta_conf_id
referencedColumnName: id
centrodecusto:
targetEntity: Amz\AmzBundle\Entity\CentroDeCustoConf
inversedBy: lancamentoconf
joinColumn:
name: amz_centro_de_custo_conf_id
referencedColumnName: id

Doctrine2 - relationship

I'm developing an application, which is looking for optimal route and timetable in public transport. I have some experience about Doctrine1, but it's my first time with Doctrine2. There is soem new fields to describe relations (mappedBy and inversedBy) and also some new ways of mapping.
I have following code:
$query = $this->em->createQuery("SELECT partial cls.{stop}, partial t.{arriveTime, departureTime} FROM \Entities\Timetable t
JOIN t.ride r
JOIN t.carrierLineStop cls
WHERE t.departureTime>=:time AND
r.idCarrierLine=:carrierLine AND
(cls.idStop=:firstStop OR cls.idStop=:lastStop)");
$query->setParameters(array(
'time' => $time,
'carrierLine' => $path->getLine(),
'firstStop' => $path->getFirstStop(),
'lastStop' => $path->getLastStop()
));
When I try to execute that script I've got an error:
[Semantical Error] line 0, col 24 near '}, partial t.{arriveTime,': Error: There is no mapped field named 'stop' on class Entities\CarrierLineStop.
Mapping files:
Entities\CarrierLineStop:
type: entity
table: carrier_line_stop
fields:
idCarrierLineStop:
id: true
type: integer
unsigned: false
nullable: false
column: id_carrier_line_stop
generator:
strategy: IDENTITY
nextStop:
type: integer
unsigned: false
nullable: true
column: next_stop
manyToOne:
idCarrierLine:
targetEntity: Entities\CarrierLine
cascade: { }
mappedBy: null
inversedBy: null
joinColumns:
id_carrier_line:
referencedColumnName: id_carrier_line
orphanRemoval: false
stop:
column: id_stop
targetEntity: Entities\Stop
cascade: { }
mappedBy: null
inversedBy: carrierLineStop
joinColumns:
id_stop:
referencedColumnName: id_stop
orphanRemoval: false
lifecycleCallbacks: { }
-
Entities\Stop:
type: entity
table: stop
fields:
idStop:
id: true
type: integer
unsigned: false
nullable: false
column: id_stop
generator:
strategy: IDENTITY
name:
type: string
length: 45
fixed: false
nullable: true
miejscowosc:
type: string
length: 45
fixed: false
nullable: true
latitude:
type: decimal
nullable: true
longitude:
type: decimal
nullable: true
oneToMany:
carrierLineStop:
targetEntity: Entities\CarrierLineStop
cascade: { }
mappedBy: stop
inversedBy: null
joinColumns:
id_stop:
referencedColumnName: id_stop
orphanRemoval: false
lifecycleCallbacks: { }
I have no idea about where the problem is...
I think that the keyword partial works only on entity fields (like idCarrierLineStop and nextStop), stop is a composite field.
If you want to leave the query like this you should delete the ManyToOne mapping and add a field mapping with id_stop or alternatively add a JOIN with the Stop entity in the query and return its id in place of cls.{stop}