1: <?php
2:
3: 4: 5: 6:
7:
8: namespace Nette\DI;
9:
10: use Nette;
11:
12:
13: 14: 15: 16: 17: 18:
19: class ContainerFactory extends Nette\Object
20: {
21:
22: public $onCompile;
23:
24:
25: public $autoRebuild = FALSE;
26:
27:
28: public $class = 'SystemContainer';
29:
30:
31: public $parentClass = 'Nette\DI\Container';
32:
33:
34: public $config = array();
35:
36:
37: public $configFiles = array();
38:
39:
40: public $tempDirectory;
41:
42:
43: private $dependencies = array();
44:
45:
46: public function __construct($tempDirectory)
47: {
48: trigger_error(__CLASS__ . " is deprecated; use ContainerLoader.", E_USER_DEPRECATED);
49: $this->tempDirectory = $tempDirectory;
50: }
51:
52:
53: 54: 55:
56: public function create()
57: {
58: if (!class_exists($this->class)) {
59: $this->loadClass();
60: }
61: return new $this->class;
62: }
63:
64:
65: 66: 67:
68: protected function generateCode()
69: {
70: $compiler = $this->createCompiler();
71: $config = $this->generateConfig();
72: $this->onCompile($this, $compiler, $config);
73:
74: $code = "<?php\n";
75: foreach ($this->configFiles as $info) {
76: if (is_scalar($info[0])) {
77: $code .= "// source: $info[0] $info[1]\n";
78: }
79: }
80: $code .= "\n" . $compiler->compile($config, $this->class, $this->parentClass);
81:
82: if ($this->autoRebuild !== 'compat') {
83: $this->dependencies = array_merge($this->dependencies, $compiler->getContainerBuilder()->getDependencies());
84: }
85: return $code;
86: }
87:
88:
89: 90: 91:
92: protected function generateConfig()
93: {
94: $config = array();
95: $loader = $this->createLoader();
96: foreach ($this->configFiles as $info) {
97: $info = is_scalar($info[0]) ? $loader->load($info[0], $info[1]) : $info[0];
98: $config = Config\Helpers::merge($info, $config);
99: }
100: $this->dependencies = array_merge($this->dependencies, $loader->getDependencies());
101:
102: return Config\Helpers::merge($config, $this->config);
103: }
104:
105:
106: 107: 108:
109: private function loadClass()
110: {
111: $key = md5(serialize(array($this->config, $this->configFiles, $this->class, $this->parentClass)));
112: $file = "$this->tempDirectory/$key.php";
113: if (!$this->isExpired($file) && (@include $file) !== FALSE) {
114: return;
115: }
116:
117: $handle = fopen("$file.lock", 'c+');
118: if (!$handle || !flock($handle, LOCK_EX)) {
119: throw new Nette\IOException("Unable to acquire exclusive lock on '$file.lock'.");
120: }
121:
122: if (!is_file($file) || $this->isExpired($file)) {
123: $this->dependencies = array();
124: $toWrite[$file] = $this->generateCode();
125: $files = $this->dependencies ? array_combine($this->dependencies, $this->dependencies) : array();
126: $toWrite["$file.meta"] = serialize(@array_map('filemtime', $files));
127:
128: foreach ($toWrite as $name => $content) {
129: if (file_put_contents("$name.tmp", $content) !== strlen($content) || !rename("$name.tmp", $name)) {
130: @unlink("$name.tmp");
131: throw new Nette\IOException("Unable to create file '$name'.");
132: }
133: }
134: }
135:
136: if ((@include $file) === FALSE) {
137: throw new Nette\IOException("Unable to include '$file'.");
138: }
139: flock($handle, LOCK_UN);
140: }
141:
142:
143: private function isExpired($file)
144: {
145: if ($this->autoRebuild) {
146: $meta = @unserialize(file_get_contents("$file.meta"));
147: $files = $meta ? array_combine($tmp = array_keys($meta), $tmp) : array();
148: return $meta !== @array_map('filemtime', $files);
149: }
150: return FALSE;
151: }
152:
153:
154: 155: 156:
157: protected function createCompiler()
158: {
159: return new Compiler;
160: }
161:
162:
163: 164: 165:
166: protected function createLoader()
167: {
168: return new Config\Loader;
169: }
170:
171: }
172: