Skip to main content
VK API Добавление групп

VK API — Добавление групп.

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

Рекомендую вам сразу выкачать код с репозитория. Так как изменения довольно объёмные, а в этой статье я буду описывать только основные нюансы. Ссылка на репозиторий.

Я поменял структуру приложения. Первое, что сделал, это добавил psr-4 загрузчик, Он позволит нам красиво оформить неймспейсы, четко разделяя приложение на компоненты. Для этого нужно привести файл composer.json к виду:

{
  "require": {
    "slim/slim": "^3.0",
    "twbs/bootstrap": "4.0.0-alpha.6",
    "illuminate/database": "^5.4",
    "slim/twig-view": "^2.2",
    "guzzlehttp/guzzle": "~6.0"
  },
    "autoload": {
        "psr-4": {
            "App\\": "app/"
        }
    }
}

Переделал файл с маршрутами. Теперь маршруты выполняют методы указанных контроллеров:

<?php

$app->get('/', \App\Controllers\SiteController::class .':index');
$app->get('/authorize', \App\Controllers\SiteController::class . ':authorize');
$app->get('/groups', \App\Controllers\GroupsController::class .':index');
$app->post('/groups/add', \App\Controllers\GroupsController::class.':insert');

Каждый контроллер, должен в конструкторе принимать объект контейнера. В контейнере находится вся информация о нашем приложении и для того, чтобы класс мог работать с приложением, нужно в конструктор класса передать этот объект.
Раньше для авторизации пользователя мы выполняли методы в колбеках наших маршрутов, сейчас я вынес все в отдельный класс:

SiteController.php

<?php
namespace App\Controllers;

use \Interop\Container\ContainerInterface as ContainerInterface;
use App\Controllers\Controller;
use App\Classes\VK;

class SiteController extends Controller
{
  private $vk;

  public function __construct (ContainerInterface $container)
  {
    $this->container = $container;
    $this->vk = new VK($this->container->get('settings')['vk']);
  }

  public function index ($request, $response, $args)
  {
    if (isset($_SESSION['vk'])) {
      if (!isset($_SESSION['account'])) {
        // Устанавливаем токен
        $this->vk->accessToken = $_SESSION['vk']->access_token;
        // Получаем информацию о текущем пользователе
        // Записываем всю информацию в сессию
        $_SESSION['account'] = $this->vk->getAccountInfo($_SESSION['vk']->user_id);
      }
      return $this->container->view->render($response,'index.html', ['vk' => $this->vk, 'account' => $_SESSION['account']->response]);
    }
    return $this->container->view->render($response,'index.html', ['vk' => $this->vk]);
  }

  public function authorize ($request, $response, $args)
  {
    if ($request->getQueryParam('code') != NULL) {
      // Получаем токен
      $_SESSION['vk'] = $this->vk->getAccessToken($request->getQueryParam('code'));
    }
    return $response->withStatus(302)->withHeader('Location', '../');
  }
}

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

GroupsController.php

<?php

namespace App\Controllers;


use \Interop\Container\ContainerInterface as ContainerInterface;
use App\Controllers\Controller;
use App\Classes\VK;
use App\Models\Group;

class GroupsController extends Controller
{
  public function __construct (ContainerInterface $container)
  {
    $this->container = $container;
  }

  public function index ($request, $response, $args)
  {
    $account = $_SESSION['account']->response;
    $groups = Group::orderBy('created_at', 'desc')->get();

    return $this->container->view->render($response, 'groups.html', ['account' => $account, 'groups' => $groups]);
  }

  public function insert ($request, $response, $args)
  {
    $data = $request->getParsedBody();

    if (!isset($data['id'])) {
      return $response->withJson(['success' => false, 'msg' => 'Не указан ID группы.']);
    }

    if ($data['id'] == '') {
      return $response->withJson(['success' => false, 'msg' => 'ID не должен быть пустым.']);
    }

    if (!is_int( (int) $data['id'])) {
      return $response->withJson(['success' => false, 'msg' => 'ID содержит недопустимые символы.']);
    }

    $groupExists = Group::where('group_id', (int) $data['id'])->count();

    if ($groupExists > 0) {
      return $response->withJson(['success' => false, 'msg' => 'Группа с таким ID уже добавлена.']);
    }

    $group = new Group;
    $group->group_id = (int) $data['id'];

    if ($group->save()) {
      $vk = new VK($this->container->get('settings')['vk']);
      $vk->accessToken = $_SESSION['vk']->access_token;;

      $groupInfo = $vk->getGroupInfo($group->group_id);
      $data = $groupInfo[0];

      $group->name = $data->name;
      $group->type = $data->type;
      $group->avatar = $data->photo_50;
      $group->followers = $data->members_count;
      $group->update();
      return $response->withJson(['success' => true, 'msg' => 'Группа успешно добавлена.', 'data' => $group]);
    }

      return $response->withJson(['success' => false, 'msg' => 'Ошибка.']);
  }

}

Здесь уже посложнее. Первое, что бросается в глаза, это участок кода в самом начале:

use App\Classes\VK;
use App\Models\Group;

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

Метод index служит для отображения страницы с группами и вывода на неё информации. Другой метод под именем insert служит для добавления групп в базу. Валидации данных не очень красивые, но на первое время подойдут, в будущем напишем свой класс валидации данных. Как вы могли заметить, все ответы, что будут отправлены клиенту, я отдаю в формате json. Это связано с тем, что добавляю я группы при помощи AJAX, поэтому ответ должен быть в формате json. Я писал небольшой туториал по работе с AJAX на примере загрузки фотографии на сервер.

С добавлением в базу группы все просто, сначала мы записываем в базу ID группы, который получили из формы.

$group = new Group;
$group->group_id = (int) $data['id'];

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

if ($group->save()) {
      $vk = new VK($this->container->get('settings')['vk']);
      $vk->accessToken = $_SESSION['vk']->access_token;;

      $groupInfo = $vk->getGroupInfo($group->group_id);
      $data = $groupInfo[0];

      $group->name = $data->name;
      $group->type = $data->type;
      $group->avatar = $data->photo_50;
      $group->followers = $data->members_count;
      $group->update();
      return $response->withJson(['success' => true, 'msg' => 'Группа успешно добавлена.', 'data' => $group]);
}

Метод getGroupInfo, делает запрос к API и возвращает нам данные о конкретной группе.

public function getGroupInfo ($id) {
    $url = 'https://api.vk.com/method/groups.getById';
    $client = new \GuzzleHttp\Client();
    $response = $client->request('POST', $url, [
      'form_params' => [
        'group_id' => $id,
        'fields' => 'photo_50,members_count',
        'access_token' => $this->accessToken
      ],
      'verify' => false
    ]);

    $data = json_decode($response->getBody());

    return $data->response;
}

Для работы с базой я взял ORM Eloquent, кто имел дело с фреймворком Laravel, тот знает, что это такое. Тем кто дела не имел, в кратце пару слов. ORM — это своеобразная прослойка между программистом и базой данных. Используя ту или инную ORM вам больше не нужно писать sql запросы к базе данных, нужно лишь настроить подключение и использовать методы, которые предоставляет ORM. Также ORM даёт нам возможность работать с данными в базе как с объектом. Простой пример:

Вместо обычного:

$groups = $pdo->query('SELECT * FROM groups ORDER BY created_at DESC');

Мы напишем:

$groups = Group::orderBy('created_at', 'desc')->get();

На выходе во втором случае мы получим коллекцию объектов, с которыми будет очень удобно работать. Более подробно о методах данной ORM написано в официальной документации.

Файл модели выглядит так:
Group.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Group extends Model
{
  protected $table = 'groups';
}

Запрос на создание таблицы groups в базе данных:

CREATE TABLE IF NOT EXISTS `groups` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `group_id` int(10) UNSIGNED DEFAULT NULL,
  `name` varchar(255) DEFAULT NULL,
  `avatar` varchar(255) DEFAULT NULL,
  `type` varchar(255) DEFAULT NULL,
  `followers` int(10) UNSIGNED DEFAULT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `group_id` (`group_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Файл для подключения к базе данных:

database.php

<?php

use Illuminate\Database\Capsule\Manager as Capsule;

$capsule = new Capsule;

$capsule->addConnection([
    'driver'    => 'mysql',
    'host'      => 'localhost',
    'database'  => 'vkapi',
    'username'  => 'vkapi',
    'password'  => 'password',
    'charset'   => 'utf8',
    'collation' => 'utf8_unicode_ci',
    'prefix'    => '',
]);

$capsule->setAsGlobal();

$capsule->bootEloquent();

Для того, чтобы база данных была доступна в нашем приложении, добавим строчку в файл app.php:

include 'database.php';

Страница для отображения списка групп и добавления новых имеет в себе таблицу, которая наполняется информацией о группах и небольшую форму для добавления новых групп. Для добавления группы, нужно ввести в форму её ID.

{% extends "layout/app.html" %}

{% block content %}

<div class="row card" style="margin-top: 30px">

    <div class="card-block">
      {% if account %}
        <h1>Группы</h1>
        <hr>
        <button class="btn btn-primary" id="showForm">Добавить группу</button>
        <form class="form-inline" style="margin-top: 30px; display: none;" id="addNewGroup">
          <div class="input-group mb-2 mr-sm-2 mb-sm-0">
            <input type="text" name="id" placeholder="Ссылка на группу" class="form-control">
          </div>
          <button type="submit" class="btn btn-success">Добавить</button>
        </form>
        <hr>
        <table class="table table-striped" id="groupsTable">
          <thead>
            <tr>
              <th>#</th>
              <th>Название</th>
              <th>Количество подписчиков</th>
              <th>Добавлена</th>
              <th>Действия</th>
            </tr>
          </thead>
          <tbody>

            {% if groups|length > 0 %}
              {% for group in groups %}
                <tr>
                  <td>{{ group.id }}</td>
                  <td>{{ group.name }}</td>
                  <td>{{ group.followers }}</td>
                  <td>{{ group.created_at }}</td>
                  <td>Действия</td>
                </tr>
              {% endfor %}
            {% endif %}
          </tbody>
        </table>
      {% else %}
        <h1>Авторизировать пользователя</h1>
        <hr>
        <a href="{{ vk.getLoginLink }}">Авторизация</a>
      {% endif %}
    </div>

</div>

{% endblock %}

{% block scripts %}
<script>
$(document).ready(function () {
  $("#showForm").click(function () {
    $('#addNewGroup').slideToggle();
  });

  $('#addNewGroup').submit(function (f) {
    f.preventDefault();
    var form = new FormData(this);
    $.ajax({
      type:'POST',
      url: '{{ base_url() }}/groups/add',
      data: form,
      cache: false,
      contentType: false,
      processData: false,
      success:function(data){

        var response = data.data;

        $('#groupsTable tbody').prepend('<tr><td>'+response.id+'</td><td>'+response.name+'</td><td>'+response.followers+'</td><td>'+response.created_at+'</td><td>Действия</td></tr>');
        console.log(response);
      }
    });
  });
});
</script>
{% endblock %}

Теперь перейдя по адресу http://localhost/groups(адрес может иметь другой вид, в зависимости от настройки вашего веб сервера), мы попадем на страницу с группами и сможем добавлять в список группы.

В следующей статье, будем удалять группы из списка и научимся парсить стену паблика.
Надеюсь у меня удалось раскрыть основные моменты, если что-то не понятно, пишите комментарии, поправим)

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

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