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 |
||
18 | class Pipeline implements |
||
19 | ArrayableInterface, |
||
20 | \JsonSerializable |
||
21 | { |
||
22 | |||
23 | private $stages = array(); |
||
24 | |||
25 | private $options = array(); |
||
26 | |||
27 | /** |
||
28 | * @var \Sokil\Mongo\Collection |
||
29 | */ |
||
30 | private $collection; |
||
31 | |||
32 | public function __construct(Collection $collection) |
||
36 | |||
37 | /** |
||
38 | * @param string $operator aggregate operator like $match, $group ... |
||
39 | * @param mixed $stage stage data |
||
40 | */ |
||
41 | private function addStage($operator, $stage) |
||
42 | { |
||
43 | $lastIndex = count($this->stages) - 1; |
||
44 | |||
45 | if ($operator == '$match' && isset($this->stages[$lastIndex][$operator])) { |
||
46 | $this->stages[$lastIndex][$operator] = array_merge($this->stages[$lastIndex][$operator], $stage); |
||
47 | } else { |
||
48 | $this->stages[] = array($operator => $stage); |
||
49 | } |
||
50 | } |
||
51 | |||
52 | /** |
||
53 | * Filter documents by expression |
||
54 | * |
||
55 | * @param array|\Sokil\Mongo\Expression $expression |
||
56 | * @return \Sokil\Mongo\Pipeline |
||
57 | * @throws \Sokil\Mongo\Exception |
||
58 | */ |
||
59 | public function match($expression) |
||
60 | { |
||
61 | if (is_callable($expression)) { |
||
62 | $expressionConfigurator = $expression; |
||
63 | $expression = new Expression(); |
||
64 | call_user_func($expressionConfigurator, $expression); |
||
65 | } |
||
66 | |||
67 | View Code Duplication | if ($expression instanceof Expression) { |
|
|
|||
68 | $expression = $expression->toArray(); |
||
69 | } elseif (!is_array($expression)) { |
||
70 | throw new Exception('Must be array, callable or instance of \Sokil\Mongo\Expression'); |
||
71 | } |
||
72 | |||
73 | $this->addStage('$match', $expression); |
||
74 | return $this; |
||
75 | } |
||
76 | |||
77 | /** |
||
78 | * Passes along the documents with only the specified fields to the next |
||
79 | * stage in the pipeline. The specified fields can be existing fields |
||
80 | * from the input documents or newly computed fields. |
||
81 | * |
||
82 | * @param array $pipeline |
||
83 | * @return \Sokil\Mongo\Pipeline |
||
84 | */ |
||
85 | public function project(array $pipeline) |
||
90 | |||
91 | /** |
||
92 | * Groups documents by some specified expression and outputs to the next |
||
93 | * stage a document for each distinct grouping. The output documents |
||
94 | * contain an _id field which contains the distinct group by key. The |
||
95 | * output documents can also contain computed fields that hold the values |
||
96 | * of some accumulator expression grouped by the $group‘s _id field. $group |
||
97 | * does not order its output documents. |
||
98 | * |
||
99 | * @link http://docs.mongodb.org/manual/reference/operator/aggregation/group/ |
||
100 | * |
||
101 | * @param array|callable $stage |
||
102 | * @return \Sokil\Mongo\Pipeline |
||
103 | * @throws \Sokil\Mongo\Exception |
||
104 | */ |
||
105 | public function group($stage) |
||
106 | { |
||
107 | if (is_callable($stage)) { |
||
108 | $configurator = $stage; |
||
109 | $stage = new GroupStage(); |
||
110 | call_user_func($configurator, $stage); |
||
111 | } |
||
112 | |||
113 | if ($stage instanceof GroupStage) { |
||
114 | $stage = $stage->toArray(); |
||
115 | } |
||
116 | |||
117 | if (!is_array($stage)) { |
||
118 | throw new Exception('Group stage must be array or instance of Sokil\Mongo\Pipeline\GroupStage or callable'); |
||
119 | } |
||
120 | |||
121 | if (!isset($stage['_id'])) { |
||
122 | throw new Exception('Group field in _id key must be specified'); |
||
123 | } |
||
124 | |||
125 | $this->addStage('$group', $stage); |
||
126 | return $this; |
||
127 | } |
||
128 | |||
129 | /** |
||
130 | * Deconstructs an array field from the input documents to output a document for each element. |
||
131 | * Each output document is the input document with the value of the array field replaced by the element. |
||
132 | * @link http://docs.mongodb.org/manual/reference/operator/aggregation/unwind/ |
||
133 | * |
||
134 | * @param string $path path to field |
||
135 | * @return \Sokil\Mongo\Pipeline |
||
136 | */ |
||
137 | public function unwind($path) |
||
138 | { |
||
139 | $this->addStage('$unwind', $path); |
||
140 | return $this; |
||
141 | } |
||
142 | |||
143 | public function sort(array $sortFields) |
||
148 | |||
149 | public function limit($limit) |
||
154 | |||
155 | public function skip($skip) |
||
156 | { |
||
157 | $this->addStage('$skip', (int) $skip); |
||
158 | return $this; |
||
159 | } |
||
160 | |||
161 | public function aggregate(array $options = array()) |
||
162 | { |
||
163 | return $this->collection->aggregate($this, $options, false); |
||
164 | } |
||
165 | |||
166 | public function aggregateCursor(array $options = array()) |
||
167 | { |
||
168 | return $this->collection->aggregate($this, $options, true); |
||
169 | } |
||
170 | |||
171 | public function toArray() |
||
175 | |||
176 | public function jsonSerialize() |
||
177 | { |
||
178 | return $this->stages; |
||
179 | } |
||
180 | |||
181 | public function __toString() |
||
185 | |||
186 | public function explain($allow = true) |
||
187 | { |
||
188 | $this->options['explain'] = (bool) $allow; |
||
189 | return $this; |
||
190 | } |
||
191 | |||
192 | public function allowDiskUse($allow = true) |
||
193 | { |
||
194 | $this->options['allowDiskUse'] = (bool) $allow; |
||
197 | |||
198 | public function setBatchSize($batchSize) |
||
203 | |||
204 | public function getOptions() |
||
208 | } |
||
209 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.