Completed
Branch master (c68f74)
by Peter
17:03 queued 07:07
created

AssociationRule   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 148
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
wmc 22
lcom 1
cbo 4
dl 0
loc 148
rs 10
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
B addOrder() 0 26 6
A addArrayIfKeyNotExists() 0 6 2
B getResult() 0 24 4
A getOrderIds() 0 4 1
A getProductIds() 0 4 1
A exportModel() 0 9 2
B getOrderProducts() 0 16 5
A getAssociationModel() 0 4 1
1
<?php
2
3
namespace Predictator;
4
5
use Predictator\AssociationRule\AssociationModel;
6
use Predictator\AssociationRule\AssociationModelInterface;
7
use Predictator\AssociationRule\OrderInterface;
8
use Predictator\AssociationRule\ProductInterface;
9
use Predictator\AssociationRule\Result;
10
11
class AssociationRule implements AssociationModelInterface
12
{
13
	/**
14
	 * @var array
15
	 */
16
	private $orderMap = [];
17
18
	/**
19
	 * @var array
20
	 */
21
	private $productMap = [];
22
23
	/**
24
	 * @var ProductInterface[]
25
	 */
26
	private $products = [];
27
28
	/**
29
	 * @param OrderInterface $order
30
	 */
31
	public function addOrder(OrderInterface $order)
32
	{
33
		$orderId = $order->getId();
34
		if (!$orderId) {
35
			throw new \InvalidArgumentException(sprintf('Bad order id: %s', $orderId));
36
		}
37
38
		$this->addArrayIfKeyNotExists($this->orderMap, $orderId);
39
40
		foreach ($order->getOrderProducts() as $orderItem) {
41
			$productId = $orderItem->getId();
42
			if (!$productId) {
43
				throw new \InvalidArgumentException(sprintf('Bad product id: %s', $productId));
44
			}
45
			if (!in_array($productId, $this->orderMap[$orderId])) {
46
				$this->orderMap[$orderId][] = $productId;
47
				$this->products[$productId] = $orderItem;
48
			}
49
50
			$this->addArrayIfKeyNotExists($this->productMap, $productId);
51
52
			if (!in_array($orderId, $this->productMap[$productId])) {
53
				$this->productMap[$productId][] = $orderId;
54
			}
55
		}
56
	}
57
58
	/**
59
	 * @param array $array
60
	 * @param string $key
61
	 */
62
	private function addArrayIfKeyNotExists(array &$array, string $key)
63
	{
64
		if (!isset($array[$key])) {
65
			$array[$key] = [];
66
		}
67
	}
68
69
	/**
70
	 * @param ProductInterface $product
71
	 * @return array|Result[]
72
	 */
73
	public function getResult(ProductInterface $product) : array
74
	{
75
		$productId = $product->getId();
76
		$orderIds = $this->getOrderIds($productId);
77
		$orderIdsCount = count($orderIds);
78
79
		$ordersProducts = $this->getOrderProducts($orderIds, $productId);
80
81
		$associatedProducts = array();
82
		foreach ($ordersProducts as $orderProductId) {
83
			$ratio = (count(array_intersect($this->getOrderIds($orderProductId), $orderIds)) / $orderIdsCount) * 100;
84
			if ($ratio) {
85
				$associatedProducts[$orderProductId] = $ratio;
86
			}
87
		}
88
89
		arsort($associatedProducts);
90
91
		$result = [];
92
		foreach ($associatedProducts as $productId => $ratio) {
93
			$result[] = new Result($this->products[$productId], $ratio);
94
		}
95
		return $result;
96
	}
97
98
	/**
99
	 * @param string $id
100
	 * @return array
101
	 */
102
	private function getOrderIds(string $id): array
103
	{
104
		return $this->productMap[$id] ?? array();
105
	}
106
107
	/**
108
	 * @param string $id
109
	 * @return array
110
	 */
111
	private function getProductIds(string $id): array
112
	{
113
		return $this->orderMap[$id] ?? array();
114
	}
115
116
	/**
117
	 * @return AssociationModelInterface
118
	 */
119
	public function exportModel() : AssociationModelInterface
120
	{
121
		$associationModel = $this->getAssociationModel();
122
		foreach ($this->products as $product) {
123
			$associationModel->addResult($product, $this->getResult($product));
124
		}
125
126
		return $associationModel;
127
	}
128
129
	/**
130
	 * @param array $orderIds
131
	 * @param string $productId
132
	 * @return array
133
	 */
134
	private function getOrderProducts(array $orderIds, string $productId): array
135
	{
136
		$ordersProducts = [];
137
		foreach ($orderIds as $orderId) {
138
			$orderProducts = $this->getProductIds($orderId);
139
			foreach ($orderProducts as $similarOrderProduct) {
140
				if (
141
					!in_array($similarOrderProduct, $ordersProducts) &&
142
					$productId != $similarOrderProduct
143
				) {
144
					$ordersProducts[] = $similarOrderProduct;
145
				}
146
			}
147
		}
148
		return $ordersProducts;
149
	}
150
151
	/**
152
	 * @return AssociationModel
153
	 */
154
	protected function getAssociationModel(): AssociationModel
155
	{
156
		return new AssociationModel();
157
	}
158
}