Commit 316c1f4a authored by webchick's avatar webchick

Issue #1468328 by Berdir: Move file entity info, managed file, and file usage...

Issue #1468328 by Berdir: Move file entity info, managed file, and file usage functionality into File module.
parent d1b31051
This diff is collapsed.
......@@ -5,3 +5,4 @@ version = VERSION
core = 8.x
configure = admin/config/services/aggregator/settings
stylesheets[all][] = aggregator.theme.css
dependencies[] = file
......@@ -10,7 +10,7 @@
*/
use Drupal\node\Node;
use Drupal\Core\File\File;
use Drupal\file\File;
use Drupal\entity\EntityInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
......
......@@ -28,7 +28,7 @@ class EntityCrudHookTest extends WebTestBase {
*
* @var array
*/
public static $modules = array('entity_crud_hook_test', 'taxonomy', 'comment');
public static $modules = array('entity_crud_hook_test', 'taxonomy', 'comment', 'file');
protected $ids = array();
......
......@@ -5,6 +5,164 @@
* Hooks for file module.
*/
/**
* Load additional information into file entities.
*
* file_load_multiple() calls this hook to allow modules to load
* additional information into each file.
*
* @param $files
* An array of file entities, indexed by fid.
*
* @see file_load_multiple()
* @see file_load()
*/
function hook_file_load($files) {
// Add the upload specific data into the file entity.
$result = db_query('SELECT * FROM {upload} u WHERE u.fid IN (:fids)', array(':fids' => array_keys($files)))->fetchAll(PDO::FETCH_ASSOC);
foreach ($result as $record) {
foreach ($record as $key => $value) {
$files[$record['fid']]->$key = $value;
}
}
}
/**
* Check that files meet a given criteria.
*
* This hook lets modules perform additional validation on files. They're able
* to report a failure by returning one or more error messages.
*
* @param Drupal\file\File $file
* The file entity being validated.
* @return
* An array of error messages. If there are no problems with the file return
* an empty array.
*
* @see file_validate()
*/
function hook_file_validate(Drupal\file\File $file) {
$errors = array();
if (empty($file->filename)) {
$errors[] = t("The file's name is empty. Please give a name to the file.");
}
if (strlen($file->filename) > 255) {
$errors[] = t("The file's name exceeds the 255 characters limit. Please rename the file and try again.");
}
return $errors;
}
/**
* Act on a file being inserted or updated.
*
* This hook is called when a file has been added to the database. The hook
* doesn't distinguish between files created as a result of a copy or those
* created by an upload.
*
* @param Drupal\file\File $file
* The file entity that is about to be created or updated.
*/
function hook_file_presave(Drupal\file\File $file) {
// Change the file timestamp to an hour prior.
$file->timestamp -= 3600;
}
/**
* Respond to a file being added.
*
* This hook is called after a file has been added to the database. The hook
* doesn't distinguish between files created as a result of a copy or those
* created by an upload.
*
* @param Drupal\file\File $file
* The file that has been added.
*/
function hook_file_insert(Drupal\file\File $file) {
// Add a message to the log, if the file is a jpg
$validate = file_validate_extensions($file, 'jpg');
if (empty($validate)) {
watchdog('file', 'A jpg has been added.');
}
}
/**
* Respond to a file being updated.
*
* This hook is called when an existing file is saved.
*
* @param Drupal\file\File $file
* The file that has just been updated.
*/
function hook_file_update(Drupal\file\File $file) {
}
/**
* Respond to a file that has been copied.
*
* @param Drupal\file\File $file
* The newly copied file entity.
* @param Drupal\file\File $source
* The original file before the copy.
*
* @see file_copy()
*/
function hook_file_copy(Drupal\file\File $file, Drupal\file\File $source) {
}
/**
* Respond to a file that has been moved.
*
* @param Drupal\file\File $file
* The updated file entity after the move.
* @param Drupal\file\File $source
* The original file entity before the move.
*
* @see file_move()
*/
function hook_file_move(Drupal\file\File $file, Drupal\file\File $source) {
}
/**
* Act prior to file deletion.
*
* This hook is invoked when deleting a file before the file is removed from the
* filesystem and before its records are removed from the database.
*
* @param Drupal\file\File $file
* The file that is about to be deleted.
*
* @see hook_file_delete()
* @see Drupal\file\FileStorageController::delete()
* @see upload_file_delete()
*/
function hook_file_predelete(Drupal\file\File $file) {
// Delete all information associated with the file.
db_delete('upload')->condition('fid', $file->fid)->execute();
}
/**
* Respond to file deletion.
*
* This hook is invoked after the file has been removed from
* the filesystem and after its records have been removed from the database.
*
* @param Drupal\file\File $file
* The file that has just been deleted.
*
* @see hook_file_predelete()
* @see Drupal\file\FileStorageController::delete()
*/
function hook_file_delete(Drupal\file\File $file) {
// Delete all information associated with the file.
db_delete('upload')->condition('fid', $file->fid)->execute();
}
/**
* Control download access to files.
*
......@@ -16,7 +174,7 @@
* The field to which the file belongs.
* @param Drupal\entity\EntityInterface $entity
* The entity which references the file.
* @param Drupal\Core\File\File $file
* @param Drupal\file\File $file
* The file entity that is being requested.
*
* @return
......@@ -26,7 +184,7 @@
*
* @see hook_field_access().
*/
function hook_file_download_access($field, Drupal\entity\EntityInterface $entity, Drupal\Core\File\File $file) {
function hook_file_download_access($field, Drupal\entity\EntityInterface $entity, Drupal\file\File $file) {
if ($entity->entityType() == 'node') {
return node_access('view', $entity);
}
......
......@@ -5,6 +5,149 @@
* Install, update and uninstall functions for File module.
*/
/**
* Implements hook_schema().
*/
function file_schema() {
$schema['file_managed'] = array(
'description' => 'Stores information for uploaded files.',
'fields' => array(
'fid' => array(
'description' => 'File ID.',
'type' => 'serial',
'unsigned' => TRUE,
'not null' => TRUE,
),
'uuid' => array(
'description' => 'Unique Key: Universally unique identifier for this entity.',
'type' => 'varchar',
'length' => 128,
'not null' => FALSE,
),
'uid' => array(
'description' => 'The {users}.uid of the user who is associated with the file.',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'filename' => array(
'description' => 'Name of the file with no path components. This may differ from the basename of the URI if the file is renamed to avoid overwriting an existing file.',
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => '',
),
'uri' => array(
'description' => 'The URI to access the file (either local or remote).',
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => '',
'binary' => TRUE,
),
'langcode' => array(
'description' => 'The {language}.langcode of this file.',
'type' => 'varchar',
'length' => 12,
'not null' => TRUE,
'default' => '',
),
'filemime' => array(
'description' => "The file's MIME type.",
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => '',
),
'filesize' => array(
'description' => 'The size of the file in bytes.',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'status' => array(
'description' => 'A field indicating the status of the file. Two status are defined in core: temporary (0) and permanent (1). Temporary files older than DRUPAL_MAXIMUM_TEMP_FILE_AGE will be removed during a cron run.',
'type' => 'int',
'not null' => TRUE,
'default' => 0,
'size' => 'tiny',
),
'timestamp' => array(
'description' => 'UNIX timestamp for when the file was added.',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
),
'indexes' => array(
'uid' => array('uid'),
'status' => array('status'),
'timestamp' => array('timestamp'),
),
'unique keys' => array(
'uuid' => array('uuid'),
'uri' => array('uri'),
),
'primary key' => array('fid'),
'foreign keys' => array(
'file_owner' => array(
'table' => 'users',
'columns' => array('uid' => 'uid'),
),
),
);
$schema['file_usage'] = array(
'description' => 'Track where a file is used.',
'fields' => array(
'fid' => array(
'description' => 'File ID.',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
),
'module' => array(
'description' => 'The name of the module that is using the file.',
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => '',
),
'type' => array(
'description' => 'The name of the object type in which the file is used.',
'type' => 'varchar',
'length' => 64,
'not null' => TRUE,
'default' => '',
),
'id' => array(
'description' => 'The primary key of the object using the file.',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'count' => array(
'description' => 'The number of times this file is used by this object.',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
),
'primary key' => array('fid', 'type', 'id', 'module'),
'indexes' => array(
'type_id' => array('type', 'id'),
'fid_count' => array('fid', 'count'),
'fid_module' => array('fid', 'module'),
),
);
return $schema;
}
/**
* Implements hook_field_schema().
*/
......
This diff is collapsed.
......@@ -2,10 +2,10 @@
/**
* @file
* Definition of Drupal\Core\File\File.
* Definition of Drupal\file\File.
*/
namespace Drupal\Core\File;
namespace Drupal\file;
use Drupal\entity\Entity;
......
......@@ -2,10 +2,10 @@
/**
* @file
* Definition of Drupal\Core\File\FileStorageController.
* Definition of Drupal\file\FileStorageController.
*/
namespace Drupal\Core\File;
namespace Drupal\file;
use Drupal\entity\DatabaseStorageController;
use Drupal\entity\StorableInterface;
......
......@@ -2,15 +2,15 @@
/**
* @file
* Definition of Drupal\system\Tests\File\CopyTest.
* Definition of Drupal\file\Tests\CopyTest.
*/
namespace Drupal\system\Tests\File;
namespace Drupal\file\Tests;
/**
* Copy related tests.
*/
class CopyTest extends FileHookTestBase {
class CopyTest extends FileManagedTestBase {
public static function getInfo() {
return array(
'name' => 'File copying',
......
......@@ -2,15 +2,15 @@
/**
* @file
* Definition of Drupal\system\Tests\File\DeleteTest.
* Definition of Drupal\file\Tests\DeleteTest.
*/
namespace Drupal\system\Tests\File;
namespace Drupal\file\Tests;
/**
* Deletion related tests.
*/
class DeleteTest extends FileHookTestBase {
class DeleteTest extends FileManagedTestBase {
public static function getInfo() {
return array(
'name' => 'File delete',
......
......@@ -2,23 +2,15 @@
/**
* @file
* Definition of Drupal\system\Tests\File\DownloadTest.
* Definition of Drupal\file\Tests\DownloadTest.
*/
namespace Drupal\system\Tests\File;
namespace Drupal\file\Tests;
/**
* Tests for download/file transfer functions.
*/
class DownloadTest extends FileTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('file_test');
class DownloadTest extends FileManagedTestBase {
public static function getInfo() {
return array(
'name' => 'File download',
......
......@@ -2,26 +2,28 @@
/**
* @file
* Definition of Drupal\system\Tests\File\FileHookTestBase.
* Definition of Drupal\file\Tests\FileManagedTestBase.
*/
namespace Drupal\system\Tests\File;
namespace Drupal\file\Tests;
use Drupal\system\Tests\File\FileTestBase;
use \stdClass;
/**
* Base class for file tests that use the file_test module to test uploads and
* hooks.
*/
abstract class FileHookTestBase extends FileTestBase {
abstract class FileManagedTestBase extends FileTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('file_test');
public static $modules = array('file_test', 'file');
function setUp() {
// Install file_test module
parent::setUp();
// Clear out any hook calls.
file_test_reset();
......@@ -84,4 +86,36 @@ function assertFileHookCalled($hook, $expected_count = 1, $message = NULL) {
}
$this->assertEqual($actual_count, $expected_count, $message);
}
/**
* Create a file and save it to the files table and assert that it occurs
* correctly.
*
* @param $filepath
* Optional string specifying the file path. If none is provided then a
* randomly named file will be created in the site's files directory.
* @param $contents
* Optional contents to save into the file. If a NULL value is provided an
* arbitrary string will be used.
* @param $scheme
* Optional string indicating the stream scheme to use. Drupal core includes
* public, private, and temporary. The public wrapper is the default.
* @return
* File object.
*/
function createFile($filepath = NULL, $contents = NULL, $scheme = NULL) {
$file = new stdClass();
$file->uri = $this->createUri($filepath, $contents, $scheme);
$file->filename = drupal_basename($file->uri);
$file->filemime = 'text/plain';
$file->uid = 1;
$file->timestamp = REQUEST_TIME;
$file->filesize = filesize($file->uri);
$file->status = 0;
// Write the record directly rather than using the API so we don't invoke
// the hooks.
$this->assertNotIdentical(drupal_write_record('file_managed', $file), FALSE, t('The file was added to the database.'), 'Create test file');
return entity_create('file', (array) $file);
}
}
......@@ -2,15 +2,15 @@
/**
* @file
* Definition of Drupal\system\Tests\File\LoadTest.
* Definition of Drupal\file\Tests\LoadTest.
*/
namespace Drupal\system\Tests\File;
namespace Drupal\file\Tests;
/**
* Tests the file_load() function.
*/
class LoadTest extends FileHookTestBase {
class LoadTest extends FileManagedTestBase {
public static function getInfo() {
return array(
'name' => 'File loading',
......
......@@ -2,15 +2,15 @@
/**
* @file
* Definition of Drupal\system\Tests\File\MoveTest.
* Definition of Drupal\file\Tests\MoveTest.
*/
namespace Drupal\system\Tests\File;
namespace Drupal\file\Tests;
/**
* Move related tests
*/
class MoveTest extends FileHookTestBase {
class MoveTest extends FileManagedTestBase {
public static function getInfo() {
return array(
'name' => 'File moving',
......
......@@ -2,10 +2,10 @@
/**
* @file
* Definition of Drupal\system\Tests\File\RemoteFileSaveUploadTest.
* Definition of Drupal\file\Tests\RemoteFileSaveUploadTest.
*/
namespace Drupal\system\Tests\File;
namespace Drupal\file\Tests;
/**
* Tests the file_save_upload() function on remote filesystems.
......
......@@ -2,15 +2,15 @@
/**
* @file
* Definition of Drupal\system\Tests\File\SaveDataTest.
* Definition of Drupal\file\Tests\SaveDataTest.
*/
namespace Drupal\system\Tests\File;
namespace Drupal\file\Tests;
/**
* Tests the file_save_data() function.
*/
class SaveDataTest extends FileHookTestBase {
class SaveDataTest extends FileManagedTestBase {
public static function getInfo() {
return array(
'name' => 'File save data',
......
......@@ -2,15 +2,15 @@
/**
* @file
* Definition of Drupal\system\Tests\File\SaveTest.
* Definition of Drupal\file\Tests\SaveTest.
*/
namespace Drupal\system\Tests\File;
namespace Drupal\file\Tests;
/**
* Tests saving files.
*/
class SaveTest extends FileHookTestBase {
class SaveTest extends FileManagedTestBase {
public static function getInfo() {
return array(
'name' => 'File saving',
......
......@@ -2,15 +2,15 @@
/**
* @file
* Definition of Drupal\system\Tests\File\SaveUploadTest.
* Definition of Drupal\file\Tests\SaveUploadTest.
*/
namespace Drupal\system\Tests\File;
namespace Drupal\file\Tests;
/**
* Test the file_save_upload() function.
*/
class SaveUploadTest extends FileHookTestBase {
class SaveUploadTest extends FileManagedTestBase {
/**
* An image file path for uploading.
*/
......
......@@ -2,15 +2,15 @@
/**
* @file
* Definition of Drupal\system\Tests\File\SpaceUsedTest.
* Definition of Drupal\file\Tests\SpaceUsedTest.
*/
namespace Drupal\system\Tests\File;
namespace Drupal\file\Tests;
/**
* This will run tests against the file_space_used() function.
*/
class SpaceUsedTest extends FileTestBase {
class SpaceUsedTest extends FileManagedTestBase {
public static function getInfo() {
return array(
'name' => 'File space used tests',
......
......@@ -2,20 +2,20 @@
/**
* @file
* Definition of Drupal\system\Tests\File\UsageTest.
* Definition of Drupal\file\Tests\UsageTest.
*/
namespace Drupal\system\Tests\File;
namespace Drupal\file\Tests;
/**