171 lines
5.6 KiB
PHP
171 lines
5.6 KiB
PHP
|
<?php
|
||
|
|
||
|
namespace Zoomyboy\Social\Classes;
|
||
|
|
||
|
use Carbon\Carbon;
|
||
|
use GuzzleHttp\Client;
|
||
|
use Event;
|
||
|
use Media\Classes\MediaLibrary;
|
||
|
use Zoomyboy\Social\Models\Page;
|
||
|
use Zoomyboy\Social\Models\Post;
|
||
|
use Zoomyboy\Social\Models\Setting;
|
||
|
|
||
|
class FacebookSyncService {
|
||
|
|
||
|
private static $baseUri = 'https://graph.facebook.com';
|
||
|
protected $client;
|
||
|
protected $page;
|
||
|
protected $token;
|
||
|
protected $version = 'v11.0';
|
||
|
protected $media;
|
||
|
|
||
|
public static function page($page, $token) {
|
||
|
return new static($page, $token);
|
||
|
}
|
||
|
|
||
|
private function __construct(Page $page) {
|
||
|
$this->media = MediaLibrary::instance();
|
||
|
$this->page = $page;
|
||
|
$this->token = $page->access_token;
|
||
|
$this->client = new Client([ 'http_errors' => false, 'base_uri' => static::$baseUri ]);
|
||
|
}
|
||
|
|
||
|
public function clear() {
|
||
|
$this->page->delete();
|
||
|
}
|
||
|
|
||
|
public function posts(): array
|
||
|
{
|
||
|
return $this->get(
|
||
|
"{$this->page->remote_id}/published_posts",
|
||
|
['fields' => 'id,created_time,full_picture,message,attachments'],
|
||
|
'data',
|
||
|
);
|
||
|
}
|
||
|
|
||
|
public function saveUrl(string $source, ?string $filename = null): string
|
||
|
{
|
||
|
$filename = $filename ?: pathinfo(parse_url($source, PHP_URL_PATH), PATHINFO_BASENAME);
|
||
|
$file = $this->page->mediaPath.$filename;
|
||
|
|
||
|
if (!$this->media->exists($file)) {
|
||
|
$this->media->put($file, file_get_contents($source));
|
||
|
Event::fire('media.file.upload', [null, $file, null]);
|
||
|
}
|
||
|
|
||
|
return $file;
|
||
|
}
|
||
|
|
||
|
public function saveCover() {
|
||
|
$cover = $this->get($this->page->remote_id, ['fields' => 'cover'], 'cover');
|
||
|
$this->page->update([ 'cover' => $this->saveUrl($cover['source']) ]);
|
||
|
}
|
||
|
|
||
|
public function saveAttachments(Post $post, $data) {
|
||
|
foreach($data as $i => $attachment) {
|
||
|
$fid = null;
|
||
|
|
||
|
switch($attachment['type']) {
|
||
|
case 'photo':
|
||
|
case 'video_inline':
|
||
|
$payload = [ 'href' => $this->saveUrl(data_get($attachment, 'media.image.src')) ]; break;
|
||
|
case 'share':
|
||
|
case 'event':
|
||
|
$fid = $post->id.'-attachment-'.$i;
|
||
|
if (!data_get($attachment, 'media.image.src')) {
|
||
|
continue 2;
|
||
|
}
|
||
|
$payload = [ 'href' => $this->saveUrl(data_get($attachment, 'media.image.src'), $fid.'.jpg') ];
|
||
|
break;
|
||
|
case 'album':
|
||
|
$payload = [ 'href' => $this->saveUrl(data_get($attachment, 'subattachments.data.0.media.image.src')) ]; break;
|
||
|
case 'multi_share':
|
||
|
$payload = [ 'href' => $this->saveUrl(data_get($attachment, 'subattachments.data.0.media.image.src')) ]; break;
|
||
|
case 'native_templates': continue 2;
|
||
|
default:
|
||
|
throw new \Exception('I dont know how to parse attachment of type '.$attachment['type']);
|
||
|
}
|
||
|
|
||
|
$fid = $fid ?: data_get($attachment, 'target.id', '');
|
||
|
$post->attachments()->updateOrCreate(['facebook_id' => $fid], array_merge($payload, [
|
||
|
'facebook_id' => $fid,
|
||
|
'type' => $attachment['type'],
|
||
|
]));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public function sync(): void
|
||
|
{
|
||
|
$this->saveCover();
|
||
|
|
||
|
foreach ($this->posts() as $post) {
|
||
|
if (!data_get($post, 'message')) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (!data_get($post, 'attachments')) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
$payload = [
|
||
|
'message' => $post['message'],
|
||
|
'facebook_id' => $post['id'],
|
||
|
'href' => data_get($post, 'attachments.data.0.target.url'),
|
||
|
'created_at' => Carbon::parse($post['created_time']),
|
||
|
];
|
||
|
|
||
|
$existing = $this->page->posts()->where('facebook_id', $post['id'])->first();
|
||
|
|
||
|
if ($existing) {
|
||
|
$existing->update($payload);
|
||
|
} else {
|
||
|
$existing = $this->page->posts()->create($payload);
|
||
|
}
|
||
|
|
||
|
$this->saveAttachments($existing, data_get($post, 'attachments.data'));
|
||
|
}
|
||
|
|
||
|
if (!is_numeric(Setting::get('max_posts'))) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
while ($this->page->posts()->get()->count() > 0 && $this->page->posts()->get()->count() > Setting::get('max_posts')) {
|
||
|
$this->page->posts()->orderBy('created_at')->first()->delete();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// -------------------------------- static api ---------------------------------
|
||
|
// *****************************************************************************
|
||
|
public static function clearAll(): void
|
||
|
{
|
||
|
foreach (Page::where('type', 'facebook')->get() as $page) {
|
||
|
$service = new static($page);
|
||
|
$service->clear();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static function syncAll(): void
|
||
|
{
|
||
|
foreach (Page::where('type', 'facebook')->get() as $page) {
|
||
|
$service = new static($page);
|
||
|
$service->sync();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// -------------------------------- Guzzle Api ---------------------------------
|
||
|
// *****************************************************************************
|
||
|
private function get(string $url, array $query = [], ?string $return = null): array
|
||
|
{
|
||
|
$response = $this->client->get("/{$this->version}/$url", [
|
||
|
'query' => array_merge($query, ['access_token' => $this->token]),
|
||
|
]);
|
||
|
|
||
|
$data = json_decode((string) $response->getBody(), true);
|
||
|
|
||
|
return $return === null
|
||
|
? $data
|
||
|
: data_get($data, $return);
|
||
|
}
|
||
|
|
||
|
}
|