how to store data in an array in a recursive function - php

I have made a recursive function, and I want to add the data it returns to an array each time the function is called.
This is my current implementation:
public function getParentCategory($categoryId) {
$category = Category::find($categoryId);
if($category != NULL){
$catArray[] = $category->id;
if($category->parent_category_id != NULL) {
$this->getParentCategory($category->parent_category_id);
}
}
}
I want to store data in catArray each time the function is called.

You can just return the data from the function. You also need to pass it to the function, or use a default parameter:
public function getParentCategory($categoryId, $catArray = array()) {
$category = Category::find($categoryId);
if ($category != NULL){
$catArray[] = $category->id;
if ($category->parent_category_id != NULL){
$catArray = $this->getParentCategory($category->parent_category_id, $catArray);
}
}
return $catArray;
}
You can use array_unshift() instead of $catArray[]= to have $catArray in reverse order (and/or add $category->id after the return from the recursion).

Related

Laravel cookie in compose function

To build my menu i have a file Providers/ViewComposerServiceProvicer.php . in this file I have:
public function boot()
{
$this->composeNavigation();
}
public function composeNavigation()
{
view()->composer('front.layouts.menu', function ($view) {
$view->with('menuItems', \App\MenuItem::orderBy('priority', 'asc')->get());
});
}
What i want is add a where query based on a Coockie value like:
$brand = $request->cookie('brand');
// if value not set use default value.
if($brand == null)
{
$brand = 1;
}
view()->composer('front.layouts.menu', function ($view) {
//extra where function
$view->with('menuItems', \App\MenuItem::Where('brand','=',$brand)->orderBy('priority', 'asc')->get());
});
How can I get the coockie value in the compose function? Is there a special way to pass Request to my composeNavigation function?
EDIT i got it working but i cant access $brand in view()->composer(), if i copy my code inside the function i cant access request
My updated code :
public function boot(Request $request)
{
$this->composeNavigation($request);
}
public function composeNavigation(Request $request)
{
$coockieValue = $request->cookie('brand');
// if value not set use default value.
if($coockieValue == null)
{
$coockieValue = null;
}
$brands = \App\Brand::orderBy('priority', 'asc')->get();
foreach($brands as $brand){
if($brand->id == $coockieValue){
$brand->menuActive = true;
}
else{
$brand->menuActive = false;
}
}
view()->composer('front.layouts.menu', function ($view) {
$view->with('brandItems',$brands );
});
}

How do I get the next item in a Laravel collection?

Let's say I have a child of a parent collection and I want to know who the next sibling is. My parent collection is ordered differently than internal id so I can't use the method described here:
Laravel previous and next records
Which would work except I'm sorting by name and time, not internal id. I'm hoping that there's a way to just get the parent collection, find this child's position within it, and then look forward or back within that collection to get next or previous.
Edit:
So, I made this, which works, but seems clunky. Is there a more efficient way to do this?
public function next()
{
$previous = null;
foreach ($this->album->media as $media)
{
if(!empty($previous && $previous->id == $this->id))
{
// Yay! Our current record is the 'next' record.
return $media->id;
}
$previous = $media;
}
return null;
}
public function previous()
{
$previous = null;
foreach ($this->album->media as $media)
{
if(!empty($previous && $media->id == $this->id))
{
// Yay! Our previous record is the 'previous' record.
return $previous;
}
$previous = $media->id;
}
return null;
}
You should never load the entire table to loop through it to find the next/previous item, instead do it this way:
$next = $this->album->media()->orderBy('id')->where('id', '>', $this->id)->first();
Here is the simple line of code
// next
function next($product_id)
{
$next = Product::where('id', '>', $product_id)->first();
return $next;
}
// previous
function previous($product_id)
{
$previous = Product::where('id', '<', $product_id)->first();
return $previous;
}
This did the trick:
public function next()
{
$previous = null;
foreach ($this->album->media as $media)
{
if(!empty($previous && $previous->id == $this->id))
{
// Yay! Our current record is the 'next' record.
return $media->id;
}
$previous = $media;
}
return null;
}
public function previous()
{
$previous = null;
foreach ($this->album->media as $media)
{
if(!empty($previous && $media->id == $this->id))
{
// Yay! Our previous record is the 'previous' record.
return $previous;
}
$previous = $media->id;
}
return null;
}

passing values to custom find in Model

I have the following custom find in my model which I'd like to re-use depending on values that are passed to it.
public function _findActive($state, $query, $result = array()) {
if ($state === 'before') {
$query['conditions'] = array('WebRequest.status' => false, 'WebRequest.read_status' => false);
$query['contain'] = false;
$query['limit'] = 25;
$query['order'] = array('WebRequest.created' => 'asc');
return $query;
}
return $result;
}
I can call this function from my controller and it will paginate the results as 25 per page. However, I would like to be able to pass the limit value to the function and limit by this volume per page as required. I can add an extra field $limit to the function parameters ($state, $query, $result = array(), $limit) which is passed into the function. If I debug at the start of the function atif($state === 'before') then the value remains as it was passed in, but as this function is called automatically twice, it by default gets reset back to null the second time the function is called, so I lose the value that was passed in. Is there any way around this?
Try this:
public function _findActive($state, $query, $result = array()) {
if ($state === 'before') {
$query['conditions'] = array(
'WebRequest.status' => false,
'WebRequest.read_status' => false
);
$query['contain'] = false;
$query['limit'] = 25;
$query['order'] = array('WebRequest.created' => 'asc');
return $query;
} elseif ($state == 'after') {
return $results;
}
}`
You can store the original $limit value in a private class variable in your model and use it for the limit. Something like:
class YourModel extends AppModel {
private $_originalLimit;
public function _findActive($state, $query, $result = array, $limit) {
....
if (!empty($limit))
$this->_originalLimit = $limit;
$query['limit'] = $this->_originalLimit;
....
}
}
When this function is called for the second time with a null $limit, your class variable, which has the original $limit value, will be used for the limit.

Function returns Null :: laravel

I have a function which gets the value from a database and returns. When I echo, the value does exist. But returned value is null;
public static function getCountryCode($country) {
$country = (int) $country;
$x = Country::where('id', $country)->get();
$country_code = '';
foreach($x as $row)
$country_code = $row->alpha_2;
//return 'bd';
echo $country_code;
return $country_code;
}
Not sure what's wrong in there. It's a laravel project.
Function that is calling this method
public function countryselect()
{
$country_id = HomeController::detectCountry();
$country_code = SiteController::getCountryCode($country_id);
var_dump($country_code);
return View::make('Layout.countryselect', compact('country_id', 'country_code'));
}
You don't have to use "foreach" function. You can get country code in much easier way. Just make some changes in getCountryCode() like
public static function getCountryCode($countryId) {
$countryId = (int) $countryId;
$country = Country::where('id', $countryId)->get()->first();
return $country->code;
}
This will return the country code of specified country id. Use descriptive name for variable like you used for the function

Searching in multidimensional php objects

public function filter($index, $value) {
if($this->tasks) {
foreach ($this->tasks as $id => $t) {
if($t->$index != $value) {
unset($this->tasks[$id]);
}
}
} else {
echo "Tasks are empty";
}
}
So I am having a problem with the function above searching multidimensional objects. What I mean by that is like these:
$task->form->id
$task->form->type
$task->author->id
$task->fields->[FIELDNAME]->value
$task->form->template->id
$task->id
etc. These are the kinds of fields that need to be accessed. I thought that I could just, in $index, put "form->id" but that didn't work. For my application, I literally can spell it out. I just don't want to have to write a function for each to the last, because some of them (as you can see) only need to be on the first level and some need to be all the way down four objects.
Just tell me what more data you need and I will give it. I know every keystroke intimately so it sometimes means I forget to share something.
If you help, thank you so much.
WHAT I DID
Okay so I got it to work but I did something different.
Within the Form class
public function search($value, $type = NULL) {
if(is_object($this->fields)) {
foreach($this->fields as $page) {
foreach($page as $name=>$field) {
if($name != "pdata") {
if ($type != NULL && $field->type == $type && $field->value == $value || $type == NULL && isset($field->value) && $field->value == $value) {
return true;
}
}
}
return false;
}
} else {
//Probably corrupted
return false;
}
return false;
}
Outside of it I can just call this function and delete or add based on whether it returns true or false.
function array_searchRecursive( $needle, $haystack, $strict=false, $path=array() )
{
if( !is_array($haystack) ) {
return false;
}
foreach( $haystack as $key => $val ) {
if( is_array($val) && $subPath = array_searchRecursive($needle, $val, $strict, $path) ) {
$path = array_merge($path, array($key), $subPath);
return $path;
} elseif( (!$strict && $val == $needle) || ($strict && $val === $needle) ) {
$path[] = $key;
return $path;
}
}
return false;
}
OR
I know you don't want to write it all out, but I have to say I love the way this is done in the Symfony framework. In symfony you have an Entity class that defines functions to retrieve each piece of information (variable) from a given object.
One way you could mimic this is to create a base class for tasks that has functions to retrieve each variable you need...such as getTaskId.
Then you could extend this base class with the one you are working with now. This would give you access to the functions you created to parse your object. Retrieving $task->form->template->id could be as simple as calling the getTemplateId function.
I know this would probably take longer than what you were looking for, but I hope it helps.
You can use get_object_vars() to process all public variables of an object and proceed recursively to reach all variables named id. Here is a simple template:
class Task {
public $author, $form, $id;
}
class Author {
public $id;
}
class Form {
public $id, $type, $template;
}
class Template {
public $id;
}
$tasks = Array();
$task = new Task();
$tasks[] = $task;
$task->id = "id1";
$task->author = new Author();
$task->author->id = "id1";
$task->form = new Form();
$task->form->template = new Template();
$task->form->template->id = "id1";
function filter($parent, $object, $id_value) {
$vars = get_object_vars($object);
foreach ($vars as $var => $value) {
if ($var == "id") {
if ($value == $id_value) {
echo "$parent -> $var == $value <br />";
}
}
else if (is_object($value) && isset($value)) {
filter("$parent -> $var", $value, $id_value);
}
}
}
foreach ($tasks as $index => $task) {
filter("Task[$index]", $task, "id1");
}
The output is:
Task[0] -> author -> id == id1
Task[0] -> form -> template -> id == id1
Task[0] -> id == id1

Categories