1: <?php
2:
3: 4: 5: 6:
7:
8: namespace Nette\DI;
9:
10: use Nette;
11:
12:
13: 14: 15:
16: class ContainerLoader
17: {
18: use Nette\SmartObject;
19:
20:
21: private $autoRebuild = FALSE;
22:
23:
24: private $tempDirectory;
25:
26:
27: public function __construct($tempDirectory, $autoRebuild = FALSE)
28: {
29: $this->tempDirectory = $tempDirectory;
30: $this->autoRebuild = $autoRebuild;
31: }
32:
33:
34: 35: 36: 37: 38:
39: public function load($generator, $key = NULL)
40: {
41: if (!is_callable($generator)) {
42: trigger_error(__METHOD__ . ': order of arguments has been swapped.', E_USER_DEPRECATED);
43: list($generator, $key) = [$key, $generator];
44: }
45: $class = $this->getClassName($key);
46: if (!class_exists($class, FALSE)) {
47: $this->loadFile($class, $generator);
48: }
49: return $class;
50: }
51:
52:
53: 54: 55:
56: public function getClassName($key)
57: {
58: return 'Container_' . substr(md5(serialize($key)), 0, 10);
59: }
60:
61:
62: 63: 64:
65: private function loadFile($class, $generator)
66: {
67: $file = "$this->tempDirectory/$class.php";
68: if (!$this->isExpired($file) && (@include $file) !== FALSE) {
69: return;
70: }
71:
72: if (!is_dir($this->tempDirectory)) {
73: @mkdir($this->tempDirectory);
74: }
75:
76: $handle = fopen("$file.lock", 'c+');
77: if (!$handle || !flock($handle, LOCK_EX)) {
78: throw new Nette\IOException("Unable to acquire exclusive lock on '$file.lock'.");
79: }
80:
81: if (!is_file($file) || $this->isExpired($file)) {
82: list($toWrite[$file], $toWrite["$file.meta"]) = $this->generate($class, $generator);
83:
84: foreach ($toWrite as $name => $content) {
85: if (file_put_contents("$name.tmp", $content) !== strlen($content) || !rename("$name.tmp", $name)) {
86: @unlink("$name.tmp");
87: throw new Nette\IOException("Unable to create file '$name'.");
88: } elseif (function_exists('opcache_invalidate')) {
89: @opcache_invalidate($name, TRUE);
90: }
91: }
92: }
93:
94: if ((@include $file) === FALSE) {
95: throw new Nette\IOException("Unable to include '$file'.");
96: }
97: flock($handle, LOCK_UN);
98: }
99:
100:
101: private function isExpired($file)
102: {
103: if ($this->autoRebuild) {
104: $meta = @unserialize(file_get_contents("$file.meta"));
105: return empty($meta[0]) || DependencyChecker::isExpired(...$meta);
106: }
107: return FALSE;
108: }
109:
110:
111: 112: 113:
114: protected function generate($class, $generator)
115: {
116: $compiler = new Compiler;
117: $compiler->setClassName($class);
118: $code = call_user_func_array($generator, [& $compiler]) ?: $compiler->compile();
119: return [
120: "<?php\n$code",
121: serialize($compiler->exportDependencies())
122: ];
123: }
124:
125: }
126: