Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
83.33% covered (warning)
83.33%
15 / 18
0.00% covered (danger)
0.00%
0 / 1
CRAP
0.00% covered (danger)
0.00%
0 / 1
WP_Post_Repository_Abstract
83.33% covered (warning)
83.33%
15 / 18
0.00% covered (danger)
0.00%
0 / 1
7.23
0.00% covered (danger)
0.00%
0 / 1
 update
83.33% covered (warning)
83.33%
15 / 18
0.00% covered (danger)
0.00%
0 / 1
7.23
1<?php
2/**
3 * Common documentation for repositories backed by WP_Post.
4 *
5 * And shared functions (mostly to convert WP_Error into an exception).
6 *
7 * @see WP_Post_Query_Abstract
8 *
9 * @package brianhenryie/bh-wp-bitcoin-gateway
10 */
11
12namespace BrianHenryIE\WP_Bitcoin_Gateway\API\Repositories;
13
14use BrianHenryIE\WP_Bitcoin_Gateway\API\Model\Wallet\Bitcoin_Address;
15use BrianHenryIE\WP_Bitcoin_Gateway\API\Model\Payments\Bitcoin_Transaction;
16use BrianHenryIE\WP_Bitcoin_Gateway\API\Model\Wallet\Bitcoin_Wallet;
17use BrianHenryIE\WP_Bitcoin_Gateway\API\Repositories\Queries\WP_Post_Query_Abstract;
18use RuntimeException;
19use WP_Error;
20
21/**
22 * PHP doesn't have generics to neatly require: (TODO: what is the PHPStan syntax for these generics)
23 *
24 * @method get_by_wp_post_id( int $post_id )
25 * @method get_all( $status ): array
26 *
27 * @phpstan-type WpUpdatePostArray array{ID?: int, post_author?: int, post_date?: string, post_date_gmt?: string, post_content?: string, post_content_filtered?: string, post_title?: string, post_excerpt?: string, meta_input?:array<string,mixed>}
28 */
29abstract class WP_Post_Repository_Abstract {
30
31    /**
32     * Run `wp_update_post()` (after setting the post id); throw on failure.
33     *
34     * TODO: This should return the object.
35     *
36     * @param Bitcoin_Wallet|Bitcoin_Address|Bitcoin_Transaction $model To get the ID to update.
37     * @param WP_Post_Query_Abstract                             $query A map from the model's properties to WP_Query arguments.
38     *
39     * @throws RuntimeException On `wp_update_post()` failure.
40     */
41    protected function update(
42        Bitcoin_Wallet|Bitcoin_Address|Bitcoin_Transaction $model,
43        WP_Post_Query_Abstract $query
44    ): void {
45
46        /** @var array<int|string,mixed> $existing_meta */
47        $existing_meta = get_post_meta( $model->get_post_id() );
48
49        /** @var WpUpdatePostArray $args */
50        $args       = $query->to_query_array();
51        $args['ID'] = $model->get_post_id();
52
53        $new_meta = $args['meta_input'] ?? array();
54
55        // Flatten the `get_post_meta()` result which treats all keys as not-single values.
56        $args['meta_input'] = array();
57        foreach ( $existing_meta as $key => $value ) {
58            if ( is_array( $value ) && count( $value ) === 1 && array_key_first( $value ) === 0 ) {
59                $args['meta_input'][ $key ] = $value[0];
60            } else {
61                $args['meta_input'][ $key ] = $value;
62            }
63        }
64        // Meta keys are string values; `array_merge()` re-indexes integer keys but that should be irrelevant here.
65        $args['meta_input'] = array_merge( $args['meta_input'], $new_meta );
66        if ( empty( $args['meta_input'] ) ) {
67            unset( $args['meta_input'] );
68        }
69
70        /** @var int|WP_Error $result */
71        $result = wp_update_post(
72            $args
73        );
74
75        if ( ! is_wp_error( $result ) ) {
76            return; // TODO: Should we return the refreshed object, `$this->get_by_wp_post_id( $result )`.
77        }
78
79        throw new RuntimeException( $result->get_error_message() );
80    }
81}