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:
Complex classes like ObjectModelSerializer often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use ObjectModelSerializer, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
26 | class ObjectModelSerializer extends ObjectModelSerializerBase implements IObjectSerialiser |
||
27 | { |
||
28 | /** |
||
29 | * Creates new instance of ObjectModelSerializer. |
||
30 | * |
||
31 | * @param IService $service |
||
32 | * @param RequestDescription $request the request submitted by the client |
||
33 | */ |
||
34 | public function __construct(IService $service, RequestDescription $request = null) |
||
35 | { |
||
36 | parent::__construct($service, $request); |
||
37 | } |
||
38 | |||
39 | /** |
||
40 | * Write a top level entry resource. |
||
41 | * |
||
42 | * @param mixed $entryObject Reference to the entry object to be written |
||
43 | * |
||
44 | * @return ODataEntry |
||
45 | */ |
||
46 | public function writeTopLevelElement($entryObject) |
||
47 | { |
||
48 | $requestTargetSource = $this->getRequest()->getTargetSource(); |
||
49 | |||
50 | View Code Duplication | if ($requestTargetSource == TargetSource::ENTITY_SET) { |
|
|
|||
51 | $resourceType = $this->getRequest()->getTargetResourceType(); |
||
52 | } else { |
||
53 | assert($requestTargetSource == TargetSource::PROPERTY, '$requestTargetSource != TargetSource::PROPERTY'); |
||
54 | $resourceProperty = $this->getRequest()->getProjectedProperty(); |
||
55 | $resourceType = $resourceProperty->getResourceType(); |
||
56 | } |
||
57 | |||
58 | $needPop = $this->pushSegmentForRoot(); |
||
59 | $entry = $this->_writeEntryElement( |
||
60 | $entryObject, |
||
61 | $resourceType, |
||
62 | $this->getRequest()->getRequestUrl()->getUrlAsString(), |
||
63 | $this->getRequest()->getContainerName() |
||
64 | ); |
||
65 | $this->popSegment($needPop); |
||
66 | |||
67 | return $entry; |
||
68 | } |
||
69 | |||
70 | /** |
||
71 | * Write top level feed element. |
||
72 | * |
||
73 | * @param array &$entryObjects Array of entry resources to be written |
||
74 | * |
||
75 | * @return ODataFeed |
||
76 | */ |
||
77 | public function writeTopLevelElements(&$entryObjects) |
||
78 | { |
||
79 | assert(is_array($entryObjects), '!is_array($entryObjects)'); |
||
80 | $requestTargetSource = $this->getRequest()->getTargetSource(); |
||
81 | if ($requestTargetSource == TargetSource::ENTITY_SET) { |
||
82 | $title = $this->getRequest()->getContainerName(); |
||
83 | View Code Duplication | } else { |
|
84 | assert($requestTargetSource == TargetSource::PROPERTY, '$requestTargetSource != TargetSource::PROPERTY'); |
||
85 | $resourceProperty = $this->getRequest()->getProjectedProperty(); |
||
86 | assert( |
||
87 | $resourceProperty->getKind() == ResourcePropertyKind::RESOURCESET_REFERENCE, |
||
88 | '$resourceProperty->getKind() != ResourcePropertyKind::RESOURCESET_REFERENCE' |
||
89 | ); |
||
90 | $title = $resourceProperty->getName(); |
||
91 | } |
||
92 | |||
93 | $relativeUri = $this->getRequest()->getIdentifier(); |
||
94 | $feed = new ODataFeed(); |
||
95 | |||
96 | if ($this->getRequest()->queryType == QueryType::ENTITIES_WITH_COUNT()) { |
||
97 | $feed->rowCount = $this->getRequest()->getCountValue(); |
||
98 | } |
||
99 | |||
100 | $needPop = $this->pushSegmentForRoot(); |
||
101 | $targetResourceType = $this->getRequest()->getTargetResourceType(); |
||
102 | assert(null != $targetResourceType, 'Target resource type must not be null'); |
||
103 | $this->_writeFeedElements( |
||
104 | $entryObjects, |
||
105 | $targetResourceType, |
||
106 | $title, |
||
107 | $this->getRequest()->getRequestUrl()->getUrlAsString(), |
||
108 | $relativeUri, |
||
109 | $feed |
||
110 | ); |
||
111 | $this->popSegment($needPop); |
||
112 | |||
113 | return $feed; |
||
114 | } |
||
115 | |||
116 | /** |
||
117 | * Write top level url element. |
||
118 | * |
||
119 | * @param mixed $entryObject The entry resource whose url to be written |
||
120 | * |
||
121 | * @return ODataURL |
||
122 | */ |
||
123 | public function writeUrlElement($entryObject) |
||
124 | { |
||
125 | $url = new ODataURL(); |
||
126 | if (!is_null($entryObject)) { |
||
127 | $currentResourceType = $this->getCurrentResourceSetWrapper()->getResourceType(); |
||
128 | $relativeUri = $this->getEntryInstanceKey( |
||
129 | $entryObject, |
||
130 | $currentResourceType, |
||
131 | $this->getCurrentResourceSetWrapper()->getName() |
||
132 | ); |
||
133 | |||
134 | $url->url = rtrim($this->absoluteServiceUri, '/') . '/' . $relativeUri; |
||
135 | } |
||
136 | |||
137 | return $url; |
||
138 | } |
||
139 | |||
140 | /** |
||
141 | * Write top level url collection. |
||
142 | * |
||
143 | * @param array $entryObjects Array of entry resources |
||
144 | * whose url to be written |
||
145 | * |
||
146 | * @return ODataURLCollection |
||
147 | */ |
||
148 | public function writeUrlElements($entryObjects) |
||
149 | { |
||
150 | $urls = new ODataURLCollection(); |
||
151 | if (!empty($entryObjects)) { |
||
152 | $i = 0; |
||
153 | foreach ($entryObjects as $entryObject) { |
||
154 | $urls->urls[$i] = $this->writeUrlElement($entryObject); |
||
155 | ++$i; |
||
156 | } |
||
157 | |||
158 | if ($i > 0 && $this->needNextPageLink(count($entryObjects))) { |
||
159 | $urls->nextPageLink = $this->getNextLinkUri( |
||
160 | $entryObjects[$i - 1], |
||
161 | $this->getRequest()->getRequestUrl()->getUrlAsString() |
||
162 | ); |
||
163 | } |
||
164 | } |
||
165 | |||
166 | if ($this->getRequest()->queryType == QueryType::ENTITIES_WITH_COUNT()) { |
||
167 | $urls->count = $this->getRequest()->getCountValue(); |
||
168 | } |
||
169 | |||
170 | return $urls; |
||
171 | } |
||
172 | |||
173 | /** |
||
174 | * Write top level complex resource. |
||
175 | * |
||
176 | * @param mixed &$complexValue The complex object to be |
||
177 | * written |
||
178 | * @param string $propertyName The name of the |
||
179 | * complex property |
||
180 | * @param ResourceType &$resourceType Describes the type of |
||
181 | * complex object |
||
182 | * |
||
183 | * @return ODataPropertyContent |
||
184 | */ |
||
185 | public function writeTopLevelComplexObject( |
||
186 | &$complexValue, |
||
187 | $propertyName, |
||
188 | ResourceType & $resourceType |
||
189 | ) { |
||
190 | $propertyContent = new ODataPropertyContent(); |
||
191 | $this->_writeComplexValue( |
||
192 | $complexValue, |
||
193 | $propertyName, |
||
194 | $resourceType, |
||
195 | null, |
||
196 | $propertyContent |
||
197 | ); |
||
198 | |||
199 | return $propertyContent; |
||
200 | } |
||
201 | |||
202 | /** |
||
203 | * Write top level bag resource. |
||
204 | * |
||
205 | * @param mixed &$BagValue The bag object to be |
||
206 | * written |
||
207 | * @param string $propertyName The name of the |
||
208 | * bag property |
||
209 | * @param ResourceType &$resourceType Describes the type of |
||
210 | * bag object |
||
211 | * |
||
212 | * @return ODataPropertyContent |
||
213 | */ |
||
214 | public function writeTopLevelBagObject( |
||
215 | &$BagValue, |
||
216 | $propertyName, |
||
217 | ResourceType & $resourceType |
||
218 | ) { |
||
219 | $propertyContent = new ODataPropertyContent(); |
||
220 | $this->_writeBagValue( |
||
221 | $BagValue, |
||
222 | $propertyName, |
||
223 | $resourceType, |
||
224 | null, |
||
225 | $propertyContent |
||
226 | ); |
||
227 | |||
228 | return $propertyContent; |
||
229 | } |
||
230 | |||
231 | /** |
||
232 | * Write top level primitive value. |
||
233 | * |
||
234 | * @param mixed &$primitiveValue The primitve value to be |
||
235 | * written |
||
236 | * @param ResourceProperty &$resourceProperty Resource property |
||
237 | * describing the |
||
238 | * primitive property |
||
239 | * to be written |
||
240 | * |
||
241 | * @return ODataPropertyContent |
||
242 | */ |
||
243 | public function writeTopLevelPrimitive( |
||
257 | |||
258 | /** |
||
259 | * Write an entry element. |
||
260 | * |
||
261 | * @param mixed $entryObject Object representing entry element |
||
262 | * @param ResourceType $resourceType Expected type of the entry object |
||
263 | * @param string $absoluteUri Absolute uri of the entry element |
||
264 | * @param string $relativeUri Relative uri of the entry element |
||
265 | * |
||
266 | * @return ODataEntry |
||
267 | */ |
||
268 | private function _writeEntryElement( |
||
318 | |||
319 | /** |
||
320 | * Writes the feed elements. |
||
321 | * |
||
322 | * @param array &$entryObjects Array of entries in the feed element |
||
323 | * @param ResourceType &$resourceType The resource type of the f the elements |
||
324 | * in the collection |
||
325 | * @param string $title Title of the feed element |
||
326 | * @param string $absoluteUri Absolute uri representing the feed element |
||
327 | * @param string $relativeUri Relative uri representing the feed element |
||
328 | * @param ODataFeed &$feed Feed to write to |
||
329 | */ |
||
330 | private function _writeFeedElements( |
||
360 | |||
361 | /** |
||
362 | * Write values of properties of given entry (resource) or complex object. |
||
363 | * |
||
364 | * @param mixed $customObject Entity or complex object |
||
365 | * with properties |
||
366 | * to write out |
||
367 | * @param ResourceType &$resourceType Resource type describing |
||
368 | * the metadata of |
||
369 | * the custom object |
||
370 | * @param string $absoluteUri Absolute uri for the given |
||
371 | * entry object |
||
372 | * NULL for complex object |
||
373 | * @param string $relativeUri Relative uri for the given |
||
374 | * custom object |
||
375 | * @param ODataEntry ODataEntry|null ODataEntry instance to |
||
376 | * place links and |
||
377 | * expansion of the |
||
378 | * entry object, |
||
379 | * NULL for complex object |
||
380 | * @param ODataPropertyContent &$odataPropertyContent ODataPropertyContent |
||
381 | * instance in which |
||
382 | * to place the values |
||
383 | */ |
||
384 | private function _writeObjectProperties( |
||
496 | |||
497 | /** |
||
498 | * Writes a primitive value and related information to the given |
||
499 | * ODataProperty instance. |
||
500 | * |
||
501 | * @param mixed &$primitiveValue The primitive value to write |
||
502 | * @param ResourceProperty &$resourceProperty The metadata of the primitive |
||
503 | * property value |
||
504 | * @param ODataProperty &$odataProperty ODataProperty instance to which |
||
505 | * the primitive value and related |
||
506 | * information to write out |
||
507 | * |
||
508 | * @throws ODataException If given value is not primitive |
||
509 | */ |
||
510 | private function _writePrimitiveValue( |
||
529 | |||
530 | /** |
||
531 | * Write value of a complex object. |
||
532 | * |
||
533 | * @param mixed &$complexValue Complex object to write |
||
534 | * @param string $propertyName Name of the |
||
535 | * complex property |
||
536 | * whose value need |
||
537 | * to be written |
||
538 | * @param ResourceType &$resourceType Expected type |
||
539 | * of the property |
||
540 | * @param string $relativeUri Relative uri for the |
||
541 | * complex type element |
||
542 | * @param ODataPropertyContent &$odataPropertyContent Content to write to |
||
543 | */ |
||
544 | private function _writeComplexValue( |
||
572 | |||
573 | /** |
||
574 | * Write value of a bag instance. |
||
575 | * |
||
576 | * @param array/NULL &$BagValue Bag value to write |
||
577 | * @param string $propertyName Property name of the bag |
||
578 | * @param ResourceType &$resourceType Type describing the |
||
579 | * bag value |
||
580 | * @param string $relativeUri Relative Url to the bag |
||
581 | * @param ODataPropertyContent &$odataPropertyContent On return, this object |
||
582 | * will hold bag value which |
||
583 | * can be used by writers |
||
584 | */ |
||
585 | private function _writeBagValue( |
||
633 | |||
634 | /** |
||
635 | * Write media resource metadata (for MLE and Named Streams). |
||
636 | * |
||
637 | * @param mixed $entryObject The entry instance being serialized |
||
638 | * @param ResourceType &$resourceType Resource type of the entry instance |
||
639 | * @param string $title Title for the current |
||
640 | * current entry instance |
||
641 | * @param string $relativeUri Relative uri for the |
||
642 | * current entry instance |
||
643 | * @param ODataEntry &$odataEntry OData entry to write to |
||
644 | */ |
||
645 | private function _writeMediaResourceMetadata( |
||
646 | $entryObject, |
||
647 | ResourceType & $resourceType, |
||
648 | $title, |
||
649 | $relativeUri, |
||
650 | ODataEntry & $odataEntry |
||
651 | ) { |
||
652 | $streamProviderWrapper = $this->getService()->getStreamProviderWrapper(); |
||
653 | assert(null != $streamProviderWrapper, "Retrieved stream provider must not be null"); |
||
654 | if ($resourceType->isMediaLinkEntry()) { |
||
655 | $odataEntry->isMediaLinkEntry = true; |
||
656 | $eTag = $streamProviderWrapper->getStreamETag($entryObject, null); |
||
657 | $readStreamUri = $streamProviderWrapper->getReadStreamUri($entryObject, null, $relativeUri); |
||
658 | $mediaContentType = $streamProviderWrapper->getStreamContentType($entryObject, null); |
||
659 | $mediaLink = new ODataMediaLink( |
||
660 | $title, |
||
661 | $streamProviderWrapper->getDefaultStreamEditMediaUri( |
||
662 | $relativeUri, |
||
663 | null |
||
664 | ), |
||
665 | $readStreamUri, |
||
666 | $mediaContentType, |
||
667 | $eTag |
||
668 | ); |
||
669 | |||
670 | $odataEntry->mediaLink = $mediaLink; |
||
671 | } |
||
672 | |||
673 | if ($resourceType->hasNamedStream()) { |
||
674 | foreach ($resourceType->getAllNamedStreams() as $title => $resourceStreamInfo) { |
||
675 | $eTag = $streamProviderWrapper->getStreamETag( |
||
676 | $entryObject, |
||
677 | $resourceStreamInfo |
||
678 | ); |
||
679 | $readStreamUri = $streamProviderWrapper->getReadStreamUri( |
||
680 | $entryObject, |
||
681 | $resourceStreamInfo, |
||
682 | $relativeUri |
||
683 | ); |
||
684 | $mediaContentType = $streamProviderWrapper->getStreamContentType( |
||
685 | $entryObject, |
||
686 | $resourceStreamInfo |
||
687 | ); |
||
688 | $mediaLink = new ODataMediaLink( |
||
689 | $title, |
||
690 | $streamProviderWrapper->getReadStreamUri( |
||
691 | $entryObject, |
||
692 | $resourceStreamInfo, |
||
693 | $relativeUri |
||
694 | ), |
||
695 | $readStreamUri, |
||
696 | $mediaContentType, |
||
697 | $eTag |
||
698 | ); |
||
699 | |||
700 | $odataEntry->mediaLinks[] = $mediaLink; |
||
701 | } |
||
702 | } |
||
703 | } |
||
704 | |||
705 | /** |
||
706 | * Convert the given primitive value to string. |
||
707 | * Note: This method will not handle null primitive value. |
||
708 | * |
||
709 | * @param ResourceType &$primitiveResourceType Type of the primitive property |
||
710 | * whose value need to be converted |
||
711 | * @param mixed $primitiveValue Primitive value to convert |
||
712 | * |
||
713 | * @return string |
||
714 | */ |
||
715 | private function _primitiveToString( |
||
734 | |||
735 | /** |
||
736 | * Write value of a complex object. |
||
737 | * Note: This method will not handle null complex value. |
||
738 | * |
||
739 | * @param mixed &$complexValue Complex object to write |
||
740 | * @param string $propertyName Name of the |
||
741 | * complex property |
||
742 | * whose value |
||
743 | * need to be written |
||
744 | * @param ResourceType &$resourceType Expected type of the |
||
745 | * property |
||
746 | * @param string $relativeUri Relative uri for the |
||
747 | * complex type element |
||
748 | * @param ODataPropertyContent &$odataPropertyContent Content to write to |
||
749 | * |
||
750 | * @return ResourceType The actual type of the complex object |
||
751 | */ |
||
752 | private function _complexObjectToContent( |
||
785 | |||
786 | /** |
||
787 | * @param $customObject |
||
788 | * @param ResourceType $resourceType |
||
789 | * @param string $relativeUri |
||
790 | * @param ODataPropertyContent $odataPropertyContent |
||
791 | * @param ResourceTypeKind $resourceTypeKind |
||
792 | * @param $navigationProperties |
||
793 | * |
||
794 | * @throws ODataException |
||
795 | * |
||
796 | * @return array |
||
797 | */ |
||
798 | private function writeObjectPropertiesUnexpanded( |
||
891 | |||
892 | public static function isMatchPrimitive($resourceKind) |
||
902 | |||
903 | |||
904 | /** |
||
905 | * @param $customObject |
||
906 | * @param ResourceType $resourceType |
||
907 | * @param string $relativeUri |
||
908 | * @param ODataPropertyContent $odataPropertyContent |
||
909 | * @param \POData\UriProcessor\QueryProcessor\ExpandProjectionParser\ProjectionNode[] $projectionNodes |
||
910 | * @param $navigationProperties |
||
911 | * |
||
912 | * @throws ODataException |
||
913 | * |
||
914 | * @return array |
||
915 | */ |
||
916 | private function writeObjectPropertiesExpanded( |
||
992 | |||
993 | } |
||
994 |
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.