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