Skip to content

Commit 272d5a2

Browse files
committed
- Completed version 1.0
1 parent 39d12ec commit 272d5a2

File tree

16 files changed

+430
-16
lines changed

16 files changed

+430
-16
lines changed

.vscode/settings.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"cSpell.words": [
3+
"Publically"
4+
]
5+
}

README.md

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
![Version](https://img.shields.io/github/v/release/jimbo2150/php-comparable)
2+
![License](https://img.shields.io/github/license/jimbo2150/php-comparable)
3+
![PHP Required Version](https://img.shields.io/packagist/dependency-v/jimbo2150/php-comparable/php)
4+
5+
# PHP Comparable Interface & Convenience Trait
6+
7+
A PHP library to allow for comparison of two objects with a comparison operator.
8+
9+
This library allows you to compare two objects using a value within the objects rather than the entirety of the object (the default for PHP).
10+
11+
## Installation
12+
13+
This library is available on Packagist using Composer. Run this command within your composer project directory:
14+
15+
```bash
16+
$ composer require jimbo2150/php-comparable
17+
```
18+
19+
## Usage (private value with convenience trait)
20+
21+
The privately comparable interface requires a protected method, `getComparableValue()`, which does not publically expose the value to be compared:
22+
23+
```php
24+
use Jimbo2150\PhpComparable\Interface\PrivatelyComparable;
25+
use Jimbo2150\PhpComparable\Trait\PrivatelyComparableTrait;
26+
use Jimbo2150\PhpComparable\Enum\Operator;
27+
28+
class Person implements PrivatelyComparable {
29+
use PrivatelyComparableTrait;
30+
31+
public function __construct(private string $name, private int $age)
32+
{
33+
assert($age > 0);
34+
}
35+
36+
public function getComparableValue(): mixed
37+
{
38+
return $this->age;
39+
}
40+
41+
}
42+
43+
$john = new Person('John', 29);
44+
$karen = new Person('Karen', 24);
45+
46+
$john->compareTo($karen); // False, compares by equals (==) by default
47+
$karen->compareTo($john, Operator::from('<')); // True, comparing with less than
48+
```
49+
50+
## Usage (publicly-visible value with convenience trait)
51+
52+
The publically comparable interface requires a public method `getComparableValue()` which exposes the value to be compared:
53+
54+
```php
55+
use Jimbo2150\PhpComparable\Interface\PublicallyComparable;
56+
use Jimbo2150\PhpComparable\Trait\PublicallyComparableTrait;
57+
58+
class GreenFood implements PublicallyComparable {
59+
use PublicallyComparableTrait;
60+
61+
/** The value to compare */
62+
private string $food = 'salad';
63+
64+
public function __construct(private string $type)
65+
{
66+
67+
}
68+
69+
public function getComparableValue(): mixed
70+
{
71+
return [$this->food, $this->type];
72+
}
73+
74+
}
75+
76+
class WheatFood implements PublicallyComparable {
77+
use PublicallyComparableTrait;
78+
79+
/** The value to compare */
80+
private $food = 'pasta';
81+
82+
public function __construct(private string $type)
83+
{
84+
85+
}
86+
87+
public function getComparableValue(): mixed
88+
{
89+
return [$this->food, $this->type];
90+
}
91+
92+
}
93+
94+
$cobbSalad = new GreenFood('cobb');
95+
$chefSalad = new GreenFood('chef');
96+
$pasta = new WheatFood('spaghetti');
97+
$pasta2 = new WheatFood('spaghetti');
98+
99+
$cobbSalad->compareTo($chefSalad); // false
100+
$pasta->compareTo($pasta2); // true
101+
```
102+
103+
## Usage (private value with custom comparison)
104+
105+
You can also implement your own custom compare function by implementing both `compareTo()` and `compareFrom()` methods:
106+
107+
```php
108+
use Jimbo2150\PhpComparable\Interface\PrivatelyComparable;
109+
use Jimbo2150\PhpComparable\Trait\PrivatelyComparableTrait;
110+
111+
class Score implements PrivatelyComparable
112+
{
113+
use PrivatelyComparableTrait;
114+
115+
public const MIN_REQUIRED_SCORE = 1;
116+
117+
public function __construct(private float $score)
118+
{
119+
}
120+
121+
public function compareDiff(PrivatelyComparable|PublicallyComparable $other): bool|int
122+
{
123+
$leftValue = $this->getComparableValue();
124+
$operator = Operator::GREATER_THAN_OR_EQUAL;
125+
$callback = fn (
126+
mixed $rightValue,
127+
Operator $operator,
128+
) => $operator->compare(
129+
$leftValue - $rightValue,
130+
self::MIN_REQUIRED_SCORE
131+
);
132+
133+
if ($other instanceof PublicallyComparable) {
134+
return $callback($other->getComparableValue(), $operator);
135+
}
136+
137+
return $other->compareFrom($callback, $operator);
138+
}
139+
140+
public function getComparableValue(): mixed
141+
{
142+
return $this->score;
143+
}
144+
}
145+
146+
$score1 = new Score(2.4);
147+
$score2 = new Score(0.7);
148+
$score3 = new Score(0.2);
149+
150+
$score1->compareDiff($score2); // True, score is >= 1
151+
$score2->compareDiff($score3); // False, score is less than 1
152+
```

src/Interface/Comparable.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,4 @@
99
interface Comparable
1010
{
1111
public function compareTo(Comparable $other, Operator $operator = Operator::EQUAL): bool|int;
12-
13-
public function compareFrom(mixed $leftValue, Operator $operator = Operator::EQUAL): bool|int;
1412
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Jimbo2150\PhpComparable\Interface;
6+
7+
use Jimbo2150\PhpComparable\Enum\Operator;
8+
9+
interface PrivatelyComparable extends Comparable
10+
{
11+
public function compareFrom(mixed $leftValue, Operator $operator = Operator::EQUAL): bool|int;
12+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Jimbo2150\PhpComparable\Interface;
6+
7+
interface PublicallyComparable extends Comparable
8+
{
9+
public function getComparableValue(): mixed;
10+
}

src/Trait/ComparableTrait.php renamed to src/Trait/PrivatelyComparableTrait.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,17 @@
55
namespace Jimbo2150\PhpComparable\Trait;
66

77
use Jimbo2150\PhpComparable\Enum\Operator;
8-
use Jimbo2150\PhpComparable\Interface\Comparable;
98

10-
trait ComparableTrait
9+
trait PrivatelyComparableTrait
1110
{
12-
public function compareTo(Comparable $other, Operator $operator = Operator::EQUAL): bool|int
13-
{
14-
return $other->compareFrom($this->getComparableValue(), $operator);
15-
}
11+
use PublicallyComparableTrait;
1612

1713
public function compareFrom(mixed $leftValue, Operator $operator = Operator::EQUAL): bool|int
1814
{
15+
if ($leftValue instanceof \Closure) {
16+
return $leftValue($this->getComparableValue(), $operator);
17+
}
18+
1919
return $operator->compare($leftValue, $this->getComparableValue());
2020
}
2121

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Jimbo2150\PhpComparable\Trait;
6+
7+
use Jimbo2150\PhpComparable\Enum\Operator;
8+
use Jimbo2150\PhpComparable\Interface\Comparable;
9+
use Jimbo2150\PhpComparable\Interface\PublicallyComparable;
10+
11+
trait PublicallyComparableTrait
12+
{
13+
public function compareTo(Comparable $other, Operator $operator = Operator::EQUAL): bool|int
14+
{
15+
if ($other instanceof PublicallyComparable) {
16+
return $operator->compare(
17+
$this->getComparableValue(), $other->getComparableValue()
18+
);
19+
}
20+
21+
return $other->compareFrom($this->getComparableValue(), $operator);
22+
}
23+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Jimbo2150\PhpComparable\Tests\Mocks\Comparable\Examples;
6+
7+
use Jimbo2150\PhpComparable\Interface\PublicallyComparable;
8+
use Jimbo2150\PhpComparable\Trait\PublicallyComparableTrait;
9+
10+
class GreenFood implements PublicallyComparable
11+
{
12+
use PublicallyComparableTrait;
13+
14+
/** The value to compare */
15+
private string $food = 'salad';
16+
17+
public function __construct(private string $type)
18+
{
19+
}
20+
21+
public function getComparableValue(): mixed
22+
{
23+
return [$this->food, $this->type];
24+
}
25+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Jimbo2150\PhpComparable\Tests\Mocks\Comparable\Examples;
6+
7+
use Jimbo2150\PhpComparable\Interface\PrivatelyComparable;
8+
use Jimbo2150\PhpComparable\Trait\PrivatelyComparableTrait;
9+
10+
class Person implements PrivatelyComparable
11+
{
12+
use PrivatelyComparableTrait;
13+
14+
public function __construct(private string $name, private int $age)
15+
{
16+
assert($age > 0);
17+
}
18+
19+
public function getComparableValue(): mixed
20+
{
21+
return $this->age;
22+
}
23+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Jimbo2150\PhpComparable\Tests\Mocks\Comparable\Examples;
6+
7+
use Jimbo2150\PhpComparable\Enum\Operator;
8+
use Jimbo2150\PhpComparable\Interface\PrivatelyComparable;
9+
use Jimbo2150\PhpComparable\Interface\PublicallyComparable;
10+
use Jimbo2150\PhpComparable\Trait\PrivatelyComparableTrait;
11+
12+
class Score implements PrivatelyComparable
13+
{
14+
use PrivatelyComparableTrait;
15+
16+
public const MIN_REQUIRED_SCORE = 1;
17+
18+
public function __construct(private float $score)
19+
{
20+
}
21+
22+
public function compareDiff(PrivatelyComparable|PublicallyComparable $other): bool|int
23+
{
24+
$leftValue = $this->getComparableValue();
25+
$operator = Operator::GREATER_THAN_OR_EQUAL;
26+
$callback = fn (
27+
mixed $rightValue,
28+
Operator $operator,
29+
): bool|int => $operator->compare(
30+
$leftValue - $rightValue,
31+
self::MIN_REQUIRED_SCORE
32+
);
33+
34+
if ($other instanceof PublicallyComparable) {
35+
return $callback($other->getComparableValue(), $operator);
36+
}
37+
38+
return $other->compareFrom($callback, $operator);
39+
}
40+
41+
public function getComparableValue(): mixed
42+
{
43+
return $this->score;
44+
}
45+
}

0 commit comments

Comments
 (0)