YAML config file in Silex Framework with dynamic replacement - php

I created a configuration provider that process configuration in yaml file for silex.
Everything is ok ! even import feature work great.
the only problem that I have is with dynamic replacement for parameters surrounded with %% parameters.
base_path: /my/path/to/base
paths:
web_path: %base_path%/web
upload_path: %web_path%/uploads
I don't really know if the Symfony Configuration component can process the data this way.

May be this code will help you
function _flattenArray($array, &$flatten, $index = null, $path = null)
{
if (\is_array($array)) {
foreach ($array as $k => $v) {
_flattenArray(
$v,
$flatten,
(isset($index) ? $index . '.' : '') . $k,
(isset($path) ? $path : '') . '[' . $k . ']'
);
}
} else {
$flatten[$index] = [
'path' => $path,
'value' => $array,
];
}
}
$config = ...; // load config
$flatten = [];
_flattenArray($config, $flatten);
$parameterBag = [];
foreach ($flatten as $k => $v) {
$parameterBag[$k] = $v['value'];
}
$parameterBag = new \Symfony\Component\DependencyInjection\ParameterBag\ParameterBag($parameterBag);
$parameterBag->resolve();
$parameterBag = $parameterBag->all();
$propertyAccessor = \Symfony\Component\PropertyAccess\PropertyAccess::createPropertyAccessor();
foreach ($parameterBag as $k => $v) {
if ($v === $flatten[$k]['value']) continue;
$propertyAccessor->setValue($config, $flatten[$k]['path'], $v);
}
dump($config);

Related

Convert multidimensional array to file path

How do i convert multidimensional array to file path.
I have this array :
$data = [
"users" => [
"joe" => [
"photos" => ["a.jpg","b.jpg"],
"files" => ["a.doc","b.doc"]
],
"annie" => [
"photos" => ["a.jpg","b.jpg"],
"files" => ["a.doc","b.doc"]
],
]
];
that i must convert to path example :
"users/joe/photos/a.jpg";
"users/joe/photos/b.jpg";
"users/joe/files/a.doc";
"users/joe/files/b.doc";
"users/annie/photos/a.jpg";
"users/annie/photos/b.jpg";
"users/annie/files/a.doc";
"users/annie/files/b.doc";
But i can't have the best result with this functions :
$path = "";
function iterate($data, $path)
{
echo "<br>";
foreach ($data as $key => $item){
if (is_array($item)){
$path .= $key.DIRECTORY_SEPARATOR;
iterate($item, $path);
}else{
echo $path.$item."<br>";
}
}
}
output :
users/joe/photos/a.jpg
users/joe/photos/b.jpg
users/joe/photos/files/a.doc
users/joe/photos/files/b.doc
users/joe/annie/photos/a.jpg
users/joe/annie/photos/b.jpg
users/joe/annie/photos/files/a.doc
users/joe/annie/photos/files/b.doc
Please help.
Thanks
You could make use of RecursiveIteratorIterator + RecursiveArrayIterator:
function computeFilePaths(array $fileTree): array
{
$filePaths = [];
$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($fileTree));
foreach ($iterator as $fileName) {
for ($folders = [], $pos = 0, $depth = $iterator->getDepth(); $pos < $depth; $pos++) {
$folders[] = $iterator->getSubIterator($pos)->key();
}
$filePaths[] = implode('/', $folders) . '/' . $fileName;
}
return $filePaths;
}
print_r(computeFilePaths($yourArrayGoesHere));
I highly suggest this question's selected answer to understand how these iterators work.

Tree map by categories

I'm trying to build a tree-map from categories.
I have the categories (I have a lot of categories and I want to remove duplicates and show them in a tree-map view)
$cat = array(
"Sneakers/Men",
"Sneakers/Women",
"Accessories/Jewellery/Men",
"Accessories/Jewellery/Women",
"Accessories/Jewellery/Men
");
...and I want them like this
$categories = array(
"Sneakers" => array(
"Men" => array(),
"Women" => array()
),
"Accessories" => array(
"Jewellery" => array(
"Men" => array(),
"Women" => array()
)
)
);
to print them like this
- Sneakers
-- Men
-- Women
- Accessories
-- Jewellery
--- Men
--- Women
Try this:
<?php
$cat = array(
"Sneakers/Men",
"Sneakers/Women",
"Accessories/Jewellery/Men",
"Accessories/Jewellery/Women",
"Accessories/Jewellery/Men
");
function buildTree($categories, $result = []){
$temp = [];
foreach($categories as $categoryString){
$catParts = explode('/',$categoryString);
if(count($catParts) > 1){
$temp[$catParts[0]][] = str_replace($catParts[0].'/','',$categoryString);
} else {
$temp[$catParts[0]] = [];
}
}
foreach($temp as $elemName => $elemVal){
$result[$elemName] = buildTree($elemVal);
}
return $result;
}
var_dump(buildTree($cat));
The most simple way is to use references, like this:
$out = [];
foreach ($cat as $str) {
$lookup =& $out;
foreach (explode("/", $str) as $part) {
$lookup =& $lookup[$part];
if (!isset($lookup)) {
$lookup = [];
}
}
}
$lookup initially refers to the whole expected result, then the reference is extended at each step to follow the path of nested members.
Note that each new member added looks like member-name => [], so that actually even final leaves are arrays: it may seem a bit weird, but is a pretty way to have a reduced code (each member is always ready to receive children).
And it's not a difficulty, though, to use the resulting array to then print it like the OP asked:
function nest_print($src, $level = 0) {
$prefix = '<br />' . str_repeat('- ', ++$level);
foreach ($src as $key => $val) {
echo $prefix . $key;
if ($val) {
nest_print($val, $level);
}
}
}
nest_print($out);
EDIT
Here is an alternate solution, including the count of final leaves, as asked by the OP in his comment:
$out = [];
foreach ($cat as $str) {
$lookup =& $out;
$parts = explode("/", $str);
foreach ($parts as $part) {
$lookup =& $lookup[$part];
if (!isset($lookup)) {
$lookup = [];
}
// when $part is a final leaf, count its occurrences
if ($part == end($parts)) {
$lookup = is_array($lookup) ? 1 : ++$lookup;
}
}
}
(might likely be improved in a more elegant way, though)
And here is how to modify the print-result snippet accordingly:
function nest_print($src, $level = 0) {
$prefix = '<br />' . str_repeat('- ', ++$level);
foreach ($src as $key => $val) {
echo $prefix . $key;
if (is_array($val)) {
nest_print($val, $level);
} else {
echo ': ' . $val;
}
}
}
nest_print($out);

Building paths from multidimensional array in PHP

I have an array such as:
$tree = array(
'folder_1' => array(
'folder_1_1',
'folder_1_2' => array(
'folder_1_2_1',
'folder_1_2_2'
),
'folder_1_3'
),
'folder_2' => array(
'folder_2_1' => array(
'folder_2_1_1' => array(
'folder_2_1_1_1',
'folder_2_1_1_2'
)
),
)
);
And I'm trying to build an array of paths:
$paths = array(
'folder_1',
'folder_1/folder_1_1',
'folder_1/folder_1_2',
'folder_1/folder_1_2/folder_1_2_1',
'folder_1/folder_1_2/folder_1_2_2',
'folder_2',
'folder_2/folder_2_1',
...
);
I can't seem to find a way to achieve this. The problem I encounter is that folder names can be array keys, but also array elements.
This is what I have done so far, but I'm not near a solution...
$paths = transform_tree_to_paths($trees);
function transform_tree_to_paths($trees, $current_path = '', $paths = array())
{
if (is_array($trees)) {
foreach ($trees as $tree => $children) {
$current_path .= $tree . '/';
return transform_tree_to_paths($children, $current_path, $paths);
}
$paths[] = $current_path;
$current_path = '';
} else {
$paths[] = $trees;
}
return $paths;
}
How about something like this?
function gen_path($tree, $parent=null) {
$paths = array();
//add trailing slash to parent if it is not null
if($parent !== null) {
$parent = $parent.'/';
}
//loop through the tree array
foreach($tree as $k => $v) {
if(is_array($v)) {
$currentPath = $parent.$k;
$paths[] = $currentPath;
$paths = array_merge($paths, gen_path($v, $currentPath));
} else {
$paths[] = $parent.$v;
}
}
return $paths;
}
You were headed in the right direction, but missed the mark a bit. The return statement before the recursive function call in your function caused everything after the foreach loop to never be called.
Here's another solution, utilizing RecursiveArrayIterator and RecursiveIteratorIterator:
function generatePaths( array $tree ) {
$result = array();
$currentPath = array();
$rii = new RecursiveIteratorIterator( new RecursiveArrayIterator( $tree ), RecursiveIteratorIterator::SELF_FIRST );
foreach( $rii as $key => $value ) {
if( ( $currentDepth = $rii->getDepth() ) < count( $currentPath ) ) {
array_splice( $currentPath, $currentDepth );
}
$currentPath[] = is_array( $value ) ? $key : $value;
$result[] = implode( '/', $currentPath );
}
return $result;
}
PS.: Baconics' solution appears to be about twice as fast as mine, though.

replace any specific character in array key

$array['a:b']['c:d'] = 'test';
$array['a:b']['e:f']= 'abc';
I need output like below. array can have multiple level . Its comes with api so we do not know where colon come.
$array['ab']['cd'] = 'test';
$array['ab']['ef']= 'abc';
(untested code) but the idea should be correct if want to remove ':' from keys:
function clean_keys(&$array)
{
// it's bad to modify the array being iterated on, so we do this in 2 steps:
// find the affected keys first
// then move then in a second loop
$to_move = array();
forach($array as $key => $value) {
if (strpos($key, ':') >= 0) {
$target_key = str_replace(':','', $key);
if (array_key_exists($target_key, $array)) {
throw new Exception('Key conflict detected: ' . $key . ' -> ' . $target_key);
}
array_push($to_move, array(
"old_key" => $key,
"new_key" => $target_key
));
}
// recursive descent
if (is_array($value)) {
clean_keys($array[$key]);
}
}
foreach($to_move as $map) {
$array[$map["new_key"]] = $array[$map["old_key"]];
unset($array[$map["old_key"]]);
}
}
try this:
$array=array();
$array[str_replace(':','','a:b')][str_replace(':','','c:d')]="test";
print_r($array);
This seems like the simplest and most performant approach:
foreach ($array as $key => $val) {
$newArray[str_replace($search, $replace, $key)] = $val;
}

Kohana 3.2 'advance' ORM joins

This is Database ERD that I use in application. I'm using Kohana 3.2. What I want to achieve is to generate menu for currently logged user. Each user can have many roles, so based on that user should get menu populated with modules (that are in relation with menu and user).
I have achieve this through several foreach loops. Is it possible to do this using ORM ?
*Table 'Modules' represents menu items.
Edit: this is my current code.
$conf_modules = Kohana::$config->load('modules');
$user_roles = $user->roles->find_all();
$result = array();
$array = array();
foreach($user_roles as $user_role)
{
$menus = $user_role->menus->find_all();
$modules = $user_role->modules->find_all();
}
foreach($menus as $menu)
{
$m = $menu->modules->find_all();
$result[]['name'] = $menu->name;
foreach ($m as $a)
{
foreach ($modules as $module)
{
if($a->name == $module->name)
{
foreach ($conf_modules as $key => $value)
{
if($module->name == $key)
{
$array = array(
'module_name' => $module->name,
'text' => $module->display_desc,
'url' => $value['url'],
);
}
}
}
}
array_push($result, $array);
}
}
I think this should be good solution.
$user = Auth::instance()->get_user();
$user_roles = $user->roles->find_all();
$conf_modules = Kohana::$config->load('modules');
$role_modules = ORM::factory('module')
->join('roles_modules')
->on('roles_modules.module_id','=','module.id')
->where('role_id','IN',$user_roles->as_array(NULL,'id'))
->find_all();
$role_menus = ORM::factory('menu')
->join('roles_menus')
->on('roles_menus.menu_id','=','menu.id')
->where('role_id','IN',$user_roles->as_array(NULL,'id'))
->find_all();
$result = array();
foreach ($role_menus as $role_menu)
{
$menu_modules = $role_menu->modules->find_all();
if ( ! isset($result[$role_menu->name]))
$result[$role_menu->name] = array('name' => $role_menu->name);
foreach ($menu_modules as $menu_module)
{
foreach ($role_modules as $role_module)
{
if($menu_module->name == $role_module->name)
{
foreach ($conf_modules as $key => $value)
{
if ($key == $role_module->name)
{
$result[$role_menu->name]['modules'][]['data'] = array('name' => $role_module->display_desc, 'url' => $value['url']);
}
}
}
}
}
}
return array_values($result);

Categories