*/ public function for_document( int $document_id ): array { global $wpdb; $table = $this->table(); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- custom table, no object cache to read from. $rows = $wpdb->get_results( $wpdb->prepare( "SELECT entity_type, entity_id FROM %i WHERE document_id = %d ORDER BY id ASC", $table, $document_id ), ARRAY_A ); return array_map( static fn( array $row ): array => array( 'entity_type' => (string) $row['entity_type'], 'entity_id' => (int) $row['entity_id'], ), is_array( $rows ) ? $rows : array() ); } /** * The document ids linked to a record. * * @param string $entity_type Record type. * @param int $entity_id Record id. * * @return int[] */ public function for_record( string $entity_type, int $entity_id ): array { global $wpdb; $table = $this->table(); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- custom table, no object cache to read from. $ids = $wpdb->get_col( $wpdb->prepare( "SELECT document_id FROM %i WHERE entity_type = %s AND entity_id = %d ORDER BY id DESC", $table, $entity_type, $entity_id ) ); return array_map( 'intval', is_array( $ids ) ? $ids : array() ); } /** * Associate a document with a record. Idempotent — the UNIQUE key absorbs a repeat. * * @param int $document_id Document. * @param string $entity_type Record type. * @param int $entity_id Record id. */ public function link( int $document_id, string $entity_type, int $entity_id ): void { global $wpdb; $table = $this->table(); // INSERT IGNORE: a link that already exists is not an error, it is the desired state. // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- custom table, no object cache to read from. $wpdb->query( $wpdb->prepare( "INSERT IGNORE INTO %i (document_id, entity_type, entity_id, created_at, created_by) VALUES (%d, %s, %d, %s, %d)", $table, $document_id, $entity_type, $entity_id, current_time( 'mysql', true ), get_current_user_id() ) ); } /** * Remove one association. * * @param int $document_id Document. * @param string $entity_type Record type. * @param int $entity_id Record id. */ public function unlink( int $document_id, string $entity_type, int $entity_id ): void { global $wpdb; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- custom table, no object cache to read from. $wpdb->delete( $this->table(), array( 'document_id' => $document_id, 'entity_type' => $entity_type, 'entity_id' => $entity_id, ) ); } /** * Drop every link a document has — called when the document is purged. * * @param int $document_id Document. */ public function purge_for_document( int $document_id ): void { global $wpdb; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- custom table, no object cache to read from. $wpdb->delete( $this->table(), array( 'document_id' => $document_id ) ); } /** * Drop every link pointing at a record — called when that record is purged. * * The documents themselves are left alone: a document is first-class and may be linked to several * records, so one record's destruction is not the document's. * * @param string $entity_type Record type. * @param int $entity_id Record id. */ public function purge_for_record( string $entity_type, int $entity_id ): void { global $wpdb; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- custom table, no object cache to read from. $wpdb->delete( $this->table(), array( 'entity_type' => $entity_type, 'entity_id' => $entity_id, ) ); } }