config = $config; $this->filename = $filename; $this->fileMode = $filemode; $this->options = $options; } /** * Render the Zend_Config into a config filestring * * @return string */ public function render() { if (file_exists($this->filename)) { $oldconfig = Config::fromIni($this->filename); $content = trim(file_get_contents($this->filename)); } else { $oldconfig = Config::fromArray(array()); $content = ''; } $doc = IniParser::parseIni($content); $this->diffPropertyUpdates($this->config, $doc); $this->diffPropertyDeletions($oldconfig, $this->config, $doc); $doc = $this->updateSectionOrder($this->config, $doc); return $doc->render(); } /** * Write configuration to file and set file mode in case it does not exist yet * * @param string $filename * @param bool $exclusiveLock * * @throws Zend_Config_Exception */ public function write($filename = null, $exclusiveLock = false) { $filePath = isset($filename) ? $filename : $this->filename; $setMode = false === file_exists($filePath); if (file_put_contents($filePath, $this->render(), $exclusiveLock ? LOCK_EX : 0) === false) { throw new Zend_Config_Exception('Could not write to file "' . $filePath . '"'); } if ($setMode) { // file was newly created $mode = $this->fileMode; if (is_int($this->fileMode) && false === @chmod($filePath, $this->fileMode)) { throw new Zend_Config_Exception(sprintf('Failed to set file mode "%o" on file "%s"', $mode, $filePath)); } } } /** * Update the order of the sections in the ini file to match the order of the new config * * @return Document A new document with the changed section order applied */ protected function updateSectionOrder(Config $newconfig, Document $oldDoc) { $doc = new Document(); $dangling = $oldDoc->getCommentsDangling(); if (isset($dangling)) { $doc->setCommentsDangling($dangling); } foreach ($newconfig->toArray() as $section => $directives) { $doc->addSection($oldDoc->getSection($section)); } return $doc; } /** * Search for created and updated properties and use the editor to create or update these entries * * @param Config $newconfig The config representing the state after the change * @param Document $doc * * @throws ProgrammingError */ protected function diffPropertyUpdates(Config $newconfig, Document $doc) { foreach ($newconfig->toArray() as $section => $directives) { if (! is_array($directives)) { Logger::warning('Section-less property ' . (string)$directives . ' was ignored.'); continue; } if (!$doc->hasSection($section)) { $domSection = new Section($section); $doc->addSection($domSection); } else { $domSection = $doc->getSection($section); } foreach ($directives as $key => $value) { if ($value === null) { continue; } if ($value instanceof ConfigObject) { throw new ProgrammingError('Cannot diff recursive configs'); } if ($domSection->hasDirective($key)) { $domSection->getDirective($key)->setValue($value); } else { $dir = new Directive($key); $dir->setValue($value); $domSection->addDirective($dir); } } } } /** * Search for deleted properties and use the editor to delete these entries * * @param Config $oldconfig The config representing the state before the change * @param Config $newconfig The config representing the state after the change * @param Document $doc * * @throws ProgrammingError */ protected function diffPropertyDeletions(Config $oldconfig, Config $newconfig, Document $doc) { // Iterate over all properties in the old configuration file and remove those that don't // exist in the new config foreach ($oldconfig->toArray() as $section => $directives) { if (! is_array($directives)) { Logger::warning('Section-less property ' . (string)$directives . ' was ignored.'); continue; } if ($newconfig->hasSection($section)) { $newSection = $newconfig->getSection($section); $oldDomSection = $doc->getSection($section); foreach ($directives as $key => $value) { if ($value instanceof ConfigObject) { throw new ProgrammingError('Cannot diff recursive configs'); } if (null === $newSection->get($key) && $oldDomSection->hasDirective($key)) { $oldDomSection->removeDirective($key); } } } else { $doc->removeSection($section); } } } }