Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
20 / 20
100.00% covered (success)
100.00%
2 / 2
CRAP
100.00% covered (success)
100.00%
1 / 1
ArticleCorrelationAffinity
100.00% covered (success)
100.00%
20 / 20
100.00% covered (success)
100.00%
2 / 2
16
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
13
 getAffinity
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2/**
3 * Jingga
4 *
5 * PHP Version 8.1
6 *
7 * @package   phpOMS\Business\Recommendation
8 * @copyright Dennis Eichhorn
9 * @license   OMS License 2.0
10 * @version   1.0.0
11 * @link      https://jingga.app
12 */
13declare(strict_types=1);
14
15namespace phpOMS\Business\Recommendation;
16
17use phpOMS\Math\Statistic\Correlation;
18
19/**
20 * Article Affinity
21 *
22 * You can consider this as a "purchased with" or "customers also purchased" algorithm
23 *
24 * @package phpOMS\Business\Recommendation
25 * @license OMS License 2.0
26 * @link    https://jingga.app
27 * @since   1.0.0
28 */
29final class ArticleCorrelationAffinity
30{
31    /**
32     * Affinity between items
33     *
34     * @var array[]
35     * @since 1.0.0
36     */
37    private array $affinity = [];
38
39    /**
40     * Item order behaviour (when are which items ordered)
41     *
42     * In tearms of the pearson correlation these are our random variables
43     *
44     * @var array
45     * @since 1.0.0
46     */
47    private array $items = [];
48
49    /**
50     * Constructor
51     *
52     * @param array[] $orders           Array of orders which contains as elements the items ordered in the respective order
53     * @param bool    $considerQuantity NOT_IMPLEMENTED!!! Should the quantity be considered
54     *
55     * @since 1.0.0
56     */
57    public function __construct(array $orders, bool $considerQuantity = false)
58    {
59        // find all possible items
60        $possibleItems = [];
61        foreach ($orders as $items) {
62            foreach ($items as $item => $quantity) {
63                if (!\in_array($item, $possibleItems)) {
64                    $possibleItems[] = $item;
65                }
66            }
67        }
68
69        // create the random variables
70        foreach ($orders as $items) {
71            foreach ($possibleItems as $item) {
72                $this->items[$item][] = $considerQuantity ? $items[$item] : (int) ($items[$item] > 0);
73            }
74        }
75
76        // create the affinity table
77        foreach ($possibleItems as $item1) {
78            foreach ($possibleItems as $item2) {
79                if ($item1 !== $item2
80                    && !isset($this->affinity[$item1][$item2])
81                    && !isset($this->affinity[$item2][$item1])
82                ) {
83                    $this->affinity[$item1][$item2] = Correlation::bravaisPersonCorrelationCoefficientPopulation($this->items[$item1], $this->items[$item2]);
84                    $this->affinity[$item2][$item1] = $this->affinity[$item1][$item2]; // php automatically creates references!
85                }
86            }
87        }
88
89        // sort correlations
90        foreach ($possibleItems as $item) {
91            \arsort($this->affinity[$item]);
92        }
93    }
94
95    /**
96     * Get the affinity between items
97     *
98     * @param mixed $item       Item to check for possible affinities
99     * @param int   $resultSize How many top matches should be returned
100     *
101     * @return array
102     *
103     * @since 1.0.0
104     */
105    public function getAffinity(mixed $item, int $resultSize = 0) : array
106    {
107        if (!isset($this->affinity[$item])) {
108            return [];
109        }
110
111        return $resultSize < 1 ? $this->affinity[$item] : \array_slice($this->affinity[$item], 0, $resultSize);
112    }
113}