mirror of
https://github.com/moodle/moodle.git
synced 2025-04-24 09:55:33 +02:00
MDL-77958 file: Add psr stream functionality to file API
This change introduces a new get_psr_stream() method to: * stored_file * file_system This allows us to fetch a Psr Stream implementing the PSR\Http\Message\StreamInterface and pass it into Guzzle, which means that there is no need to load the entire file content into memory to serve it.
This commit is contained in:
parent
fd8184a295
commit
96a1a0abce
@ -14,15 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Core file system class definition.
|
||||
*
|
||||
* @package core_files
|
||||
* @copyright 2017 Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
/**
|
||||
* File system class used for low level access to real files in filedir.
|
||||
@ -631,6 +623,16 @@ abstract class file_system {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a PSR7 Stream for the specified file which implements the PSR Message StreamInterface.
|
||||
*
|
||||
* @param stored_file $file
|
||||
* @return StreamInterface
|
||||
*/
|
||||
public function get_psr_stream(stored_file $file): StreamInterface {
|
||||
return \GuzzleHttp\Psr7\Utils::streamFor($this->get_content_file_handle($file));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the mime information for the specified stored file.
|
||||
*
|
||||
|
@ -23,6 +23,8 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot . '/lib/filestorage/file_progress.php');
|
||||
@ -437,6 +439,18 @@ class stored_file {
|
||||
return $this->filesystem->get_content_file_handle($this, $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a read-only PSR-7 stream for this file.
|
||||
*
|
||||
* Note: This stream is read-only. If you want to modify the file, create a new file and delete the old one.
|
||||
* The File API creates immutable files.
|
||||
*
|
||||
* @return StreamInterface
|
||||
*/
|
||||
public function get_psr_stream(): StreamInterface {
|
||||
return $this->filesystem->get_psr_stream($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps file content to page.
|
||||
*/
|
||||
|
@ -1077,6 +1077,24 @@ class file_system_test extends \advanced_testcase {
|
||||
$fs->get_content_file_handle($file, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that get_content_file_handle returns a valid file handle.
|
||||
*
|
||||
* @covers ::get_psr_stream
|
||||
*/
|
||||
public function test_get_psr_stream(): void {
|
||||
$file = $this->get_stored_file('');
|
||||
|
||||
$fs = $this->get_testable_mock(['get_remote_path_from_storedfile']);
|
||||
$fs->method('get_remote_path_from_storedfile')
|
||||
->willReturn(__FILE__);
|
||||
|
||||
$stream = $fs->get_psr_stream($file);
|
||||
$this->assertInstanceOf(\Psr\Http\Message\StreamInterface::class, $stream);
|
||||
$this->assertEquals(file_get_contents(__FILE__), $stream->getContents());
|
||||
$this->assertFalse($stream->isWritable());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that mimetype_from_hash returns the correct mimetype with
|
||||
* a file whose filename suggests mimetype.
|
||||
@ -1248,4 +1266,3 @@ class file_system_test extends \advanced_testcase {
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,4 +91,33 @@ class stored_file_test extends advanced_testcase {
|
||||
$this->assertEquals(1200, $size['width']);
|
||||
$this->assertEquals(297, $size['height']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that get_content_file_handle returns a valid file handle.
|
||||
*
|
||||
* @covers ::get_psr_stream
|
||||
*/
|
||||
public function test_get_psr_stream(): void {
|
||||
global $CFG;
|
||||
$this->resetAfterTest();
|
||||
|
||||
$filename = 'testimage.jpg';
|
||||
$filepath = $CFG->dirroot . '/lib/filestorage/tests/fixtures/' . $filename;
|
||||
$filerecord = [
|
||||
'contextid' => context_system::instance()->id,
|
||||
'component' => 'core',
|
||||
'filearea' => 'unittest',
|
||||
'itemid' => 0,
|
||||
'filepath' => '/',
|
||||
'filename' => $filename,
|
||||
];
|
||||
$fs = get_file_storage();
|
||||
$file = $fs->create_file_from_pathname($filerecord, $filepath);
|
||||
|
||||
$stream = $file->get_psr_stream();
|
||||
$this->assertInstanceOf(\Psr\Http\Message\StreamInterface::class, $stream);
|
||||
$this->assertEquals(file_get_contents($filepath), $stream->getContents());
|
||||
$this->assertFalse($stream->isWritable());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -138,6 +138,8 @@ information provided here is intended especially for developers.
|
||||
- taskslimit - to limit the number of tasks in one run
|
||||
- failed - to limit the run to only the tasks that failed in their previous run
|
||||
Can be mixed, apart from 'id' of course.
|
||||
* The file_system class now declares a new, optional, `get_psr_stream` function which allows a Stream implementing `\Psr\Http\Message\StreamInterface` to be returned.
|
||||
A default implementation which uses the existing file handle resource is used by default, but this should be extended by file_system implementations where relevant.
|
||||
|
||||
=== 4.1 ===
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user