Skip to content

Commit 8fe34c1

Browse files
author
daniel-abbey
committed
Merge pull request #713 from LearningLocker/issue/cloud_storage
Adds support for FlySystem,
2 parents 539459b + cf2d24f commit 8fe34c1

23 files changed

+592
-71
lines changed

.env.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?php
22

33
return [
4-
'LOCAL_FILESTORE' => __DIR__.'/uploads',
5-
'SESSION_FILESTORE' => __DIR__.'/app/storage/sessions',
4+
'FS_REPO' => 'Local',
5+
'FS_LOCAL_ENDPOINT' => __DIR__.'/uploads',
66
'LOG_FILESTORE' => __DIR__.'/app/storage/logs/laravel.log',
77
];

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
composer.phar
44
.DS_Store
55
Thumbs.db
6+
.phpintel
7+
.env.*.php
68

79
/app/config/ht2
810
/app/config/production
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
use Illuminate\Console\Command;
3+
use Symfony\Component\Console\Input\InputOption;
4+
use Symfony\Component\Console\Input\InputArgument;
5+
use Locker\Repository\File\Factory as FileFactory;
6+
7+
class FileRepositoryCommand extends Command {
8+
protected $name = 'll:file-repo';
9+
protected $description = 'Migrates files from one file repository (i.e. Local) to another (i.e. Rackspace).';
10+
11+
public function fire() {
12+
$from_var = $this->option('from');
13+
$to_var = $this->argument('to');
14+
$from_repo = FileFactory::createRepo($from_var);
15+
$to_repo = FileFactory::createRepo($to_var);
16+
$files = $from_repo->index([]);
17+
18+
$count = 0;
19+
foreach ($files as $file) {
20+
$path = $file['path'];
21+
if ($file['type'] === 'file' && !$to_repo->has($path, [])) {
22+
$count += 1;
23+
$to_repo->update($path, ['content' => $from_repo->show($path, [])], []);
24+
echo "Migrated '{$path}' from '{$from_var}' to '{$to_var}'.".PHP_EOL;
25+
}
26+
}
27+
28+
echo "Migrated $count files and ignored ".(count($files) - $count).".".PHP_EOL;
29+
}
30+
31+
protected function getArguments() {
32+
return [
33+
['to', InputArgument::REQUIRED, 'The repository to migrate to.']
34+
];
35+
}
36+
37+
protected function getOptions() {
38+
return [
39+
['from', 'f', InputOption::VALUE_OPTIONAL, 'The repository to migrate from.', 'Local'],
40+
];
41+
}
42+
43+
}

app/config/session.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
|
4747
*/
4848

49-
'files' => Helpers::getEnvVar('SESSION_FILESTORE'),
49+
'files' => null,
5050

5151
/*
5252
|--------------------------------------------------------------------------

app/controllers/xapi/DocumentController.php

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<?php namespace Controllers\xAPI;
2-
3-
use \Locker\Repository\Document\DocumentRepository as Document;
4-
use \Carbon\Carbon;
5-
use \Locker\Helpers\Exceptions as Exceptions;
2+
use Locker\Repository\Document\DocumentRepository as Document;
3+
use Carbon\Carbon;
4+
use Locker\Helpers\Exceptions as Exceptions;
5+
use Locker\Repository\File\Factory as FileFactory;
66

77
abstract class DocumentController extends BaseController {
88

@@ -238,11 +238,13 @@ public function documentResponse($data) {
238238
case "text/plain":
239239
return \Response::make($document->content, 200, $headers);
240240
default:
241-
return \Response::download(
242-
$document->getFilePath(),
243-
$document->content,
244-
$headers
245-
);
241+
$stream = FileFactory::create()->stream($document->getFilePath(), []);
242+
return \Response::stream(function () use ($stream) {
243+
while (!feof($stream)) {
244+
echo fread($stream, 8192); flush();ob_flush();
245+
}
246+
fclose($stream);
247+
}, 200, $headers);
246248
}
247249
}
248250
}

app/controllers/xapi/StatementIndexController.php

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -49,17 +49,21 @@ public function index($options) {
4949
// Defines the content type and body of the response.
5050
if ($opts['attachments'] === true) {
5151
$content_type = 'multipart/mixed; boundary='.static::BOUNDARY;
52-
$body = $this->makeAttachmentsResult($statements, $count, $opts);
52+
$body = function () use ($statements, $count, $opts) {
53+
return $this->makeAttachmentsResult($statements, $count, $opts);
54+
};
5355
} else {
5456
$content_type = 'application/json;';
55-
$body = $this->makeStatementsResult($statements, $count, $opts);
57+
$body = function () use ($statements, $count, $opts) {
58+
return $this->makeStatementsResult($statements, $count, $opts);
59+
};
5660
}
5761

5862
// Creates the response.
59-
return \Response::make($body, 200, [
63+
return \Response::stream($body, 200, [
6064
'Content-Type' => $content_type,
6165
'X-Experience-API-Consistent-Through' => Helpers::getCurrentDate()
62-
]);;
66+
]);
6367
}
6468

6569
/**
@@ -83,7 +87,7 @@ private function makeStatementsResult(array $statements, $count, array $opts) {
8387
'statements' => $statements
8488
];
8589

86-
return json_encode($statement_result);
90+
$this->emit(json_encode($statement_result));
8791
}
8892

8993
/**
@@ -96,24 +100,37 @@ private function makeAttachmentsResult(array $statements, $count, array $opts) {
96100
$boundary = static::BOUNDARY;
97101
$eol = static::EOL;
98102
$content_type = 'multipart/mixed; boundary='.$boundary;
99-
$statement_result = "Content-Type:application/json$eol$eol".$this->makeStatementsResult(
103+
104+
$this->emit("--$boundary$eol");
105+
$this->emit("Content-Type:application/json$eol$eol");
106+
$this->makeStatementsResult(
100107
$statements,
101108
$count,
102109
$opts
103110
);
104111

105-
return "--$boundary$eol".implode(
106-
"$eol--$boundary$eol",
107-
array_merge([$statement_result], array_map(function ($attachment) use ($eol, $boundary) {
108-
return (
112+
$attachments = $this->statements->getAttachments($statements, $opts);
113+
foreach ($attachments as $attachment) {
114+
$this->emit(
115+
"$eol--$boundary$eol".
109116
'Content-Type:'.$attachment->content_type.$eol.
110117
'Content-Transfer-Encoding:binary'.$eol.
111118
'X-Experience-API-Hash:'.$attachment->hash.
112-
$eol.$eol.
113-
$attachment->content
119+
$eol.$eol
114120
);
115-
}, $this->statements->getAttachments($statements, $opts)))
116-
)."$eol--$boundary--";
121+
while (!feof($attachment->content)) {
122+
$this->emit(fread($attachment->content, 8192));
123+
}
124+
fclose($attachment->content);
125+
}
126+
127+
$this->emit("$eol--$boundary--");
128+
}
129+
130+
private function emit($value) {
131+
echo $value;
132+
flush();
133+
ob_flush();
117134
}
118135

119136
private function getMoreLink($count, $limit, $offset) {

app/database/migrations/2015_03_31_130813_attachment_rename.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
class AttachmentRename extends Migration {
88

99
public function up() {
10-
$uploads = Helpers::getEnvVar('LOCAL_FILESTORE');
10+
$uploads = Helpers::getEnvVar('FS_LOCAL_ENDPOINT');
1111
$LRSs = $this->getDirectores($uploads);
1212

1313
// Gets the attachments.

app/locker/repository/Document/EloquentDocumentRepository.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,6 @@ public function storeActivityDoc( $options, $data, $updated, $method ){
387387

388388
$document->updated_at = new Carbon($updated);
389389
$document->setContent( $data['content_info'], $method ); //set the content for the document
390-
391390
if( $document->save() ){
392391
return $document;
393392
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php namespace Locker\Repository\File;
2+
use Locker\Helpers\Helpers as Helpers;
3+
4+
class Factory {
5+
public static function create() {
6+
$repo = Helpers::getEnvVar('FS_REPO');
7+
8+
return static::createRepo($repo);
9+
}
10+
11+
public static function createRepo($repo) {
12+
$repos = [
13+
'Local' => 'LocalFlyRepository',
14+
'Rackspace' => 'RackspaceFlyRepository',
15+
];
16+
$repo = ucfirst(strtolower($repo));
17+
$conf = function ($var) {
18+
return Helpers::getEnvVar($var);
19+
};
20+
21+
if (isset($repos[$repo])) {
22+
$selected_repo = 'Locker\Repository\File\\'.$repos[$repo];
23+
return new $selected_repo($conf);
24+
} else {
25+
throw new \Exception('Valid `FS_REPO` not specified in ".env.'.\App::environment().'.php". Valid values include: "'.implode('", "', array_keys($repos)).'". You provided "'.$repo.'".');
26+
}
27+
}
28+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php namespace Locker\Repository\File;
2+
use League\Flysystem\Filesystem as Filesystem;
3+
use League\Flysystem\AdapterInterface as AdapterInterface;
4+
5+
abstract class FlyRepository implements Repository {
6+
protected $filesystem;
7+
8+
public function __construct(Callable $conf) {}
9+
10+
protected function constructFileSystem(AdapterInterface $adapter) {
11+
$this->filesystem = new Filesystem($adapter);
12+
}
13+
14+
public function index(array $opts) {
15+
return $this->filesystem->listContents('.', true);
16+
}
17+
18+
public function show($id, array $opts) {
19+
return $this->filesystem->read($id);
20+
}
21+
22+
public function destroy($id, array $opts) {
23+
$this->filesystem->delete($id);
24+
return true;
25+
}
26+
27+
public function store(array $data, array $opts) {
28+
throw new \BadMethodCallException();
29+
}
30+
31+
public function update($id, array $data, array $opts) {
32+
$this->filesystem->put($id, $data['content']);
33+
return $data;
34+
}
35+
36+
public function stream($id, array $opts) {
37+
$stream = $this->filesystem->readStream($id);
38+
fseek($stream, 0);
39+
return $stream;
40+
}
41+
42+
public function has($id, array $opts) {
43+
return $this->filesystem->has($id);
44+
}
45+
46+
}

0 commit comments

Comments
 (0)