PHP dynamic multidimensional array creation - php

I'm scanning a folder and it's subfolders for files with PHP. I want to store the folders and files in a PHP array so I can create a treeview in another page. This is the format I get files paths in:
/home/project/index.php
/home/project/folder/myclass.php
/home/project/folder/myclass2.php
/home/project/folder/subfolder/anotherclass.php
I want to get these files in the following array:
[home][project] = array('index.php')
[home][project][folder] = array(myclass.php, myclass2.php)
[home][project][folder][subfolder] = array(anotherclass.php)
Note that the folder structure can change at any point. How can I achieve this?

The easiest way would be to use the built in (SPL) DirectoryIterator class and a simple recursive function.
An untested example:
public function directoryToArray($directoryPath)
{
$items = new DirectoryIterator($directoryPath);
$data = array();
foreach($items as $item) {
$name = $item->getFileName();
if ($item->isFile()) {
$data[] = $name;
}
else if ($item->isDir()) {
$data[$name] = directoryToArray($item->getPath());
}
}
return $data;
}

Related

Laravel 5 how to manipulate my variable in an for each in my controller and then pass it to my view

I have a database table named 'services'. With the function below I get all the records from that table. This function is located in my ServicesController.php.
public function index() {
$roadmap = Roadmap::all();
return view('services', compact('roadmap'));
}
Now in my view I also do the following:
<?php
foreach($roadmap as $roadmap_item) {
$new = array();
$splitted = explode("|", $roadmap_item->steps);
foreach($splitted as $split) {
$new = explode(":", $split);
}
}
?>
Lets say I get the string 'step1:hello|step2:bye' back from '$roadmap-item->steps'. I split them in substrings with explode etc. This is working by the way.
But is there a way I can manipulate the string in the Controller so my view will be nice and clean without many php code and still remain the variable $roadmap with all the database records.
Kind regards,
Dylan
I think you can do very similar things in your controller. Do foreach in your controller first then make a changes in every item in your collection and pass the new collection.
For example:
$roadmaps = Roadmap::all();
foreach($roadmaps as $roadmap){
$roadmap->something = " the changes you want to do as string " . $roadmap->something;
$roadmap->save();
}
return view('services', compact('roadmaps'));
or
$roadmaps = Roadmap::all();
$new = new Collection();
foreach($roadmaps as $roadmap){
$new[] = array('roadmap' => $roadmap, 'something' => $roadmap->string . " etcetc ")
$new->save();
}
return view('services', compact('new'));

PHP how to split path to object attribute

I have source of data and it is like:
$sourceData = json_decode($sourceData);
OR
$sourceData = simplexml_load_string($sourceData);
but possibly it could be another type of source and the result is probably php object with path to attributes like this:
$sourceData->product->time[$x]->location->precipitation['value'];
and I would like to split the path like this:
$rootPath = $sourceData->product->time[$x];
$rest = ?
/* probably something like '{$location}->{$precipitation}['value']
but I want the rest in one variable like
$rest = 'location->precipitation['value'];
*/
so at the end I should load paths like or similar to:
$temperature = 'location->data->something->temperature['value'];'
$precipitation = 'location->xxx->yyy->precip['data'];'
and use like:
for($i)
{
$temp = $root[$i]->temperature;
$precip = $root[$i]->precipitation;
}
This can be done with dynamic paths (like "dot notation"), but I'd hold off with it and make sure I really need that. It might be slow and it's used in more generic situations - unknown variable paths that client will provide.
Cleaner way would be encapsulating each root subtree ($data->product->time) within object with methods that can reach deep inside and return what you want. For example:
class ProductProperties
{
private $data;
public function __construct($data)
{
$this->data = $data;
}
public function temperature()
{
return $this->data->location->something->temperature['value'];
}
//...
}
Then creating instance and calling it within loop (or separate loops):
foreach ($sourceData as $root) {
$properties = new ProductProperties($root);
$temp = $properties->temperature();
}

Returning two Json or save it

I have a site developed in codeigniter and I have a model where I have to create two Json but I don't know if is better to save it into my server or pass it itno the controller and after in the view but how?
This is my model simplify:
public function calledFromController(){
//code...
$this->makeRequest();
}
public function makeRequest(){
//code...
foreach ($foo as $foo2){
$values[] = $foo2->value;
}
foreach ($hello as $hello2){
$values_hello[] = $hello2->value;
}
//save it into my server
$file = fopen('foo.json','w+');
fwrite($file, $foo);
fclose($file);
$file2 = fopen('hello.json','w+');
fwrite($file2, $file2);
fclose($file2);
}
Now I save it, but can be a very lot of data and after I have to open each json and parse it into javascript (backbone).
Is better this mode or return this two json (I have to mantain separate Json)?
Is I have to return this two Json how Can I do?
From my controller I call the function calledFromController in the model.
Try by creating an array and returning the array if you want to return both the json:
$data = array();
$data['foo'] = $foo;
$data['hello'] = $hello;
return $data;
In the controller:
$return = $this->model->function();
$foo = $return['foo'];
$hello = $return['hello'];

php -- combining arrays

So I'm trying to write a function that does the following: I have about 20 or so XML files (someday I will have over a hundred) and in the header of each file is the name of a person who was a peer review editor <editor role="PeerReviewEditor">John Doe</editor>. I want to run through the directory where these files are stored and capture the name of the Peer-Review-Editor for that file. I want to end up with an variable $reviewEditorNames that contains all of the different names. (I will then use this to display a list of editors, etc.)
Here's what I've got so far. I'm worried about the last part. I feel like the attempt to turn $editorReviewName into $editorReviewNames is not going to combine the individuals for each file, but an array found within a given file (even if there is only one name in a given file, and thus it is an array of 1)
I'm grateful for your help.
function editorlist()
{
$filename = readDirectory('../editedtranscriptions');
foreach($filename as $file)
{
$xmldoc = simplexml_load_file("../editedtranscriptions/$file");
$xmldoc->registerXPathNamespace("tei", "http://www.tei-c.org/ns/1.0");
$reviewEditorName = $xmldoc->xpath("//tei:editor[#role='PeerReviewEditor']");
return $reviewEditorNames[] = $reviewEditorName;
}
}
I would put things more apart, that helps as well when you need to change your code later on.
Next to that, you need to check the return of the xpath, most likely you want to process only the first match (is there one editor per file?) and you want to return it as string.
If you put things into functions of it's own it's more easy to make a function to only do one thing and so it's easier to debug and improve things. E.g. you can first test if a editorFromFile function does what it should and then run it on multiple files:
/**
* get PeerReviewEditor from file
*
* #param string $file
* #return string
*/
function editorFromFile($file)
{
$xmldoc = simplexml_load_file($file);
$xmldoc->registerXPathNamespace("tei", "http://www.tei-c.org/ns/1.0");
$node = $xmldoc->xpath("//tei:editor[#role='PeerReviewEditor'][1]");
return (string) $node[0];
}
/**
* get editors from a path
*
* #param string $path
* #return array
*/
function editorlist($path)
{
$editors = array();
$files = glob(sprintf('%s/*.xml', $path), GLOB_NOSORT);
foreach($files as $file)
{
$editors[] = editorFromFile($file);
}
return $editors;
}
Just a little update:
function editorlist() {
$reviewEditorNames = array(); // init the array
$filename = readDirectory('../editedtranscriptions');
foreach($filename as $file) {
$xmldoc = simplexml_load_file("../editedtranscriptions/$file");
$xmldoc->registerXPathNamespace("tei", "http://www.tei-c.org/ns/1.0");
// add to the array
$result = $xmldoc->xpath("//tei:editor[#role='PeerReviewEditor']");
if (sizeof($result) > 0) {
$reviewEditorNames[] = (string)$result[0];
}
}
// return the array
return $reviewEditorNames;
}

Copy a Doctrine object with all relations

I want to copy a record with all his relations.
I'm trying with:
$o = Doctrine::getTable('Table')->Find(x);
$copy = $object->copy();
$relations = $o->getRelations();
foreach ($relations as $name => $relation) {
$copy->$relation = $object->$relation->copy();
}
$copy->save();
This code doesn't works, but I think it's on the way.
I never could get the deep copy function to operate correctly.
I manually coded a deep copy function for one of my models like this
public function copyAndSave ()
{
$filters = array('id', 'created');
$survey = $this->copy();
$survey->Survey_Entries = new Doctrine_Collection("Survey_Model_Entry");
$survey->Assignment_Assignments = new Doctrine_Collection("Assignment_Model_Assignment");
$survey->Survey_Questions = new Doctrine_Collection("Survey_Model_Question");
$survey->save();
foreach ($this->Survey_Questions as $question)
{
$answers = $question->Survey_Answers;
$newQuestion = $question->copy();
$newQuestion->survey_surveys_id = $survey->id;
$newQuestion->save();
$newAnswers = new Doctrine_Collection("Survey_Model_Answer");
foreach($answers as $answer)
{
$answer = $answer->copy();
$answer->save();
$answer->survey_questions_id = $newQuestion->id;
$newAnswers->add($answer);
}
$newQuestion->Survey_Answers = $newAnswers;
$survey->Survey_Questions->add($newQuestion);
}
return $survey->save();
}
You can read about copy() here. It takes an optional parameter $deep:
$deep
whether to duplicates the objects targeted by the relations
So
$copy = $object->copy(true);
should do it.
Sorry if I'm resurrecting this thread...
I found myself in search of a solution recently where I needed to copy a record and retain the references of the original. A deep copy $record->copy(true) copies the references, which was no good for me. This was my solution:
$record = Doctrine_Core::getTable('Foo')->find(1);
$copy = $record->copy();
foreach($record->getTable()->getRelations() as $relation) {
if ($relation instanceof Doctrine_Relation_Association) {
$ids = array();
foreach ($relation->fetchRelatedFor($record) as $r) {
$ids[] = $r->getId();
}
$copy->link($relation->getAlias(), $ids);
}
}
if ($copy->isValid()) {
$copy->save();
}
Hope this helps :)
This is how i done, but some fix is needed.
$table = $entidade->getTable();
$relations = $table->getRelations();
foreach($relations as $relation => $data) {
try {
$entity->loadReference($relation);
} catch(Exception $e) {
die($e->getMessage());
}
}
I am using Symfony1.4.1 and that uses Doctrine 1.2.1 (I think).
I have been trying to make a function that did all the above myself, when I found one that already exists.
Try this in any function and look at the results:
$tmp=$this->toArray(TRUE);
var_dump($tmp);
$this->refreshRelated();
$tmp=$this->toArray();
var_dump($tmp);
$tmp=$this->toArray(TRUE);
var_dump($tmp);
exit();
I am going to try two different things:
A/ put $this->refreshRelated() into the constructor of all my model objects.
B/ write a function that takes an array depicting the object graph that I want populated. Calling the function refereshRelatedGraph($objectGraphArray). With the right structure of the array (having all the appropriate relation names at each level), I could control which relations get populated and which don't. One use for this is to populate only children, not parent relations. The other is for when a ERD/Schema/ObjectGraph has an element that is 'owned' by more than one object (many to many, other special circumstances that I have), I could control which side of the relationships get pre(non lazy) loaded.

Categories