Angular tree from folder structure - php

I'm trying to create a tree that shows on the front end.
The user gives a location which the backend reads and creates a tree from and sends this back.
This tree can look many different ways. How can i get it so that the front end reads this and created the right tree for it?
example:
Frontend sends the path: /usr/test/dir1/
Backend reads this with the following function:
function dirtree($dir)
{
$dh = scandir($dir);
$return = array();
foreach ($dh as $folder) {
if ($folder != '.' && $folder != '..') {
if (is_dir($dir . '/' . $folder)) {
$return[] = array($folder => $this->dirtree($dir . '/' . $folder));
} else {
$return[] = $folder;
}
}
}
return $return;
}
Backend returns something like:
{
"maindir": [
".DS_Store",
{
"dir1": []
},
{
"subdir1": [
".DS_Store",
{
"subdir2": [
{
"subdir3": []
},
{
"subdir4": []
}
]
},
}
How can I translate this to the front-end?
Or how can I add a type children to this?

Related

Loop through menu items recursively starting from second level

I have navigation which looks like this in the system:
At the moment, I am able to print an array of objects containing the menu items recursively, and the code looks like this:
public function get() {
$current_path = \Drupal::service('path.current')->getPath();
$path_items = explode ('/',$current_path);
$menu_array = [];
$menu = $path_items[4];
if(!empty ($menu) ){
$sub_nav = \Drupal::menuTree()->load($menu, new \Drupal\Core\Menu\MenuTreeParameters());
foreach($sub_nav as $nav){
array_push($menu_array, $nav);
}
$manipulators = array(
array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'),
);
$sub_nav = \Drupal::menuTree()->transform($sub_nav, $manipulators);
$this->generateSubMenuTree($menu_array, $sub_nav);
$response = array_values($menu_array);
}
return (new ResourceResponse($response))->addCacheableDependency(array('#cache' => array('max-age' => 0)));
}
private function generateSubMenuTree(&$output, &$input, $parent = FALSE) {
$input = array_values($input);
$items = 0;
foreach($input as $key => $item) {
//If menu element disabled skip this branch
if ($item->link->isEnabled()) {
if ($item->link instanceof \Drupal\menu_link_content\Plugin\Menu\MenuLinkContent) {
$uuid = $item->link->getDerivativeId();
$entity = \Drupal::service('entity.repository')
->loadEntityByUuid('menu_link_content', $uuid);
}
$link_data['name'] = $item->link->getTitle();
if(!empty($item->link->pluginDefinition['url'])){
$link_data['href'] = $item->link->pluginDefinition['url'];
}
//If not root element, add as child
if ($parent === FALSE) {
$output[$key] = $link_data;
} else {
$output['children'][$key] = $link_data;
}
if ($item->hasChildren) {
if ($item->depth == 1) {
$this->generateSubMenuTree($output[$key], $item->subtree, $key);
} else {
$this->generateSubMenuTree($output['children'][$key], $item->subtree, $key);
}
}
$items ++;
}
}
}
The code above results into the following:
However my specification now changed in the sense that for Nav Data and Departments, I should only start including from the child elements onwards.
The result should be something like this:
{
[
{
name : "Shop"
children : [
{
name : "Promotions"
tabletColumn : 0
desktopColumn : 0
children : [...] 3 items
},
{ ... }
]
},
{...}
],
[
{
name : "Personal"
children : [...] 0 items
selected : true
}
],
{...}
{...}
}
Have been struggling with this logic for 24 hours already.

PHP - reading folder, all subfolders, and files in subfolders

I have a folder named "inspections" which has a number of subfolders named "location 1", "location 2", "location 3", etc. each with around 10-20 .png images in it.
What I am trying to do, is to read the directories of the "inspections" folder, and then read all the image files in each of the folders before returning them as a gallery on my index.php site. The problem is that I get no error message but the script doesnt return anything. I believe the problem is with generating the $files variable for each subfolder as I deploy the same script for reading folder content on another site.
Perhaps someone can point me in the right direction?
<?php
$dir = './inspections/';
if ($handle = opendir($dir))
{
$blacklist = array('.', '..', 'default', 'default.php', 'desc.txt');
while (false !== ($folder = readdir($handle)))
{
if (!in_array($folder, $blacklist))
{
if (file_exists($dir . $folder . '/desc.txt'))
{
while (false !== ($file = readdir($handle)))
{
if (!in_array($file, $blacklist))
{
$chain = file_get_contents($dir . $folder . '/chain.txt');
$website = file_get_contents($dir . $folder . '/website.txt');
$location = file_get_contents($dir . $folder . '/location.txt');
$desc = file_get_contents($dir . $folder . '/desc.txt', NULL, NULL, 0, 250) . '...';
echo "
<!-- Post -->
<div class=\"post\">
<div class=\"user-block\">
<img class=\"img-circle img-bordered-sm\" src=\"../dist/img/logo/logo_".$chain."\" alt=\"\">
<span class=\"username\">
".$folder."
</span>
<span class=\"description\"><i class=\"fa fa-map-pin\"></i> ".$location." - Posted on ". $date . "</span>
</div>
<!-- /.user-block -->
<p>".$desc."</p>
<div class=\"lightBoxGallery\">
<img src=\"".$dir . $folder . "/".$file."\" style=\"height:100px; width:100px;\">
</div>
";
}
}
}
}
}
closedir($handle);
}
?>
EDIT:
following #JazZ suggestion, I have adjusted the code and it works well now, however, assuming that one does not want to display the resized pictures itself, but rather thumbnails stored in a subfolder (eg. ./location1/thumbs/), how would I go about this?
<?php
$dir = './inspections/';
if ($handle = opendir($dir)) {
$blacklist = array('.', '..', 'default', 'default.php', 'desc.txt');
while (false !== ($folder = readdir($handle))) {
if (!in_array($folder, $blacklist)) {
echo "
<!-- Post -->
<div class=\"post\">
<div class=\"user-block\">
<img class=\"img-circle img-bordered-sm\" src=\"../dist/img/logo/gallery_icon_".$chain.".jpg\" alt=\"\">
<span class=\"username\">
".$hotel_name."".$status."
</span>
<span class=\"description\"><i class=\"fa fa-map-pin\"></i> ".$location." - Posted on ".date('jS F, Y - H:m', strtotime($posted_on))."</span>
</div>
<!-- /.user-block -->
<p>".$desc."</p>
<div class=\"lightBoxGallery\">
";
foreach (glob($dir . $folder . "/*.jpg") as $filename) {
echo "
<img src=\"".$filename."\" style=\"height:100px; width:100px;\">";
}
echo "</div>
</div>
<!-- /. POST -->
";
}
}
closedir($handle);
}
?>
I think your issue comes from here :
while (false !== ($file = readdir($handle))) // it reads again the same directory as it did in the first while loop
Try to replace it with
if ($sub_handle = opendir($dir . $folder)) {
while (false !== ($file = readdir($sub_handle))) {
...
}
closedir($sub_handle);
}
Also, in your case, I would use php glob() function
See a working example for your case :
$dir = './inspections/';
if ($handle = opendir($dir)) {
$blacklist = array('.', '..', 'default', 'default.php', 'desc.txt');
while (false !== ($folder = readdir($handle))) {
if (!in_array($folder, $blacklist)) {
foreach (glob($dir . $folder . "/*.png") as $filename) {
echo "$filename was found !";
echo "\r\n";
}
}
}
closedir($handle);
}
Output :
./inspections/location_4/img_1.png was found !
./inspections/location_4/img_2.png was found !
./inspections/location_4/img_3.png was found !
./inspections/location_4/img_4.png was found !
./inspections/location_4/img_5.png was found !
./inspections/location_4/img_6.png was found !
./inspections/location_3/img_1.png was found !
./inspections/location_3/img_2.png was found !
./inspections/location_3/img_3.png was found !
./inspections/location_3/img_4.png was found !
./inspections/location_3/img_5.png was found !
./inspections/location_3/img_6.png was found !
./inspections/location_2/img_1.png was found !
./inspections/location_2/img_2.png was found !
./inspections/location_2/img_3.png was found !
./inspections/location_2/img_4.png was found !
./inspections/location_2/img_5.png was found !
./inspections/location_2/img_6.png was found !
./inspections/location_1/img_1.png was found !
./inspections/location_1/img_2.png was found !
./inspections/location_1/img_3.png was found !
./inspections/location_1/img_4.png was found !
./inspections/location_1/img_5.png was found !
./inspections/location_1/img_6.png was found !
EDIT
To loop in the /inspections/location1/thumbs/ directories, this would work :
foreach (glob($dir . $folder . "/thumbs/*.png") as $filename) {
echo "$filename was found !";
echo "\r\n";
}
RE-EDIT
To glob multiple folders with the glob() function, your code should look like :
foreach (glob($dir.$folder."{/thumbs/*.png,/*.png}", GLOB_BRACE) as $filename) {
echo "$filename was found !";
echo "\r\n";
}
Perhaps the Function below helps. It is also somewhat commented. It scans a directory recursively (in this case, extracting image files from each directory/sub-directory).
<?php
$rootPath = './inspections/';
$regex = "#(\.png$)|(\.jpg$)|(\.jpeg$)|(\.tiff$)|(\.gif$)#";
/**
* #param string $directory => DIRECTORY TO SCAN
* #param string $regex => REGULAR EXPRESSION TO BE USED IN MATCHING FILE-NAMES
* #param string $get => WHAT DO YOU WANT TO GET? 'dir'= DIRECTORIES, 'file'= FILES, 'both'=BOTH FILES+DIRECTORIES
* #param bool $useFullPath => DO YOU WISH TO RETURN THE FULL PATH TO THE FOLDERS/FILES OR JUST THEIR BASE-NAMES?
* #param array $dirs => LEAVE AS IS: USED DURING RECURSIVE TRIPS
* #return array
*/
function scanDirRecursive($directory, $regex=null, $get="file", $useFullPath=false, &$dirs=[], &$files=[]) {
$iterator = new DirectoryIterator ($directory);
foreach($iterator as $info) {
$fileDirName = $info->getFilename();
if ($info->isFile () && !preg_match("#^\..*?#", $fileDirName)) {
if($get == 'file' || $get == 'both'){
if($regex) {
if(preg_match($regex, $fileDirName)) {
if ($useFullPath) {
$files[] = $directory . DIRECTORY_SEPARATOR . $fileDirName;
}
else {
$files[] = $fileDirName;
}
}
}else{
if($useFullPath){
$files[] = $directory . DIRECTORY_SEPARATOR . $fileDirName;
}else{
$files[] = $fileDirName;
}
}
}
}else if ($info->isDir() && !$info->isDot()) {
$fullPathName = $directory . DIRECTORY_SEPARATOR . $fileDirName;
if($get == 'dir' || $get == 'both') {
$dirs[] = ($useFullPath) ? $fullPathName : $fileDirName;
}
scanDirRecursive($fullPathName, $regex, $get, $useFullPath, $dirs, $files);
}
}
if($get == 'dir') {
return $dirs;
}else if($get == 'file'){
return $files;
}
return ['dirs' => $dirs, 'files' => $files];
}
$images = scanDirRecursive($rootPath, $regex, 'file', true);
var_dump($images);

How to get a list of files of subfolders and write them in a JSON using php?

I'm already able to list all the file names and current directory/folder but I don't know how to create JSON entries for subdirectories
Here is my code
<?php
$dir = "office/";
if(is_dir($dir)){
if($dh = opendir($dir)){
while(($file = readdir($dh)) != false){
if($file != "." and $file != ".."){
$files_array[] = array('file' => $file); // Add the file to the array
}
}
}
$return_array =array('dir' => $files_array);
exit (json_encode($return_array));
}
?>
and output is
{
"dir": [
{
"file": "FreeWallpapersApp.zip"
},
{
"file": "20151211_ClipArtForTextView.7z"
},
{
"file": "QRite.7z"
},
{
"file": "CustomDialog_app_contacts.zip"
},
{
"file": "LockScreenBasicApp.apk"
},
{
"file": "ImgViewEffects.zip"
},
]
}
How to show files inside subfolder using php to also generate file names which are in subdirectories .
One way to achieve the recursive listing of a directory is using a recursive function.
/*
* Converts a filesystem tree to a PHP array.
*/
function dir_to_array($dir)
{
if (! is_dir($dir)) {
// If the user supplies a wrong path we inform him.
return null;
}
// Our PHP representation of the filesystem
// for the supplied directory and its descendant.
$data = [];
foreach (new DirectoryIterator($dir) as $f) {
if ($f->isDot()) {
// Dot files like '.' and '..' must be skipped.
continue;
}
$path = $f->getPathname();
$name = $f->getFilename();
if ($f->isFile()) {
$data[] = [ 'file' => $name ];
} else {
// Process the content of the directory.
$files = dir_to_array($path);
$data[] = [ 'dir' => $files,
'name' => $name ];
// A directory has a 'name' attribute
// to be able to retrieve its name.
// In case it is not needed, just delete it.
}
}
// Sorts files and directories if they are not on your system.
\usort($data, function($a, $b) {
$aa = isset($a['file']) ? $a['file'] : $a['name'];
$bb = isset($b['file']) ? $b['file'] : $b['name'];
return \strcmp($aa, $bb);
});
return $data;
}
/*
* Converts a filesystem tree to a JSON representation.
*/
function dir_to_json($dir)
{
$data = dir_to_array($dir);
$data = json_encode($data);
return $data;
}
In your example,
echo dir_to_json('office/');
would output this
{
"dir": [
{
"file": "FreeWallpapersApp.zip"
},
{
"file": "20151211_ClipArtForTextView.7z"
},
// ...
{
"dir": [
{
"file": "App.zip"
},
{
"file": "View.7z"
},
"name": "A Directory With Files",
]
},
]
}
Update 1:
I updated the answer to explicitly sort the files and directories.

List all files and directories in JSON

I am wanting away to list all my files and folders in a JSON but I need to be able to call the files using jQuery
Basically what I have is the following
public function listproductimagedirectory($rootPath) {
$pathStack = array($rootPath);
$contentsRoot = array();
$contents = &$contentsRoot;
while ($path = array_pop($pathStack)) {
$contents[basename($path)] = array();
$contents = &$contents[basename($path)];
foreach (scandir($path) as $filename) {
if ('.' != substr($filename, 0, 1)) {
$newPath = $path.'/'.$filename;
if (is_dir($newPath)) {
array_push($pathStack, $newPath);
$contents[basename($newPath)] = array();
} else {
$contents[basename($filename)] = $newPath;
}
}
}
}
return $contentsRoot[basename($rootPath)];
}
which outputs
{"giftcard":{"31791_319x242_0.jpg":"..\/products\/giftcard\/31791_319x242_0.jpg","7520921_0_9999_lge_v1_m56577569834701600.jpg":"..\/products\/giftcard\/7520921_0_9999_lge_v1_m56577569834701600.jpg","AMF.jpg":"..\/products\/giftcard\/AMF.jpg","accor.jpg":"..\/products\/giftcard\/accor.jpg","accorhotel.png":"..\/products\/giftcard\/accorhotel.png","cellarmasters.png":"..\/products\/giftcard\/cellarmasters.png","dusk.png":"..\/products\/giftcard\/dusk.png","giftca_100ath_lrg.png":"..\/products\/giftcard\/giftca_100ath_lrg.png","giftca_100goo_lrg.png":"..\/products\/giftcard\/giftca_100goo_lrg.png","giftca_100sun_lrg.png":"..\/products\/giftcard\/giftca_100sun_lrg.png","giftca_20itu_lrg.png":"..\/products\/giftcard\/giftca_20itu_lrg.png","giftca_25abc_lrg.png":"..\/products\/giftcard\/giftca_25abc_lrg.png","giftca_25jay_lrg.png":"..\/products\/giftcard\/giftca_25jay_lrg.png","giftca_30bra_lrg.png":"..\/products\/giftcard\/giftca_30bra_lrg.png","giftca_30div_lrg.png":"..\/products\/giftcard\/giftca_30div_lrg.png","giftca_40ebg_lrg.png":"..\/products\/giftcard\/giftca_40ebg_lrg.png","giftca_50col_lrg.png":"..\/products\/giftcard\/giftca_50col_lrg.png","giftca_50cou_lrg.png":"..\/products\/giftcard\/giftca_50cou_lrg.png","giftca_50dot_lrg.png":"..\/products\/giftcard\/giftca_50dot_lrg.png","giftca_50dym_lrg.png":"..\/products\/giftcard\/giftca_50dym_lrg.png","giftca_50hoy_lrg.png":"..\/products\/giftcard\/giftca_50hoy_lrg.png","giftca_50itu_lrg.png":"..\/products\/giftcard\/giftca_50itu_lrg.png","giftca_50jac_lrg.png":"..\/products\/giftcard\/giftca_50jac_lrg.png","giftca_50jea_lrg.png":"..\/products\/giftcard\/giftca_50jea_lrg.png","giftca_50pet_lrg.png":"..\/products\/giftcard\/giftca_50pet_lrg.png","giftca_50por_lrg.png":"..\/products\/giftcard\/giftca_50por_lrg.png","giftca_50reb_lrg.png":"..\/products\/giftcard\/giftca_50reb_lrg.png","giftca_50san_lrg.png":"..\/products\/giftcard\/giftca_50san_lrg.png","isubscribe.jpg":"..\/products\/giftcard\/isubscribe.jpg","isubscribe.png":"..\/products\/giftcard\/isubscribe.png","peteralexander.png":"..\/products\/giftcard\/peteralexander.png","rydges hotel.png":"..\/products\/giftcard\/rydges hotel.png","smiggle.png":"..\/products\/giftcard\/smiggle.png","sportsgirl.png":"..\/products\/giftcard\/sportsgirl.png","sussan.png":"..\/products\/giftcard\/sussan.png","wiggles.png":"..\/products\/giftcard\/wiggles.png"}}
What I see and I could be wrong but there is nothing the allows me to tell the ID of the array for e.g I am use to calling a JSON by using the each function and using something like this
obj.title that would tell me that its the title of the json row.
put your objects in an array... so you would have..
var myobject = { giftcard: [ {filename: "image1.png", path: "path"}, {filename: "image2.png", path: "path""}, {filename: "image3.png", path: "path"} etc...]}
then you can:
$.each(myobject.giftcard, function(index, image) {
image.filename
image.path
});

Is using Controller::render() in a Model::afterSave() possible with CakePHP?

I've got some sample code that I'd like to refactor as I need it to work after a record is saved. It currently works after the record is first rendered (using the afterFilter). What it does is render the view that I want with the layout and saves it to a file.
function afterFilter() {
parent::afterFilter();
if($this->params['pass'][0] == 'contact') {
$surrenderOuput = $this->surrender($this->params['pass'][0]);
$path = WWW_ROOT . 'cache' . DS . $this->params['pass'][0] . DS . 'index.html';
$file = new File($path, true);
$file->write($surrenderOuput);
$file->close();
}
}
function surrender($action = null, $layout = null, $file = null) {
$this->beforeRender();
$viewClass = $this->view;
if ($this->view != 'View') {
if (strpos($viewClass, '.') !== false) {
list($plugin, $viewClass) = explode('.', $viewClass);
}
$viewClass = $viewClass . 'View';
App::import('View', $this->view);
}
$this->Component->beforeRender($this);
$this->params['models'] = $this->modelNames;
if (Configure::read() > 2) {
$this->set('cakeDebug', $this);
}
$View =& new $viewClass($this);
if (!empty($this->modelNames)) {
$models = array();
foreach ($this->modelNames as $currentModel) {
if (isset($this->$currentModel) && is_a($this->$currentModel, 'Model')) {
$models[] = Inflector::underscore($currentModel);
}
$isValidModel = (
isset($this->$currentModel) && is_a($this->$currentModel, 'Model') &&
!empty($this->$currentModel->validationErrors)
);
if ($isValidModel) {
$View->validationErrors[Inflector::camelize($currentModel)] =&
$this->$currentModel->validationErrors;
}
}
$models = array_diff(ClassRegistry::keys(), $models);
foreach ($models as $currentModel) {
if (ClassRegistry::isKeySet($currentModel)) {
$currentObject =& ClassRegistry::getObject($currentModel);
if (is_a($currentObject, 'Model') && !empty($currentObject->validationErrors)) {
$View->validationErrors[Inflector::camelize($currentModel)] =&
$currentObject->validationErrors;
}
}
}
}
$this->autoRender = false;
$output = $View->render($action, $layout, $file);
return $output;
}
So I'm basically rendering the view with it's layout, and returning it as output, and saving it to a file. Great. Is there any way to do something similar in a model?
You may consider setting a member variable in your afterSave() in the model and checking that value in your afterFilter() in your controller.
I found this thread while searching for how to render a view from a model. In my case I'm calling a custom method in the model, so this might not work for afterSave(), but if you're calling a custom method you can do it like this:
Controller:
$this->Model->myFunc($this);
Model
public function myFunc($object) {
$object->render();
}
Hopefully that helps someone else who comes across this thread.

Categories