Wherefore art thou Data?
As a novice eZPublish programmer 6 year ago my biggest problem was always trying to find my data. Of course attribute(show) was invaluable... and at first I wrote a shell script to parse that data to make it readable and years later I wrote ezfire to make that data more accessible... But, for much of the time I was cursing and thinking - to paraphrase Mojo Nixon - "Where the hell's my data."
It's still a hurdle today. The learning curve is high for eZPublish - at least to really know what it's doing. And, frankly, for all the good things about eZPublish, some things can be better. And hopefully this blog (besides the random rants) will be an occasional series about where the hell to find your data.
One of the problems that I've been having lately is figuring out which ini file is actually serving which value.
One of the greatest things about eZPublish is how configurable it is but that's also one of the high hurdles to understanding how it works. It also makes debugging more difficult.
So, which is it? Is it the ActiveExtensions in the settings/override or the ActiveAccessExtension in the settings/siteaccess or an extension site.ini or a the extension siteaccess or what happens if you call an ActiveAccessExtension from another ActiveAccessExtension and then you have the settings directory or the siteaccess directory there. And, what happens if you have the same value in two extensions at the same level?
Well, through painful experience I can answer a few things: If you call an extension from another extension it will be ignored and if you have a value in two extensions then whatever is listed first in the ini file will take precedence. Of course, don't touch the web gui to manipulate extensions because it'll (sometimes catastrophically) reorder your extension list alphabetically - which I think was fixed? I normally would disable that sort. Well, there is a way of defining prerequisites now (4.4+?) for extensions, but I haven't figured out how to use that yet.
Settings can become complicated, because for multilingual sites what we'll end up having is the stuff in settings/siteaccess just pointing to a settings extension, because really the only thing that's different for all the languages is the RegionalSettings and maybe a few other minor things. The default ezpublish way has a lot of duplication even if you symbolically link everything except the site.ini.access.php file.
So essentially RegionalSettings can be set in the extension/siteaccess files while the meat of the settings are in the extension/settings directory (and settings/override). But of course, you want admin to be able to access design stuff without picking up those settings... so you have to seperate the design settings in a design extension. I also like to set up (on development machines) a debug siteaccess which is a symbolic link to default but all the debug settings defined in a debug extension (with custom settingstoolbar.php and quicksettings.tpl) so that if I go to site/debug, cache is off and debug is on while the other siteaccesses work like they would with live.
So, this can really quickly become incomprehensible - the above paragraph is incomprehensible and I just wrote it. Oh, well. I think humans can deal with about 6 levels of abstraction before they start losing the thread (this could just be me) and we're way past that at this point.
So, yes, there is settings/view on the backend... but that's not really useful to me... you have to choose the ini file and then search for the block of what you want (may as well just vi the files) for one thing I'm way more comfortable on the command line. Maybe a vestige of the old school but hey get off my lawn.
What I really want to be able to say is give me [Block]Variable and tell me what the value is and where it's coming from... it would also be nice to be able to search for stuff so as to be able to misspell something. I haven't figured out how to do that, any ideas? I'm thinking load the array into an xml object and use some XPath magic... but another part of me is saying that's stupid... dunno. Hmmm, maybe get ezfind to index the ini files - no, no, sheer lunacy.
So, I'll dump the code below. It's a work in progress and not really much of an addition to the settings/view code (a couple of extra dropdowns and it would work on the backend), and the arrays look a bit funny if they have a blank value to start and I've haven't tested much but it looks like it may be getting the source wrong if there are multiple sources to an array.. But, I hope this is the beginning of a conversation of how this can be improved.
Now, to the code:
<?php // function recursiveDump($obj) { if(is_array($obj)) { foreach($obj as $value) { if ($value) $new[] = recursiveDump($value); } return "\n".implode("\t\t",$new); } else { return $obj; } } require_once("autoload.php"); $cli = eZCLI::instance(); $script = eZScript::instance( array( 'description' => ( "Displays Setting information" ), 'use-session' => false, 'use-modules' => true, 'use-extensions' => true ) ); $script->startup(); $options = $script->getOptions( "[ini:][block:][variable:][i:][b:][v:]", "", array( 'ini' => "ini file", 'block' => "BlockName", 'variable' => "Variable" ) ); $script->initialize(); $siteaccess = $options['siteaccess'] ? $options['siteaccess'] : false; $script->setUseSiteAccess( $siteaccess ); if ($options['ini']) $settingFiles = array( $options['ini'] ); elseif ($options['i']) $settingFiles = array( $options['i'] ); else { // no .ini file chosen - do them all -- yeehah! $rootDir = 'settings'; $iniFiles = eZDir::recursiveFindRelative( $rootDir, '', '.ini' ); foreach ( eZINI::defaultOverrideDirs() as $iniDataSet ) { $iniPath = $iniDataSet[1] ? $iniDataSet[0] : 'settings/' . $iniDataSet[0]; $iniFiles = array_merge( $iniFiles, eZDir::recursiveFindRelative( $iniPath, '', '.ini' ) ); $iniFiles = array_merge( $iniFiles, eZDir::recursiveFindRelative( $iniPath, '', '.ini.append.php' ) ); } foreach ( eZINI::globalOverrideDirs('extension') as $iniDataSet ) { $iniPath = $iniDataSet[1] ? $iniDataSet[0] : 'settings/' . $iniDataSet[0]; $iniFiles = array_merge( $iniFiles, eZDir::recursiveFindRelative( $iniPath, '', '.ini' ) ); $iniFiles = array_merge( $iniFiles, eZDir::recursiveFindRelative( $iniPath, '', '.ini.append.php' ) ); } // extract all .ini files without path $iniFiles = preg_replace('%.*/%', '', $iniFiles ); // remove *.ini[.append.php] from file name $iniFiles = preg_replace('%\.ini.*%', '.ini', $iniFiles ); sort( $iniFiles ); $settingFiles = array_unique( $iniFiles ); } if ($options['block']) $optionBlock = $options['block']; elseif ($options['b']) $optionBlock = $options['b']; if ($options['variable']) $optionVariable = $options['variable']; elseif ($options['v']) $optionVariable = $options['variable']; // create a site ini instance using $useLocalOverrides $siteIni = eZSiteAccess::getIni( $siteaccess, 'site.ini' ); if (!$siteaccess) $siteaccess = $siteIni->variable( 'SiteSettings', 'DefaultAccess' ); //If there is no ini file defined... then it should be ALL ini files foreach($settingFiles as $settingFile) { // load settings file with $useLocalOverrides = true & $addArrayDefinition = true $ini = new eZINI( /*$fileName =*/ $settingFile, /*$rootDir =*/ 'settings', /*$useTextCodec =*/ null, /*$useCache =*/ false, /*$useLocalOverrides =*/ true, /*$directAccess =*/ false, /*$addArrayDefinition =*/ true, /*$load =*/ false ); $ini->setOverrideDirs( $siteIni->overrideDirs( false ) ); $ini->load(); $blocks = $ini->groups(); $placements = $ini->groupPlacements(); $settings = array(); $blockCount = 0; $totalSettingCount = 0; foreach( $blocks as $block=>$key ) { if($optionBlock AND $optionBlock != $block) continue; $settingsCount = 0; $blockRemoveable = false; $blockEditable = true; foreach( $key as $setting=>$settingKey ) { if($optionVariable AND $optionVariable != $setting) continue; $hasSetPlacement = false; $type = $ini->settingType( $settingKey ); $removeable = false; switch ( $type ) { case 'array': if ( count( $settingKey ) == 0 ) $settings[$block]['content'][$setting]['content'] = array(); foreach( $settingKey as $settingElementKey=>$settingElementValue ) { $settingPlacement = $ini->findSettingPlacement( $placements[$block][$setting][$settingElementKey] ); if ( $settingElementValue != null ) { // Make a space after the ';' to make it possible for // the browser to break long lines $settings[$block]['content'][$setting]['content'][$settingElementKey]['content'] = str_replace( ';', "; ", $settingElementValue ); } else { $settings[$block]['content'][$setting]['content'][$settingElementKey]['content'] = ""; } $settings[$block]['content'][$setting]['content'][$settingElementKey]['placement'] = $settingPlacement; $hasSetPlacement = true; if ( $settingPlacement != 'default' ) { $removeable = true; $blockRemoveable = true; } } break; case 'string': if( strpos( $settingKey, ';' ) ) { // Make a space after the ';' to make it possible for // the browser to break long lines $settingArray = str_replace( ';', "; ", $settingKey ); $settings[$block]['content'][$setting]['content'] = $settingArray; } else { $settings[$block]['content'][$setting]['content'] = $settingKey; } break; default: $settings[$block]['content'][$setting]['content'] = $settingKey; } $settings[$block]['content'][$setting]['type'] = $type; $settings[$block]['content'][$setting]['placement'] = ""; if ( !$hasSetPlacement ) { $placement = $ini->findSettingPlacement( $placements[$block][$setting] ); $settings[$block]['content'][$setting]['placement'] = $placement; if ( $placement != 'default' ) { $removeable = true; $blockRemoveable = true; } } $editable = $ini->isSettingReadOnly( $settingFile, $block, $setting ); $removeable = $editable === false ? false : $removeable; $settings[$block]['content'][$setting]['editable'] = $editable; $settings[$block]['content'][$setting]['removeable'] = $removeable; ++$settingsCount; } $blockEditable = $ini->isSettingReadOnly( $settingFile, $block ); $settings[$block]['count'] = $settingsCount; $settings[$block]['removeable'] = $blockRemoveable; $settings[$block]['editable'] = $blockEditable; $totalSettingCount += $settingsCount; ++$blockCount; } ksort( $settings ); if ($settings AND count($settingFiles) > 1 ) //Only really want to see this if there is a match and there is more than one ini file echo "########## $settingFile #########\n"; foreach($settings as $key => $setting) { foreach($setting['content'] as $contentKey => $value ) { echo $key." ".$contentKey." ".$value['placement']." ".$value['type']." ".recursiveDump($value['content'])."\n"; } } } echo "siteaccess ".$siteaccess."\n"; $script->shutdown(); ?>