AssociationRule::addArrayIfKeyNotExists()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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