Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 70
0.00% covered (danger)
0.00%
0 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
CampaignLog
0.00% covered (danger)
0.00%
0 / 70
0.00% covered (danger)
0.00%
0 / 2
702
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 29
0.00% covered (danger)
0.00%
0 / 1
42
 changes
0.00% covered (danger)
0.00%
0 / 41
0.00% covered (danger)
0.00%
0 / 1
420
1<?php
2
3class CampaignLog {
4    /** @var string[] */
5    private static $basic_fields = [
6        'start', 'end', 'enabled', 'preferred', 'locked', 'geo', 'buckets'
7    ];
8    /** @var string[] */
9    private static $list_fields = [ 'projects', 'languages', 'countries', 'regions' ];
10    /** @var string[] */
11    private static $map_fields = [ 'banners' ];
12
13    /** @var mixed[] */
14    private $begin;
15    /** @var mixed[] */
16    private $end;
17    /** @var string */
18    private $campaign;
19    /** @var string */
20    private $action;
21    /** @var string|int */
22    private $timestamp;
23    /** @var string|null */
24    private $comment;
25
26    /**
27     * @param stdClass|null $row
28     */
29    public function __construct( $row = null ) {
30        $this->begin = [];
31        $this->end = [];
32        if ( $row ) {
33            $comma_explode = static function ( $str ) {
34                return explode( ", ", $str );
35            };
36
37            $json_decode = static function ( $json ) {
38                return json_decode( $json, true );
39            };
40
41            $store = function ( $name, $decode = null ) use ( $row ) {
42                $beginField = 'notlog_begin_' . $name;
43                $endField = 'notlog_end_' . $name;
44
45                if ( !$decode ) {
46                    $decode = static function ( $v ) {
47                        return $v;
48                    };
49                }
50                $this->begin[ $name ] = $decode( $row->$beginField );
51                $this->end[ $name ] = $decode( $row->$endField );
52            };
53
54            foreach ( static::$basic_fields as $name ) {
55                $store( $name );
56            }
57            foreach ( static::$list_fields as $name ) {
58                $store( $name, $comma_explode );
59            }
60            foreach ( static::$map_fields as $name ) {
61                $store( $name, $json_decode );
62            }
63        }
64
65        $this->campaign = $row->notlog_not_name;
66        $this->action = $row->notlog_action;
67        $this->timestamp = $row->notlog_timestamp;
68        // TODO temporary code for soft dependency on schema change
69        $this->comment = $row->notlog_comment ?? '';
70    }
71
72    # TODO: use in logpager
73    public function changes() {
74        $removed = [];
75        $added = [];
76
77        $diff_basic = function ( $name ) use ( &$removed, &$added ) {
78            if ( $this->begin[ $name ] !== $this->end[ $name ] ) {
79                if ( $this->begin[ $name ] !== null ) {
80                    $removed[ $name ] = $this->begin[ $name ];
81                }
82                if ( $this->end[ $name ] !== null ) {
83                    $added[ $name ] = $this->end[ $name ];
84                }
85            }
86        };
87        $diff_list = function ( $name ) use ( &$removed, &$added ) {
88            if ( $this->begin[ $name ] !== $this->end[ $name ] ) {
89                $removed[ $name ] = array_diff( $this->begin[ $name ], $this->end[ $name ] );
90                if ( !$removed[ $name ] || $removed[ $name ] === [ "" ] ) {
91                    unset( $removed[ $name ] );
92                }
93                $added[ $name ] = array_diff( $this->end[ $name ], $this->begin[ $name ] );
94                if ( !$added[ $name ] || $added[ $name ] === [ "" ] ) {
95                    unset( $added[ $name ] );
96                }
97            }
98        };
99        $diff_map = function ( $name ) use ( &$removed, &$added ) {
100            $removed[ $name ] = $this->begin[ $name ];
101            $added[ $name ] = $this->end[ $name ];
102
103            if ( $this->begin[ $name ] && $this->end[ $name ] ) {
104                $all_keys = array_keys( array_merge( $this->begin[ $name ], $this->end[ $name ] ) );
105                foreach ( $all_keys as $item ) {
106                    # simplification: match contents, but diff at item level
107                    if ( array_key_exists( $item, $this->begin[ $name ] )
108                        && array_key_exists( $item, $this->end[ $name ] )
109                        && $added[ $name ][ $item ] === $removed[ $name ][ $item ]
110                    ) {
111                        unset( $added[ $name ][ $item ] );
112                        unset( $removed[ $name ][ $item ] );
113                    }
114                }
115            }
116            if ( !$removed[ $name ] ) {
117                unset( $removed[ $name ] );
118            }
119            if ( !$added[ $name ] ) {
120                unset( $added[ $name ] );
121            }
122        };
123        foreach ( static::$basic_fields as $name ) {
124            $diff_basic( $name );
125        }
126        foreach ( static::$list_fields as $name ) {
127            $diff_list( $name );
128        }
129        foreach ( static::$map_fields as $name ) {
130            $diff_map( $name );
131        }
132
133        return [ 'removed' => $removed, 'added' => $added ];
134    }
135}