I am working on a function that will take a an array of options. These options are retrived from a database, and could have other options inputted throughout the system. When adding my options, I am constrained by only being able to add a single option at a time. I can't currently add an array of options. The options that the system adds can be unpredictable, because of the codebase. The resulting array from the database call could look like this, except for the option keys I define starting with custom_
, those I can rely on being there, since I set them:
array(
0 => '...',
'menu_items' => array(
'item1' => '...',
'item2' => '...',
'item3' => '...',
'item4' => '...',
),
'another_item' => '...',
'custom_contact_office_name' => 'The Office Name',
'custom_contact_office_address' => '1234 Address St',
'custom_contact_office_phone' => '555.555.5555',
'custom_contact_office_email' => '[email protected]',
'custom_contact_office_fax' => '555.555.5555',
'custom_contact_office_leader_name' => 'Mr. Pickles',
'custom_contact_office_leader_address' => '5678 Address St',
'custom_contact_office_leader_phone' => '555.555.5555',
'custom_contact_office_leader_email' => '[email protected]',
'custom_social_linkedin' => 'linkedin.com/profile_url',
'custom_social_facebook' => 'facebook.com/profile_url',
'custom_social_twitter' => 'twitter.com/profile_url',
'custom_social_gplus' => 'google.com/plus/profile_url',
'custom_social_github' => 'github.com/profile_url',
'custom_social_youtube' => 'youtube.com/profile_url',
'another_option' => '...',
'some_other_kind_of_option' => '...',
'some_more_items_of_this' => '...',
);
The way the system works is to serialize all the options in one array and save it to the db table. So you have to register the option by "id" which is really just used as the key in the massive serialized array that gets saved, so it needs to be unique, thus all the prefixes. I'm not interested in the other defined options, in fact, I want to skip over them while parsing through the array. So I wrote a couple functions to parse the office
section:
/**
* Parse the settings passed in
*
* @param $main_pattern
* @param $sub_pattern
* @param $option_name
* @param $option_value
*
* @return null
*/
function setting_parser($main_pattern, $sub_pattern, $option_name, $option_value) {
if (preg_match( $main_pattern, $option_name )) {
if (preg_match( $sub_pattern, $option_name )) {
return $option_value;
}
}
return null;
}
/**
* Apply the values to the multi-dimensional array
*
* @param array $theme_options
* @param array $info_types
* @param string $section
* @param string $section_pattern
* @param bool $is_option_string
*
* @return array
*/
function apply_multi_dimensional_values(array $theme_options, array $info_types, $section, $section_pattern, $is_option_string) {
$array_ref = array();
foreach ($theme_options as $option_name => $option_value) {
if ($is_option_string && preg_match( '/custom/', $option_name )) {
/* Check if it's a string, to avoid numerically indexed values */
if ( is_string( $option_name ) ) {
if ($info_types !== null && is_array( $info_types )) {
for ($i = 0; $i<count( $info_types ); $i++) {
if (preg_match( sprintf( '/%s/', $info_types[ $i ] ), $option_name ) && preg_match( $section_pattern, $option_name )) {
$array_ref[$section][$info_types[$i]] = setting_parser( $section_pattern, sprintf( '/%s/', $info_types[$i] ), $option_name, $option_value );
}
}
}
}
} else {
if ($info_types !== null && is_array( $info_types ) && preg_match( '/custom/', $option_name )) {
for ($i = 0; $i<count( $info_types ); $i++) {
if (preg_match( sprintf( '/%s/', $info_types[ $i ] ), $option_name ) && preg_match( $section_pattern, $option_name )) {
$array_ref[$section][$info_types[$i]] = setting_parser( $section_pattern, sprintf( '/%s/', $info_types[$i] ), $option_name, $option_value );
}
}
}
}
}
return $array_ref;
}
/**
* Get the office info
*
* @param array $theme_options
* @param bool $is_option_string
*
* @return array
* @throws Exception
*/
function get_office_info(array $theme_options, $is_option_string = true) {
$info_types = array(
'name',
'address',
'phone',
'email',
'fax'
);
// if leader does NOT come after office, but it in office array
// uses positive look-ahead
$section_pattern = '/office_(?!leader)/';
$section = 'office';
if (empty( $theme_options )) throw new Exception("First argument MUST be a valid array.");
$office_info = apply_multi_dimensional_values( $theme_options, $info_types, $section, $section_pattern, $is_option_string );
return $office_info;
}
/**
* @param array $theme_options
* @param bool $is_option_string
*
* @return array
* @throws Exception
*/
function get_leader_info(array $theme_options, $is_option_string = true) {
$info_types = array(
'name',
'address',
'phone',
'email'
);
// If leader comes after office, put it in leader array
// uses negative look-ahead
$section_pattern = '/(office_(?=leader))/';
$section = 'leader';
if (empty( $theme_options )) throw new Exception("First argument MUST be a valid array.");
$leader_info = apply_multi_dimensional_values( $theme_options, $info_types, $section, $section_pattern, $is_option_string );
return $leader_info;
}
The purpose of parsing these arrays is to basically group them into the relevant data. I group them by a section key that I pass into both the get_office_info()
function and the get_leader_info()
function. The bit of code handling this looks like this:
$array_ref[$section][$info_types[$i]] = ...
So that the result of calling get_office_info()
will be an array like this:
'office' => array(
'name' => 'The Office Name',
'address' => '1234 Address St',
'phone' => '555.555.5555',
'email' => '[email protected]',
'fax' => '555.555.5555'
)
The result of calling get_leader_info()
will be an array like this:
'leader' => array(
'name' => 'Mr. Pickles',
'address' => '5678 Address St',
'phone' => '555.555.5555',
'email' => '[email protected]'
)
I just can't help but feeling like there's a cleaner way to do this that I am missing, or don't have enough experience to recognize. I am doing a similar thing with social, but it's different because it will be a single-dimensional, numerically indexed array containing a social profile link that I can just loop through. If the clean-up for this solution doesn't kill both birds, I will post that as a seperate code review.
The calling goes like this get_(office|leader)_info()
-> apply_multi_dimensional_values()
-> setting_parser()
which will get called in a loop.
The part in particular that I am concerned about is all the logic inside the apply_multi_dimensional_values()
function. Please let me know if you need any more information to review the code.