Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
| 1 | <?php | ||
| 11 | class Configuration implements ConfigurationInterface | ||
| 12 | { | ||
| 13 | /** | ||
| 14 | * @var ResolverFactoryInterface[] | ||
| 15 | */ | ||
| 16 | protected $resolversFactories; | ||
| 17 | |||
| 18 | /** | ||
| 19 | * @var LoaderFactoryInterface[] | ||
| 20 | */ | ||
| 21 | protected $loadersFactories; | ||
| 22 | |||
| 23 | /** | ||
| 24 | * @param ResolverFactoryInterface[] $resolversFactories | ||
| 25 | * @param LoaderFactoryInterface[] $loadersFactories | ||
| 26 | */ | ||
| 27 | public function __construct(array $resolversFactories, array $loadersFactories) | ||
| 32 | |||
| 33 | /** | ||
| 34 |      * {@inheritdoc} | ||
| 35 | */ | ||
| 36 | public function getConfigTreeBuilder() | ||
| 37 |     { | ||
| 38 | $treeBuilder = new TreeBuilder(); | ||
| 39 |         $rootNode = $treeBuilder->root('liip_imagine', 'array'); | ||
| 40 | |||
| 41 | $resolversPrototypeNode = $rootNode | ||
| 42 | ->children() | ||
| 43 |                 ->arrayNode('resolvers') | ||
| 44 |                     ->useAttributeAsKey('name') | ||
| 45 |                     ->prototype('array') | ||
| 46 | ->performNoDeepMerging() | ||
| 47 | ; | ||
| 48 | $this->addResolversSections($resolversPrototypeNode); | ||
| 49 | |||
| 50 | $loadersPrototypeNode = $rootNode | ||
| 51 | ->children() | ||
| 52 |                 ->arrayNode('loaders') | ||
| 53 |                     ->useAttributeAsKey('name') | ||
| 54 |                     ->prototype('array') | ||
| 55 | ; | ||
| 56 | $this->addLoadersSections($loadersPrototypeNode); | ||
| 57 | |||
| 58 | $rootNode | ||
| 59 | ->beforeNormalization() | ||
| 60 |                 ->ifTrue(function ($v) { | ||
| 61 | return | ||
| 62 | empty($v['loaders']) || | ||
| 63 | empty($v['loaders']['default']) || | ||
| 64 | empty($v['resolvers']) || | ||
| 65 | empty($v['resolvers']['default']) | ||
| 66 | ; | ||
| 67 | }) | ||
| 68 |                 ->then(function ($v) { | ||
| 69 |                     if (empty($v['loaders'])) { | ||
| 70 | $v['loaders'] = array(); | ||
| 71 | } | ||
| 72 | |||
| 73 |                     if (false == is_array($v['loaders'])) { | ||
|  | |||
| 74 |                         throw new \LogicException('Loaders has to be array'); | ||
| 75 | } | ||
| 76 | |||
| 77 | View Code Duplication |                     if (false == array_key_exists('default', $v['loaders'])) { | |
| 78 |                         $v['loaders']['default'] = array('filesystem' => null); | ||
| 79 | } | ||
| 80 | |||
| 81 |                     if (empty($v['resolvers'])) { | ||
| 82 | $v['resolvers'] = array(); | ||
| 83 | } | ||
| 84 | |||
| 85 |                     if (false == is_array($v['resolvers'])) { | ||
| 86 |                         throw new \LogicException('Resolvers has to be array'); | ||
| 87 | } | ||
| 88 | |||
| 89 | View Code Duplication |                     if (false == array_key_exists('default', $v['resolvers'])) { | |
| 90 |                         $v['resolvers']['default'] = array('web_path' => null); | ||
| 91 | } | ||
| 92 | |||
| 93 | return $v; | ||
| 94 | }) | ||
| 95 | ->end() | ||
| 96 | ; | ||
| 97 | |||
| 98 | $rootNode | ||
| 99 |             ->fixXmlConfig('filter_set', 'filter_sets') | ||
| 100 | ->children() | ||
| 101 |                 ->scalarNode('driver')->defaultValue('gd') | ||
| 102 | ->validate() | ||
| 103 |                         ->ifTrue(function ($v) { return !in_array($v, array('gd', 'imagick', 'gmagick')); }) | ||
| 104 |                         ->thenInvalid('Invalid imagine driver specified: %s') | ||
| 105 | ->end() | ||
| 106 | ->end() | ||
| 107 |                 ->scalarNode('cache')->defaultValue('default')->end() | ||
| 108 |                 ->scalarNode('cache_base_path')->defaultValue('')->end() | ||
| 109 |                 ->scalarNode('data_loader')->defaultValue('default')->end() | ||
| 110 |                 ->scalarNode('default_image')->defaultNull()->end() | ||
| 111 |                 ->arrayNode('controller') | ||
| 112 | ->addDefaultsIfNotSet() | ||
| 113 | ->children() | ||
| 114 |                         ->scalarNode('filter_action')->defaultValue('liip_imagine.controller:filterAction')->end() | ||
| 115 |                         ->scalarNode('filter_runtime_action')->defaultValue('liip_imagine.controller:filterRuntimeAction')->end() | ||
| 116 | ->end() | ||
| 117 | ->end() | ||
| 118 |                 ->arrayNode('filter_sets') | ||
| 119 |                     ->useAttributeAsKey('name') | ||
| 120 |                     ->prototype('array') | ||
| 121 |                         ->fixXmlConfig('filter', 'filters') | ||
| 122 | ->children() | ||
| 123 |                             ->scalarNode('quality')->defaultValue(100)->end() | ||
| 124 |                             ->scalarNode('jpeg_quality')->defaultNull()->end() | ||
| 125 |                             ->scalarNode('png_compression_level')->defaultNull()->end() | ||
| 126 |                             ->scalarNode('png_compression_filter')->defaultNull()->end() | ||
| 127 |                             ->scalarNode('format')->defaultNull()->end() | ||
| 128 |                             ->booleanNode('animated')->defaultFalse()->end() | ||
| 129 |                             ->scalarNode('cache')->defaultNull()->end() | ||
| 130 |                             ->scalarNode('data_loader')->defaultNull()->end() | ||
| 131 |                             ->scalarNode('default_image')->defaultNull()->end() | ||
| 132 |                             ->arrayNode('filters') | ||
| 133 |                                 ->useAttributeAsKey('name') | ||
| 134 |                                 ->prototype('array') | ||
| 135 |                                     ->useAttributeAsKey('name') | ||
| 136 |                                     ->prototype('variable')->end() | ||
| 137 | ->end() | ||
| 138 | ->end() | ||
| 139 |                             ->arrayNode('post_processors') | ||
| 140 | ->defaultValue(array()) | ||
| 141 |                                 ->useAttributeAsKey('name') | ||
| 142 |                                 ->prototype('array') | ||
| 143 |                                     ->useAttributeAsKey('name') | ||
| 144 |                                     ->prototype('variable')->end() | ||
| 145 | ->end() | ||
| 146 | ->end() | ||
| 147 | ->end() | ||
| 148 | ->end() | ||
| 149 | ->end() | ||
| 150 | ->end(); | ||
| 151 | |||
| 152 | return $treeBuilder; | ||
| 153 | } | ||
| 154 | |||
| 155 | /** | ||
| 156 | * @param ArrayNodeDefinition $resolversPrototypeNode | ||
| 157 | */ | ||
| 158 | protected function addResolversSections(ArrayNodeDefinition $resolversPrototypeNode) | ||
| 166 | |||
| 167 | /** | ||
| 168 | * @param ArrayNodeDefinition $resolversPrototypeNode | ||
| 169 | */ | ||
| 170 | protected function addLoadersSections(ArrayNodeDefinition $resolversPrototypeNode) | ||
| 178 | } | ||
| 179 | 
When comparing two booleans, it is generally considered safer to use the strict comparison operator.