richard
/
cyca
Archived
1
0
Fork 0
This repository has been archived on 2024-05-04. You can view files and clone it, but cannot push or open issues or pull requests.
cyca/app/Services/Importer.php

322 lines
7.7 KiB
PHP
Executable File

<?php
namespace App\Services;
use App\Models\Document;
use App\Models\Feed;
use App\Models\Folder;
use App\Models\Group;
use App\Models\Highlight;
use App\Models\IgnoredFeed;
use App\Models\User;
use Illuminate\Http\Request;
/**
* Imports data in Cyca.
*/
class Importer
{
/**
* Adapter used to import data.
*
* @var \App\Contracts\ImportAdapter
*/
protected $importAdapter;
/**
* User to import data for.
*
* @var \App\Models\User
*/
protected $forUser;
/**
* Folder to import bookmarks and feeds to.
*
* @var \App\Models\Folder
*/
protected $inFolder;
/**
* Should we import highlights as well ?
*
* @var bool
*/
protected $withHighlights = true;
/**
* Data to be imported as an array.
*
* @var array
*/
protected $dataArray = [];
/**
* Group to import data to.
*
* @var \App\Models\Group
*/
protected $inGroup;
/**
* Indicates which adapter to use for importation.
*
* @param string $adapterName
*
* @return self
*/
public function using($adapterName)
{
$className = config(sprintf('importers.adapters.%s.adapter', $adapterName));
if (empty($className)) {
abort(422, sprintf('Unknown import adapter %s', $className));
}
$this->importAdapter = new $className();
return $this;
}
/**
* Defines which user to import data for. If not defined, user will be
* extracted from request.
*
* @return self
*/
public function forUser(User $user)
{
$this->forUser = $user;
return $this;
}
/**
* Defines the group to import data to.
*
* @return self
*/
public function inGroup(Group $group)
{
$this->inGroup = $group;
return $this;
}
/**
* Defines in which folder data will be imported to. If not defined, root
* folder attached to specified user will be used.
*
* @return self
*/
public function inFolder(Folder $folder)
{
$this->inFolder = $folder;
return $this;
}
/**
* Should we ignore highlights during import ? By default, highlights will
* be imported as well.
*
* @return self
*/
public function withoutHighlights()
{
$this->withHighlights = false;
return $this;
}
/**
* Import data from specified file. Must be a valid json file, valid from
* Cyca's architecture point of view.
*
* @param string $path Full path to file to import
*
* @return self
*/
public function fromFile($path)
{
if (empty($this->forUser)) {
abort(422, 'Target user not specified');
}
$contents = file_get_contents($path);
if (empty($contents)) {
abort(422, 'File does not exists');
}
$this->dataArray = json_decode($contents, true);
return $this;
}
/**
* Import data using current request informations.
*
* @return self
*/
public function fromRequest(Request $request)
{
if (empty($this->importAdapter)) {
$this->using($request->input('importer'));
}
if (empty($this->importAdapter)) {
abort(422, 'An import adapter must be specified');
}
if (empty($this->forUser)) {
$this->forUser = $request->user();
}
$this->dataArray = $this->importAdapter->importFromRequest($request);
return $this;
}
/**
* Perform the import.
*/
public function import()
{
if (empty($this->inGroup)) {
$this->inGroup = $this->forUser->groups()->wherePivot('status', '=', 'own')->first();
}
if (empty($this->inFolder)) {
$this->inFolder = $this->inGroup->folders()->ofType('root')->first();
}
if ($this->withHighlights && !empty($this->dataArray['highlights'])) {
$this->importHighlights($this->dataArray['highlights']);
}
if (!empty($this->dataArray['bookmarks'])) {
$this->importBookmarks($this->dataArray['bookmarks']);
}
}
/**
* Import highlights from specified array.
*
* @param array $highlights
*/
protected function importHighlights($highlights)
{
foreach ($highlights as $highlightData) {
$highlight = Highlight::where('user_id', $this->forUser->id)->where('expression', $highlightData['expression'])->first();
if (!$highlight) {
$highlight = new Highlight();
$highlight->user_id = $this->forUser->id;
$highlight->expression = $highlightData['expression'];
$highlight->color = $highlightData['color'];
$highlight->save();
}
}
}
/**
* Import bookmarks from specified array.
*
* @param array $bookmarks
*/
protected function importBookmarks($bookmarks)
{
$this->importDocuments($this->inFolder, $bookmarks['documents'] ?: []);
$this->importFolders($this->inFolder, $bookmarks['folders'] ?: []);
}
/**
* Import folders.
*
* @param \App\Models\Folder Destination folder
* @param array $foldersData Array of sub-folders definitions
* @param mixed $folder
*/
protected function importFolders($folder, $foldersData)
{
foreach ($foldersData as $folderData) {
$children = $this->inGroup->folders()->save(new Folder([
'title' => $folderData['title'],
'parent_id' => $folder->id,
'user_id' => $this->forUser->id,
]));
$this->importDocuments($children, $folderData['documents']);
$this->importFolders($children, $folderData['folders']);
}
}
/**
* Import documents.
*
* @param \App\Models\Folder Destination folder
* @param array $documentsData Array of documents definitions
* @param mixed $folder
*/
protected function importDocuments($folder, $documentsData)
{
foreach ($documentsData as $docData) {
if (empty($docData['url'])) {
continue;
}
$url = urldecode($docData['url']);
$document = Document::firstOrCreate(['url' => $url]);
if (array_key_exists('feeds', $docData)) {
$this->importFeeds($document, $docData['feeds']);
}
$folder->documents()->save($document, [
'initial_url' => $url,
]);
}
}
/**
* Import feeds.
*
* @param \App\Models\Document $document Destination document
* @param array $feedsData Array of feeds definitions
*/
protected function importFeeds($document, $feedsData)
{
$feedsToAttach = $document->feeds()->get()->pluck('id')->all();
foreach ($feedsData as $feedData) {
if (empty($feedData['url'])) {
continue;
}
$feedUrl = urldecode($feedData['url']);
$feed = Feed::firstOrCreate(['url' => $feedUrl]);
$feedsToAttach[] = $feed->id;
if ($feedData['is_ignored']) {
$ignoredFeed = IgnoredFeed::where('user_id', $this->forUser->id)->where('feed_id', $feed->id)->first();
if (!$ignoredFeed) {
$ignoredFeed = new IgnoredFeed();
$ignoredFeed->user()->associate($this->forUser);
$ignoredFeed->feed()->associate($feed);
$ignoredFeed->save();
}
}
}
$document->feeds()->sync($feedsToAttach);
}
}