db->prepare( 'SELECT * FROM %i WHERE `id` = %d LIMIT 1', $this->table( 'payments' ), $id ); $row = $this->db->get_row( $sql, ARRAY_A ); return is_array( $row ) ? $this->hydrate( $row ) : null; } /** * Find by uuid. * * {@inheritDoc} * * @param Uuid $uuid Parameter. * @since 0.1.0 */ public function find_by_uuid( Uuid $uuid ): ?Payment { $sql = $this->db->prepare( 'SELECT * FROM %i WHERE `uuid` = %s LIMIT 1', $this->table( 'payments' ), $uuid->to_string() ); $row = $this->db->get_row( $sql, ARRAY_A ); return is_array( $row ) ? $this->hydrate( $row ) : null; } /** * Find by idempotency key. * * {@inheritDoc} * * @param string $key Parameter. * @since 0.1.0 */ public function find_by_idempotency_key( string $key ): ?Payment { $sql = $this->db->prepare( 'SELECT * FROM %i WHERE `idempotency_key` = %s LIMIT 1', $this->table( 'payments' ), $key ); $row = $this->db->get_row( $sql, ARRAY_A ); return is_array( $row ) ? $this->hydrate( $row ) : null; } /** * {@inheritDoc} * * @param string $gateway Parameter. * @param string $gateway_payment_id Parameter. */ public function find_by_gateway_payment_id( string $gateway, string $gateway_payment_id ): ?Payment { $sql = $this->db->prepare( 'SELECT * FROM %i WHERE `gateway` = %s AND `gateway_payment_id` = %s LIMIT 1', $this->table( 'payments' ), $gateway, $gateway_payment_id ); $row = $this->db->get_row( $sql, ARRAY_A ); return is_array( $row ) ? $this->hydrate( $row ) : null; } /** * {@inheritDoc} * * @param \DateTimeImmutable $before Parameter. * @param int $limit Parameter. */ public function find_stale_processing( \DateTimeImmutable $before, int $limit ): array { $sql = $this->db->prepare( 'SELECT * FROM %i WHERE `status` = %s AND `updated_at` < %s ORDER BY `updated_at` ASC LIMIT %d', $this->table( 'payments' ), PaymentStatus::Processing->value, $this->format_datetime( $before ), max( 1, $limit ) ); $rows = $this->db->get_results( $sql, ARRAY_A ); if ( ! is_array( $rows ) ) { return []; } $out = []; foreach ( $rows as $row ) { if ( is_array( $row ) ) { $out[] = $this->hydrate( $row ); } } return $out; } /** * {@inheritDoc} * * @param int $booking_id Parameter. * @param int|null $order_id Parameter. * @return list */ public function find_for_booking( int $booking_id, ?int $order_id ): array { if ( $booking_id < 1 ) { return []; } if ( null === $order_id || $order_id < 1 ) { $sql = $this->db->prepare( 'SELECT * FROM %i WHERE `booking_id` = %d ORDER BY `id` ASC', $this->table( 'payments' ), $booking_id ); } else { $sql = $this->db->prepare( 'SELECT * FROM %i WHERE `booking_id` = %d OR `order_id` = %d ORDER BY `id` ASC', $this->table( 'payments' ), $booking_id, $order_id ); } $rows = $this->db->get_results( $sql, ARRAY_A ); if ( ! is_array( $rows ) ) { return []; } $out = []; $seen = []; foreach ( $rows as $row ) { if ( ! is_array( $row ) ) { continue; } $payment = $this->hydrate( $row ); $id = $payment->id(); if ( null === $id || isset( $seen[ $id ] ) ) { continue; } $seen[ $id ] = true; $out[] = $payment; } return $out; } /** * Save. * * {@inheritDoc} * * @param Payment $payment Parameter. * @since 0.1.0 */ public function save( Payment $payment ): void { $data = [ 'uuid' => $payment->uuid()->to_string(), 'order_id' => $payment->order_id(), 'booking_id' => $payment->booking_id(), 'gateway' => $payment->gateway(), 'gateway_payment_id' => $payment->gateway_payment_id(), 'gateway_customer_id' => $payment->gateway_customer_id(), 'type' => $payment->type()->value, 'status' => $payment->status()->value, 'amount_minor' => $payment->amount()->amount_minor(), 'currency' => $payment->amount()->currency(), 'refunded_minor' => $payment->refunded()->amount_minor(), 'idempotency_key' => $payment->idempotency_key(), 'failure_code' => $payment->failure_code(), 'failure_message' => $payment->failure_message(), 'meta' => $this->encode_meta( $payment->meta() ), 'created_at' => $this->format_datetime( $payment->created_at() ), 'updated_at' => $this->format_datetime( $payment->updated_at() ), ]; if ( null === $payment->id() ) { $this->db->insert( $this->table( 'payments' ), $data ); $payment->assign_id( $this->last_insert_id() ); return; } $this->db->update( $this->table( 'payments' ), $data, [ 'id' => $payment->id() ] ); } /** * Map a database row to an entity. * * @param array $row Database row. */ private function hydrate( array $row ): Payment { $currency = (string) $row['currency']; return new Payment( (int) $row['id'], new Uuid( (string) $row['uuid'] ), (int) $row['order_id'], null !== $row['booking_id'] ? (int) $row['booking_id'] : null, (string) $row['gateway'], null !== $row['gateway_payment_id'] ? (string) $row['gateway_payment_id'] : null, null !== $row['gateway_customer_id'] ? (string) $row['gateway_customer_id'] : null, PaymentType::from( (string) $row['type'] ), PaymentStatus::from( (string) $row['status'] ), new Money( (int) $row['amount_minor'], $currency ), new Money( (int) $row['refunded_minor'], $currency ), null !== $row['idempotency_key'] ? (string) $row['idempotency_key'] : null, null !== $row['failure_code'] ? (string) $row['failure_code'] : null, null !== $row['failure_message'] ? (string) $row['failure_message'] : null, $this->decode_meta( isset( $row['meta'] ) ? (string) $row['meta'] : null ), $this->parse_datetime( (string) $row['created_at'] ), $this->parse_datetime( (string) $row['updated_at'] ), ); } }