php-plug-social/src/VK/Post.php
Snider 7b2b7968d3 feat: extract social providers from app/Plug/Social
LinkedIn, Meta, Pinterest, Reddit, TikTok, Twitter, VK, YouTube
providers with Core\Plug\Social namespace alignment.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 17:27:54 +00:00

129 lines
3.6 KiB
PHP

<?php
declare(strict_types=1);
namespace Core\Plug\Social\VK;
use Core\Plug\Concern\BuildsResponse;
use Core\Plug\Concern\ManagesTokens;
use Core\Plug\Concern\UsesHttp;
use Core\Plug\Contract\Postable;
use Core\Plug\Response;
use Illuminate\Support\Collection;
/**
* VK wall post publishing.
*/
class Post implements Postable
{
use BuildsResponse;
use ManagesTokens;
use UsesHttp;
private const API_URL = 'https://api.vk.com/method';
private const API_VERSION = '5.199';
public function publish(string $text, Collection $media, array $params = []): Response
{
$groupId = $params['group_id'] ?? null;
$ownerId = $groupId ? "-{$groupId}" : ($this->getToken()['data']['user_id'] ?? '');
$postParams = [
'owner_id' => $ownerId,
'message' => $text,
'from_group' => $groupId ? 1 : 0,
'access_token' => $this->accessToken(),
'v' => self::API_VERSION,
];
// Handle media attachments
if ($media->isNotEmpty()) {
$attachments = [];
$mediaUploader = (new Media)->withToken($this->getToken());
if ($groupId) {
$mediaUploader->forGroup((int) $groupId);
}
foreach ($media as $item) {
$result = $mediaUploader->upload($item);
if ($result->hasError()) {
continue; // Skip failed uploads
}
$attachments[] = $result->get('attachment');
}
if (! empty($attachments)) {
$postParams['attachments'] = implode(',', $attachments);
}
}
// Handle link attachment
if (! empty($params['link'])) {
$existingAttachments = $postParams['attachments'] ?? '';
$postParams['attachments'] = $existingAttachments
? $existingAttachments.','.$params['link']
: $params['link'];
}
// Handle scheduled publishing
if (! empty($params['publish_date'])) {
$postParams['publish_date'] = $params['publish_date'];
}
$response = $this->http()
->get(self::API_URL.'/wall.post', $postParams)
->json();
if (isset($response['error'])) {
$errorCode = $response['error']['error_code'] ?? 0;
// Handle rate limiting (error code 9)
if ($errorCode === 9) {
return $this->rateLimit(60);
}
// Handle captcha required (error code 14)
if ($errorCode === 14) {
return $this->error('Captcha required. Please post from VK directly.');
}
return $this->error($response['error']['error_msg'] ?? 'Failed to publish post');
}
$postId = $response['response']['post_id'] ?? null;
if (! $postId) {
return $this->error('Post created but no ID returned');
}
return $this->ok([
'id' => (string) $postId,
'owner_id' => $ownerId,
'post_id' => $postId,
]);
}
/**
* Get external URL to a VK post.
*/
public static function externalPostUrl(string $ownerId, string $postId): string
{
return "https://vk.com/wall{$ownerId}_{$postId}";
}
/**
* Get external URL to a VK profile.
*/
public static function externalAccountUrl(string $accountId, ?string $screenName = null): string
{
if ($screenName) {
return "https://vk.com/{$screenName}";
}
return "https://vk.com/id{$accountId}";
}
}