5 Commits

Author SHA1 Message Date
b6f9698e59 20250214
+ [TwoDimSize]: Класс, описывающий двумерный размер.

+ [HashGetType]: Перечисление типов получения хэша.

+ [FileHash]: Класс для работы с хэшем файла или строки.
2025-02-14 16:41:50 +03:00
3fd75364a1 20250208
+ [ObjectArray]: Добавлена функция Skip для пропуска $offset элементов массива.
+ [ObjectArray]: Добавлена функция Take для получения $count элементов массива.
+ [ObjectArray]: Добавлена функция SkipAndTake для получения $count элементов массива, начиная с индекса $startFrom.
2025-02-08 17:57:09 +03:00
f247253f9e Merge remote-tracking branch 'origin/master' 2025-02-05 23:46:12 +03:00
c623b435e9 20250205-1
+ [ObjectArray]: Добавлена функция First для получения первого объекта из массива объектов.

+ [ObjectArray]: Добавлена функция Last для получения последнего объекта из массива объектов.
2025-02-05 23:46:00 +03:00
c32c8643ee 20250205
+ [ObjectArray]: Добавлена функция GetColumnCallback для лучшего получения колонки.
2025-02-05 18:54:56 +03:00
7 changed files with 622 additions and 6 deletions

View File

@@ -0,0 +1,79 @@
<?php
namespace goodboyalex\php_components_pack\classes;
use goodboyalex\php_components_pack\enums\HashGetType;
use goodboyalex\php_components_pack\extensions\StringExtension;
/**
* Класс для работы с хэшем файла или строки.
*
* @author Александр Бабаев
* @package php_components_pack
* @version 1.0
* @since 1.0.5
*/
final class FileHash
{
/**
* @var string $Hash Хэш файла.
*/
private(set) string $Hash;
/**
* @var HashGetType Тип получения хэша.
*/
public HashGetType $HashBy;
/**
* Конструктор.
*
* @param string $str Строка или имя файла.
* @param HashGetType $HashBy Тип получения хэша.
*/
public function __construct (string $str = "", HashGetType $HashBy = HashGetType::ByString)
{
$this->HashBy = $HashBy;
$this->Hash = match ($HashBy) {
HashGetType::ByString => $this->pGetHash($str),
HashGetType::ByFile => $this->pGetFileHash($str)
};
}
/**
* Получение хэша файла по строке.
*
* @param string $str Строка.
*
* @return string Хэш строки.
*/
private function pGetHash (string $str): string
{
return hash('sha256', $str);
}
/**
* Получение хэша файла по имени файла.
*
* @param string $fileName Имя файла.
*
* @return string Хэш файла.
*/
private function pGetFileHash (string $fileName): string
{
return hash_file('sha256', $fileName);
}
/**
* Сравнивает текущий хэш с хэшем <code>otherHash</code> и выдаёт <code>true</code>, если совпадают, и
* <code>false</code>, если не совпадают.
*
* @param FileHash $otherHash Другой хэш.
*
* @return bool <code>true</code>, если совпадают, и <code>false</code>, если не совпадают.
*/
public function IsEqual (FileHash $otherHash): bool
{
return StringExtension::Compare($this->Hash, $otherHash->Hash, true) === 0;
}
}

View File

@@ -0,0 +1,183 @@
<?php
namespace goodboyalex\php_components_pack\classes;
use Exception;
use goodboyalex\php_components_pack\interfaces\ISerializable;
/**
* Класс, описывающий двумерный размер.
*
* @author Александр Бабаев
* @package php_components_pack
* @version 1.0
* @since 1.0.5
*/
final class TwoDimSize implements ISerializable
{
/**
* Разделитель частей по умолчанию.
*/
public const string DEFAULT_DELIMITER = ':';
/**
* @var bool $NoNegativeValues Значения не должны быть отрицательными.
*/
public bool $NoNegativeValues = true;
/**
* @var int $Width Длина (публичная)
*/
public int $Width {
get {
return $this->pWidth;
}
set {
$this->pWidth = $this->NoNegativeValues ? max($value, 0) : $value;
}
}
/**
* @var int $Height Ширина (публичная)
*/
public int $Height {
get {
return $this->pHeight;
}
set {
$this->pHeight = $this->NoNegativeValues ? max($value, 0) : $value;
}
}
/**
* @var int $pWidth Длина (приватное)
*/
private int $pWidth = 0;
/**
* @var int $pHeight Ширина (приватное)
*/
private int $pHeight = 0;
/**
* Конструктор.
*
* @param int $width Длина.
* @param int $height Ширина.
* @param bool $noNegativeValues Значения не должны быть отрицательными.
*/
public function __construct (int $width = 0, int $height = 0, bool $noNegativeValues = true)
{
$this->Width = $width;
$this->Height = $height;
$this->NoNegativeValues = $noNegativeValues;
}
/**
* Конвертация в строку (магический метод).
*
* @return string Строка.
*/
public function __toString (): string
{
return $this->AsString();
}
/**
* Конвертация в строку (расширенный метод).
*
* @param string $delimiter Делитель размера.
*
* @return string Строка.
*/
public function AsString (string $delimiter = self::DEFAULT_DELIMITER): string
{
return $this->Width . $delimiter . $this->Height;
}
/**
* @inheritDoc
*/
public function Serialize (): string
{
// Получаю строковое значение
$str = $this->AsString("x");
// Добавляю допустимы ли отрицательные значения
$str .= $this->NoNegativeValues ? "x1" : "x0";
// Возвращаю строку
return $str;
}
/**
* @inheritDoc
*/
public function UnSerialize (string $serialized): void
{
// Десериализую строку
$result = explode("x", $serialized);
// Присваиваю параметры
$this->NoNegativeValues = $result[2] === "1";
// Объединяю длину и ширину
$tdSize = $result[0] . self::DEFAULT_DELIMITER . $result[1];
// Пытаюсь получить размер
try {
$result = self::Parse($tdSize, noNegativeValues: $this->NoNegativeValues);
}
catch (Exception $e) {
$result = new TwoDimSize(noNegativeValues: $this->NoNegativeValues);
}
// Присваиваю длину
$this->Width = $result->Width;
// Присваиваю ширину
$this->Height = $result->Height;
}
/**
* Получение размера из строки.
*
* @param string $str Строка.
* @param string $delimiter Разделитель размеров.
* @param bool $noNegativeValues Значения не должны быть отрицательными.
*
* @return TwoDimSize Модель размеров.
* @throws Exception Если в строке <code>str</code> не содержится символа <code>delimiter</code> или таких
* разделителей слишком много.
*/
public static function Parse (string $str, string $delimiter = self::DEFAULT_DELIMITER,
bool $noNegativeValues = true): TwoDimSize
{
// Разделяю значения
$splitSizes = explode($delimiter, $str);
// Проверяю, что массив имеет ровно два элемента
if (count($splitSizes) != 2)
throw new Exception(sprintf("Похоже, что в строке %s не содержится символа «%s» или таких разделителей слишком много!",
$str, $delimiter));
// Пытаюсь получить длину
$width = filter_var($splitSizes[0], FILTER_VALIDATE_INT);
// Если не удалось получить длину
if ($width === false)
$width = 0;
// Пытаюсь получить ширину
$height = filter_var($splitSizes[1], FILTER_VALIDATE_INT);
// Если не удалось получить ширину
if ($height === false)
$height = 0;
// Вывожу значение
return new TwoDimSize($width, $height, $noNegativeValues);
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace goodboyalex\php_components_pack\enums;
use goodboyalex\php_components_pack\traits\EnumExtensionsTrait;
/**
* Перечисление типов получения хэша.
*
* @author Александр Бабаев
* @package php_components_pack
* @version 1.0
* @since 1.0.5
*/
enum HashGetType: int
{
// Подключаю расширение для Enum
use EnumExtensionsTrait;
/**
* По строке.
*/
case ByString = 0;
/**
* По файлу.
*/
case ByFile = 1;
}

View File

@@ -143,6 +143,22 @@ trait ObjectArrayLINQTrait
* @return array Ассоциированный массив с результатом выборки. * @return array Ассоциированный массив с результатом выборки.
*/ */
public function GetColumn (string $column, ?callable $wherePredicate = null): array public function GetColumn (string $column, ?callable $wherePredicate = null): array
{
return $this->GetColumnCallback(fn ($item) => property_exists($item, $column) ? $item->$column : null,
$wherePredicate);
}
/**
* Получает колонку в массиве данных.
*
* @param callable $columnPredicate Функция <code>fn (mixed $item): mixed</code>, возвращающая значение элемента
* колонки.
* @param callable|null $wherePredicate Условие выборки <code>fn (mixed $item): bool</code>, которое проверяет,
* подходит элемент или нет.
*
* @return array Ассоциированный массив с результатом выборки.
*/
public function GetColumnCallback (callable $columnPredicate, ?callable $wherePredicate = null): array
{ {
// Создаю результат // Создаю результат
$result = []; $result = [];
@@ -153,16 +169,12 @@ trait ObjectArrayLINQTrait
if (!is_object($item)) if (!is_object($item))
continue; continue;
// - пропускаю не имеющие требуемого свойства
if (!property_exists($item, $column))
continue;
// - пропускаю не удовлетворяющие условию // - пропускаю не удовлетворяющие условию
if ($wherePredicate !== null && !$wherePredicate($item)) if ($wherePredicate !== null && !$wherePredicate($item))
continue; continue;
// - добавляю значение свойства в результат // - добавляю значение свойства в результат
$result[] = $item->$column; $result[] = $columnPredicate($item);
} }
// Возвращаю результат // Возвращаю результат
@@ -172,7 +184,7 @@ trait ObjectArrayLINQTrait
/** /**
* Заменяет данные в строке\ массива. * Заменяет данные в строке\ массива.
* *
* @param mixed $setItem Заменяемые элемент. * @param array $setItems Заменяемые элементы.
* @param callable $wherePredicate Условие выборки <code>fn (mixed $item): bool</code>, которое проверяет, * @param callable $wherePredicate Условие выборки <code>fn (mixed $item): bool</code>, которое проверяет,
* подходит элемент или нет. * подходит элемент или нет.
* *
@@ -280,4 +292,91 @@ trait ObjectArrayLINQTrait
// Возвращаем результат // Возвращаем результат
return $result; return $result;
} }
/**
* Возвращает первый элемент массива или значение по умолчанию.
*
* @param mixed|null $default Значение по умолчанию. По умолчанию, null.
*
* @return mixed|null Возвращает первый элемент массива или значение по умолчанию.
*/
public function First (mixed $default = null): mixed
{
// Получение первого элемента
$firstElement = reset($this->Container);
// Проверяем получение
if ($firstElement === false)
// - возвращаем значение по умолчанию
return $default;
// Возвращаем первый элемент
return $firstElement;
}
/**
* Возвращает последний элемент массива или значение по умолчанию.
*
* @param mixed|null $default Значение по умолчанию. По умолчанию, null.
*
* @return mixed|null Возвращает последний элемент массива или значение по умолчанию.
*/
public function Last (mixed $default = null): mixed
{
// Получение последнего элемента
$lastElement = end($this->Container);
// Проверяем получение
if ($lastElement === false)
// - возвращаем значение по умолчанию
return $default;
// Возвращаем первый элемент
return $lastElement;
}
/**
* Пропускает первые $count элементов массива. Возвращает новый массив.
*
* ВНИМАНИЕ: рекомендуется использовать ТОЛЬКО на отсортированных массивах.
*
* @param int $count Количество элементов, которые необходимо обрезать с начала массива.
*
* @return ObjectArray Возвращает новый массив, состоящий из элементов, начиная с $count + 1 элемента.
*/
public function Skip (int $count): ObjectArray
{
return new ObjectArray(array_slice($this->Container, $count));
}
/**
* Получает первые $count элементов массива. Возвращает новый массив.
*
* ВНИМАНИЕ: рекомендуется использовать ТОЛЬКО на отсортированных массивах.
*
* @param int $count Количество элементов, которые необходимо получить с начала массива.
*
* @return ObjectArray Возвращает новый массив, состоящий из первых $count элементов старого массива.
*/
public function Take (int $count): ObjectArray
{
return new ObjectArray(array_slice($this->Container, 0, $count));
}
/**
* Совмещает в себе две функции, которые одновременно применяет к массиву: Skip ($startFrom) и Take ($count).
* Возвращает новый массив.
*
* ВНИМАНИЕ: рекомендуется использовать ТОЛЬКО на отсортированных массивах.
*
* @param int $startFrom Начальный индекс массива, с которого нужно получить.
* @param int $count Количество элементов, которые необходимо получить.
*
* @return ObjectArray Возвращает новый массив, состоящий из $count элементов старого массива, начиная с индекса
* $startFrom.
*/
public function SkipAndTake (int $startFrom, int $count): ObjectArray
{
return new ObjectArray(array_slice($this->Container, $startFrom, $count));
}
} }

View File

@@ -0,0 +1,42 @@
<?php
namespace goodboyalex\php_components_pack\tests\classes;
use goodboyalex\php_components_pack\classes\FileHash;
use goodboyalex\php_components_pack\enums\HashGetType;
use PHPUnit\Framework\TestCase;
class FileHashTest extends TestCase
{
public function test__construct ()
{
$this->PrepareForTest();
$fileHash = new FileHash("Тестовое слово");
$this->assertEquals("000e22f7ba01ae35f781bc3069038110c46593306cafef6b489f7c83b34629b7", $fileHash->Hash);
$fileHash = new FileHash(__DIR__ . '/../data/A.php', HashGetType::ByFile);
$this->assertEquals("fc8dad93af5de5dd7c7d64e04faadfa22557e577a1538737fe462a5f78699fa2", $fileHash->Hash);
$fileHash = new FileHash(__DIR__ . '/../data/B.php', HashGetType::ByFile);
$this->assertEquals("f419262e46e9461517af46d0c1e4faf25f38990bb50351b691d84f1ad51f2299", $fileHash->Hash);
}
private function PrepareForTest (): void
{
require_once __DIR__ . '/../../sources/traits/EnumExtensionsTrait.php';
require_once __DIR__ . '/../../sources/enums/HashGetType.php';
require_once __DIR__ . '/../../sources/extensions/StringExtension.php';
require_once __DIR__ . '/../../sources/classes/FileHash.php';
}
public function testIsEqual ()
{
$this->PrepareForTest();
$fileHash = new FileHash("Тестовое слово");
$this->assertTrue($fileHash->IsEqual(new FileHash("Тестовое слово")));
$this->assertFalse($fileHash->IsEqual(new FileHash("Тестовое слово2")));
}
}

View File

@@ -312,4 +312,122 @@ class ObjectArrayTest extends TestCase
$this->assertEquals('a', $sr->a); $this->assertEquals('a', $sr->a);
$this->assertTrue($sr->c); $this->assertTrue($sr->c);
} }
public function testFirst ()
{
$this->PrepareForTest();
$array = [
new A("a", 3, true),
new A("c", 2, false),
new A("b", 1, true),
];
$a_Array = new ObjectArray($array);
$sr = $a_Array->First();
$this->assertNotNull($sr);
$this->assertInstanceOf(A::class, $sr);
$this->assertEquals('a', $sr->a);
$this->assertTrue($sr->c);
}
public function testLast ()
{
$this->PrepareForTest();
$array = [
new A("a", 3, true),
new A("c", 2, false),
new A("b", 1, true),
];
$a_Array = new ObjectArray($array);
$sr = $a_Array->Last();
$this->assertNotNull($sr);
$this->assertInstanceOf(A::class, $sr);
$this->assertEquals('b', $sr->a);
$this->assertTrue($sr->c);
}
public function testSkip ()
{
$this->PrepareForTest();
$array = [
new A("a", 3, true),
new A("c", 2, false),
new A("b", 1, true),
new A("d", 5, true),
new A("e", 4, true),
new A("f", 6, false)
];
$a_Array = new ObjectArray($array);
// Для начала отсортируем по b
$a_Array->Sort("b");
$b_Array = $a_Array->Skip(2);
$this->assertNotNull($b_Array);
$this->assertEquals(4, $b_Array->Count());
$this->assertEquals(3, $b_Array->First()->b);
$this->assertEquals(6, $b_Array->Last()->b);
}
public function testTake ()
{
$this->PrepareForTest();
$array = [
new A("a", 3, true),
new A("c", 2, false),
new A("b", 1, true),
new A("d", 5, true),
new A("e", 4, true),
new A("f", 6, false)
];
$a_Array = new ObjectArray($array);
// Для начала отсортируем по b
$a_Array->Sort("b");
$b_Array = $a_Array->Take(3);
$this->assertNotNull($b_Array);
$this->assertEquals(3, $b_Array->Count());
$this->assertEquals(1, $b_Array->First()->b);
$this->assertEquals(3, $b_Array->Last()->b);
}
public function testSkipAndTake ()
{
$this->PrepareForTest();
$array = [
new A("a", 3, true),
new A("c", 2, false),
new A("b", 1, true),
new A("d", 5, true),
new A("e", 4, true),
new A("f", 6, false)
];
$a_Array = new ObjectArray($array);
// Для начала отсортируем по b
$a_Array->Sort("b");
$b_Array = $a_Array->SkipAndTake(2, 3);
$this->assertNotNull($b_Array);
$this->assertEquals(3, $b_Array->Count());
$this->assertEquals(3, $b_Array->First()->b);
$this->assertEquals(5, $b_Array->Last()->b);
}
} }

View File

@@ -0,0 +1,66 @@
<?php
namespace goodboyalex\php_components_pack\tests\classes;
use Exception;
use goodboyalex\php_components_pack\classes\TwoDimSize;
use PHPUnit\Framework\TestCase;
class TwoDimSizeTest extends TestCase
{
public function testParse ()
{
$this->PrepareForTest();
try {
$size = TwoDimSize::Parse("10x20", "x");
}
catch (Exception $e) {
$this->fail($e->getMessage());
}
$this->assertEquals(10, $size->Width);
$this->assertEquals(20, $size->Height);
}
private function PrepareForTest (): void
{
require_once __DIR__ . '/../../sources/interfaces/ISerializable.php';
require_once __DIR__ . '/../../sources/classes/TwoDimSize.php';
}
public function test__toString ()
{
$this->PrepareForTest();
$size = new TwoDimSize(10, 20);
$this->assertEquals("10:20", $size->__toString());
}
public function testSerialize ()
{
$this->PrepareForTest();
$size = new TwoDimSize(10, 20);
$this->assertEquals("10x20x1", $size->Serialize());
}
public function testUnSerialize ()
{
$this->PrepareForTest();
$serialized = "10x20x1";
$size = new TwoDimSize();
$size->UnSerialize($serialized);
$this->assertEquals(10, $size->Width);
$this->assertEquals(20, $size->Height);
$this->assertTrue($size->NoNegativeValues);
}
}