class Collection
{
public const ASC = 1;
public const DESC = 0;
private $generic;
private $collection = [];
public function __construct(string $class)
{
$this->generic = $class;
}
public function addOne(object $object): self
{
if (!($object instanceof $this->generic)) {
throw new InvalidArgumentException(
'Object mast be instanceof ' . $this->generic . ' class, ' . get_class($object) . ' given'
);
}
$this->collection[] = $object;
return $this;
}
public function addAll(array $objects): self
{
array_map([$this, 'addOne'], $objects);
return $this;
}
public function count(): int
{
return count($this->collection);
}
public function immutable(): self
{
return clone $this;
}
public function getGeneric(): string
{
return $this->generic;
}
private function cmp(string $key, int $order): callable
{
return static function (object $a, object $b) use ($key, $order) {
return $order ? $a->$key <=> $b->$key : $b->$key <=> $a->$key;
};
}
public function where(string $query): self
{
$linq = new Linq($this);
return (new self($this->getGeneric()))->addAll($linq->where($query)->get());
}
public function sort(string $key, int $order = Collection::ASC): self
{
uasort($this->collection, $this->cmp($key, $order));
return $this;
}
public function delete(int $id): void
{
if (array_key_exists($id, $this->collection)) {
unset($this->collection[$id]);
} else {
throw new InvalidArgumentException(
'Key ' . $id . ' is not isset in collection'
);
}
}
public function limit(int $limit, int $offset = 0): self
{
$this->collection = array_slice($this->collection, $offset, $limit);
return $this;
}
public function get(): array
{
return $this->collection;
}
}
class Linq
{
private $collection;
private const CONDITIONS_TYPES = [
'=',
'!=',
'>',
'<',
'<=',
'>=',
];
public function __construct(Collection $collection)
{
$this->collection = $collection;
}
public function where(string $query): self
{
$pattern = '#(?P<field>.*)?(?P<condition>' . implode('|', self::CONDITIONS_TYPES) . ')(?P<value>.*)#is';
preg_match($pattern, $query, $matches);
$count = count($matches);
if (!$count || $count < 4) {
throw new InvalidArgumentException('Not matches ' . '<pre>' . print_r($matches, true) . '</pre>');
}
$args = array_map('trim', $matches);
$array = [
'=' => '===',
'!=' => '!==',
];
return $this->prepare(
$args['field'],
(in_array($args['condition'], $array, true) ? $array[$args['condition']] : $args['condition']),
$args['value']
);
}
private function condition($valFirst, string $condition, $valSecond): bool
{
switch ($condition) {
case '=':
return $valFirst === $valSecond;
case '!=':
return $valFirst !== $valSecond;
case '>':
return $valFirst > $valSecond;
case '<':
return $valFirst < $valSecond;
case '>=':
return $valFirst >= $valSecond;
case '<=':
return $valFirst <= $valSecond;
default:
throw new InvalidArgumentException('Condition not set');
}
}
private function prepare(string $field, string $condition, $value): self
{
$new = new Collection($this->collection->getGeneric());
foreach ($this->collection->get() as $val) {
!$this->condition($val->$field, $condition, $value) ?: $new->addOne($val);
}
$this->collection = $new;
return $this;
}
public function get(): array
{
return $this->collection->get();
}
}
class Changer
{
private $types = [];
private $countTypes;
private $nextType;
public const NEXT = 1;
public const RANDOM = 0;
public static $count = 0;
public function __construct(array $array, int $nextType = self::NEXT)
{
$this->types = $array;
$this->countTypes = count($array);
$this->nextType = $nextType;
}
public function getNext(): string
{
$type = $this->nextType ? $this->types[self::$count++] : $this->types[array_rand($this->types)];
if (self::$count === $this->countTypes) {
self::$count = 0;
}
return $type;
}
}
function getFileList(string $dir): array
{
$array = [];
$fileSPLObjects = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator(realpath($dir)),
RecursiveIteratorIterator::CHILD_FIRST
);
foreach ($fileSPLObjects as $fullFileName => $fileSPLObject) {
if ($fileSPLObject->isFile()) {
$array[] = $fullFileName;
}
}
return $array;
}
// $array = getFileList('./clips');
$array = file('./files.txt', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
$result = [];
foreach ($array as $key => $value) {
$parts = explode(' ', $value);
$params = explode('_', $parts[0]);
$result[$key] = (object)[
'pk' => $key,
'author' => (int)$params[0],
'type1' => $params[1],
'type2' => $params[2],
'name' => $value
];
}
$collection = new Collection('stdClass');
$collection->addAll($result);
$clipList = ['LZ', 'MD', 'BS'];
$special = ['AN', 'DB', 'KB'];
$playlist = [];
$genreList = new Changer($clipList);
$spList = new Changer($special);
for ($i = 0; $i < 640; $i++) {
$stype = 'type1';
if ($i) {
$searchKey = $i % 7 === 0 ? $spList->getNext() : $genreList->getNext();
} else {
$searchKey = $genreList->getNext();
}
$linq = $collection->where($stype . ' = ' . $searchKey);
if ($linq->count()) {
$item = $linq->get()[0];
$collection->delete($item->pk);
} else {
$item->name = 'Не найдено ' . $searchKey;
}
$playlist[] = $item->name;
}
echo '<pre>' . print_r($playlist, true) . '</pre>';
exit;