Делаем простенький web-сервис с помощью API Яндекс.Метрики / Хабр

6 Уведомление пользователя о том, что товары не найдены

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

В приведенном ниже коде мы устанавливаем код ответа 404 – Не найдено и сообщение, что Товары не найдены.

Делаем собственный сервис на основе api метрики

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

Попробуем сделать что-то подобное для Метрики.

Лирическое отступление

Давно вынашивал идею написать что-то основательное про API Метрики. Взяться за дело меня вдохновила эта статья на хабре, посвященная выгрузке данных с помощью API Яндекс.Метрики. Но в ней, на мой взгляд, все сложновато, зачем создавать инстансы в Amazon, чтобы писать Python-скрипты?

Достаточно поставить IPython и будет интерактивное счастье прямо в браузере, с блэкджеком и скаттер-плотами (для тех кто понимает о чем я). Но о том как использовать API Метрики с помощью IPython я напишу когда-нибудь потом, а в этой статье я хотел бы рассказать о том как научиться работать с API и получать данные Метрики в формате CSV с помощью одного запроса через браузер. Один раз скопировать запрос и никакой интерфейс Метрики больше не нужен.

Получаем OAuth-токен

Чтобы получить OAuth-токен перейдите на страницу создания приложения.

Обязательным для заполнения является поле Название приложения* – можете использовать любое.

Далее в секции Платформы выбираете чекбокс Веб-сервисы и нажмите на ссылку Подставить URL для разработки.

Затем в секции Доступы* нажимаем на Яндекс.Метрика и выбираем чекбокс Получение статистики, чтение параметров своих и доверенных счётчиков.

Нажимаем Создать приложение.

На странице увидите следующие данные:

Установка gulp-babel в проект

Babel 7

.1 Создание файла read_paging.php

В папке product создайте файл read_paging.php со следующим кодом.

<?php
// необходимые HTTP-заголовки
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");

// подключение файлов
include_once "../config/core.php";
include_once "../shared/utilities.php";
include_once "../config/database.php";
include_once "../objects/product.php";

// utilities
$utilities = new Utilities();

// создание подключения
$database = new Database();
$db = $database->getConnection();

// инициализация объекта
$product = new Product($db);

// запрос товаров
$stmt = $product->readPaging($from_record_num, $records_per_page);
$num = $stmt->rowCount();

// если больше 0 записей
if ($num>0) {

    // массив товаров
    $products_arr=array();
    $products_arr["records"]=array();
    $products_arr["paging"]=array();

    // получаем содержимое нашей таблицы
    while ($row = $stmt->fetch(PDO::FETCH_ASSOC)){
        // извлечение строки
        extract($row);

        $product_item=array(
            "id" => $id,
            "name" => $name,
            "description" => html_entity_decode($description),
            "price" => $price,
            "category_id" => $category_id,
            "category_name" => $category_name
        );

        array_push($products_arr["records"], $product_item);
    }

    // подключим пагинацию
    $total_rows=$product->count();
    $page_url="{$home_url}product/read_paging.php?";
    $paging=$utilities->getPaging($page, $total_rows, $records_per_page, $page_url);
    $products_arr["paging"]=$paging;

    // установим код ответа - 200 OK
    http_response_code(200);

    // вывод в json-формате
    echo json_encode($products_arr);
} else {

    // код ответа - 404 Ничего не найдено
    http_response_code(404);

    // сообщим пользователю, что товаров не существует
    echo json_encode(array("message" => "Товары не найдены."), JSON_UNESCAPED_UNICODE);
}
?>

.2 Создание файла core.php

Этот файл содержит нашу базовую конфигурацию, такую как базовый URL и переменные пагинации.

Откройте папку config и создайте в ней файл core.php со следующим содержимым.

.3 Создание метода readPaging()

В папке objects откройте файл product.php и добавьте метод readPaging(). Этот метод вернет список записей, ограниченный тем, что мы установили в $records_per_page файла core.php.

// чтение товаров с пагинацией
public function readPaging($from_record_num, $records_per_page){

    // выборка
    $query = "SELECT
                c.name as category_name, p.id, p.name, p.description, p.price, p.category_id, p.created
            FROM
                " . $this->table_name . " p
                LEFT JOIN
                    categories c
                        ON p.category_id = c.id
            ORDER BY p.created DESC
            LIMIT ?, ?";

    // подготовка запроса
    $stmt = $this->conn->prepare( $query );

    // свяжем значения переменных
    $stmt->bindParam(1, $from_record_num, PDO::PARAM_INT);
    $stmt->bindParam(2, $records_per_page, PDO::PARAM_INT);

    // выполняем запрос
    $stmt->execute();

    // вернём значения из базы данных
    return $stmt;
}

.4 Создание метода count()

Так же в классе Product (файл product.php) добавьте метод count() для создания массива пагинации.

.5 Получение массива пагинации

В корне создайте папку shared, в ней файл utilities.php со следующим кодом.

.1 Создание объекта Category

Откройте папку objects и создайте новый файл category.php со следующим кодом.

.2 Создание файла read.php

Создайте новую папку category в корне, и в ней файл read.php со следующим кодом.

.3 Создание метода read()

Откройте в папке objects файл category.php и создайте метод read() для класса Category.

Frontend часть данного приложения (продолжение) – jQuery AJAX JSON.

Если вам понравилась данная статья, рекомендую к прочтению создание регистрации и авторизации в php с использованием JWT.

Группировки и метрики

Яндекс.Метрика (и её API) оперирует двумя основными сущностями: Dimensions (группировки) и Metrics (метрики). Эта терминология пришла из технологии обработки данных OLAP, она также встречается и в Google Analytics. Благодаря этому, API GA и API Метрики 2.

Группировки/Dimensions (мне их привычнее называть «измерениями», но буду придерживаться терминологии Метрики) — это какой-либо атрибут визита или хита. Как ясно из названия, группировки позволяют группировать данные по определенным признакам.

Примеры группировок: Источник трафик, Город, Браузер, Страница входа.

Группировки — это все те параметры, которые можно найти в одноименном разделе при построении отчета в интерфейсе Метрики:

Метрики/Metrics — это числовые величины, которые связаны с визитом или хитом.

Примеры метрик: количество визитов, показатель отказов, среднее время на сайте.

В интерфейсе метрики представлены в правой части табличных отчетов и их также список также можно настраивать:

Настройка gulpfile.js

.pipe(babel()) – используйте перед конкатенацией и минификацией.

Формирование запроса и сохранение полученных данных

Нам необходимо сформировать запрос для получения данных от Яндекс.Метрики и сохранить пришедшие данные (JSON) на сервере.

Создадим файл metric-api.php:

<?php

$options = array(
    "http" => array(
        "method" => "GET",
        "header" => array(
            "Content-Type: application/x-yametrika json",
            "Authorization: OAuth ваш_токен"
        )
    )
);

$context = stream_context_create($options);

$url = "https://api-metrika.yandex.ru/stat/v1/data";

$parameters = [
    "ids"               => "",                            // номер счётчика метрики
    "metrics"           => "ym:pv:pageviews,ym:pv:users", // данные по: страницам и количеству просмотров
    "dimensions"        => "ym:pv:URLHash",               // группировка по URLHash
    "date1"             => "2022-09-01",                  // с какой даты получить отчёт
    "accuracy"          => "full",                        // точная статистика (без округления)
    "limit"             => "100000",                      // максимальный лимит данных
    "proposed_accuracy" => "false"                        // без округления данных
];

array_walk($parameters, function (&$key, $value) {
    return $key = "$value=$key";
});

$parameters = implode($parameters, "&");

$url = $url . "?&" . $parameters;

$metrikaRequest = file_get_contents($url, false, $context);

if (!empty($metrikaRequest)) {
    file_put_contents($_SERVER["DOCUMENT_ROOT"] . "/metrics.json", $metrikaRequest);
};

Обратите внимание на аргументы:

Если по каким-либо причинам, вы получите ошибку, можно заменить file_get_contents на curl.Пример ошибки:

Настройка планировщика

Теперь нам необходимо настроить CRON (планировщик), чтобы наш файл metric-api.php отрабатывал (выполнялся) спустя определённое время, например, каждый час. Т.е. каждый час будет выполняться запрос на получение данных Яндекс.Метрики и обновлять файл, вносить свежие данные в metrics.json.

В панели управления хостингом необходимо перейти во вкладку Планировщик (Crontab).

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

Используя php:

Или используя wget:

Пример

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

Пускай, это единственное посещение за всю историю сайта. Атрибуты посетителя, например, его город, браузер, источник трафик, пол, возвраст, все что удалось определить Яндекс.Метрике — это группировки. Яндекс.Метрика определила, что пользователь: пришел из Москвы, из поисковой системы Яндекс.

  • Значение группировки «Город» для этого посещения будет «Москва»
  • Значение группировки «Источник трафика» — «Переходы из поисковых систем»

В ходе посещения посетитель просматривает 5 страниц в течение 4 минут 40 секунд, тогда:

  • Значение метрики «Просмотры» будет равно 5 страницам
  • Значение метрики «Длительность визита» — 280 секунд
  • Значение метрики «Отказы» будет равно 0%, т. к.
    доля отказов для этого посещения будет равна 0%, т. к. пользователь просмотрел более одной страницы. Общая статистика посещений будет выглядеть так:

Общая статистика — это отчет, в котором отсутствуют группировки. Создав отчет с группировкой «Город» и метриками «Визиты» и «Просмотры» мы получим вот такой отчет:

Добавим группировку «Источник трафика» и отчет станет выглядеть вот так:

А теперь предположим, что пришел второй посетитель, тоже через ПС Яндекс, но из Петербурга. Он просмотрел за свой визит 1 страницу и был на сайте меньше 15 секунд. Такой визит будет считаться отказным, значит:

  • Значение метрики «Просмотры» будет равно 1 странице
  • Значение метрики «Длительность визита» — 0 секунд
  • Значение метрики «Отказы» — 100%

Общая статистика посещений станет такой:

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

Теперь изменим группировку отчета на «Город»:

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

Надеюсь, этот пример дал понимание что такое группировки и метрики.

Создание конфигурационного файла .babelrc

Необходимо создать файл .babelrc со следующим содержимым:

Babel для Gulp успешно установлен и настроен, теперь у вас есть возможность использования ES6 синтаксиса в своих проектах на Gulp.

2 Дамп данных для таблицы категорий

INSERT INTO `categories` (`id`, `name`, `description`, `created`, `modified`) VALUES
(1, "Fashion", "Category for anything related to fashion.", "2022-06-01 00:35:07", "2022-05-30 17:34:33"),
(2, "Electronics", "Gadgets, drones and more.", "2022-06-01 00:35:07", "2022-05-30 17:34:33"),
(3, "Motors", "Motor sports and more", "2022-06-01 00:35:07", "2022-05-30 17:34:54"),
(5, "Movies", "Movie products.", "2022-05-20 10:22:05", "2022-08-20 10:30:15"),
(6, "Books", "Kindle books, audio books and more.", "2022-03-14 08:05:25", "2022-05-20 11:29:11"),
(13, "Sports", "Drop into new winter gear.", "2022-01-09 02:24:24", "2022-01-09 01:24:24");

4 Дамп данных для таблицы товаров

INSERT INTO `products` (`id`, `name`, `description`, `price`, `category_id`, `created`, `modified`) VALUES
(1, "LG P880 4X HD", "My first awesome phone!", "336", 3, "2022-06-01 01:12:26", "2022-05-31 17:12:26"),
(2, "Google Nexus 4", "The most awesome phone of 2022!", "299", 2, "2022-06-01 01:12:26", "2022-05-31 17:12:26"),
(3, "Samsung Galaxy S4", "How about no?", "600", 3, "2022-06-01 01:12:26", "2022-05-31 17:12:26"),
(6, "Bench Shirt", "The best shirt!", "29", 1, "2022-06-01 01:12:26", "2022-05-31 02:12:21"),
(7, "Lenovo Laptop", "My business partner.", "399", 2, "2022-06-01 01:13:45", "2022-05-31 02:13:39"),
(8, "Samsung Galaxy Tab 10.1", "Good tablet.", "259", 2, "2022-06-01 01:14:13", "2022-05-31 02:14:08"),
(9, "Spalding Watch", "My sports watch.", "199", 1, "2022-06-01 01:18:36", "2022-05-31 02:18:31"),
(10, "Sony Smart Watch", "The coolest smart watch!", "300", 2, "2022-06-06 17:10:01", "2022-06-05 18:09:51"),
(11, "Huawei Y300", "For testing purposes.", "100", 2, "2022-06-06 17:11:04", "2022-06-05 18:10:54"),
(12, "Abercrombie Lake Arnold Shirt", "Perfect as gift!", "60", 1, "2022-06-06 17:12:21", "2022-06-05 18:12:11"),
(13, "Abercrombie Allen Brook Shirt", "Cool red shirt!", "70", 1, "2022-06-06 17:12:59", "2022-06-05 18:12:49"),
(26, "Another product", "Awesome product!", "555", 2, "2022-11-22 19:07:34", "2022-11-21 20:07:34"),
(28, "Wallet", "You can absolutely use this one!", "799", 6, "2022-12-04 21:12:03", "2022-12-03 22:12:03"),
(31, "Amanda Waller Shirt", "New awesome shirt!", "333", 1, "2022-12-13 00:52:54", "2022-12-12 01:52:54"),
(42, "Nike Shoes for Men", "Nike Shoes", "12999", 3, "2022-12-12 06:47:08", "2022-12-12 05:47:08"),
(48, "Bristol Shoes", "Awesome shoes.", "999", 5, "2022-01-08 06:36:37", "2022-01-08 05:36:37"),
(60, "Rolex Watch", "Luxury watch.", "25000", 1, "2022-01-11 15:46:02", "2022-01-11 14:46:02");

5 Подключение к базе данных

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

Создайте папку api и откройте её. Создайте папку config и в ней создайте файл database.php со следующим кодом.

Получение доступа к API

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

Пример использования gulp-babel

Пример использования gulp-babel в реальном проекте:

Создание счётчика просмотров страницы

Создадим счётчик просмотров страницы с помощью JavaScript. Как вы помните, мы получаем данные по:

1 Создание объекта Product

Код ниже содержит класс с именем Product и несколько свойств. Также показан метод конструктора, который принимает соединение с базой данных.

Мы будем использовать этот класс для чтения данных из базы. Откройте папку api. Создайте папку objects. Откройте папку её и создайте файл product.php. Поместите в него следующий код.

2 Создание файла для чтения товаров

Код ниже содержит заголовки о том, кто может читать этот файл и какой тип содержимого он будет возвращать.

В данном случае наш файл read.php может быть прочитан кем угодно (звездочка * означает все) и вернет данные в формате JSON.

Откройте папку api. Создайте в ней папку product. Откройте её и создайте файл read.php со следующим кодом.

3 Подключение к базе данных и таблице товаров

В приведенном ниже коде мы подключаем файлы database.php и product.php. Это файлы, которые мы создали ранее.

Нам нужно использовать метод getConnection() класса Database для получения соединения с базой данных. Мы передаем это подключение классу Product.

4 Чтение товаров из базы данных

В приведенном ниже коде мы используем метод read() класса Product для чтения данных из базы. Через переменную $num мы проверяем, найдены ли записи.

Если найдены записи, мы перебираем их с помощью цикла while, добавляем каждую запись в массив $products_arr, устанавливаем код ответа 200 OK и показываем его пользователю в формате JSON.

5 Создание метода read()

Мы использовали метод read() в предыдущем разделе, но он пока ещё не существует в классе Product. Нам нужно добавить этот метод. С помощью кода ниже, мы делаем запрос для получения записей из базы данных.

Откройте папку objects. Откройте файл product.php. Поместите следующий код в класс Product перед последней закрывающей фигурной скобкой вместо комментария // здесь будет метод read().

Структура запроса к API

Итак, у нас есть токен и теперь мы можем делать запрос. В качестве примера токена я буду использовать тестовый токен, указанный в документации Яндекс.Метрики: 05dd3dd84ff948fdae2bc4fb91f13e22bb1f289ceef0037

В API Метрики есть несколько типов запросов:

  • Таблица
  • Drill down
  • Получение данных по времени
  • Сравнение сегментов
  • Сравнение — drill down

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

Запрос «Таблица» вытягивает «плоские» табличные данные, тогда как «Drill down» отдает иерархически вложенные друг в друга данные. Эта логика есть и в интерфейсе. Переключитесь между видом «Линейный список» и «Древовидный список»:

Вид «Древовидный список» удобен для анализа данных в интерфейсе: в поиске озарения можно углубляться и углубляться в данные до тех пор пока не кончатся группировки. Вид «линейный список» удобнее для анализа с помощью табличных процессоров (например, Excel) или обработки с помощью SQL-запросов, в датафрейме R или Pandas.

1 Создание файла create.php

Откройте папку product и создайте в ней файл create.php со следующим содержимым.

2 Создание метода create()

Откройте папку objects. Откройте файл product.php и добавьте следующий код внутри класса Product (objects / product.php).

// метод create - создание товаров
function create(){

    // запрос для вставки (создания) записей
    $query = "INSERT INTO
                " . $this->table_name . "
            SET
                name=:name, price=:price, description=:description, category_id=:category_id, created=:created";

    // подготовка запроса
    $stmt = $this->conn->prepare($query);

    // очистка
    $this->name=htmlspecialchars(strip_tags($this->name));
    $this->price=htmlspecialchars(strip_tags($this->price));
    $this->description=htmlspecialchars(strip_tags($this->description));
    $this->category_id=htmlspecialchars(strip_tags($this->category_id));
    $this->created=htmlspecialchars(strip_tags($this->created));

    // привязка значений
    $stmt->bindParam(":name", $this->name);
    $stmt->bindParam(":price", $this->price);
    $stmt->bindParam(":description", $this->description);
    $stmt->bindParam(":category_id", $this->category_id);
    $stmt->bindParam(":created", $this->created);

    // выполняем запрос
    if ($stmt->execute()) {
        return true;
    }

    return false;
}

Формируем запрос к API

Начнем составление нашего запроса к API

1 — В параметре metrics нужно перечислить список метрик. Они разделяются через запятую. Наименования метрик чувствительны к регистру. Максимальное число метрик в запросе — 20. Со списком метрик уровня визитов можно ознакомиться по ссылке.

Для тестового запроса выберем метрики «Визиты» (ym:s:visits) и «Просмотры» (ym:s:pageviews):metrics=ym:s:visits,ym:s:pageviews

2 — В параметре dimensions нужно перечислить список группировок. Группировки — это необязательный параметр и если их не задать, то в отчете будет представлена общая статистика по сайту. Они также как и метрики разделяются запятой, тоже чувствительны к регистру.

Максимальное их число — 10 в одном запросе. Со списком группировок уровня визитов можно ознакомиться по ссылке. Группировки более разнообразны чем метрики. Лично я чаще всего сталкиваюсь с тем, что набор метрик в запросе всегда неизменен, а вот группировки применяю самые различные, в зависимости от стоящей задачи. Поэтому я бы порекомендовал подробно ознакомиться со списком доступных группировок.

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

  • ym:s:<attribution>SearchEngine> — поисковая система
  • ym:s:<attribution>SearchPhrase> — поисковый запрос
  • ym:s:startURL — посадочная страница

Для группировки по датам можно добавить параметр ym:s:date.

Мы видим в группировках параметр <attribution> В некоторых группировках нужно задать атрибуцию трафика. Она определяет как сессии пользователей будут привязываться к источнику трафика. Например, если мы поставили атрибуцию по последнему источнику, то к конкретному источнику в отчете будут отнесены сессии посетителей, у которых этот источник был последним. Существует несколько типов атрибуции трафика:

  • first — атрибуция по первому источнику
  • last — атрибуция по последнему источнику
  • prev — атрибуция по предыдущему источнику
  • lastSign — атрибуция по последнему значимому источнику (значимым считается любой источник, отличный от прямых и внутренних переходов).

Атрибуция в группировках задается с помощью параметризации и тут существует два способа:

  • Подставить вместо <attribution> один из типов (first, last или lastSign) (например, …&dimensions = ym:s:lastSignSearchEngine&…)
  • Оставить <attribution> в группировке и добавить в запрос параметр attribution (например …&dimensions = ym:s:<attribution>SearchEngine&attribution=lastSign…)

Для тестового запроса выберем группировку «Источник трафика» (ym:s:referer):dimensions=ym:s:referer

О чем еще важно знать:

  1. Существует разделение области действия группировок и метрик на «визиты» и «хиты». Это разделение важно учитывать во внимание при запросах к API, нельзя использовать вместе измерения или метрики, которые относятся к разным областям применения. Группировки и метрики, начинающиеся с «ym:s:», имеют область действия «визиты» (s — session), а группировки и метрики, начинающиеся с «ym:pv:» относятся к «хитам» (pv — pageview — просмотр страницы).
  1. Есть группировки, которые могут принимать в определенных случаях пустое значение (null). Например, группировка «поисковая фраза» будет принимать какое-то значение только, когда есть информация о поисковой фразе. Ясно, что если переход был, к примеру, из социальной сети, то поискового запроса там и в помине не будет. Поэтому если группировка стоит первой в перечне, то при получении статистики из API Метрики будут отображены только те данные, где группировка не принимает пустое значение.

3 — date1 — дата начала отчетного периода в формате YYYY-MM-DD (например, 2022-08-31). Кроме абсолютных значений в формате YYYY-MM-DD можно задавать относительные значения:

  • today — сегодняшняя дата
  • yesterday — вчерашняя дата
  • ndaysAgo — n дней назад от сегодняшней даты, где вместо n надо указать количество дней, например 30daysAgo.

Если не задать начальную дату, то применится значение по умолчанию — 6daysAgo (6 дней назад от текущей даты).

Поставим в качестве даты начала отчета 1 января 2022 года:date1=2022-01-01

4 — date2 — дата окончания отчетного периода в формате YYYY-MM-DD. Формат такой же как у date1. Важно, чтобы date2 не была меньше date1, а так date2 может быть даже в будущем, запрос будет работать.

Конечная дата date2 в нашем отчете будет вчерашним днем:date2=yesterday

5 — параметр limit — ограничение на количество возвращаемых результатов. По умолчанию — 100, но максимум — 10000. Я чаще всего во всех запросах использую limit=10000, этого хватает для большинства запросов, но бывает, что отчет возвращает больше строк и тогда нам поможет следующий параметр.

В нашем запросе будем получать максимум — 10000 строк:limit=10000

6 — параметр offset определяет первую строку выборки, значение по умолчанию — 1, что означает, что отчет будет генерироваться с первой строки. Этот параметр полезен, когда отчет содержит больше чем 10000 строк. Предположим, у нас больше 10000 строк.

Первым запросом с offset=1 и limit=10000 мы выгрузим первые 10000 строк. Установив offset=10001 мы выгрузим данные, начиная с 10001 строки, при limit=10000 это означает, что будут выгружены строки 10001-20000. Если данных больше, чем 20000, то нужно сделать третий запрос, увеличив offset еще на 10000. И так далее в зависимости от объемов данных.

Устанавливаем первую строку:offset=1

7 — ids содержит перечень идентификаторов счетчиков. Это поле поддерживает более одного значения, это значит мы можем одним запросом выгружать данные с нескольких счетчиков.

Для нашего тестового запроса возьмем значения ids=2138128,2215573.

Важно помнить, что если мы включаем в отчет данные более чем 1 счетчика, то они будут сгруппированы по тем группировкам, которые мы задали в dimensions. Это означает, что для того, чтобы разделить данные на отдельные сайты нужно передать в отчет какой-то параметр, который будет точно идентифицировать каждый из сайтов, например, добавить группировку «Домен страницы входа» (ym:s:startURLDomain).

Тогда полный список наших группировок будет таким:dimensions=ym:s:referer,ym:s:startURLDomain

1 Создание файла read_one.php

Откройте папку product, создайте в ней файл read_one.php со следующим содержимым.

2 Создание метода readOne()

Откройте папку objects. Откройте файл product.php и добавьте следующий код внутри класса Product.

// используется при заполнении формы обновления товара
function readOne() {

    // запрос для чтения одной записи (товара)
    $query = "SELECT
                c.name as category_name, p.id, p.name, p.description, p.price, p.category_id, p.created
            FROM
                " . $this->table_name . " p
                LEFT JOIN
                    categories c
                        ON p.category_id = c.id
            WHERE
                p.id = ?
            LIMIT
                0,1";

    // подготовка запроса
    $stmt = $this->conn->prepare( $query );

    // привязываем id товара, который будет обновлен
    $stmt->bindParam(1, $this->id);

    // выполняем запрос
    $stmt->execute();

    // получаем извлеченную строку
    $row = $stmt->fetch(PDO::FETCH_ASSOC);

    // установим значения свойств объекта
    $this->name = $row["name"];
    $this->price = $row["price"];
    $this->description = $row["description"];
    $this->category_id = $row["category_id"];
    $this->category_name = $row["category_name"];
}

Выполняем запрос

Теперь вставим запрос в адресную строку браузера и выполним его, перейдя по URL (ну или просто перейдите по ссылке выше).

Получили вот такой ответ:

Не стоит пугаться, это ответ в формате JSON. На самом деле, это крайне удобный формат данных, но пригоден он для использования в программировании, формировании post-запросов на веб-сервера, а вот человеку не очень просто быстро в нем разобраться. Чтобы облегчить эту задачу сделаем JSON более «красивым», добавив к запросу параметр pretty=true:

1 Создание файла update.php

Откройте папку product, создайте в ней файл update.php и поместите в него следующий код.

2 Создание метода update()

В папке objects откройте файл product.php и добавьте новый метод update() внутри класса Product.

Импорт в Excel

CSV очень просто загрузить в Excel, воспользовавшись функцией «Получение внешних данных из текста», которая находится в разделе «Данные»:

Сначала указываем путь к данным:

Указываем, что наши данные содержат разделители и задаем кодировку файла UTF-8:

Далее указываем используемый разделитель «запятая» и нажимаем «Готово»:

Помещаем данные на имеющийся или новый лист и вуаля:

1 Создание файла delete.php

Откройте папку product и создайте файл delete.php со следующим содержимым.

2 Создание метода delete()

В папке objects откройте файл product.php и добавьте новый метод в класс Product.

1 Создание файла search.php

В папке product создайте файл search.php со следующим кодом.

<?php
// необходимые HTTP-заголовки
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");

// подключение необходимых файлов
include_once "../config/core.php";
include_once "../config/database.php";
include_once "../objects/product.php";

// создание подключения к БД
$database = new Database();
$db = $database->getConnection();

// инициализируем объект
$product = new Product($db);

// получаем ключевые слова
$keywords=isset($_GET["s"]) ? $_GET["s"] : "";

// запрос товаров
$stmt = $product->search($keywords);
$num = $stmt->rowCount();

// проверяем, найдено ли больше 0 записей
if ($num>0) {

    // массив товаров
    $products_arr=array();
    $products_arr["records"]=array();

    // получаем содержимое нашей таблицы
    // fetch() быстрее чем fetchAll()
    while ($row = $stmt->fetch(PDO::FETCH_ASSOC)){
        // извлечём строку
        extract($row);

        $product_item=array(
            "id" => $id,
            "name" => $name,
            "description" => html_entity_decode($description),
            "price" => $price,
            "category_id" => $category_id,
            "category_name" => $category_name
        );

        array_push($products_arr["records"], $product_item);
    }

    // код ответа - 200 OK
    http_response_code(200);

    // покажем товары
    echo json_encode($products_arr);
}

else {
    // код ответа - 404 Ничего не найдено
    http_response_code(404);

    // скажем пользователю, что товары не найдены
    echo json_encode(array("message" => "Товары не найдены."), JSON_UNESCAPED_UNICODE);
}
?>

2 Создание метода search()

В папке objects откройте product.php и добавьте метод search().

// метод search - поиск товаров
function search($keywords){

    // выборка по всем записям
    $query = "SELECT
                c.name as category_name, p.id, p.name, p.description, p.price, p.category_id, p.created
            FROM
                " . $this->table_name . " p
                LEFT JOIN
                    categories c
                        ON p.category_id = c.id
            WHERE
                p.name LIKE ? OR p.description LIKE ? OR c.name LIKE ?
            ORDER BY
                p.created DESC";

    // подготовка запроса
    $stmt = $this->conn->prepare($query);

    // очистка
    $keywords=htmlspecialchars(strip_tags($keywords));
    $keywords = "%{$keywords}%";

    // привязка
    $stmt->bindParam(1, $keywords);
    $stmt->bindParam(2, $keywords);
    $stmt->bindParam(3, $keywords);

    // выполняем запрос
    $stmt->execute();

    return $stmt;
}

Валидация input с помощью html

Для этой задачи воспользуемся атрибутом pattern. При использовании такого подхода, обязательно нужно сообщить пользователю в каком формате необходимо вводить в данное конкретное поле (с помощью label и/или title).

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

Для составления более сложных паттернов необходимо хорошо знать регулярные выражения.

Более сложный пример: валидация номера телефона.

Валидация input с помощью javascript

Теперь будем проверять правильность ввода с помощью JavaScript. С таким подходом можно более оперативно оповещать пользователя о неверном вводе. Повешаем на событие keyup функцию проверки правильности ввода

HTML:

Разрешим ввод только цифр:

Первый аргумент метода replace() – это регулярное выражение (шаблон, по которому будем делать проверку), второй – пустая строка ” “.Т.е. при соответствии заданного шаблона мы очищаем недопустимые символы.

Т.о., пользователь не сможет ввести отличный от цифр символ.

Пример. Введите любое число:

Используя регулярные выражения можно задать абсолютно любой шаблон для input.

Выполнение кода в зависимости от нажатой клавиши

Давайте теперь будем выполнять необходимые действия в зависимости от нажатой клавиши

Для этой задачи воспользуемся оператором switch.

В конструкции case укажите номер кнопки, для которой будет выполнен необходимый код.

Вместо console.log выполняйте необходимые действия.

Если была нажата клавиша, которой нет в списке, то для неё можете выполнить другой код. Писать в default.

Главное преимущество для программиста

После работы с API GA и его громоздким

XML-форматом,

мне хотелось бы отдельно подчеркнуть ещё один важный момент: Метрика позволяет получать данные в JSON! На мой взгляд, это одно из важнейших конкурентных преимуществ перед GA. Все современные языки умеют работать с JSON из коробки, и таким образом отпадает нужда в каких-либо дополнительных библиотеках. В отличие от Google с Метрикой можно сразу сесть и ехать.

Зачем оно нужно?


Итак, зачем же нужно API метрики? С его помощью можно натворить много интересных вещей, например:

  1. Показывать на сайте статистику в реальном времени
  2. Интегрировать статистику сайта в свою CRM
  3. Автоматизировать и упростить работу сотрудников

Информация о нажатой кнопке мыши javascript

Рассмотрим, как определить какая кнопка мыши нажимается над объектом: левая кнопка, правая или дабл клик.

Выполнение кода при клике левой кнопкой мыши:

Выполнение кода при клике правой кнопкой мыши:

Выполнение кода при двойном клике по кнопке:

Использование gulp-terser

Возможно, вы решили воспользоваться gulp-babel, из-за того что вам порядком надоели ошибки: GulpUglifyError: unable to minify JavaScript :

  • Caused by: SyntaxError: Unexpected token: keyword «const»
  • Caused by: SyntaxError: Invalid assignment
  • Caused by: SyntaxError: Unexpected token: name «», expected: punc «;»

Тогда вы можете воспользоваться плагином gulp-terser с поддержкой ECMAScript 2022. ссылка.

Данный пакет сжимает (минифицирует) ES6 код.

Используя fetch api

Код будет работать аналогичным образом, но будет написан с помощью более современного метода fetch().

Как отследить комбинации нажатых клавиш

Отследить нажатие CTRL, SHIFT и ALT можно также другими способами (данный способ необходим чтобы отследить комбинации).

  • ctrlKey – CTRL
  • altKey – ALT
  • shiftKey – SHIFT

Например, отследить нажатие CTRL можно следующим образом:

Используя всю ранее полученную информацию, определим нажатую комбинацию клавиш, например, CTRL F5:

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

Мы рассмотрели, как получить информацию о нажатой клавише на клавиатуре. Теперь давайте рассмотрим, как обработать события мыши.

Кратко об api метрики

Главное отличие API Метрики от API Google Analytics заключается в том, что оно фокусируется на отчетах, а не показателях. Программист, пользующийся GA, должен сказать сервису «я хочу видеть визиты с рекламных источников разбитые по цели 1, количеству визитов, показателю отказов», пользователь Метрики скажет «я хочу видеть отчет по содержанию».

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

Тем не менее, у текущего подхода есть и недостатки. Во-первых, можно запрашивать у сервиса только заранее определенные программистами Яндекса отчеты. Во-вторых, поскольку структуру отчетов менять нельзя, каждый раз вы будете получать избыточный объём информации, что может отразиться на времени отклика сервиса.

Метрика развивается очень быстро (за время написания статьи даже успел немножко поменяться API), поэтому я уверен, что уже скоро можно будет так же, как и в GA, формировать отчеты только для нужных показателей, и описанные выше проблемы пропадут.

Поделиться в pinterest

Для pinterest необходимо так же добавить изображение записи (страницы)

Получение данных с помощью curl php

Изменим немного наш код, переписав с функции file_get_contents на cURL.

Изменённый код:

<?php

ini_set("error_reporting", E_ALL);
ini_set("display_errors", 1);
ini_set("display_startup_errors", 1);

$parameters = array(
    "ids"               => "",                            // номер счётчика метрики
    "metrics"           => "ym:pv:pageviews,ym:pv:users", // данные по: страницам и количеству просмотров
    "dimensions"        => "ym:pv:URLHash",               // группировка по URLHash
    "date1"             => "2022-09-01",                  // с какой даты получить отчёт
    "date2"             => "today",                       // до какой
    "accuracy"          => "full",                        // точная статистика (без округления)
    "limit"             => "100000",                      // максимальный лимит данных
    "proposed_accuracy" => "false"                        // без округления данных
);

array_walk($parameters, function (&$key, $value) {
    return $key = "$value=$key";
});

$parameters = implode("&", $parameters);

$url = "https://api-metrika.yandex.net/stat/v1/data" . "?" . $parameters;

function get_file_curl($url)
{
    $ch = curl_init();
    $headers = [
        "Content-type: application/x-yametrika json",
        "Authorization: OAuth ваш_токен",
    ];

    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // Чтобы curl возвращал данные, вместо того, чтобы выводить их в браузер.
    curl_setopt($ch, CURLOPT_URL, $url);

    $data = curl_exec($ch);
    curl_close($ch);

    return $data;
}

$metrikaRequest = get_file_curl($url);

// echo $metrikaRequest;

if (!empty($metrikaRequest)) {
    file_put_contents($_SERVER["DOCUMENT_ROOT"] . "/metriks.json", $metrikaRequest);
};

Отлично! Мы создали php-файл, который будет получать и сохранять данные API Метрики на нашем сервере.

Статьи про gulp:

  1. Что такое Gulp, зачем он нужен и как его использовать (1 часть).
  2. Использование SASS в Gulp (2 часть).
  3. Автоматическое обновление страницы с помощью browser-sync для Gulp (3 часть).
  4. Использование Babel в Gulp (4 часть – текущая).
  5. Моментальная загрузка сайта на хостинг и синхронизация файлов – gulp-rsync (5 часть).

Стилизация верного и неверного поля ввода.

В основном комбинированием каких-то из этих трёх свойств мы оповещаем пользователя о возможности дальнейшей отправки формы.

Верный ввод:

НЕверный ввод:

Верный ввод при фокусе:

НЕверный ввод при фокусе:

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

НЕверный ввод при фокусе обязательного input

Достаточно гибко можно стилизовать поля для ввода с помощью CSS.

Appendix

Поиграться со сделанным сервисом можно по адресу

Итоговый код за 4 статьи

Резюмируя предыдущие статьи по Gulp, получаем следующий gulpfile.js:

const { src, dest, watch, lastRun, series, parallel } = require("gulp");
const sass = require("gulp-sass");
const sourcemaps = require("gulp-sourcemaps");
const browserSync = require("browser-sync").create(); // сервер   перезагрузка
const babel = require("gulp-babel");                  // для работы с JS
const concat = require("gulp-concat");                // объединение файлов в один

function HTML() {
    return src("app/**/*.html", { since: lastRun(HTML) })
        .pipe(dest("dist/"))
        .pipe(browserSync.stream())
}
exports.HTML = HTML;

function SASS() {
    return src("app/assets/sass/**/*.sass")
        .pipe(sourcemaps.init())
        .pipe(sass({
            outputStyle: "nested"
        }).on("error", sass.logError))
        .pipe(sourcemaps.write("."))
        .pipe(dest("app/assets/css/"))
        .pipe(dest("dist/assets/css/"))
        .pipe(browserSync.stream())
}
exports.SASS = SASS;

function scripts() {
    return src([
        "app/assets/js/script_1.js",
        "app/assets/js/script_2.js",
        "app/assets/js/main.js"
    ], { since: lastRun(HTML) })
        .pipe(sourcemaps.init())
        .pipe(babel({
            presets: ["@babel/preset-env"]
        }))
        .pipe(concat("app.js"))
        .pipe(sourcemaps.write("."))
        .pipe(dest("app/assets/js/"))
        .pipe(dest("dist/assets/js/"))
        .pipe(browserSync.stream())
}
exports.scripts = scripts;

function myServer() {
    browserSync.init({
        server: {
            baseDir: "app" // папка для локального сервера
        },
        notify: false
    });

    watch("app/**/*.html", { usePolling: true }, HTML);            // следим за HTML
    watch("app/assets/sass/**/*.sass", { usePolling: true }, SASS) // следим за SASS
    watch("app/assets/js/**/*.js", { usePolling: true }, scripts)  // следим за JS
}

exports.default = series(HTML, SASS, scripts, myServer);
Похожее:  Плеер moonwalk | Пикабу

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *