GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

TypeMapFactory   A
last analyzed

Complexity

Total Complexity 25

Size/Duplication

Total Lines 165
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 10

Importance

Changes 8
Bugs 5 Features 3
Metric Value
wmc 25
c 8
b 5
f 3
lcom 1
cbo 10
dl 0
loc 165
rs 10

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
B createTypeMap() 0 30 5
C mapDestinationMemberToSource() 0 39 7
A findTypeMember() 0 10 3
A nameMatches() 0 9 1
A splitDestinationMemberName() 0 5 2
A createNameSnippet() 0 13 1
A parseTypeFromAnnotation() 0 5 2
A findReflector() 0 10 3
1
<?php
2
3
namespace Papper\Internal;
4
5
use Papper\ClassNotFoundException;
6
use Papper\MappingOptionsInterface;
7
use Papper\PropertyMap;
8
use Papper\TypeMap;
9
10
class TypeMapFactory
11
{
12
	/**
13
	 * @var \ReflectionClass[]
14
	 */
15
	private $reflectorsCache = array();
16
	/**
17
	 * @var MemberAccessFactory
18
	 */
19
	private $memberAccessFactory;
20
	/**
21
	 * @var AnnotationTypeReader
22
	 */
23
	private $annotationTypeReader;
24
25
	public function __construct()
26
	{
27
		$this->memberAccessFactory = new MemberAccessFactory();
28
		$this->annotationTypeReader = new AnnotationTypeReader();
29
	}
30
31
	public function createTypeMap($sourceType, $destinationType, MappingOptionsInterface $mappingOptions)
32
	{
33
		$sourceReflector = $this->findReflector($sourceType);
34
		$destReflector = $this->findReflector($destinationType);
35
36
		$typeMap = new TypeMap($sourceType, $destinationType, new SimpleObjectCreator($destReflector));
37
38
		/** @var $destMembers \ReflectionProperty[]|\ReflectionMethod[] */
39
		$destMembers = array_merge(
40
			ReflectionHelper::getPublicMethods($destReflector, 1),
41
			$destReflector->getProperties(\ReflectionProperty::IS_PUBLIC)
42
		);
43
44
		foreach ($destMembers as $destMember) {
45
			if ($destMember instanceof \ReflectionMethod && $destMember->isConstructor()) {
46
				continue;
47
			}
48
49
			$sourceMembers = array();
50
51
			$setter = $this->memberAccessFactory->createMemberSetter($destMember, $mappingOptions);
0 ignored issues
show
Unused Code introduced by
The call to MemberAccessFactory::createMemberSetter() has too many arguments starting with $mappingOptions.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
52
			$getter = $this->mapDestinationMemberToSource($sourceMembers, $sourceReflector, $destMember->getName(), $mappingOptions)
53
				? $this->memberAccessFactory->createMemberGetter($sourceMembers, $mappingOptions)
54
				: null;
55
56
			$typeMap->addPropertyMap(new PropertyMap($setter, $getter));
57
		}
58
59
		return $typeMap;
60
	}
61
62
	/**
63
	 * @param \ReflectionProperty[]|\ReflectionMethod[] $sourceMembers
64
	 * @param \ReflectionClass $sourceReflector
65
	 * @param string $nameToSearch
66
	 * @param MappingOptionsInterface $mappingOptions
67
	 * @return bool
68
	 */
69
	public function mapDestinationMemberToSource(array &$sourceMembers, \ReflectionClass $sourceReflector, $nameToSearch,
70
		MappingOptionsInterface $mappingOptions)
71
	{
72
		$sourceProperties = $sourceReflector->getProperties(\ReflectionProperty::IS_PUBLIC);
73
		$sourceNoArgMethods = ReflectionHelper::getPublicMethods($sourceReflector, 0);
74
75
		$member = $this->findTypeMember($sourceProperties, $sourceNoArgMethods, $nameToSearch, $mappingOptions);
76
77
		$foundMatch = $member !== null;
78
79
		if ($foundMatch) {
80
			$sourceMembers[] = $member;
81
		} else {
82
			$matches = $this->splitDestinationMemberName($nameToSearch, $mappingOptions);
83
			$matchesCount = count($matches);
84
85
			for ($i = 0; ($i < $matchesCount) && !$foundMatch; $i++) {
86
				$snippet = $this->createNameSnippet($matches, $i, $mappingOptions);
87
88
				$member = $this->findTypeMember($sourceProperties, $sourceNoArgMethods, $snippet['first'], $mappingOptions);
89
				if ($member !== null) {
90
					$sourceMembers[] = $member;
91
92
					$nestedSourceReflector = $this->parseTypeFromAnnotation($member);
93
94
					if ($nestedSourceReflector) {
95
						$foundMatch = $this->mapDestinationMemberToSource(
96
							$sourceMembers, $nestedSourceReflector, $snippet['second'], $mappingOptions
97
						);
98
					}
99
100
					if (!$foundMatch) {
101
						array_pop($sourceMembers);
102
					}
103
				}
104
			}
105
		}
106
		return $foundMatch;
107
	}
108
109
	private function findTypeMember(array $properties, array $getMethods, $nameToSearch, MappingOptionsInterface $mappingOptions)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
110
	{
111
		/** @var $member \ReflectionProperty|\ReflectionMethod */
112
		foreach (array_merge($getMethods, $properties) as $member) {
113
			if ($this->nameMatches($member->getName(), $nameToSearch, $mappingOptions)) {
114
				return $member;
115
			}
116
		}
117
		return null;
118
	}
119
120
	private function nameMatches($sourceMemberName, $destMemberName, MappingOptionsInterface $mappingOptions)
121
	{
122
		$possibleSourceNames = NamingHelper::possibleNames($sourceMemberName, $mappingOptions->getSourcePrefixes());
123
		$possibleDestNames = NamingHelper::possibleNames($destMemberName, $mappingOptions->getDestinationPrefixes());
124
125
		return count(array_uintersect($possibleSourceNames, $possibleDestNames, function($a, $b){
126
			return strcasecmp($a, $b);
127
		})) > 0;
128
	}
129
130
	private function splitDestinationMemberName($nameToSearch, MappingOptionsInterface $mappingOptions)
131
	{
132
		preg_match_all($mappingOptions->getDestinationMemberNamingConvention()->getSplittingExpression(), $nameToSearch, $matches);
133
		return isset($matches[0]) ? $matches[0] : array();
134
	}
135
136
	private function createNameSnippet(array $matches, $i, MappingOptionsInterface $mappingOptions)
137
	{
138
		return array(
139
			'first' => implode(
140
				$mappingOptions->getSourceMemberNamingConvention()->getSeparatorCharacter(),
141
				array_slice($matches, 0, $i)
142
			),
143
			'second' => implode(
144
				$mappingOptions->getSourceMemberNamingConvention()->getSeparatorCharacter(),
145
				array_slice($matches, $i)
146
			),
147
		);
148
	}
149
150
	/**
151
	 * @param \ReflectionProperty|\ReflectionMethod $reflector
152
	 * @throws \Exception
153
	 * @throws \TokenReflection\Exception\BrokerException
154
	 * @throws \TokenReflection\Exception\ParseException
155
	 * @throws \TokenReflection\Exception\RuntimeException
156
	 * @return null|\ReflectionClass
157
	 */
158
	private function parseTypeFromAnnotation($reflector)
159
	{
160
		$type = $this->annotationTypeReader->getType($reflector);
161
		return $type ? new \ReflectionClass($type) : null;
162
	}
163
164
	private function findReflector($type)
165
	{
166
		if (!class_exists($type)) {
167
			throw new ClassNotFoundException(sprintf('Type %s must be a class', $type));
168
		}
169
170
		return isset($this->reflectorsCache[$type])
171
			? $this->reflectorsCache[$type]
172
			: $this->reflectorsCache[$type] = new \ReflectionClass($type);
173
	}
174
}
175