Skip to content

Commit

Permalink
DependencyChecker::isExpired() can alter $phpFiles modification times [
Browse files Browse the repository at this point in the history
…Closes #144]
  • Loading branch information
dg committed Feb 27, 2017
1 parent f3bed1e commit 6f8218e
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 8 deletions.
16 changes: 11 additions & 5 deletions src/DI/ContainerLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,12 @@ private function loadFile($class, $generator)
throw new Nette\IOException("Unable to acquire exclusive lock on '$file.lock'.");
}

if (!is_file($file) || $this->isExpired($file)) {
list($toWrite[$file], $toWrite["$file.meta"]) = $this->generate($class, $generator);
if (!is_file($file) || $this->isExpired($file, $updatedMeta)) {
if (isset($updatedMeta)) {
$toWrite["$file.meta"] = $updatedMeta;
} else {
list($toWrite[$file], $toWrite["$file.meta"]) = $this->generate($class, $generator);
}

foreach ($toWrite as $name => $content) {
if (file_put_contents("$name.tmp", $content) !== strlen($content) || !rename("$name.tmp", $name)) {
Expand All @@ -98,11 +102,13 @@ private function loadFile($class, $generator)
}


private function isExpired($file)
private function isExpired($file, &$updatedMeta = NULL)
{
if ($this->autoRebuild) {
$meta = @unserialize(file_get_contents("$file.meta")); // @ - file may not exist
return empty($meta[0]) || DependencyChecker::isExpired(...$meta);
$meta = $orig = @unserialize((string) file_get_contents("$file.meta")); // @ - file may not exist
return empty($meta[0])
|| DependencyChecker::isExpired(...$meta)
|| ($orig !== $meta && $updatedMeta = serialize($meta));
}
return FALSE;
}
Expand Down
7 changes: 4 additions & 3 deletions src/DI/DependencyChecker.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,14 @@ public function export()
* Are dependencies expired?
* @return bool
*/
public static function isExpired($version, $files, $phpFiles, $classes, $functions, $hash)
public static function isExpired($version, $files, &$phpFiles, $classes, $functions, $hash)
{
$current = @array_map('filemtime', array_combine($tmp = array_keys($files), $tmp)); // @ - files may not exist
$currentClass = @array_map('filemtime', array_combine($tmp = array_keys($phpFiles), $tmp)); // @ - files may not exist
$origPhpFiles = $phpFiles;
$phpFiles = @array_map('filemtime', array_combine($tmp = array_keys($phpFiles), $tmp)); // @ - files may not exist
return $version !== self::VERSION
|| $files !== $current
|| ($phpFiles !== $currentClass && $hash !== self::calculateHash($classes, $functions));
|| ($phpFiles !== $origPhpFiles && $hash !== self::calculateHash($classes, $functions));
}


Expand Down
56 changes: 56 additions & 0 deletions tests/DI/ContainerLoader.isExpired.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

/**
* Test: Nette\DI\ContainerLoader expiration test.
*/

declare(strict_types=1);

use Nette\DI;
use Tester\Assert;


require __DIR__ . '/../bootstrap.php';


$loader = new DI\ContainerLoader(TEMP_DIR . '/subdir', TRUE);

// create container
Assert::with($loader, function () {
$this->loadFile('class1', function () {});
});

// ensure files are created
$file = (new ReflectionClass('class1'))->getFileName();
Assert::true(is_file($file));
Assert::true(is_file("$file.meta"));


// load again, nothing was modified
Assert::with($loader, function () use ($file) {
Assert::false($this->isExpired($file, $newMeta));
Assert::null($newMeta);
});


// alter filemtime in files
$meta = file_get_contents("$file.meta");
$altered = unserialize($meta);
$altered[1][__FILE__] = 123;
file_put_contents("$file.meta", serialize($altered));

Assert::with($loader, function () use ($file) {
Assert::true($this->isExpired($file, $newMeta));
Assert::null($newMeta);
});


// alter filemtime in classes
$altered = unserialize($meta);
$altered[2][key($altered[2])] = 123;
file_put_contents("$file.meta", serialize($altered));

Assert::with($loader, function () use ($file, $meta) {
Assert::true($this->isExpired($file, $newMeta));
Assert::same($meta, $newMeta);
});
32 changes: 32 additions & 0 deletions tests/DI/ContainerLoader.loadFile.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

/**
* Test: Nette\DI\ContainerLoader expiration test.
*/

declare(strict_types=1);

use Nette\DI;
use Tester\Assert;


require __DIR__ . '/../bootstrap.php';


$loader = new DI\ContainerLoader(TEMP_DIR . '/subdir', TRUE);

// create container
Assert::with($loader, function () {
$this->loadFile('class1', function () {});
});

// ensure files are created
$file = (new ReflectionClass('class1'))->getFileName();
Assert::true(is_file($file));
Assert::true(is_file("$file.meta"));

// load again
file_put_contents($file, ''); // remove file to avoid class redeclare error
Assert::with($loader, function () {
$this->loadFile('class1', function () { Assert::fail('Should not be recreated'); });
});

0 comments on commit 6f8218e

Please sign in to comment.