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: $this->tempDirectory = $tempDirectory;
48: }
49:
50:
51: 52: 53:
54: public function create()
55: {
56: if (!class_exists($this->class)) {
57: $this->loadClass();
58: }
59: return new $this->class;
60: }
61:
62:
63: 64: 65:
66: protected function generateCode()
67: {
68: $compiler = $this->createCompiler();
69: $config = $this->generateConfig();
70: $this->onCompile($this, $compiler, $config);
71:
72: $code = "<?php\n";
73: foreach ($this->configFiles as $info) {
74: $code .= "// source: $info[0] $info[1]\n";
75: }
76: $code .= "\n" . $compiler->compile($config, $this->class, $this->parentClass);
77:
78: if ($this->autoRebuild !== 'compat') {
79: $this->dependencies = array_merge($this->dependencies, $compiler->getContainerBuilder()->getDependencies());
80: }
81: return $code;
82: }
83:
84:
85: 86: 87:
88: protected function generateConfig()
89: {
90: $config = array();
91: $loader = $this->createLoader();
92: foreach ($this->configFiles as $info) {
93: $config = Config\Helpers::merge($loader->load($info[0], $info[1]), $config);
94: }
95: $this->dependencies = array_merge($this->dependencies, $loader->getDependencies());
96:
97: return Config\Helpers::merge($config, $this->config);
98: }
99:
100:
101: 102: 103:
104: private function loadClass()
105: {
106: $key = md5(serialize(array($this->config, $this->configFiles, $this->class, $this->parentClass)));
107: $handle = fopen($file = "$this->tempDirectory/$key.php", 'c+');
108: if (!$handle) {
109: throw new Nette\IOException("Unable to open or create file '$file'.");
110: }
111:
112: flock($handle, LOCK_SH);
113: $stat = fstat($handle);
114: if ($stat['size']) {
115: if ($this->autoRebuild) {
116: foreach ((array) @unserialize(file_get_contents($file . '.meta')) as $f => $time) {
117: if (@filemtime($f) !== $time) {
118: goto write;
119: }
120: }
121: }
122: } else {
123: write:
124: ftruncate($handle, 0);
125: flock($handle, LOCK_EX);
126: $stat = fstat($handle);
127: if (!$stat['size']) {
128: $this->dependencies = array();
129: $code = $this->generateCode();
130: if (fwrite($handle, $code, strlen($code)) !== strlen($code)) {
131: ftruncate($handle, 0);
132: throw new Nette\IOException("Unable to write file '$file'.");
133: }
134:
135: $tmp = array();
136: foreach ($this->dependencies as $f) {
137: $tmp[$f] = @filemtime($f);
138: }
139: file_put_contents($file . '.meta', serialize($tmp));
140: }
141: flock($handle, LOCK_SH);
142: }
143:
144: require $file;
145: }
146:
147:
148: 149: 150:
151: protected function createCompiler()
152: {
153: return new Compiler;
154: }
155:
156:
157: 158: 159:
160: protected function createLoader()
161: {
162: return new Config\Loader;
163: }
164:
165: }
166: