├── src ├── .gitkeep ├── YandexMetrikaFacade.php ├── YandexMetrikaServiceProvider.php ├── DataPreparation.php └── YandexMetrika.php ├── config ├── .gitkeep └── yandex-metrika.php ├── .gitignore ├── composer.json ├── LICENSE.md └── README.md /src/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /config/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.idea/ 3 | /vendor/ 4 | composer.phar 5 | 6 | -------------------------------------------------------------------------------- /src/YandexMetrikaFacade.php: -------------------------------------------------------------------------------- 1 | 60, //Время жизни кэша в минутах , с версии laravel 5.8 в секундах 9 | 'counter_id' => '', //Id счетчика Яндекс метрики 10 | 'token' => '', //oauth token 11 | ]; 12 | -------------------------------------------------------------------------------- /src/YandexMetrikaServiceProvider.php: -------------------------------------------------------------------------------- 1 | publishes([$configPath => config_path('yandex-metrika.php')], 19 | 'yandex-metrika'); 20 | } 21 | 22 | /** 23 | * Register the service provider. 24 | * 25 | * @return void 26 | */ 27 | public function register() 28 | { 29 | $this->app->bind('yandexMetrika', function () { 30 | 31 | return new \Alexusmai\YandexMetrika\YandexMetrika; 32 | }); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "alexusmai/yandex-metrika", 3 | "description": "Laravel - Yandex Metrika", 4 | "keywords": ["laravel", "yandex", "metrika"], 5 | "homepage": "https://github.com/alexusami/yandex-metrika", 6 | "license": "MIT", 7 | "authors": [ 8 | { 9 | "name": "Alex Manekin", 10 | "email": "alexusmai@gmail.com" 11 | } 12 | ], 13 | "require": { 14 | "php": ">=5.4.0", 15 | "illuminate/support": "^5.0|^6.0|^7.0|^8.0", 16 | "guzzlehttp/guzzle": "^7.2" 17 | }, 18 | "autoload": { 19 | "psr-4": { 20 | "Alexusmai\\YandexMetrika\\": "src" 21 | } 22 | }, 23 | "extra": { 24 | "laravel": { 25 | "providers": [ 26 | "Alexusmai\\YandexMetrika\\YandexMetrikaServiceProvider" 27 | ], 28 | "aliases": { 29 | "YandexMetrika": "Alexusmai\\YandexMetrika\\YandexMetrikaFacade" 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 alexusmai alexusmai@gmail.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Yandex Metrika Laravel 5 Package 2 | 3 | [![Latest Stable Version](https://poser.pugx.org/alexusmai/yandex-metrika/v/stable)](https://packagist.org/packages/alexusmai/yandex-metrika) 4 | [![Total Downloads](https://poser.pugx.org/alexusmai/yandex-metrika/downloads)](https://packagist.org/packages/alexusmai/yandex-metrika) 5 | [![Latest Unstable Version](https://poser.pugx.org/alexusmai/yandex-metrika/v/unstable)](https://packagist.org/packages/alexusmai/yandex-metrika) 6 | [![License](https://poser.pugx.org/alexusmai/yandex-metrika/license)](https://packagist.org/packages/alexusmai/yandex-metrika) 7 | 8 | Пакет предназначен для получения данных статистики Яндекс Метрики. 9 | 10 | **В связи с последними изменениями, token перенесен в HTTP заголовок - установите v1.0** 11 | 12 | ``` 13 | Передача авторизационного токена в параметрах URL перестанет работать 14 | 13 февраля 2019 года. Чтобы продолжить работу с API Метрики, 15 | настройте авторизацию по токену в HTTP-заголовке. 16 | ``` 17 | 18 | ## Установка 19 | 20 | С помощью Composer 21 | 22 | ``` bash 23 | composer require alexusmai/yandex-metrika 24 | ``` 25 | 26 | Если у вас установлен Laravel 5.4 или более ранней версии, то в app/config/app.php нужно добавить провайдера, 27 | 28 | ``` php 29 | Alexusmai\YandexMetrika\YandexMetrikaServiceProvider::class, 30 | ``` 31 | 32 | и добавить алиас. 33 | 34 | ``` php 35 | 'YandexMetrika' => Alexusmai\YandexMetrika\YandexMetrikaFacade::class, 36 | ``` 37 | 38 | 39 | Публикуем файл настроек 40 | 41 | ``` php 42 | php artisan vendor:publish --provider="Alexusmai\YandexMetrika\YandexMetrikaServiceProvider" --tag="yandex-metrika" 43 | ``` 44 | 45 | ## Настройка 46 | 47 | Метрика использует протокол OAuth, этот протокол позволяет работать с данными Яндекса от лица пользователя Яндекса через приложение, зарегистрированное на Яндексе. 48 | Для начала нужно зарегистрировать новое приложение, и получить token 49 | 50 | - Заходим на страницу 51 | ``` 52 | https://oauth.yandex.ru/ 53 | ``` 54 | - Нажимаем «Зарегистрировать новое приложение» 55 | - Запоняем поле «Название» 56 | - Выбираем в разделе права пункт - Яндекс.Метрика и ставим галочку напротив пункта «Получение статистики, чтение параметров своих и доверенных счетчиков» 57 | - Выбираем «Подставить URL для разработки» под полем «Callback URL» 58 | - Сохраняем 59 | - Копируем ID приложения и заходим на Яндекс под той учетной записью, от имени которой будет работать приложение 60 | - Переходим по URL: 61 | ``` 62 | https://oauth.yandex.ru/authorize?response_type=token&client_id=подставим сюда идентификатор приложения 63 | ``` 64 | - Приложение запросит разрешение на доступ, нажимаем «Разрешить» 65 | - Заносим полученный токен в файл конфигурации пакета. 66 | 67 | 68 | ## Использование 69 | 70 | Большинтсво запросов взято из документации API Яндекс Метрики https://tech.yandex.ru/metrika/ 71 | 72 | Результат запроса - объект. 73 | 74 | ``` 75 | YandexMetrika {#464 ▼ 76 | #url: "https://api-metrika.yandex.net/stat/v1/data" 77 | #counter_id: "12345678" 78 | #getMethodName: "getVisitsViewsUsers" 79 | #adaptMethodName: "adaptVisitsViewsUsers" 80 | +data: array:12 [▼ 81 | "query" => array:14 [▶] 82 | "data" => array:31 [▶] 83 | "total_rows" => 31 84 | "total_rows_rounded" => false 85 | "sampled" => false 86 | "sample_share" => 1.0 87 | "sample_size" => 350 88 | "sample_space" => 350 89 | "data_lag" => 100 90 | "totals" => array:3 [▶] 91 | "min" => array:3 [▶] 92 | "max" => array:3 [▶] 93 | ] 94 | +adaptData: null 95 | } 96 | ``` 97 | Если данные не получены - null. 98 | Ошибки возникающие при запросе данных пишутся в лог с названием Yandex Metrika: 99 | 100 | Все запросы кэшируются, время жизни кэша указывается в конфигурационном файле. 101 | 102 | Для обработки полученных данных есть дополнительные методы, которые делают данные более удобными для применения. 103 | Для их спользования используйте метод adapt() 104 | Не у всех методов для получения данных есть метод для обработки. У getRequestToApi() - нету 105 | 106 | ### Использование нескольких счетчиков. 107 | 108 | Если вам нужно получать данные от разных счетчиков 109 | 110 | ```php 111 | YandexMetrika::setCounter($token, $counterId, $cache)->тут имя метода; 112 | 113 | // Например 114 | YandexMetrika::setCounter($token, $counterId, $cache)->getVisitsViewsUsers(); 115 | 116 | // $token и $counterId - нужно передавать обязательно, параметр $cache - необязательно(если не передан то будет использоваться из настроек) 117 | ``` 118 | 119 | ### Получаем кол-во: визитов, просмотров, уникальных посетителей по дням 120 | 121 | ``` php 122 | YandexMetrika::getVisitsViewsUsers(); //По умолчанию - за последние 30 дней 123 | //Пример 124 | YandexMetrika::getVisitsViewsUsers(10); //За последние 10 дней 125 | //За период 126 | YandexMetrika::getVisitsViewsUsersForPeriod(DateTime $startDate, DateTime $endDate) //За указанный период 127 | //Обработка полученных данных для построения графика Highcharts › Basic line 128 | YandexMetrika::getVisitsViewsUsers()->adapt(); 129 | ``` 130 | 131 | ### Самые просматриваемые страницы 132 | 133 | ``` php 134 | YandexMetrika::getTopPageViews(); //По умолчанию за последние 30 дней, количество результатов - 10 135 | //Пример 136 | YandexMetrika::getTopPageViews(10, 50); //За последние 10 дней, максимум 50 результатов 137 | //За период 138 | YandexMetrika::getTopPageViewsForPeriod(DateTime $startDate, DateTime $endDate, $maxResults = 10) //По умолчанию максимум 10 результатов 139 | //Обработка полученных данных 140 | YandexMetrika::getTopPageViews()->adapt(); 141 | ``` 142 | 143 | ### Отчет "Источники - Сводка" 144 | 145 | ``` php 146 | YandexMetrika::getSourceSummary(); //По умолчанию за последние 30 дней 147 | //Пример 148 | YandexMetrika::getSourceSummary(7); //За последние 10 дней 149 | //За период 150 | YandexMetrika::getSourcesSummaryForPeriod(DateTime $startDate, DateTime $endDate) 151 | //Обработка полученных данных 152 | YandexMetrika::getSourcesSummary()->adapt(); 153 | ``` 154 | 155 | ### Отчет "Источники - Поисковые фразы" 156 | 157 | ``` php 158 | YandexMetrika::getSourcesSearchPhrases(); //По умолчанию за последние 30 дней, количество результатов - 10 159 | //Пример 160 | YandexMetrika::getSourcesSearchPhrases(15, 20); //За последние 15 дней, максимум 20 результатов 161 | //За период 162 | YandexMetrika::getSourcesSearchPhrasesForPeriod(DateTime $startDate, DateTime $endDate, $maxResult = 10) //По максимум - 10 результатов 163 | //Обработка полученных данных 164 | YandexMetrika::getSourcesSearchPhrases()->adapt(); 165 | ``` 166 | 167 | ### Отчет "Технологии - Браузеры" 168 | 169 | ``` php 170 | YandexMetrika::getTechPlatforms(); //По умолчанию за последние 30 дней, макс количество результатов - 10 171 | //Пример 172 | YandexMetrika::getTechPlatforms(12, 5); //За последние 12 дней, максимум 5 результатов 173 | //За период 174 | YandexMetrika::getTechPlatformsForPeriod(DateTime $startDate, DateTime $endDate, $maxResult = 10) //По умолчанию максимум 10 результатов 175 | //Обработка полученных данных 176 | YandexMetrika::getTechPlatforms()->adapt(); 177 | ``` 178 | 179 | ### Количество визитов и посетителей с учетом поисковых систем 180 | 181 | ``` php 182 | YandexMetrika::getVisitsUsersSearchEngine(); //По умолчанию за последние 30 дней, макс количество результатов - 10 183 | //Пример 184 | YandexMetrika::getVisitsUsersSearchEngine(24, 60); //За последние 24 дня, максимум 60 результатов 185 | //За период 186 | YandexMetrika::getVisitsUsersSearchEngineForPeriod(DateTime $startDate, DateTime $endDate, $maxResult = 10) //По умолчанию максимум 10 результатов 187 | //Обработка полученных данных 188 | YandexMetrika::getVisitsUsersSearchEngine()->adapt(); 189 | ``` 190 | 191 | ### Количество визитов с заданной глубиной просмотра 192 | 193 | ``` php 194 | YandexMetrika::getVisitsViewsPageDepth(); //По умолчанию за последние 30 дней, количество просмотренных страниц - 5 195 | //Пример 196 | YandexMetrika::getVisitsViewsPageDepth(14, 30); //За последние 14 дней, макс количество результатов - 30 197 | //За период 198 | YandexMetrika::getVisitsViewsPageDepthForPeriod(DateTime $startDate, DateTime $endDate, $pages = 5) //По умолчанию - 5 страниц 199 | //Обработка полученных данных 200 | YandexMetrika::getVisitsViewsPageDepth()->adapt(); 201 | ``` 202 | 203 | ### Отчеты о посещаемости сайта с распределением по странам и регионам 204 | 205 | ``` php 206 | YandexMetrika::getGeoCountry(); //По умолчанию за последние 7 дней, макс количество результатов - 100 207 | //Пример 208 | YandexMetrika::getGeoCountry(12, 30); //За последние 12 дней, макс количество результатов - 30 209 | //За период 210 | YandexMetrika::getGeoCountryForPeriod(DateTime $startDate, DateTime $endDate, $maxResult = 100) //По умолчанию максимум 100 результатов 211 | //Обработка полученных данных для построения графика Highcharts.js > Pie with drilldown 212 | YandexMetrika::getGeoCountry()->adapt()(); 213 | ``` 214 | 215 | ### Отчеты о посещаемости сайта с распределением по областям и городам 216 | 217 | ``` php 218 | YandexMetrika::getGeoArea(); //По умолчанию за последние 7 дней, макс количество результатов - 100, Страна - Россия (id-225) 219 | //Пример 220 | YandexMetrika::getGeoArea(12, 30, 187); //За последние 12 дней, макс количество результатов - 30, страна - Украина 221 | //За период 222 | YandexMetrika::getGeoAreaForPeriod(DateTime $startDate, DateTime $endDate, $maxResult = 100, $countryId = 225) 223 | //Обработка полученных данных для построения графика Highcharts.js > Pie with drilldown 224 | YandexMetrika::getGeoArea()->adapt()(); 225 | ``` 226 | 227 | Для методов getGeoCountry() и getGeoArea() - метод обработки данных общий - adaptGeoPie() 228 | 229 | ### Произвольный запрос к Api Yandex Metrika 230 | 231 | ``` php 232 | //Параметры запроса 233 | $urlParams = [ 234 | 'ids' => '123456', //id счетчика 235 | 'date1' => Carbon::today()->subDays(10), //Начальная дата 236 | 'date2' => Carbon::today(), //Конечная дата 237 | 'metrics' => 'ym:s:visits', 238 | 'filters' => 'ym:s:pageViews>5' 239 | ]; 240 | //Запрос 241 | YandexMetrika::getRequestToApi($urlParams); 242 | ``` 243 | -------------------------------------------------------------------------------- /src/DataPreparation.php: -------------------------------------------------------------------------------- 1 | data['data'] as $item) { 19 | $itemArray['date'][] = Carbon::createFromFormat('Y-m-d', 20 | $item['dimensions'][0]['name'])->formatLocalized('%e.%m'); 21 | $itemArray['visits'][] = $item['metrics'][0]; 22 | $itemArray['pageviews'][] = $item['metrics'][1]; 23 | $itemArray['users'][] = $item['metrics'][2]; 24 | } 25 | 26 | $dataArray = [ 27 | ['name' => 'Визиты', 'data' => $itemArray['visits']], 28 | ['name' => 'Просмотры', 'data' => $itemArray['pageviews']], 29 | ['name' => 'Посетители', 'data' => $itemArray['users']], 30 | ]; 31 | 32 | $this->adaptData = [ 33 | 'dataArray' => json_encode($dataArray, JSON_UNESCAPED_UNICODE), 34 | 'dateArray' => json_encode($itemArray['date'], 35 | JSON_UNESCAPED_UNICODE), 36 | ]; 37 | } 38 | 39 | /** 40 | * Самые просматриваемые страницы 41 | */ 42 | protected function adaptTopPageViews() 43 | { 44 | $dataArray = []; 45 | 46 | //Формируем массив 47 | foreach ($this->data['data'] as $item) { 48 | $dataArray[] = [ 49 | 'url' => $item['dimensions'][0]['name'], 50 | 'title' => $item['dimensions'][1]['name'], 51 | 'pageviews' => $item['metrics'][0], 52 | ]; 53 | } 54 | 55 | $this->adaptData = $dataArray; 56 | } 57 | 58 | /** 59 | * Отчет "Источники - Сводка" 60 | */ 61 | protected function adaptSourcesSummary() 62 | { 63 | $dataArray = []; 64 | 65 | //Формируем массив 66 | foreach ($this->data['data'] as $item) { 67 | $dataArray['data'][] = [ 68 | 'trafficSource' => $item['dimensions'][0]['name'], 69 | 'sourceEngine' => $item['dimensions'][1]['name'], 70 | 'visits' => $item['metrics'][0], 71 | //Визиты 72 | 'bounceRate' => $item['metrics'][1], 73 | //Отказы % 74 | 'pageDepth' => $item['metrics'][2], 75 | //Глубина просмотра 76 | 'avgVisitDurationSeconds' => date("i:s", $item['metrics'][3]) 77 | //Время проведенное на сайте мин:сек. 78 | ]; 79 | } 80 | 81 | //Итого и средние значения 82 | $dataArray['totals'] = [ 83 | 'visits' => $this->data['totals'][0], 84 | 'bounceRate' => $this->data['totals'][1], 85 | 'pageDepth' => $this->data['totals'][2], 86 | 'avgVisitDurationSeconds' => date("i:s", $this->data['totals'][3]), 87 | ]; 88 | 89 | $this->adaptData = $dataArray; 90 | } 91 | 92 | /** 93 | * Отчет "Источники - Поисковые фразы" 94 | */ 95 | protected function adaptSourcesSearchPhrases() 96 | { 97 | $dataArray = []; 98 | 99 | //Формируем массив 100 | foreach ($this->data['data'] as $item) { 101 | $dataArray['data'][] = [ 102 | 'searchPhrase' => $item['dimensions'][0]['name'], 103 | 'searchEngineRoot' => $item['dimensions'][1]['name'], 104 | 'visits' => $item['metrics'][0], 105 | //Визиты 106 | 'bounceRate' => $item['metrics'][1], 107 | //Отказы % 108 | 'pageDepth' => $item['metrics'][2], 109 | //Глубина просмотра 110 | 'avgVisitDurationSeconds' => date("i:s", $item['metrics'][3]) 111 | //Время проведенное на сайте мин:сек. 112 | ]; 113 | } 114 | 115 | //Итого и средние значения 116 | $dataArray['totals'] = [ 117 | 'visits' => $this->data['totals'][0], 118 | 'bounceRate' => $this->data['totals'][1], 119 | 'pageDepth' => $this->data['totals'][2], 120 | 'avgVisitDurationSeconds' => date("i:s", $this->data['totals'][3]), 121 | ]; 122 | 123 | $this->adaptData = $dataArray; 124 | } 125 | 126 | /** 127 | * Отчет "Технологии - Браузеры" 128 | */ 129 | protected function adaptTechPlatforms() 130 | { 131 | $dataArray = []; 132 | 133 | //Формируем массив 134 | foreach ($this->data['data'] as $item) { 135 | $dataArray['data'][] = [ 136 | 'browser' => $item['dimensions'][0]['name'], 137 | 'visits' => $item['metrics'][0], 138 | //Визиты 139 | 'bounceRate' => $item['metrics'][1], 140 | //Отказы % 141 | 'pageDepth' => $item['metrics'][2], 142 | //Глубина просмотра 143 | 'avgVisitDurationSeconds' => date("i:s", $item['metrics'][3]) 144 | //Время проведенное на сайте мин:сек. 145 | ]; 146 | } 147 | 148 | //Итого и средние значения 149 | $dataArray['totals'] = [ 150 | 'visits' => $this->data['totals'][0], 151 | 'bounceRate' => $this->data['totals'][1], 152 | 'pageDepth' => $this->data['totals'][2], 153 | 'avgVisitDurationSeconds' => date("i:s", $this->data['totals'][3]), 154 | ]; 155 | 156 | $this->adaptData = $dataArray; 157 | } 158 | 159 | /** 160 | * Количество визитов и посетителей с учетом поисковых систем 161 | */ 162 | protected function adaptVisitsUsersSearchEngine() 163 | { 164 | $dataArray = []; 165 | 166 | //Формируем массив 167 | foreach ($this->data['data'] as $item) { 168 | $dataArray['data'][] = [ 169 | 'searchEngine' => $item['dimensions'][0]['name'], 170 | 'users' => $item['metrics'][0] //Юзеры 171 | ]; 172 | } 173 | 174 | //Итого 175 | $dataArray['totals'] = [ 176 | 'users' => $this->data['totals'][0], 177 | ]; 178 | 179 | $this->adaptData = $dataArray; 180 | } 181 | 182 | /** 183 | * Количество визитов с глубиной просмотра больше $pages страниц, за $days дней 184 | */ 185 | protected function adaptVisitsViewsPageDepth() 186 | { 187 | $this->adaptData = $this->data['totals'][0]; 188 | } 189 | 190 | /** 191 | * Вызов общего метода adaptGeoPie() 192 | */ 193 | protected function adaptGeoArea() 194 | { 195 | $this->adaptGeoPie(); 196 | } 197 | 198 | /** 199 | * Вызов общего метода adaptGeoPie() 200 | */ 201 | protected function adaptGeoCountry() 202 | { 203 | $this->adaptGeoPie(); 204 | } 205 | 206 | /** 207 | * География посещений Страны/Области 208 | * Подготовка данных для построения графика Highcharts > Pie with drilldown 209 | */ 210 | protected function adaptGeoPie() 211 | { 212 | //Выбираем уникальные id стран/областей 213 | $key_array = []; 214 | 215 | //Результирующий массив с id и названием страны/области 216 | $idArray = []; 217 | 218 | foreach ($this->data['data'] as $value) { 219 | //Проверяем есть ли такое значение в массиве 220 | if (!in_array($value['dimensions'][0]['id'], $key_array)) { 221 | //Если нет то заносим в массив для поиска и в результирующий массив 222 | $key_array[] = $value['dimensions'][0]['id']; 223 | $idArray[] = $value['dimensions'][0]; 224 | } 225 | } 226 | 227 | //Колличество уникальных стран/областей 228 | $cnt = count($idArray); 229 | 230 | //Массивы для построения графика 231 | $dataArray = []; // страны/области 232 | $drilldownArray = []; // области/города 233 | 234 | for ($i = 0; $i < $cnt; $i++) { 235 | $dataArray[$i] = [ 236 | 'name' => $idArray[$i]['name'], 237 | 'y' => 0, 238 | 'drilldown' => $idArray[$i]['name'], 239 | ]; 240 | 241 | $drilldownArray[$i] = [ 242 | 'name' => $idArray[$i]['name'], 243 | 'id' => $idArray[$i]['name'], 244 | 'data' => [], 245 | ]; 246 | 247 | //Перебираем исходный массив и выбираем нужные данные 248 | foreach ($this->data['data'] as $item) { 249 | 250 | //Если id страны/области совпадает 251 | if ($item['dimensions'][0]['id'] == $idArray[$i]['id']) { 252 | //Добавляем кол-во визитов в общий список страны/области 253 | $dataArray[$i]['y'] += $item['metrics'][0]; 254 | 255 | //Если нет названия у области/города 256 | if ($item['dimensions'][1]['name']) { 257 | $region = $item['dimensions'][1]['name']; 258 | } else { 259 | $region = 'Не определено'; 260 | } 261 | 262 | //Добавляем данные по области/городу 263 | $drilldownArray[$i]['data'][] = [ 264 | $region, 265 | $item['metrics'][0], 266 | ]; 267 | } 268 | } 269 | } 270 | 271 | $this->adaptData = [ 272 | 'dataArray' => json_encode($dataArray, JSON_UNESCAPED_UNICODE), 273 | 'drilldownArray' => json_encode($drilldownArray, 274 | JSON_UNESCAPED_UNICODE), 275 | ]; 276 | } 277 | } 278 | -------------------------------------------------------------------------------- /src/YandexMetrika.php: -------------------------------------------------------------------------------- 1 | counter_id = config('yandex-metrika.counter_id'); 79 | $this->token = config('yandex-metrika.token'); 80 | $this->cache = config('yandex-metrika.cache'); 81 | } 82 | 83 | /** 84 | * Вызов методов получения данных 85 | * 86 | * @param $name 87 | * @param $arguments 88 | * 89 | * @return $this 90 | */ 91 | public function __call($name, $arguments) 92 | { 93 | if (method_exists($this, $name)) { 94 | 95 | $this->getMethodName = $name; 96 | 97 | $this->adaptMethodName = str_replace(['get', 'ForPeriod'], 98 | ['adapt', ''], $this->getMethodName); 99 | 100 | call_user_func_array([$this, $name], $arguments); 101 | } 102 | 103 | return $this; 104 | } 105 | 106 | /** 107 | * Приводим полученные данные в удобочитаемый вид 108 | * 109 | * @return $this 110 | */ 111 | public function adapt() 112 | { 113 | if (method_exists($this, $this->adaptMethodName) && $this->data) { 114 | call_user_func([$this, $this->adaptMethodName]); 115 | } 116 | 117 | return $this; 118 | } 119 | 120 | /** 121 | * Установить другой счетчик 122 | * 123 | * @param $token 124 | * @param $counterId 125 | * @param null $cache 126 | * 127 | * @return $this 128 | */ 129 | public function setCounter($token, $counterId, $cache = null) 130 | { 131 | $this->token = $token; 132 | $this->counter_id = $counterId; 133 | $this->cache = $cache ? $cache : config('yandex-metrika.cache'); 134 | 135 | return $this; 136 | } 137 | 138 | /** 139 | * Получаем кол-во: визитов, просмотров, уникальных посетителей по дням, 140 | * за выбранное кол-во дней 141 | * 142 | * @param int $days 143 | */ 144 | protected function getVisitsViewsUsers($days = 30) 145 | { 146 | list($startDate, $endDate) = $this->calculateDays($days); 147 | 148 | $this->getVisitsViewsUsersForPeriod($startDate, $endDate); 149 | } 150 | 151 | /** 152 | * Получаем кол-во: визитов, просмотров, уникальных посетителей по дням, 153 | * за выбранный период 154 | * 155 | * @param DateTime $startDate 156 | * @param DateTime $endDate 157 | */ 158 | protected function getVisitsViewsUsersForPeriod( 159 | DateTime $startDate, 160 | DateTime $endDate 161 | ) { 162 | $cacheName = md5(serialize('visits-views-users' 163 | .$startDate->format('Y-m-d').$endDate->format('Y-m-d'))); 164 | 165 | $urlParams = [ 166 | 'ids' => $this->counter_id, 167 | 'date1' => $startDate->format('Y-m-d'), 168 | 'date2' => $endDate->format('Y-m-d'), 169 | 'metrics' => 'ym:s:visits,ym:s:pageviews,ym:s:users', 170 | 'dimensions' => 'ym:s:date', 171 | 'sort' => 'ym:s:date', 172 | ]; 173 | 174 | $this->data = $this->request($urlParams, $cacheName); 175 | } 176 | 177 | /** 178 | * Самые просматриваемые страницы за $days, количество - $maxResult 179 | * 180 | * @param int $days 181 | * @param int $maxResults 182 | */ 183 | protected function getTopPageViews($days = 30, $maxResults = 10) 184 | { 185 | list($startDate, $endDate) = $this->calculateDays($days); 186 | 187 | $this->getTopPageViewsForPeriod($startDate, $endDate, $maxResults); 188 | } 189 | 190 | /** 191 | * Самые просматриваемые страницы за выбранный период, количество - $maxResult 192 | * 193 | * @param DateTime $startDate 194 | * @param DateTime $endDate 195 | * @param int $maxResults 196 | */ 197 | protected function getTopPageViewsForPeriod( 198 | DateTime $startDate, 199 | DateTime $endDate, 200 | $maxResults = 10 201 | ) { 202 | $cacheName = md5(serialize('top-pages-views'.$startDate->format('Y-m-d') 203 | .$endDate->format('Y-m-d').$maxResults)); 204 | 205 | //Параметры запроса 206 | $urlParams = [ 207 | 'ids' => $this->counter_id, 208 | 'date1' => $startDate->format('Y-m-d'), 209 | 'date2' => $endDate->format('Y-m-d'), 210 | 'metrics' => 'ym:pv:pageviews', 211 | 'dimensions' => 'ym:pv:URLPathFull,ym:pv:title', 212 | 'sort' => '-ym:pv:pageviews', 213 | 'limit' => $maxResults, 214 | ]; 215 | 216 | $this->data = $this->request($urlParams, $cacheName); 217 | } 218 | 219 | /** 220 | * Отчет "Источники - Сводка" за последние $days дней 221 | * 222 | * @param int $days 223 | */ 224 | protected function getSourcesSummary($days = 30) 225 | { 226 | list($startDate, $endDate) = $this->calculateDays($days); 227 | 228 | $this->getSourcesSummaryForPeriod($startDate, $endDate); 229 | } 230 | 231 | /** 232 | * Отчет "Источники - Сводка" за период 233 | * 234 | * @param DateTime $startDate 235 | * @param DateTime $endDate 236 | */ 237 | protected function getSourcesSummaryForPeriod( 238 | DateTime $startDate, 239 | DateTime $endDate 240 | ) { 241 | $cacheName = md5(serialize('sources-summary'.$startDate->format('Y-m-d') 242 | .$endDate->format('Y-m-d'))); 243 | 244 | $urlParams = [ 245 | 'ids' => $this->counter_id, 246 | 'date1' => $startDate->format('Y-m-d'), 247 | 'date2' => $endDate->format('Y-m-d'), 248 | 'preset' => 'sources_summary', 249 | ]; 250 | 251 | $this->data = $this->request($urlParams, $cacheName); 252 | } 253 | 254 | /** 255 | * Отчет "Источники - Поисковые фразы" за $days дней, кол-во результатов - $maxResult 256 | * 257 | * @param int $days 258 | * @param int $maxResult 259 | */ 260 | protected function getSourcesSearchPhrases($days = 30, $maxResult = 10) 261 | { 262 | list($startDate, $endDate) = $this->calculateDays($days); 263 | 264 | $this->getSourcesSearchPhrasesForPeriod($startDate, $endDate, 265 | $maxResult); 266 | } 267 | 268 | /** 269 | * Отчет "Источники - Поисковые фразы" за период, кол-во результатов - $maxResult 270 | * 271 | * @param DateTime $startDate 272 | * @param DateTime $endDate 273 | * @param int $maxResult 274 | */ 275 | protected function getSourcesSearchPhrasesForPeriod( 276 | DateTime $startDate, 277 | DateTime $endDate, 278 | $maxResult = 10 279 | ) { 280 | $cacheName = md5(serialize('sources-search-phrases' 281 | .$startDate->format('Y-m-d').$endDate->format('Y-m-d').$maxResult)); 282 | 283 | $urlParams = [ 284 | 'ids' => $this->counter_id, 285 | 'date1' => $startDate->format('Y-m-d'), 286 | 'date2' => $endDate->format('Y-m-d'), 287 | 'preset' => 'sources_search_phrases', 288 | 'limit' => $maxResult, 289 | ]; 290 | 291 | $this->data = $this->request($urlParams, $cacheName); 292 | } 293 | 294 | /** 295 | * Отчет "Технологии - Браузеры" за $days дней, кол-во результатов - $maxResult 296 | * 297 | * @param int $days 298 | * @param int $maxResult 299 | */ 300 | protected function getTechPlatforms($days = 30, $maxResult = 10) 301 | { 302 | list($startDate, $endDate) = $this->calculateDays($days); 303 | 304 | $this->getTechPlatformsForPeriod($startDate, $endDate, $maxResult); 305 | } 306 | 307 | /** 308 | * Отчет "Технологии - Браузеры" за период, кол-во результатов - $maxResult 309 | * 310 | * @param DateTime $startDate 311 | * @param DateTime $endDate 312 | * @param int $maxResult 313 | */ 314 | protected function getTechPlatformsForPeriod( 315 | DateTime $startDate, 316 | DateTime $endDate, 317 | $maxResult = 10 318 | ) { 319 | $cacheName = md5(serialize('tech_platforms'.$startDate->format('Y-m-d') 320 | .$endDate->format('Y-m-d').$maxResult)); 321 | 322 | $urlParams = [ 323 | 'ids' => $this->counter_id, 324 | 'date1' => $startDate->format('Y-m-d'), 325 | 'date2' => $endDate->format('Y-m-d'), 326 | 'preset' => 'tech_platforms', 327 | 'dimensions' => 'ym:s:browser', 328 | 'limit' => $maxResult, 329 | ]; 330 | 331 | $this->data = $this->request($urlParams, $cacheName); 332 | } 333 | 334 | /** 335 | * Количество визитов и посетителей с учетом поисковых систем за $days дней 336 | * 337 | * @param int $days 338 | * @param int $maxResult 339 | */ 340 | protected function getVisitsUsersSearchEngine($days = 30, $maxResult = 10) 341 | { 342 | list($startDate, $endDate) = $this->calculateDays($days); 343 | 344 | $this->getVisitsUsersSearchEngineForPeriod($startDate, $endDate, 345 | $maxResult); 346 | } 347 | 348 | /** 349 | * Количество визитов и посетителей с учетом поисковых систем за период 350 | * 351 | * @param DateTime $startDate 352 | * @param DateTime $endDate 353 | * @param int $maxResult 354 | */ 355 | protected function getVisitsUsersSearchEngineForPeriod( 356 | DateTime $startDate, 357 | DateTime $endDate, 358 | $maxResult = 10 359 | ) { 360 | $cacheName = md5(serialize('visits-users-searchEngine' 361 | .$startDate->format('Y-m-d').$endDate->format('Y-m-d').$maxResult)); 362 | 363 | $urlParams = [ 364 | 'ids' => $this->counter_id, 365 | 'date1' => $startDate->format('Y-m-d'), 366 | 'date2' => $endDate->format('Y-m-d'), 367 | 'metrics' => 'ym:s:users', 368 | 'dimensions' => 'ym:s:searchEngine', 369 | 'filters' => "ym:s:trafficSource=='organic'", 370 | 'limit' => $maxResult, 371 | ]; 372 | 373 | $this->data = $this->request($urlParams, $cacheName); 374 | } 375 | 376 | /** 377 | * Количество визитов с глубиной просмотра больше $pages страниц, за $days дней 378 | * 379 | * @param int $days 380 | * @param int $pages 381 | */ 382 | protected function getVisitsViewsPageDepth($days = 30, $pages = 5) 383 | { 384 | list($startDate, $endDate) = $this->calculateDays($days); 385 | 386 | $this->getVisitsViewsPageDepthForPeriod($startDate, $endDate, $pages); 387 | } 388 | 389 | /** 390 | * Количество визитов с глубиной просмотра больше $pages страниц, за период 391 | * 392 | * @param DateTime $startDate 393 | * @param DateTime $endDate 394 | * @param int $pages 395 | */ 396 | protected function getVisitsViewsPageDepthForPeriod( 397 | DateTime $startDate, 398 | DateTime $endDate, 399 | $pages = 5 400 | ) { 401 | $cacheName = md5(serialize('visits-views-page-depth' 402 | .$startDate->format('Y-m-d').$endDate->format('Y-m-d').$pages)); 403 | 404 | //Параметры запроса 405 | $urlParams = [ 406 | 'ids' => $this->counter_id, 407 | 'date1' => $startDate->format('Y-m-d'), 408 | 'date2' => $endDate->format('Y-m-d'), 409 | 'metrics' => 'ym:s:visits', 410 | 'filters' => 'ym:s:pageViews>'.$pages, 411 | ]; 412 | 413 | $this->data = $this->request($urlParams, $cacheName); 414 | } 415 | 416 | /** 417 | * Отчеты о посещаемости сайта с распределением по странам и регионам, за последние $days, 418 | * кол-во результатов - $maxResult 419 | * 420 | * @param int $days 421 | * @param int $maxResult 422 | */ 423 | protected function getGeoCountry($days = 7, $maxResult = 100) 424 | { 425 | list($startDate, $endDate) = $this->calculateDays($days); 426 | 427 | $this->getGeoCountryForPeriod($startDate, $endDate, $maxResult); 428 | } 429 | 430 | /** 431 | * Отчеты о посещаемости сайта с распределением по странам и регионам, за период 432 | * 433 | * @param DateTime $startDate 434 | * @param DateTime $endDate 435 | * @param int $maxResult 436 | */ 437 | protected function getGeoCountryForPeriod( 438 | DateTime $startDate, 439 | DateTime $endDate, 440 | $maxResult = 100 441 | ) { 442 | $cacheName = md5(serialize('geo_country'.$startDate->format('Y-m-d') 443 | .$endDate->format('Y-m-d').$maxResult)); 444 | 445 | //Параметры запроса 446 | $urlParams = [ 447 | 'ids' => $this->counter_id, 448 | 'date1' => $startDate->format('Y-m-d'), 449 | 'date2' => $endDate->format('Y-m-d'), 450 | 'dimensions' => 'ym:s:regionCountry,ym:s:regionArea', 451 | 'metrics' => 'ym:s:visits', 452 | 'sort' => '-ym:s:visits', 453 | 'limit' => $maxResult, 454 | ]; 455 | 456 | $this->data = $this->request($urlParams, $cacheName); 457 | } 458 | 459 | /** 460 | * Отчеты о посещаемости сайта с распределением по областям и городам, за последние $days, 461 | * кол-во результатов - $maxResult, $countryId - id страны(225 - Россия, 187 - Украина... и т.п.) 462 | * 463 | * @param int $days 464 | * @param int $maxResult 465 | * @param int $countryId 466 | */ 467 | protected function getGeoArea($days = 7, $maxResult = 100, $countryId = 225) 468 | { 469 | list($startDate, $endDate) = $this->calculateDays($days); 470 | 471 | $this->getGeoAreaForPeriod($startDate, $endDate, $maxResult, 472 | $countryId); 473 | } 474 | 475 | /** 476 | * Отчеты о посещаемости сайта с распределением по областям и городам, за период 477 | * 478 | * @param DateTime $startDate 479 | * @param DateTime $endDate 480 | * @param int $maxResult 481 | * @param int $countryId 482 | */ 483 | protected function getGeoAreaForPeriod( 484 | DateTime $startDate, 485 | DateTime $endDate, 486 | $maxResult = 100, 487 | $countryId = 225 488 | ) { 489 | $cacheName = md5(serialize('geo_region'.$startDate->format('Y-m-d') 490 | .$endDate->format('Y-m-d').$maxResult.$countryId)); 491 | 492 | $urlParams = [ 493 | 'ids' => $this->counter_id, 494 | 'date1' => $startDate->format('Y-m-d'), 495 | 'date2' => $endDate->format('Y-m-d'), 496 | 'dimensions' => 'ym:s:regionArea,ym:s:regionCity', 497 | 'metrics' => 'ym:s:visits', 498 | 'sort' => '-ym:s:visits', 499 | 'filters' => "ym:s:regionCountry=='$countryId'", 500 | //225 - Россия 501 | 'limit' => $maxResult, 502 | ]; 503 | 504 | $this->data = $this->request($urlParams, $cacheName); 505 | } 506 | 507 | /** 508 | * Произвольный запрос к Api Yandex Metrika 509 | * Пример: 510 | * $urlParams = [ 511 | * 'ids' => id счетчика, 512 | * 'date1' => Дата в формате 'Y-m-d', 513 | * 'date2' => Дата в формате 'Y-m-d', 514 | * 'filters' => 'ym:s:pageViews>5', 515 | * 'metrics' => 'ym:s:visits' 516 | * ] 517 | * 518 | * @param array $urlParams 519 | * 520 | * @return $this 521 | */ 522 | public function getRequestToApi(array $urlParams) 523 | { 524 | $cacheName = md5(serialize($urlParams)); 525 | 526 | $this->data = $this->request($urlParams, $cacheName); 527 | 528 | return $this; 529 | } 530 | 531 | /** 532 | * GET запрос данных и кэширование 533 | * 534 | * @param $urlParams 535 | * @param $name 536 | * 537 | * @return mixed|null 538 | */ 539 | protected function request($urlParams, $name) 540 | { 541 | $cacheName = $this->counter_id.'_'.$name; 542 | 543 | if (Cache::has($cacheName)) { 544 | return Cache::get($cacheName); 545 | } 546 | 547 | try { 548 | $client = new GuzzleClient([ 549 | 'headers' => [ 550 | 'Content-Type' => 'application/x-yametrika+json', 551 | 'Authorization' => 'OAuth '.$this->token, 552 | ], 553 | ]); 554 | 555 | $response = $client->request('GET', $this->url, 556 | ['query' => $urlParams]); 557 | 558 | $result = json_decode($response->getBody(), true); 559 | 560 | } catch (ClientException $e) { 561 | Log::error('Yandex Metrika: '.$e->getMessage()); 562 | 563 | $result = null; 564 | } 565 | 566 | if ($result) { 567 | Cache::put($cacheName, $result, $this->cache); 568 | } 569 | 570 | return $result; 571 | } 572 | 573 | /** 574 | * Вычисляем даты 575 | * 576 | * @param $numberOfDays 577 | * 578 | * @return array 579 | */ 580 | protected function calculateDays($numberOfDays) 581 | { 582 | $endDate = Carbon::today(); 583 | $startDate = Carbon::today()->subDays($numberOfDays); 584 | 585 | return [$startDate, $endDate]; 586 | } 587 | } 588 | --------------------------------------------------------------------------------