Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
84.34% covered (warning)
84.34%
70 / 83
66.67% covered (warning)
66.67%
6 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
Question
84.34% covered (warning)
84.34%
70 / 83
66.67% covered (warning)
66.67%
6 / 9
27.40
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 __get
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
4
 __set
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
20
 fill
75.00% covered (warning)
75.00%
6 / 8
0.00% covered (danger)
0.00%
0 / 1
6.56
 validateAllValues
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
12
 all
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
2
 allWithCustomerAnswers
100.00% covered (success)
100.00%
21 / 21
100.00% covered (success)
100.00%
1 / 1
2
 unansweredBy
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
2
 jsonSerialize
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace LDC\LDCCRM\Models;
4
5use LDC\LDCCRM\Enums\QuestionType;
6use LDC\LDCCRM\Utils;
7
8/**
9 * This class represents a question
10 * It has some static methods to retrieve questions and answers
11 *
12 * @property string $id The question id
13 * @property string|null $question The actual question as a string
14 * @property \LDC\LDCCRM\Enums\QuestionType|null $type
15 * The question type to display,
16 * it also hints wether it can accept one or multiple responses,
17 * so only checkbox allows multiple responses
18 * @property \LDC\LDCCRM\Models\Answer[] $answers An array with answers
19 *
20 * @category Api Models
21 * @package LDCCrmClient
22 * @subpackage models
23 * @author Jérémy Munsch <jeremy.munsch@ldc.fr>
24 */
25class Question extends ClientModel
26{
27    /**
28     * The question id
29     *
30     * Required
31     * Field Type bigInt
32     *
33     * @var integer
34     */
35    private int $id;
36
37    /**
38     * The actual question as a string
39     *
40     * Required
41     * Max length 255
42     * Field Type varchar
43     *
44     * @var string|null
45     */
46    private ?string $question = null;
47
48    /**
49     * The question type
50     *
51     * Validate: in QuestionType::toValues()
52     *
53     * Required
54     * Field Type tinyInteger
55     *
56     * @var \LDC\LDCCRM\Enums\QuestionType|null
57     */
58    private ?int $type = null;
59
60    /**
61     * The question answers
62     *
63     * \LDC\LDCCRM\Models\Answer
64     *
65     * @var array
66     */
67    private array $answers = [];
68
69    /**
70     * The crm customer fields
71     *
72     * @var array
73     */
74    protected array $modelFields = [
75        'id',
76        'question',
77        'type',
78        'answers',
79    ];
80
81    /**
82     * Validation rules
83     *
84     * @var array
85     */
86    protected static array $validation = [
87        'id'       => 'required|int',
88        'question' => 'required|string|max:255',
89        'type'     => ['required'],
90        'answers'  => 'required|array'
91    ];
92
93    /**
94     * Question
95     *
96     * @param array $properties
97     * @throws \LDC\LDCCRM\Exceptions\ValidationException If a field could not be validated.
98     */
99    public function __construct(array $properties = [])
100    {
101        parent::__construct();
102        $this->fill($properties);
103        return $this;
104    }
105
106    /**
107     * General accessor
108     *
109     * @param string $field
110     * @return mixed
111     */
112    public function __get(string $field)
113    {
114        $props = \array_diff(
115            $this->modelFields,
116            $this->invisibleFields
117        );
118        if (in_array($field, $props)) {
119            if ($field === 'type' and !\is_object($this->{$field})) {
120                return QuestionType::make($this->{$field});
121            }
122        }
123        return parent::__get($field);
124    }
125
126    /**
127     * Set prop on the model.
128     *
129     * @param string $field
130     * @param mixed  $value
131     * @return void
132     * @throws \LDC\LDCCRM\Exceptions\ValidationException If a field could not be validated.
133     * @throws \LDC\LDCCRM\Exceptions\AccessError If trying to set a value on a unknown property.
134     */
135    public function __set(string $field, mixed $value): void
136    {
137        if ($field === 'type') {
138            $value = (\is_object($value) and
139                get_class($value) === QuestionType::class) ? $value->value() : $value;
140        }
141        parent::__set($field, $value);
142    }
143
144    /**
145     * Fill values into model using validation rules.
146     *
147     * @param array $properties
148     * @return void
149     * @throws \LDC\LDCCRM\Exceptions\ValidationException If a field could not be validated.
150     */
151    public function fill(array $properties)
152    {
153        if (isset($properties['type'])) {
154            try {
155                $properties['type'] = (\is_object($properties['type']) and
156                    get_class($properties['type']) === QuestionType::class) ?
157                    $properties['type']->value : (ctype_digit($properties['type']) ?
158                        (int)$properties['type'] : $properties['type']);
159            } catch (\TypeError | \BadMethodCallException) {
160                // * Cast anyway
161                $properties['type'] = (int)$properties['type'];
162            }
163        }
164        parent::fill($properties);
165    }
166
167    /**
168     * Validate all model properties
169     *
170     * @param array $ignore
171     * @return array the validated values
172     * @throws \LDC\LDCCRM\Exceptions\ValidationException If a field could not be validated.
173     */
174    protected function validateAllValues(array $ignore = []): array
175    {
176        $out = [];
177        if (!\in_array('type', $ignore)) {
178            try {
179                $this->validateValue('type', QuestionType::make(Utils::getRawProperty($this, 'type')));
180            } catch (\TypeError | \BadMethodCallException) {
181                // Use this to throw validation error.
182                $this->validateValue('type', Utils::getRawProperty($this, 'type'));
183            }
184            $out['type'] = Utils::getRawProperty($this, 'type');
185        }
186        return array_merge($out, parent::validateAllValues(array_merge(['type'], $ignore)));
187    }
188
189    // * PUBLIC METHODS
190
191    /**
192     * Get all questions only
193     *
194     * @return array of \LDC\LDCCRM\Models\Question
195     * @throws \LDC\LDCCRM\Exceptions\CrmException If an error occurs on server side or on getting response.
196     * @throws \LDC\LDCCRM\Exceptions\ApiErrorException If any error or \LDC\LDCCRM\Enums\ApiError occurs.
197     * @phpcs:ignore Squiz.Commenting.FunctionCommentThrowTag.WrongNumber
198     */
199    public static function all(): array
200    {
201        static::setUpApiInterface();
202        $request = Utils::getResquest('apiV4.questions.index');
203
204        $response = static::$apiInterface->call($request);
205        $out      = [];
206        foreach ($response->data as $question) {
207            $answers             = \array_map(function ($answer) {
208                return new Answer($answer);
209            }, $question['answers']);
210            $question['answers'] = $answers;
211            $out[]               = new self($question);
212        }
213        return $out;
214    }
215
216    /**
217     * Get all the questions with customer answers
218     *
219     * @param \LDC\LDCCRM\Models\Customer $customer
220     * @return array
221     *
222     *   [
223     *        0 => [
224     *             'question' => \LDC\LDCCRM\Models\Question,
225     *             'customerAnswers' => \LDC\LDCCRM\Models\Answer[]
226     *        ]
227     *   ]
228     *
229     * with \LDC\LDCCRM\Models\Question[]
230     * and the customer \LDC\LDCCRM\Models\Answer[]
231     * @throws \LDC\LDCCRM\Exceptions\ValidationException If a customer's hashcode could not be validated.
232     * @throws \LDC\LDCCRM\Exceptions\CrmException If an error occurs on server side or on getting response.
233     * @throws \LDC\LDCCRM\Exceptions\ApiErrorException If any error or \LDC\LDCCRM\Enums\ApiError occurs.
234     * Possibles are : - modelNotFound, If the customer could not be found(CRM side).
235     * @phpcs:ignore Squiz.Commenting.FunctionCommentThrowTag.WrongNumber
236     */
237    public static function allWithCustomerAnswers(Customer $customer): array
238    {
239        self::assertValidHascode($customer->hashcode);
240        static::setUpApiInterface();
241        $request = Utils::getResquest('apiV4.questions.indexWithResponse', [
242            'serviceCustomer' => $customer->hashcode
243        ]);
244
245        $response = static::$apiInterface->call($request);
246        $out      = [];
247        foreach ($response->data as $question) {
248            $answers         = \array_map(function ($answer) {
249                return new Answer($answer);
250            }, $question['answers']);
251            $customerAnswers = \array_map(function ($answer) {
252                return new Answer($answer);
253            }, $question['customerAnswers']);
254            unset($question['customerAnswers']);
255            $question['answers'] = $answers;
256            $out[]               = [
257                'question' => new self($question),
258                'customerAnswers' => $customerAnswers,
259            ];
260        }
261        return $out;
262    }
263
264    /**
265     * Get unanswered question for a specific customer
266     *
267     * @param \LDC\LDCCRM\Models\Customer $customer
268     * @return array of \LDC\LDCCRM\Models\Question
269     * @throws \LDC\LDCCRM\Exceptions\ValidationException If a customer's hashcode could not be validated.
270     * @throws \LDC\LDCCRM\Exceptions\CrmException If an error occurs on server side or on getting response.
271     * @throws \LDC\LDCCRM\Exceptions\ApiErrorException If any error or \LDC\LDCCRM\Enums\ApiError occurs.
272     * Possibles are : - modelNotFound, If the customer could not be found(CRM side).
273     * @phpcs:ignore Squiz.Commenting.FunctionCommentThrowTag.WrongNumber
274     */
275    public static function unansweredBy(Customer $customer): array
276    {
277        self::assertValidHascode($customer->hashcode);
278        static::setUpApiInterface();
279        $request = Utils::getResquest(
280            'apiV4.questions.unAnsweredBy',
281            ['serviceCustomer' => $customer->hashcode]
282        );
283
284        $response = static::$apiInterface->call($request);
285        $out      = [];
286        foreach ($response->data as $question) {
287            $answers             = \array_map(function ($answer) {
288                return new Answer($answer);
289            }, $question['answers']);
290            $question['answers'] = $answers;
291            $out[]               = new self($question);
292        }
293        return $out;
294    }
295
296    /**
297     * Serialize this object to an array
298     *
299     * @return array
300     */
301    public function jsonSerialize()
302    {
303        return [
304            'id'       => $this->id,
305            'question' => $this->question,
306            'type'     => $this->type,
307            'answers'  => $this->answers
308        ];
309    }
310}