1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Extension\Core\DataTransformer;
13
14use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface;
15use Symfony\Component\Form\DataTransformerInterface;
16use Symfony\Component\Form\Exception\TransformationFailedException;
17
18/**
19 * @author Bernhard Schussek <bschussek@gmail.com>
20 */
21class ChoicesToBooleanArrayTransformer implements DataTransformerInterface
22{
23    private $choiceList;
24
25    public function __construct(ChoiceListInterface $choiceList)
26    {
27        $this->choiceList = $choiceList;
28    }
29
30    /**
31     * Transforms an array of choices to a format appropriate for the nested
32     * checkboxes/radio buttons.
33     *
34     * The result is an array with the options as keys and true/false as values,
35     * depending on whether a given option is selected. If this field is rendered
36     * as select tag, the value is not modified.
37     *
38     * @param mixed $array An array
39     *
40     * @return mixed An array
41     *
42     * @throws TransformationFailedException If the given value is not an array
43     *                                       or if the choices can not be retrieved.
44     */
45    public function transform($array)
46    {
47        if (null === $array) {
48            return array();
49        }
50
51        if (!is_array($array)) {
52            throw new TransformationFailedException('Expected an array.');
53        }
54
55        try {
56            $values = $this->choiceList->getValues();
57        } catch (\Exception $e) {
58            throw new TransformationFailedException('Can not get the choice list', $e->getCode(), $e);
59        }
60
61        $valueMap = array_flip($this->choiceList->getValuesForChoices($array));
62
63        foreach ($values as $i => $value) {
64            $values[$i] = isset($valueMap[$value]);
65        }
66
67        return $values;
68    }
69
70    /**
71     * Transforms a checkbox/radio button array to an array of choices.
72     *
73     * The input value is an array with the choices as keys and true/false as
74     * values, depending on whether a given choice is selected. The output
75     * is an array with the selected choices.
76     *
77     * @param mixed $values An array
78     *
79     * @return mixed An array
80     *
81     * @throws TransformationFailedException If the given value is not an array,
82     *                                       if the recuperation of the choices
83     *                                       fails or if some choice can't be
84     *                                       found.
85     */
86    public function reverseTransform($values)
87    {
88        if (!is_array($values)) {
89            throw new TransformationFailedException('Expected an array.');
90        }
91
92        try {
93            $choices = $this->choiceList->getChoices();
94        } catch (\Exception $e) {
95            throw new TransformationFailedException('Can not get the choice list', $e->getCode(), $e);
96        }
97
98        $result = array();
99        $unknown = array();
100
101        foreach ($values as $i => $selected) {
102            if ($selected) {
103                if (isset($choices[$i])) {
104                    $result[] = $choices[$i];
105                } else {
106                    $unknown[] = $i;
107                }
108            }
109        }
110
111        if (count($unknown) > 0) {
112            throw new TransformationFailedException(sprintf('The choices "%s" were not found', implode('", "', $unknown)));
113        }
114
115        return $result;
116    }
117}
118