Verification: a143cc29221c9be0

Php array find all keys

Допустим у нас есть массив

$arr = [
	2 => 'Виноград',
	1 => 'Арбуз',
	3 => 'Банан',
];

Он неправильно отсортирован, как видите ключи (1,2,3) и значения (виноград, арбуз, банан) идут не по порядку. Давайте это исправим:

Сортировка массива по ключу

ksort($arr); // По возрастанию
krsort($arr); // По убыванию

Сортировка массива по значению

sort($arr);// По возрастанию 
asort($arr);// По возрастанию, сохраняет ключи
rsort($arr); // По убыванию
arsort($arr); // По убыванию, сохраняет ключи
array_reverse($arr); // От конца к началу
array_reverse($arr, true); // От конца к началу, сохраняет ключи
shuffle($arr); // Перемешать массив в случайном порядке

Свои способы сортировки

Если предложенные способы сортировки вам не подходят, то можно создать свой способ сортировки ключей и значений массивов. Для этого есть 3 функции uasort, uksort и usort. С их помощью мы можем задать свою callback функцию, которая будет сравнивать элементы между собой и определять какой из них "больше" и какой "меньше".

  • uasort — Сортирует массив, используя пользовательскую функцию для сравнения элементов с сохранением ключей
  • uksort — Сортирует массив по ключам, используя пользовательскую функцию для сравнения ключей
  • usort — Сортирует массив по значениям используя пользовательскую функцию для сравнения элементов

Принцип работы следующий, мы создаем callback функцию сравнения по какому-то необычному признаку. Она должна сравнивать элементы и возвращать одно из трех значений: -1, 0 или 1

Давайте рассмотрим как они работают напримере функции uasort, которая сравнивает значения с сохранением ключей.

// Наша функция сравнения
$callbackCmpFunction = function cmp($a, $b) {
    if ($a == $b) { // если 2 значения массива равны
        return 0; // вернем 0
    }
    return ($a 
  • -1 - возвращается, когда элемент, который слева больше правого
  • 0 - когда элементы равны
  • 1 - когда правый больше левого

Применить нашу новую функцию можно так:

// Сортируемый массив
$array = array('a' => 4, 'b' => 8, 'c' => -1, 'd' => -9, 'e' => 2, 'f' => 5, 'g' => 3, 'h' => -4);
print_r($array);

// Сортируем и выводим получившийся массив
uasort($array, $callbackCmpFunction); // вторым параметром указываем нашу callback функцию
print_r($array);

Сохранение ключей означает, что каждый ключ как бы привязан к своему значению.

Функции без сохранения ключей sort и rsort, сбрасывают ключи и они начинают идти по порядку (0, 1, 2, ...)

Иногда бывает полезно одно, иногда - другое. В зависимости от задачи.

Если сортировка не дает ожидаемый результат, то изучите флаги сортировки. По умолчанию используется обычный тип сортировки SORT_REGULAR

Флаги типа сортировки:

  • SORT_REGULAR - обычное сравнение элементов; подробности описаны в разделе операторы сравнения
  • SORT_NUMERIC - числовое сравнение элементов
  • SORT_STRING - строковое сравнение элементов
  • SORT_LOCALE_STRING - сравнение элементов как строки на основе текущего языкового стандарта. Используется языковой стандарт, который можно изменить с помощью setlocale()
  • SORT_NATURAL - сравнение элементов как строки, используя "естественный порядок", например natsort()
  • SORT_FLAG_CASE - можно объединять (побитовое ИЛИ) с SORT_STRING или SORT_NATURAL для сортировки строк без учёта регистра. Пример: sort($arr, SORT_NATURAL | SORT_FLAG_CASE)

Флаг сортировки передается в функцию сортировки, например так:

sort($arr, SORT_STRING); 

Подробнее о том, как работают флаги сортировки и зачем они нужны.

Сортировка многомерных массивов

Создадим функцию, которая нам поможет в сортировке массивов

// создадим функцию которая нам поможет в сортировке массивов
function array_orderby()
{
    $args = func_get_args();
    $data = array_shift($args);
    foreach ($args as $n => $field) {
        if (is_string($field)) {
            $tmp = array();
            foreach ($data as $key => $row)
                $tmp[$key] = $row[$field];
            $args[$n] = $tmp;
            }
    }
    $args[] = &$data;
    call_user_func_array('array_multisort', $args);
    return array_pop($args);
}

Пример работы этой функции array_orderby():

$data = [
	['volume' => 67, 'edition' => 2],
	['volume' => 86, 'edition' => 1],
	['volume' => 85, 'edition' => 6],
	['volume' => 98, 'edition' => 2],
	['volume' => 86, 'edition' => 6],
	['volume' => 67, 'edition' => 7],
];
	
// Сортируем массив $data сначала по volume, затем по edition
$sorted = array_orderby($data, 'volume', SORT_DESC, 'edition', SORT_ASC);
// SORT_ASC - по возрастанию
// SORT_DESC - по убыванию

print_r($sorted); // выводим результат

Если вам нужно что-то совсем уж специфическое при сортировки многомерных массивов

Можете создать и другие callback функции сортировки самостоятельно.

$data = [
	['volume' => 67, 'edition' => 2],
	['volume' => 86, 'edition' => 1],
	['volume' => 85, 'edition' => 6],
	['volume' => 98, 'edition' => 2],
	['volume' => 86, 'edition' => 6],
	['volume' => 67, 'edition' => 7],
];

// Создадим 2 функции
function cmp_function($a, $b){ // volume по возрастанию
	return ($a['volume'] > $b['volume']);
}

function cmp_function_desc($a, $b){ // volume по убыванию
	return ($a['volume'] 


Определение и использование

Метод find() возвращает значение первого элемента массива, прошедшего тест (предоставляется в виде функции).

Метод find() выполняет функцию один раз для каждого элемента, присутствующего в массиве:

  • Если он находит элемент массива, где функция возвращает значение true, функция find() возвращает значение этого элемента массива (и не проверяет остальные значения)
  • В противном случае он возвращает undefined

Примечание: find() не выполняет функцию для пустых массивов.

Примечание: find() не изменяет исходный массив.


Поддержка браузера

Цыфры в таблице указывают первую версию браузера, которая полностью поддерживает этот метод.

Метод
find() 45.0 12.0 25.0 7.1 32.0

Синтаксис

array.find(function(currentValue, index, arr),thisValue)

Значения параметров

Параметр Описание
function(currentValue, index, arr) Требуемый. Функция, выполняемая для каждого элемента массива.
Аргументы функции:
Аргумент Описание
currentValue Требуемый. Значение текущего элемента
index Необязательный. Индекс массива текущего элемента
arr Необязательный. Объект массива, к которому принадлежит текущий элемент
thisValue Необязательный. Значение, которое должно быть передано функции, которая будет использоваться в качестве ее "этого" значения.
Если этот параметр пуст, то значение "не определено" и будет принят в качестве "этого" значения


Технические детали

Возвращаемое значение: Возвращает значение элемента массива, если какой-либо из элементов массива проходит тест, в противном случае он возвращает undefined
Версия JavaScript: ECMAScript 6

Еще примеры

Пример

Получить значение первого элемента в массиве, который имеет значение выше определенного числа:

Минимальный возраст:


Любого указанного возраста:

function checkAdult(age) {
  return age >= document.getElementById("ageToCheck").value;
}

function myFunction() {
  document.getElementById("demo").innerHTML = ages.find(checkAdult);
}

Попробуйте сами »


Введение

При создании API вам может потребоваться слой преобразования, который находится между вашими моделями Eloquent и ответами JSON, которые фактически возвращаются пользователям вашего приложения. Например, бывает необходимо отображать определенные атрибуты только для некоторого сегмента пользователей, а не для всех, или бывает необходимо всегда отображать определенные отношения в JSON-представление ваших моделей. Классы ресурсов Eloquent позволяют легко и выразительно преобразовывать модели и коллекции моделей в JSON.

Конечно, вы всегда можете преобразовать модели или коллекции Eloquent в JSON, используя их методы toJson; однако ресурсы Eloquent обеспечивают более детальный и надежный контроль над сериализацией в JSON ваших моделей и их отношений.

Генерация ресурсов

Ресурсы расширяют класс Illuminate\Http\Resources\Json\JsonResource. Чтобы сгенерировать новый ресурс, используйте команду make:resource Artisan. Эта команда поместит новый класс ресурса в каталог app/Http/Resources вашего приложения:

php artisan make:resource UserResource

Генерация коллекций ресурса

Помимо создания ресурсов, преобразующих отдельные модели, вы можете создавать ресурсы, отвечающие за преобразование коллекций моделей. Это позволяет вашим ответам JSON включать ссылки и другую метаинформацию, имеющую отношение ко всей коллекции конкретного ресурса.

Чтобы сгенерировать новую коллекцию ресурса, вы должны использовать флаг --collection при создании ресурса. Или включение слова Collection в имя ресурса укажет Laravel, что он должен создать коллекцию ресурса. Коллекции ресурса расширяют класс Illuminate\Http\Resources\Json\ResourceCollection:

php artisan make:resource User --collection

php artisan make:resource UserCollection

Обзор концепции

Это лишь общий обзор ресурсов и коллекций ресурса. Мы настоятельно рекомендуем вам прочитать другие разделы этой документации, чтобы получить более глубокое понимание возможностей создания и настройки ресурса, предлагаемые вам.

Прежде чем углубляться во все варианты, доступные вам при написании ресурсов, давайте сначала рассмотрим, как ресурсы используются в Laravel. Класс ресурсов представляет собой единую модель, которую необходимо преобразовать в структуру JSON. Например, вот простой класс ресурса UserResource:

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class UserResource extends JsonResource
{
    
    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'email' => $this->email,
            'created_at' => $this->created_at,
            'updated_at' => $this->updated_at,
        ];
    }
}

Каждый класс ресурсов определяет метод toArray, который возвращает массив атрибутов, которые должны быть преобразованы в JSON, когда ресурс возвращается в качестве ответа из метода маршрута или контроллера.

Обратите внимание, что мы можем получить доступ к свойствам модели непосредственно из переменной $this. Это связано с тем, что класс ресурсов автоматически проксирует свойства и методы к базовой модели для удобства доступа. Как только ресурс определен, он может быть возвращен из маршрута или контроллера. Ресурс принимает основной экземпляр модели через свой конструктор:

use App\Http\Resources\UserResource;
use App\Models\User;

Route::get('/user/{id}', function ($id) {
    return new UserResource(User::findOrFail($id));
});

Коллекции ресурса

Если вы возвращаете коллекцию ресурса или ответ с постраничной разбивкой, то вы должны использовать метод collection класса ресурса, при создании экземпляра ресурса в вашем маршруте или контроллере:

use App\Http\Resources\UserResource;
use App\Models\User;

Route::get('/users', function () {
    return UserResource::collection(User::all());
});

Обратите внимание, что это не позволит добавить пользовательские метаданные, которые могут потребоваться при возвращении с вашей коллекцией. Если вы хотите получить больший контроль над ответом коллекции ресурса, то вы можете создать выделенный ресурс для представления коллекции:

php artisan make:resource UserCollection

После создания класса коллекции ресурса, вы можете легко определить любые метаданные, которые должны быть включены в ответ:

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\ResourceCollection;

class UserCollection extends ResourceCollection
{
    
    public function toArray($request)
    {
        return [
            'data' => $this->collection,
            'links' => [
                'self' => 'link-value',
            ],
        ];
    }
}

После определения вашей коллекции ресурса, ее можно вернуть из маршрута или контроллера:

use App\Http\Resources\UserCollection;
use App\Models\User;

Route::get('/users', function () {
    return new UserCollection(User::all());
});

Сохранение ключей коллекции

При возврате коллекции ресурсов из маршрута, Laravel сбрасывает ключи коллекции для расположения их в числовом порядке. Однако, вы можете добавить свойство $preserveKeys в свой класс ресурса, указывающее, должны ли сохраняться исходные ключи коллекции:

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class UserResource extends JsonResource
{
    
    public $preserveKeys = true;
}

Когда для свойства $preserveKeys установлено значение true, ключи коллекции будут сохранены, когда коллекция будет возвращена из маршрута или контроллера:

use App\Http\Resources\UserResource;
use App\Models\User;

Route::get('/users', function () {
    return UserResource::collection(User::all()->keyBy->id);
});

Настройка базового класса ресурсов

Обычно свойство $this->collection коллекции ресурса автоматически заполняется результатом сопоставления каждого элемента коллекции с его единственным классом ресурсов. Предполагается, что единственным классом ресурса является имя класса коллекции без завершающей части Collection. Кроме того, в зависимости от личных предпочтений, класс ресурсов в единственном числе может иметь суффикс Resource, а может и не иметь его.

Например, UserCollection попытается сопоставить переданные экземпляры пользователя с ресурсом UserResource. Чтобы изменить это поведение, вы можете переопределить свойство $collects вашей коллекции ресурса:

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\ResourceCollection;

class UserCollection extends ResourceCollection
{
    
    public $collects = Member::class;
}

Написание ресурсов

Если вы не читали обзор концепции, настоятельно рекомендуется сделать это, прежде чем приступить к работе с этой документацией.

По сути, ресурсы просты. Им нужно только преобразовать переданную модель в массив. Итак, каждый ресурс содержит метод toArray, который переводит атрибуты вашей модели в удобный для API массив, который может быть возвращен из маршрутов или контроллеров вашего приложения:

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class UserResource extends JsonResource
{
    
    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'email' => $this->email,
            'created_at' => $this->created_at,
            'updated_at' => $this->updated_at,
        ];
    }
}

Как только ресурс определен, он может быть возвращен непосредственно из маршрута или контроллера:

use App\Http\Resources\UserResource;
use App\Models\User;

Route::get('/user/{id}', function ($id) {
    return new UserResource(User::findOrFail($id));
});

Отношения

Если вы хотите включить связанные ресурсы в свой ответ, вы можете добавить их в массив, возвращаемый методом вашего ресурса toArray. В этом примере мы будем использовать метод collection ресурса PostResource, чтобы добавить посты пользователя из блога в ответ ресурса:

use App\Http\Resources\PostResource;


public function toArray($request)
{
    return [
        'id' => $this->id,
        'name' => $this->name,
        'email' => $this->email,
        'posts' => PostResource::collection($this->posts),
        'created_at' => $this->created_at,
        'updated_at' => $this->updated_at,
    ];
}
Если вы хотите включить отношения только тогда, когда они уже загружены, ознакомьтесь с документацией по условным отношениям.

Коллекции ресурса

В то время как ресурсы преобразуют одну модель в массив, коллекции ресурса преобразуют коллекцию моделей в массив. Однако, необязательно определять класс коллекции ресурса для каждой из ваших моделей, поскольку все ресурсы предоставляют метод collection для генерации «специальной» (ad hoc) коллекции ресурсов на лету:

use App\Http\Resources\UserResource;
use App\Models\User;

Route::get('/users', function () {
    return UserResource::collection(User::all());
});

Однако, если вам нужно настроить метаданные, возвращаемые с коллекцией, необходимо определить собственную коллекцию ресурса:

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\ResourceCollection;

class UserCollection extends ResourceCollection
{
    
    public function toArray($request)
    {
        return [
            'data' => $this->collection,
            'links' => [
                'self' => 'link-value',
            ],
        ];
    }
}

Как и отдельные ресурсы, коллекции ресурса могут быть возвращены непосредственно из маршрутов или контроллеров:

use App\Http\Resources\UserCollection;
use App\Models\User;

Route::get('/users', function () {
    return new UserCollection(User::all());
});

Обертывание данных

По умолчанию, ваш самый верхний ресурс будет заключен в ключ data, когда ответ ресурса преобразуется в JSON. Так, например, типичный ответ коллекции ресурса выглядит следующим образом:

{
    "data": [
        {
            "id": 1,
            "name": "Eladio Schroeder Sr.",
            "email": "therese28@example.com",
        },
        {
            "id": 2,
            "name": "Liliana Mayert",
            "email": "evandervort@example.com",
        }
    ]
}

Если вы хотите использовать собственный ключ вместо data, вы можете определить свойство $wrap в классе ресурса:

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class UserResource extends JsonResource
{
    
    public static $wrap = 'user';
}

Если вы хотите отключить обертывание самого верхнего ресурса, то вы должны вызвать метод withoutWrapping базового класса Illuminate\Http\Resources\Json\JsonResource. Обычно вы должны вызывать этот метод из вашего AppServiceProvider или другого сервис-провайдера:

namespace App\Providers;

use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    
    public function register()
    {
        
    }

    
    public function boot()
    {
        JsonResource::withoutWrapping();
    }
}
Метод withoutWrapping влияет только на самый верхний уровень ответа и не удаляет ключи data, которые вы вручную добавляете в свои собственные коллекции ресурса.

Обертывание вложенных ресурсов

У вас есть полная свобода определять, как обернуты отношения между вашими ресурсами. Если вы хотите, чтобы все коллекции ресурсов были обернуты ключом data, независимо от их вложенности, то вы должны определить класс коллекции для каждого ресурса и вернуть коллекцию с ключом data.

Вам может быть интересно: не приведет ли это к тому, что верхний уровень вашего ресурса будет дважды обернут ключом data? Не волнуйтесь, Laravel не позволит вашим ресурсам быть случайно обернутыми двойной оберткой, поэтому вам не нужно беспокоиться об уровне вложенности трансформируемой коллекции ресурсов:

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\ResourceCollection;

class CommentsCollection extends ResourceCollection
{
    
    public function toArray($request)
    {
        return ['data' => $this->collection];
    }
}

Обертывание данных и постраничная разбивка

При возврате разбитых на страницы коллекций через ответ ресурса, Laravel обернет ваши данные ресурса в ключ data, даже если был вызван метод withoutWrapping. Это потому, что разбитые на страницы ответы всегда содержат ключи meta и links с информацией о состоянии постраничной разбивки:

{
    "data": [
        {
            "id": 1,
            "name": "Eladio Schroeder Sr.",
            "email": "therese28@example.com",
        },
        {
            "id": 2,
            "name": "Liliana Mayert",
            "email": "evandervort@example.com",
        }
    ],
    "links":{
        "first": "http://example.com/pagination?page=1",
        "last": "http://example.com/pagination?page=1",
        "prev": null,
        "next": null
    },
    "meta":{
        "current_page": 1,
        "from": 1,
        "last_page": 1,
        "path": "http://example.com/pagination",
        "per_page": 15,
        "to": 10,
        "total": 10
    }
}

Постраничная разбивка

Вы можете передать экземпляр пагинатора Laravel методу collection ресурса или вашей коллекции ресурса:

use App\Http\Resources\UserCollection;
use App\Models\User;

Route::get('/users', function () {
    return new UserCollection(User::paginate());
});

Ответы с постраничной разбивкой всегда содержат ключи meta и links с информацией о состоянии пагинатора:

{
    "data": [
        {
            "id": 1,
            "name": "Eladio Schroeder Sr.",
            "email": "therese28@example.com",
        },
        {
            "id": 2,
            "name": "Liliana Mayert",
            "email": "evandervort@example.com",
        }
    ],
    "links":{
        "first": "http://example.com/pagination?page=1",
        "last": "http://example.com/pagination?page=1",
        "prev": null,
        "next": null
    },
    "meta":{
        "current_page": 1,
        "from": 1,
        "last_page": 1,
        "path": "http://example.com/pagination",
        "per_page": 15,
        "to": 10,
        "total": 10
    }
}

Условные атрибуты

По желанию можно включить атрибут в ответ ресурса, только если какое-то условие выполнено. Например, бывает необходимо включить значение, только если текущий пользователь является «администратором». Laravel предлагает множество вспомогательных методов, которые помогут вам в этой ситуации. Метод when используется для условного добавления атрибута в ответ ресурса:

use Illuminate\Support\Facades\Auth;


public function toArray($request)
{
    return [
        'id' => $this->id,
        'name' => $this->name,
        'email' => $this->email,
        'secret' => $this->when(Auth::user()->isAdmin(), 'secret-value'),
        'created_at' => $this->created_at,
        'updated_at' => $this->updated_at,
    ];
}

В этом примере ключ secret будет возвращен в конечном ответе ресурса только в том случае, если метод isAdmin аутентифицированного пользователя вернет true. Если метод возвращает false, то ключ secret будет удален из ответа ресурса перед его отправкой клиенту. Метод when позволяет вам выразительно определять ваши ресурсы, не прибегая к условным операторам при построении массива.

Метод when также принимает замыкание в качестве второго аргумента, позволяя вам вычислить результирующее значение, только если переданное условие истинно:

'secret' => $this->when(Auth::user()->isAdmin(), function () {
    return 'secret-value';
}),

Слияние условных атрибутов

Иногда у вас может быть несколько атрибутов, которые следует включать в ответ ресурса только при одном и том же условии. В этом случае вы можете использовать метод mergeWhen для включения атрибутов в ответ только в том случае, если переданное условие истинно:


public function toArray($request)
{
    return [
        'id' => $this->id,
        'name' => $this->name,
        'email' => $this->email,
        $this->mergeWhen(Auth::user()->isAdmin(), [
            'first-secret' => 'value',
            'second-secret' => 'value',
        ]),
        'created_at' => $this->created_at,
        'updated_at' => $this->updated_at,
    ];
}

Опять же, если переданное условие равносильно false, то эти атрибуты будут удалены из ответа ресурса перед его отправкой клиенту.

Метод mergeWhen не следует использовать в массивах, в которых смешиваются строковые и числовые ключи. Кроме того, его не следует использовать в массивах с цифровыми ключами, которые не упорядочены последовательно.

Условные отношения

В дополнение к условной загрузке атрибутов, вы можете условно включать отношения в свои ответы ресурса в зависимости от того, было ли отношение уже загружено в модель. Это позволяет вашему контроллеру решать, какие отношения должны быть загружены в модель, и ваш ресурс может легко включить их, только когда они действительно были загружены. В конечном итоге это позволяет избежать проблем «N+1» с запросами в ваших ресурсах.

Метод whenLoaded используется для условной загрузки отношения. Чтобы избежать ненужной загрузки отношений, этот метод принимает имя отношения вместо самого отношения:

use App\Http\Resources\PostResource;


public function toArray($request)
{
    return [
        'id' => $this->id,
        'name' => $this->name,
        'email' => $this->email,
        'posts' => PostResource::collection($this->whenLoaded('posts')),
        'created_at' => $this->created_at,
        'updated_at' => $this->updated_at,
    ];
}

В этом примере, если отношение не было загружено, ключ posts будет удален из ответа ресурса перед его отправкой клиенту.

Условная сводная информация

В дополнение к условному включению информации об отношениях в ответах ваших ресурсов, вы можете условно включать данные из сводных таблиц отношений «многие ко многим» с помощью метода whenPivotLoaded. Метод whenPivotLoaded принимает имя сводной таблицы в качестве своего первого аргумента. Второй аргумент должен быть замыканием, возвращающем значение, если в модели доступна сводная информация:


public function toArray($request)
{
    return [
        'id' => $this->id,
        'name' => $this->name,
        'expires_at' => $this->whenPivotLoaded('role_user', function () {
            return $this->pivot->expires_at;
        }),
    ];
}

Если ваши отношения используют пользовательскую модель сводной таблицы, то вы можете передать экземпляр модели сводной таблицы в качестве первого аргумента методу whenPivotLoaded. :

'expires_at' => $this->whenPivotLoaded(new Membership, function () {
    return $this->pivot->expires_at;
}),

Если ваша сводная таблица использует аксессор, отличный от pivot, то вы можете использовать метод whenPivotLoadedAs:


public function toArray($request)
{
    return [
        'id' => $this->id,
        'name' => $this->name,
        'expires_at' => $this->whenPivotLoadedAs('subscription', 'role_user', function () {
            return $this->subscription->expires_at;
        }),
    ];
}

Добавление метаданных

Некоторые стандарты API JSON требуют добавления метаданных в ответы ваших ресурсов и коллекции ресурсов. Это часто включает такие вещи, как «ссылки» на ресурс или связанные ресурсы или метаданные о самом ресурсе. Если вам нужно вернуть дополнительные метаданные о ресурсе, включите их в свой метод toArray. Например, вы можете включить информацию links при преобразовании коллекции ресурса:


public function toArray($request)
{
    return [
        'data' => $this->collection,
        'links' => [
            'self' => 'link-value',
        ],
    ];
}

При возврате дополнительных метаданных из ваших ресурсов вам никогда не придется беспокоиться о случайном переопределении ключей links или meta, которые автоматически добавляются Laravel при возврате ответов с постраничной разбивкой. Любые дополнительные links, которые вы определяете, будут объединены с предоставленными пагинатором.

Метаданные верхнего уровня

По желанию можно включить в ответ ресурса только определенные метаданные, если ресурс является самым верхним из возвращаемых ресурсов. Обычно это метаинформация об ответе в целом. Чтобы определить эти метаданные, добавьте метод with к вашему классу ресурсов. Этот метод должен возвращать массив метаданных, которые будут включены в ответ ресурса, только если ресурс является самым верхним ресурсом, который преобразуется:

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\ResourceCollection;

class UserCollection extends ResourceCollection
{
    
    public function toArray($request)
    {
        return parent::toArray($request);
    }

    
    public function with($request)
    {
        return [
            'meta' => [
                'key' => 'value',
            ],
        ];
    }
}

Добавление метаданных при создании ресурсов

Вы также можете добавить данные верхнего уровня при создании экземпляров ресурсов в своем маршруте или контроллере. Метод additional, доступный для всех ресурсов, принимает массив данных, которые должны быть добавлены в ответ ресурса:

return (new UserCollection(User::all()->load('roles')))
                ->additional(['meta' => [
                    'key' => 'value',
                ]]);

Организация массива

Как писалось выше, массив состоит из элементов, каждый из которых имеет ключ и значение. Например массив содержащий информацию о ценах в ресторанном меню может выглядеть так:

Ключ Значение
breakfast 700
dinner 1500
supper 1100

Массив может иметь только один элемент с заданным ключом, т.е. в приведённом выше массиве не может быть двух элементов с ключом dinner. При попытке «добавить» второй dinner, мы просто перезапишем значение уже существующего элемента. В данном примере мы рассмотрели наиболее частый случай организации массива, а именно в виде ассоциативного. Ассоциативный массив удобнее использовать в коде, т.к. его ключи имеют осмысленные наименования (ассоциируются с какими-то частями приложения или данными которые обрабатывает скрипт). Но есть более простой пример массив, это числовые массивы. При их создании не нужно указывать ключ, он задаётся автоматически в виде целого числа, начиная с нуля.

Ключ Значение
0 700
1 1500
2 1100

Рассмотрим пример:


//Пример создания ассоциативного массива
$menuPrice = [
    'breakfast' => 700,
    'dinner' => 1500,
    'supper' => 1100
];

//Пример создания «числового» массива
$prices = [700, 1500, 1100];

В первом случае элементы массива представляют из себя пару ключ-значение, где в качестве ключа используются строковые названия «блюд» (приёмов пищи на самом деле, но пусть будет блюд), а значение это цена блюда. Во втором же случае я указал только цены, при этом интерпретатор PHP автоматически проставит ключи элементам массива.

Операции с массивами

Один из случаев ключевой операции с массивами, а именно его создание мы рассмотрели выше. А как ещё можно создать массив? Самый простой случай, это создание пустого массива:


//Создаём пустой массив
$array = [];

Создание и модификация массива

Пустой массив может служить заготовкой под определённую коллекцию данных. Конечно его можно не определять заранее и создать прямо в цикле где он должен заполняться, но тогда это будет менее понятный код.

Вы так же можете заполнить массив на лету, например данными из базы данных:


//Заполняем массив данными из БД
$users = [];
//...некая выборка значения, например пользователей users
while($user = $db->query('SELECT * FROM users')->fetch(PDO::FETCH_ASSOC)){
    $users[] = $user;
}

Перебор массивов

С другой стороны готовый массив можно перебрать и например вывести его элементы на экран:


//Перебор массива
$week = ['Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота', 'Воскресенье'];

//Выведем список дней недели
echo '
    '; foreach ($week as $key => $day) { echo '
  • '. $day .'
  • '; } echo '
';

Вообще в php существует больше 70 функций для работы с массивами, однако в большинстве случаев вы будет использовать не больше двадцати. Приведу некоторые из них:

  • in_array — проверяет присутствие элемента в массиве
  • key_exists  — проверяет присутствует ли в массиве указанный ключ или индекс
  • array_search  — осуществляет поиск заданного значения в массиве и возвращает ключ первого найденного значения
  • array_merge — объединяет 2 и более массивов в один
  • array_chunk — разбивает массив на части

Сортировка массива

Отдельным блоком может идти операции связанные с сортировкой массив. В PHP существует несколько встроенных функций для быстрой сортировки массивов, например по возрастанию/убыванию значения или в алфавитном порядке. Причём сортировка может идти как по ключам массива так и по значениям. Одной из интересных возможностей предоставляет функция usort(), при помощи которой вы можете отсортировать элементы массива используя собственный алгоритм сравнения. Рассмотрим пример:


//Пользовательская функция сравнения элементов массива
function compare($a, $b)
{
    if ($a == $b) {
        return 0;
    }
    return ($a 

В результате выполнения данного примера получим такой массив:


array(5) {
  [0]=>int(1)
  [1]=>int(2)
  [2]=>int(3)
  [3]=>int(5)
  [4]=>int(6)
}

Как вы понимаете данный пример максимально упрощён. Но внутри вашей функции compare() можно реализовать любой алгоритм сравнения элементов. Главное правильно возвращать значение, ноль — если элементы не отличаются и их не надо менять местами и 1 или -1 если нужно изменить порядок элементов.

Вы так же можете пробросить в тело функции compare() внешнюю переменную используя анонимную функцию и ключевое слово use:


//Пользовательская функция сравнения элементов массива
$params = ['min_value'=>0, 'max_value'=>3];
function compare($params){
    return function ($a, $b) use ($params)
    {
        if ($a == $b) {
            return 0;
        }

        if($a = $params['min_value'] && $a 

Как видите теперь compare() принимает параметры $params и возвращает анонимную функцию в которой уже реализован ваш алгоритм сравнения в котором используются переданные параметры. Результат при таком алгоритме изменится:


array(5) {
  [0]=>int(1)
  [1]=>int(2)
  [2]=>int(3)
  [3]=>int(6)
  [4]=>int(5)
}

Грубо говоря сортировка по возрастанию шла пока значение $a попадало в диапазон от 0 до 3-х.

Глобальные массивы

В PHP начиная с версии 4 ввели такой сущность как «суперглобальные массивы». Это особые переменные доступные в любой части приложения и содержат информацию, например о состоянии сервера (массив $_SERVER) сессии, куках или переданных от пользователя запросах, одним словом о состоянии среды выполнения приложения. На данный момент в PHP доступно девять суперглобальных массивов:

Наименование Описание массива
$GLOBALS Этот массив содержим все переменные объявленные в скрипте, при этом имена переменных являются ключами этого массива.
$_SERVER Данный массив содержит всю информацию о сервере, а так же настройки среды в которой выполняется скрипт
$_GET Массив переменных переданных PHP скрипту по средствам GET запроса (через адресную строку браузера или другими методами, например curl())
$_POST Так же как и GET содержит переданные скрипту переменные, только уже методом POST
$_COOKIE Содержим coockies-ы пользователя
$_REQUEST Объединяет в себе массивы $GET, $POST и $COOKIE. Не рекомендуется использовать, не безопасно, хотя и удобно.
$_FILES Содержим список файлов загружаемых на сервер через веб-формы (имя, временный путь, размеры и т.д.)
$_ENV Содержит переменные окружения в котором запущен PHP скрипт
$_SESSION В данном массиве содержаться все переменные сессии текущего пользователя

 Чаще всего, вы будете сталкиваться с массивами $_GET и $_POST т.к. с их помощью в скрипты на сервере передаются данные от клиентской части (через веб-формы).

Использование ClassTransformer

С его помощью я автоматически привожу данные к нужному мне классу. Рассмотрим более подробно все также на примере создание пользователя. К нам приходит запрос, и данные из него мы должны отправить в метод. В моем случае на Laravel проекте это выглядит вот так:

class UserController extends Controller {
	public function __construct(
      private UserService $userService,
	) {}

	public function createUser(CreateUserRequest $request)
	{
      $dto = ClassTransformer::transform(CreateUserDTO::class, $request);
      $user = $this->userService->create($dto);
      return response(UserResources::make($user));
	}
}
class CreateUserDTO
{
    public string $name;
    public string $email;
    public string $phone;
}

В запросе к нам приходит массив параметров: name, phone и email. Пакет просто смотрит есть ли такие параметры у класса, и, если есть, сохраняет значение. В противном случае просто отсеивает их. На входе transform можно передавать не только массив, это может быть другой object, из которого также будут разобраны нужные параметры.

Но наименования аргументов могут отличаться. Тогда, в созданной нами DTO, мы можем спокойно описать свою реализацию приведения:

class CreateUserDTO
{
    public string $name;
    public string $email;
    public string $phone;
    
    public static function transform(mixed $args):CreateUserDTO
    {
        $dto = new self();
        $dto->name = $args['fullName'];
        $dto->email = $args['mail'];
        $dto->phone = $args['phone'];
        return $dto;
    }
}

Существуют объекты гораздо сложнее, с параметрами определенного класса, либо массивом объектов. Что же с ними? Все просто, указываем параметру в PHPDoc путь к классу и все. В случае массива нужно указать, каких именно объектов этот массив:

class PurchaseDTO
{
    /** @var array $products Product list */
    public array $products;
    
    /** @var \DTO\UserDTO $user */
    public UserDTO $user;
}

Указывая параметру класс, вы можете строить более сложные цепочки связей. Пакет рекурсивно будет проходить по всем типизированным параметрам и приведет их к нужному формату.

Путь к классу обязательно должен быть полным, т.к. иначе гораздо сложнее реализовать нахождение класса для инициализации. Или это вообще будет alias и нужно будет парсить файл, а это уже будет оверхед для такого сервиса.

Что мы получаем?

  • Метод сервиса работает с конкретным набором данным

  • Знаем все параметры, которые есть у объекта

  • Можно задать типизацию каждому параметру

  • Вызов метода становится проще, за счет удаления приведения вручную

  • В IDE работают все подсказки.

Аналоги

Увы, я не нашел подобных решений. Отмечу лишь пакет от Spatie - https://github.com/spatie/data-transfer-object

Он пытает решить ту же проблему используя DTO, но их подход заставляет ваш класс наследоваться от их DTO, и самим вызывать инициализацию, передавая в конструктор набор данных. При такой реализации я не вижу особо профита использования, ведь я так же могу сам прописать new DTO() и заполнить параметры.

Я же, в свою очередь, был вдохновлен методом преобразования из NestJS - plainToClass. Такой подход не заставляет реализовывать свои интерфейсы, что позволяет делать преобразования более гибким, и любой набор данных можно привести к любому классу. Хоть массив данных сразу в ORM модель (если прописаны параметры), но лучше так не надо:)

Инициализация

Чтобы использовать Mongo ODM, создайте соединение Mongo DB. Например:

$mapper = new \DB\Mongo\Mapper(\DB\Mongo $db, string $collection);

Если вы хотите создать класс модели, то:

$f3->set('DB', new \DB\Mongo('mongodb://localhost:27017','fatfree'));
 
class User extends \DB\Mongo\Mapper {
    public function __construct() {
        parent::__construct( \Base::instance()->get('DB'), 'users' );
    }
}
 
$user = new User();
$user->load(array('_id' => new \MongoId('50ecaa466afa2f8c1c000004')));
// etc.

Синтаксис

$ filter

$filter Mongo принимает общий массив Mongo найти, см db.collection.find ссылки и запросы документов учебника.

array([ array $find ]);

Вот простой пример поиска в Mongo:

$userList = $user->find(array('email'=> new \MongoRegex('/gmail/')));
// returns all users with an email address that contains GMAIL
 
// ends with gmail.com => /gmail\.com$/
// starts with john  => /^john/

Или просто загрузите одного пользователя по его ID:

$user->load(array('_id'=> new \MongoId('507c35dd8fada716c89d0013')));

$ option

Аргумент Mongo $option принимает имеет структуру:

array(
    'group' => array (
        'keys',
        'initial',
        'reduce',
        'finalize'
    ),
    'order' => string $order,
    'limit' => integer $limit,
    'offset' => integer $offset
    )
 

Дополнительные сведения о group и order.

Цикл each (jQuery.each). Примеры использования

Синтаксис функции each:

// array или object - массив или объект, элементы или свойства которого необходимо перебрать
// callback - функция, которая будет выполнена для каждого элемента массива или свойства объекта
$.each(array или object,callback);

Работу с функцией each разберём на примерах.

Пример №1. В нём выполним переберор всех элементов массива (array).

// массив, состоящий из 3 строк
var arr = ['Автомобиль','Грузовик','Автобус'];

// переберём массив arr
$.each(arr,function(index,value){

  // действия, которые будут выполняться для каждого элемента массива
  // index - это текущий индекс элемента массива (число)
  // value - это значение текущего элемента массива
  
  //выведем индекс и значение массива в консоль
  console.log('Индекс: ' + index + '; Значение: ' + value);

});

/*
Результат (в консоли):
Индекс: 0; Значение: Автомобиль
Индекс: 1; Значение: Грузовик
Индекс: 2; Значение: Автобус
*/

В вышеприведённом коде функция each используется для перебора массива. Функция имеет 2 обязательных параметра. Первый параметр - это сущность (массив или объект), элементы (свойства) которой необходимо перебрать. В данном случае - это массив arr. Второй параметр - это функция обратного вызова, которая будет выполнена для каждого элемента (в данном случае) массива. Она имеет 2 параметра, которые доступны внутри неё посредством соответствующих переменных. Первый параметр - это порядковый номер элемента (отсчёт выполняется с 0). Второй параметр - это значение текущего элемента массива.

Пример №2. В этом примере осуществим перебор всех свойств объекта.

// объект smartphone, имеющий 5 свойств
var smartphone = {
  "name": "LG G5 se",
  "year": "2016",
  "screen-size": "5.3",
  "screen-resolution": "2560 x 1440",
  "os" : "Android 6.0 (Marshmallow)"
};

// переберём объект smartphone
$.each(smartphone, function( key, value ) {

  // действия, которые будут выполняться для каждого свойства объекта
  // key - текущее имя свойства массива
  // value - значение текущего свойства объекта
 
  // выведем имя свойства и его значение в консоль
  console.log( 'Свойство: ' +key + '; Значение: ' + value );

});

/*
Результат (в консоли):
Свойство: name; Значение: LG G5 se
Свойство: year; Значение: 2016
Свойство: screen-size; Значение: 5.3
Свойство: screen-resolution; Значение: 2560 x 1440
Свойство: os; Значение: Android 6.0 (Marshmallow)
*/

Функция each может использоваться для перебора JavaScript объектов. Отличие её использования заключается только в том, что параметры функции обратного вызова имеют другие значения. Первый параметр хранит название свойства объекта, а второй - значение этого свойства.

Пример №3. В нём осуществим перебор более сложной структуры (рассмотрим, как использовать вложенные each).

// объект, состоящий из 2 свойств. Каждое свойство этого объект имеет в качестве значения массив, элементами которого являются тоже объекты
var articles = {
  "Bootstrap": [
    {"id":"1", "title":"Введение"},
    {"id":"2", "title":"Как установить"},
    {"id":"3", "title":"Сетка"}
  ],
  "JavaScript": [
    {"id":"4", "title":"Основы"},
    {"id":"5", "title":"Выборка элементов"}
  ]  
};

$.each(articles,function(key,data) {
  console.log('Раздел: ' + key);
  $.each(data, function(index,value) {
    console.log('Статья: id = ' + value['id'] + '; Название = '+ value['title']);
  });
});

/*
Результат:
Раздел: Bootstrap
Статья: id = 1; Название = Введение
Статья: id = 2; Название = Как установить
Статья: id = 3; Название = Сетка
Раздел: JavaScript
Статья: id = 4; Название = Основы
Статья: id = 5; Название = Выборка элементов
*/

Как прервать each (выйти из цикла)

Прерывание (break) цикла each осуществляется с помощью оператора return, который должен возвращать значение false.

Например, прервём выполнение цикла each после того как найдём в массиве arr число 7:

// массив, состоящий из 5 чисел
var arr = [5, 4, 7, 17, 19];

// число, которое необходимо найти
var find = 7;

// переберём массив arr
$.each(arr, function (index, value) {
  // если необходимое число найдено, то..
  if (value === find) {
    // вывести его в консоль
    console.log('Ура! Число ' + find + ' найдено! Данное число имеет индекс: ' + index);
    // прервать выполнение цикла
    return false;
  } else {
  // иначе вывести в консоль текущее число
  console.log('Текущее число: ' + value);
  }
});

/* Результат (в консоли):
Текущее число: 5
Текущее число: 4
Ура! Число 7 найдено! Данное число имеет индекс: 2
*/

Как перейти к следующей итерации (each continue)

В each прерывание выполнения текущей итерации и переход к следующей осуществляется с помощью оператора return, который должен иметь значение отличное от false.

// массив, состоящий из чисел
var arr = [3, 5, 4, 9, 17, 19, 30, 35, 40];

// массив, который должен содержать все элементы массива arr, кроме чётных чисел
var newarr = [];

// переберём массив arr
$.each(arr, function (index, value) {

  // если элемент чётный, то пропустим его
  if (value % 2 === 0) {
    // прервём выполнение текущей итерации и перейдём к следующей
    return;
  }
  // добавить в массив newarr значение value
  newarr.push(value);

});

console.log('Исходный массив (arr): ' + arr.join());
console.log('Результирующий массив (newarr): ' + newarr.join());

/* Результат (в консоли):
Исходный массив (arr): 3,5,4,9,17,19,30,35,40
Результирующий массив (newarr): 3,5,9,17,19,35
*/