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