Passed
Pull Request — master (#70)
by Christian
02:13 queued 50s
created

Maphper::getColumns()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 2
rs 10
1
<?php
2
namespace Maphper;
3
class Maphper implements \Countable, \ArrayAccess, \IteratorAggregate {
4
	const FIND_EXACT 		= 	0x1;
5
	const FIND_LIKE 		= 	0x2;
6
	const FIND_STARTS 		= 	0x4;
7
	const FIND_ENDS 		= 	0x8;
8
	const FIND_BIT 			= 	0x10;
9
	const FIND_GREATER 		= 	0x20;
10
	const FIND_LESS 		=	0x40;
11
	const FIND_EXPRESSION 	= 	0x80;
12
	const FIND_AND 			= 	0x100;
13
	const FIND_OR 			= 	0x200;
14
	const FIND_NOT 			= 	0x400;
15
	const FIND_BETWEEN		= 	0x800;
16
	const FIND_NOCASE		= 	0x1000;
17
18
	private $dataSource;
19
	private $relations = [];
20
	private $settings = ['filter' => [], 'sort' => null, 'limit' => null, 'offset' => null, 'resultClass' => '\\stdClass'];
21
	private $iterator = 0;
22
	private $entity;
23
24
	public function __construct(DataSource $dataSource, array $settings = [], array $relations = []) {
25
		$this->dataSource = $dataSource;
26
		$this->settings = array_replace($this->settings, $settings);
27
		$this->relations = $relations;
28
		$this->entity = new Lib\Entity($this, $this->settings['resultClass'] ?? null);
29
	}
30
31
	public function addRelation($name, Relation $relation) {
32
		$this->relations[$name] = $relation;
33
	}
34
35
	public function count($group = null) {
36
		return $this->dataSource->findAggregate('count', $group == null ? $this->dataSource->getPrimaryKey() : $group, $group, $this->settings['filter']);
37
	}
38
39
	//Allow filter(['user' => $user]) where $user is an object instead of
40
	//filter(['userId' => $user->id])
41
	private function wrapFilter() {
42
		foreach ($this->settings['filter'] as $name => $value) {
43
			if (isset($this->relations[$name])) {
44
				$filter = $this->relations[$name]->getFilter($value);
45
				$this->settings['filter'] = array_merge($this->settings['filter'], $filter);
46
				unset($this->settings['filter'][$name]);
47
			}
48
		}
49
	}
50
51
	private function getResults() {
52
		$this->wrapFilter();
53
		foreach ($this->settings['filter'] as $name => &$filter) {
54
			if (isset($this->relations[$name])) {
55
				$this->relations[$name]->overwrite($filter, $filter[$name]);
56
			}
57
		}
58
		$results = $this->dataSource->findByField($this->settings['filter'],
59
			['order' => $this->settings['sort'], 'limit' => $this->settings['limit'], 'offset' => $this->settings['offset'] ]);
60
61
		$siblings = new \ArrayObject();
62
63
		foreach ($results as &$result) $result = $this->entity->create($result, $this->relations, $siblings);
64
65
		return $results;
66
	}
67
68
	public function getColumns() {
69
		return $this->dataSource->getColumns();
0 ignored issues
show
Bug introduced by
The method getColumns() does not exist on Maphper\DataSource. It seems like you code against a sub-type of Maphper\DataSource such as Maphper\DataSource\Database. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

69
		return $this->dataSource->/** @scrutinizer ignore-call */ getColumns();
Loading history...
70
	}
71
72
	public function item($n) {
73
		$array = $this->getResults();
74
		return isset($array[$n]) ? $array[$n] : null;
75
	}
76
77
	public function getIterator() {
78
		return new Iterator($this->getResults(), $this->dataSource->getPrimaryKey());
79
	}
80
81
	private function processFilters($value) {
82
		//When saving to a mapper with filters, write the filters back into the object being stored
83
		foreach ($this->settings['filter'] as $key => $filterValue) {
84
			if (empty($value->$key) && !is_array($filterValue)) $value->$key = $filterValue;
85
		}
86
		return $value;
87
	}
88
89
	public function offsetSet($offset, $valueObj) {
90
        if ($valueObj instanceof \Maphper\Relation) throw new \Exception();
91
92
        //Extract private properties from the object
93
        $visibilityOverride = new \Maphper\Lib\VisibilityOverride($valueObj);
94
        $value = $visibilityOverride->getProperties($valueObj);
0 ignored issues
show
Unused Code introduced by
The call to Maphper\Lib\VisibilityOverride::getProperties() has too many arguments starting with $valueObj. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

94
        /** @scrutinizer ignore-call */ 
95
        $value = $visibilityOverride->getProperties($valueObj);

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. Please note the @ignore annotation hint above.

Loading history...
95
96
        $value = $this->processFilters($value);
97
        $pk = $this->dataSource->getPrimaryKey();
98
        if ($offset !== null) $value->{$pk[0]} = $offset;
99
        $valueCopy = $this->removeRelations(clone $value, $pk);
100
        $value = $this->entity->wrap($this->relations, $value);
101
        $this->dataSource->save($value);
102
        $visibilityOverride->write($value);
103
        $value = $this->entity->create((array_merge((array)$value, (array)$valueCopy)), $this->relations);
104
        $visibilityOverride->write($value);
105
	}
106
107
	private function removeRelations($obj, $pk) { // Prevent saving ManyMany twice except when pk isn't initially set
108
		foreach ($this->relations as $name => $relation)
109
			if ($relation instanceOf \Maphper\Relation\ManyMany && isset($obj->$name) && !empty($obj->{$pk[0]})) unset($obj->$name);
110
111
		if (empty($obj->{$pk[0]})) unset($obj->{$pk[0]});
112
		return $obj;
113
	}
114
115
	public function offsetExists($offset) {
116
		if (count($this->dataSource->getPrimaryKey()) > 1) return new MultiPk($this, $offset, $this->dataSource->getPrimaryKey());
0 ignored issues
show
Bug Best Practice introduced by
The expression return new Maphper\Multi...ource->getPrimaryKey()) returns the type Maphper\MultiPk which is incompatible with the return type mandated by ArrayAccess::offsetExists() of boolean.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
117
        if (!empty($this->settings['filter'])) {
118
            $data = $this->dataSource->findByField(array_merge($this->settings['filter'], [$this->dataSource->getPrimaryKey()[0] => $offset]));
0 ignored issues
show
Bug introduced by
The call to Maphper\DataSource::findByField() has too few arguments starting with options. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

118
            /** @scrutinizer ignore-call */ 
119
            $data = $this->dataSource->findByField(array_merge($this->settings['filter'], [$this->dataSource->getPrimaryKey()[0] => $offset]));

This check compares calls to functions or methods with their respective definitions. If the call has less 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. Please note the @ignore annotation hint above.

Loading history...
119
            return isset($data[0]);
120
        }
121
		return (bool) $this->dataSource->findById($offset);
122
	}
123
124
	public function offsetUnset($id) {
125
		$this->dataSource->deleteById($id);
126
	}
127
128
	public function offsetGet($offset) {
129
		if (count($this->dataSource->getPrimaryKey()) > 1) return new MultiPk($this, $offset, $this->dataSource->getPrimaryKey());
130
        if (!empty($this->settings['filter'])) {
131
            $data = $this->dataSource->findByField(array_merge($this->settings['filter'], [$this->dataSource->getPrimaryKey()[0] => $offset]));
0 ignored issues
show
Bug introduced by
The call to Maphper\DataSource::findByField() has too few arguments starting with options. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

131
            /** @scrutinizer ignore-call */ 
132
            $data = $this->dataSource->findByField(array_merge($this->settings['filter'], [$this->dataSource->getPrimaryKey()[0] => $offset]));

This check compares calls to functions or methods with their respective definitions. If the call has less 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. Please note the @ignore annotation hint above.

Loading history...
132
            return $this->entity->create(isset($data[0]) ? $data[0] : null, $this->relations);
133
        }
134
		return $this->entity->create($this->dataSource->findById($offset), $this->relations);
135
	}
136
137
	public function __call($method, $args) {
138
		if (array_key_exists($method, $this->settings)) {
139
			$maphper = new Maphper($this->dataSource, $this->settings, $this->relations);
140
			if (is_array($maphper->settings[$method])) $maphper->settings[$method] = $args[0] + $maphper->settings[$method];
141
			else $maphper->settings[$method] = $args[0];
142
			return $maphper;
143
		}
144
		else throw new \Exception('Method Maphper::' . $method . ' does not exist');
145
	}
146
147
	public function findAggregate($function, $field, $group = null) {
148
		return $this->dataSource->findAggregate($function, $field, $group, $this->settings['filter']);
149
	}
150
151
	public function delete() {
152
		$this->dataSource->deleteByField($this->settings['filter'], ['order' => $this->settings['sort'], 'limit' => $this->settings['limit'], 'offset' => $this->settings['offset']]);
153
	}
154
}
155