Your IP : 216.73.216.196
<?php
namespace Bunyad\Util;
/**
* Utility PHP functions and other utils.
*/
/**
* Insert into array after a certain key.
*
* Note: Doesn't play with numeric indices in inserted arrays when
* dealing with associative arrays.
*
* @param array $array The array to modify.
* @param integer|string $key Target key to insert before or after.
* @param array $insert Array to insert.
* @param string $position 'before' or 'after'.
*
* @return void
*/
function array_insert(&$array, $key, $insert, $position = 'after')
{
$index = array_search($key, array_keys($array));
// Inserting after or before.
if ($position === 'after') {
$pos = false === $index ? count($array) : $index + 1;
}
else {
$pos = false === $index ? 0 : $index;
}
// Add at beginning.
if ($key === null || $pos < 0) {
$pos = 0;
}
$array = array_merge(
array_slice($array, 0, $pos),
$insert,
array_slice($array, $pos)
);
}
/**
* Modify both keys and values in a an array recursively, while preserving sort.
*
* @param array $array Original array.
* @param callable $callback Callback function takes two params (key, value) and
* returns the new [key, value] to as an array.
*
* @return array
*/
function array_modify_recursive(array $array, callable $callback)
{
$output = [];
foreach ($array as $key => $value) {
if (is_array($value)) {
$value = array_modify_recursive($value, $callback);
}
$new_key = $key;
$new_value = $value;
// Get output from callback and use as key/value.
$replace = $callback($key, $value);
if (is_array($replace)) {
list($new_key, $new_value) = $replace;
}
// If callback returns false, skip.
if ($replace !== false) {
$output[$new_key] = $new_value;
}
}
return $output;
}
/**
* Remove prefix/suffix from set of keys, recursively.
*
* @param array $array
* @param string $affix
* @param boolean $is_prefix
* @return array
*/
function deaffix_keys(array $array, $affix, $is_prefix = true, $args = [])
{
$args = array_replace([
'require_affix' => false
], $args);
$new_array = [];
foreach ($array as $key => $val) {
if (is_array($val)) {
$val = deaffix_keys($val, $affix, $is_prefix);
}
// Flag to denote if an affix was found and changes made.
$affixed = false;
// Prefix
if ($is_prefix && strpos($key, $affix) === 0) {
$affixed = true;
$key = substr($key, strlen($affix));
}
elseif (!$is_prefix) {
// Finding and removing a suffix.
$offset = strlen($key) - strlen($affix);
if (strpos($key, $affix, $offset) !== false) {
$affixed = true;
$key = substr($key, 0, -strlen($affix));
}
}
// Discard if affix is required.
if ($args['require_affix'] && !$affixed) {
continue;
}
$new_array[$key] = $val;
}
return $new_array;
}
/**
* Remove affix in keys of array and pick only the affixed keys.
*
* @see defaffix_keys()
* @return array
*/
function pick_deaffixed(array $array, $affix, $is_prefix = true)
{
return deaffix_keys($array, $affix, $is_prefix, ['require_affix' => true]);
}
/**
* Create multiple options based on provided replacements and a template array.
*
* @param array $templates
* @param array $field_types
* @param array $options
* @param array $config
* @return void
*/
function repeat_options($templates, $field_types, &$options, $config = [])
{
$config = array_replace([
// Main dynamic key to be replaced by $field_types[$key] in loop.
'key' => '{key}',
// By default, {key} is replaced in 'name' and recursively for 'css'.
'replace_in' => ['css'],
// Static keys to replace besides main dynamic key in {key}.
// Replacements can also be added to $field_types[replacements]
'replacements' => [],
], $config);
foreach ($field_types as $key => $type) {
foreach ($templates as $id => $template) {
// Skip this specific field.
if (isset($type['skip']) && in_array($template['name'], $type['skip'])) {
continue;
}
// Copy all provided data except for internal function-specific configs.
$copy_data = array_diff_key($type, array_flip([
'overrides',
'replace_in',
'fields_css',
'skip',
'replacements'
]));
$to_add = array_replace_recursive($template, $copy_data);
$to_add['name'] = str_replace($config['key'], $key, $to_add['name']);
// Overrides for specific keys.
if (!empty($type['overrides']) && isset($type['overrides'][ $template['name'] ])) {
$to_add = array_replace(
$to_add,
(array) $type['overrides'][ $template['name'] ]
);
}
// Override 'css' with data from 'fields_css'.
if (!empty($type['fields_css'][$id])) {
$to_add['css'] = $type['fields_css'][$id];
}
// Use substitute options.
if (isset($template['template']) && !empty($template['template'][$key])) {
// Not doing recursive replace as things like 'css' and 'options' have to
// replaced, not necessarily merged.
$to_add = array_replace($to_add, $template['template'][$key]);
// 'template' is intentionally preserved for a second run at replacement.
// unset($to_add['template']);
}
/**
* All the replacements the keys in replace_in.
*/
if ($config['replace_in']) {
// {key} already done above. But we need to perform for 'replacements' too.
array_push($config['replace_in'], 'name');
}
// Use config replacements map and add main key from fields loop.
$replacements = array_replace(
$config['replacements'],
(isset($type['replacements']) ? $type['replacements'] : []),
[
$config['key'] => $key
]
);
$replace_keys = array_keys($replacements);
$replace_vals = array_values($replacements);
foreach ($config['replace_in'] as $replace) {
if (empty($to_add[ $replace ])) {
continue;
}
if (is_array($to_add[ $replace ])) {
/**
* Recursively replace provided key => value map in both keys and values.
*/
$to_add[ $replace ] = \Bunyad\Util\array_modify_recursive($to_add[ $replace ], function($new_key, $new_val) use($replace_keys, $replace_vals) {
$new_key = str_replace($replace_keys, $replace_vals, $new_key);
if (is_string($new_val)) {
$new_val = str_replace($replace_keys, $replace_vals, $new_val);
}
return [$new_key, $new_val];
});
}
else {
$to_add[ $replace ] = str_replace($replace_keys, $replace_vals, $to_add[ $replace ]);
}
}
$options[] = $to_add;
}
}
}
/**
* Format a provided number into a readable shorter version with K or M.
*
* @param int|float $number
* @return int|float
*/
function readable_number($number)
{
if ($number < 1000) {
return $number;
}
if ($number < 10^6) {
return number_format_i18n(round($number / 1000, 1)) . 'K';
}
return number_format_i18n(round($number / 10^6, 1)) . 'M';
}
/**
* Get any callback as string.
*/
function get_as_string($callback, ...$args)
{
if (!is_callable($callback)) {
throw new \Exception('Invalid callback provided.');
}
ob_start();
$return_value = call_user_func_array($callback, $args);
$capture = ob_get_clean();
if ($return_value && is_string($return_value)) {
return $return_value;
}
return $capture;
}
/**
* Remove empty string values from an array.
*
* @param array $array
* @return array
*/
function filter_empty_strings($array)
{
return array_filter($array, static function($v) {
return $v !== '';
});
}
/**
* Returns the heading tag to use in HTML context, based on allow heading tags.
*
* @param string $tag
* @param array $allowed
*/
function filter_allowed_h_tags($tag, array $allowed = [])
{
$allowed = $allowed ?: [
'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'div', 'span'
];
$tag = strtolower((string) $tag);
if (in_array($tag, $allowed)) {
return $tag;
}
return 'h3';
}