I have the controller:
class Comments extends Controller
{
public function GenerateComments($id)
{
$theme = DB::table('New_Themes')
->where('id', $id)
->get();
$Comments = NewTheme_Comment::where('id_theme', $id)->get();
$array = $this->tree($Comments);
function tree($Comments, $parent_id = 0, $level=0, $c=0)
{
global $var;
global $array;
global $m;
foreach($Comments as $Comment)
{
if ($Comment['parent_id'] == $parent_id) {
$m++;
$array[$m][0]=$Comment['id'];
If ($level > $var) {$var++; $array[$m][1]=0;} else {
if ($c < 0) $array[$m][1]=$var-$level+1; else {$c--; $array[$m][1]=0;};
$var=$level;
};
tree($Comments, $Comment['id'], $level+1,$c);
}
};
return $this->$array;
};
return view('comments', ['Themes'=> $theme, 'Comments'=> $Comments, 'Array' => $array]);
}
The problem is
Method [tree] does not exist.
but I don't understand why it appears, if I am calling a function within a function (like that below)
$array = $this->tree($Comments);
function tree($Comments, $parent_id = 0, $level=0, $c=0)
{
return $this->$array;
}
Are there any ideas why this isn't working?
You are calling your function tree with $this which means PHP will look tree as a method inside Comments class instead of your GenerateComments method.
Change
$array = $this->tree($Comments);
To this
$array = tree($Comments);
Note: You are also defining your function after you are calling it. PHP will look tree as it is in the namespace so it'll either won't work. Instead just define your function before you call it. Like so
function tree($Comments, $parent_id = 0, $level = 0, $c = 0) {
// ...
}
$array = tree($Comments);
It is also not recommended to define your function inside of a function. Instead doing that, just make your tree function a method inside your controller and use that instead. Like so
class Comments extends Controller
{
public function GenerateComments()
{
// ...
$array = $this->tree($comments);
}
public function tree($tree)
{
// ...
}
}
Your tree function is inside the controller GenerateComments function.
It appears you want to use it as a class method.
Try calling the function with call_user_func this way:
$array = call_user_func('tree', $Comments);
Related
I got two functions in my model:
function getPersonsByGroup($groupId, $callback) {
$group = StutGroup::where('stg_id', $groupId)->get();
$persons = [];
foreach($group as $gr) {
foreach($gr->students as $stud) {
$persons[] = $stud->person;
}
}
return $callback(collect($persons));
}
function joinStudentsToPersons($person) {
return $person->each(function ($pers) {
$pers->student = \DB::connection('pgsql2')->table('students')->where('stud_pers_id', $pers->pers_id)->get();
});
}
I'm trying to call the function getPersonsByGroup in my controller passing the reference to the callback as follows:
$students = $studGroup->getPersonsByGroup($request->group, $studGroup->joinStudentsToPersons);
But if I pass an anonymous function to the getPersonsByGroup everything works well:
$students = $studGroup->getPersonsByGroup($request->group, function($person) {
return $person->each(function ($pers) {
$pers->student = \DB::connection('pgsql2')->table('students')->where('stud_pers_id', $pers->pers_id)->get();
});
});
What am I doing wrong?
The solution to your problem, if you want to keep this kind of structure, is to make the method return the closure like so:
function joinStudentsToPersons() {
return function ($person) {
$person->each(function ($pers) {
$pers->student = \DB::connection('pgsql2')->table('students')
->where('stud_pers_id', $pers->pers_id)
->get();
});
};
}
And then call it like:
$students = $studGroup->getPersonsByGroup($request->group, $studGroup->joinStudentsToPersons());
I would like overwrite array element returned as reference. I can do it like this:
$tmp = $this->event_users_details;
$tmp = &$tmp->firstValue("surcharge");
$tmp += $debt_amount;
I would do it in one line like:
$this->event_users_details->firstValue("surcharge") += $debt_amount;
but I get Can't use method return value in write context
Where $this->event_users_details is a object injected in constructor.
My function look like:
public function & firstValue(string $property) {
return $this->first()->{$property};
}
public function first() : EventUserDetails {
return reset($this->users);
}
and users is a private array.
You can't do it without temporary variable stores "surcharge" value.
From documentation:
To return a reference from a function, use the reference operator & in both the function declaration and when assigning the returned value to a variable:
<?php
function &returns_reference()
{
return $someref;
}
$newref =& returns_reference();
?>
I checked it with this code:
class Item
{
public $foo = 0;
}
class Container
{
private $arr = [];
public function __construct()
{
$this->arr = [new Item()];
}
public function &firstValue($propNme)
{
return $this->first()->{$propNme};
}
private function first()
{
return reset($this->arr);
}
}
$container = new Container();
var_dump($value = &$container->firstValue('foo')); // 0
$value += 1;
var_dump($container->firstValue('foo')); // 1
My current code:
public function countThreads() {
$count = $this->threads->count();
if ($this->hasSubforum()) {
foreach ($this->subforums as $subforum) {
$count += $this->countThreads($subforum);
}
}
return $count;
}
I am currently accessing the "thread" as $this inside my model. I need to pass in the $subforum to itself but how can I do that in a class?
In my controller, I'm simply doing:
$forum = Forum::where('id', $id)->first();
$forum->countThreads();
How can I do recursion with this? thanks!
You don't need to pass any arguments*, you can call the countThreads method on the subforum $subforum->countThreads()
public function countThreads()
{
$count = $this->threads->count();
if ($this->hasSubforum()) {
foreach ($this->subforums as $subforum) {
$count += $subforum->countThreads();
}
}
return $count;
}
If you really want to pass it in as an argument, the correct way would be to write it as a service outside of the model
I want to use array_filter to remove those items in an array whose value is equal to a specific character like '.' . To do, so I used the following code but I don't know how to pass the callback function to array_filter:
class Myclass(){
private function isPunc($var){
if($var=='.'){
return TRUE;
}else{
return FALSE;
}
public function myfunction($arr){
$arr = array_filter($arr,"isPunc");
}
}
Any idea how to solve this problem?
class Myclass(){
private function isPunc($var) {
if ($var=='.') {
return TRUE;
} else {
return FALSE;
}
}
public function myfunction($arr) {
$arr = array_filter($arr, array($this,'isPunc'));
}
}
use $arr = array_filter($arr, array($this, 'isPunc'));
array_filter() expects a Callable. This is an special internal type in PHP that can be on of four things:
a string with function name
an array with an object and method name as elements
an anonymous function
a functor (an object that implements __invoke)
In your case the second variant should work:
class FilterIsDot {
private function accept($element) {
if($element == '.'){
return TRUE;
}else{
return FALSE;
}
}
public function filter($array) {
return array_filter(
$array, array($this, 'accept')
);
}
}
$in = array('.', 'foo');
$filter = new FilterIsDot();
var_dump($filter->filter($in));
I would suggest a different approach avoiding array_filter(). SPL contains a FilterIterator class. You can extends this class:
class FilterIsDot extends FilterIterator {
public function __construct($arrayOrIterator) {
parent::__construct(
is_array($arrayOrIterator)
? new ArrayIterator($arrayOrIterator)
: $arrayOrIterator
);
}
public function accept() {
if($this->current() == '.') {
return TRUE;
}else{
return FALSE;
}
}
}
$in = array('.', 'foo');
$filter = new FilterIsDot($in);
var_dump(iterator_to_array($filter));
In this case the filter works on the fly. It is only used if the elements are actually accessed.
I tried a lot of search but unable to figure out why array $wordlinks in function DoWordLink is not carrying values from function __construct. PHP class code as below:
<?php
class autolinkkeyword
{
public $wordlinks = array();
public function __construct(){
$query = mysql_query("SELECT keyword FROM library");
while ($row = mysql_fetch_array($query))
{
$this->wordlinks [$row["keyword"]] = $row["keyword"];
}
}
public function linkkeywords ($posts)
{
function DoWordLink($match)
{
$rpl=$match[1];
if(isset($wordlinks[$rpl]))
{
$kword = $this->wordlinks[$rpl];
$rpl="<a class=\"keyword_link\" href=\"#\" onclick=\"popup('popUpDiv');
ajax_loadContent('kword', 'library.php?keyword=$kword')\">$kword</a>";
unset($this->wordlinks[$match[1]]);
}
return $rpl;
}
$wl=array_keys($this->wordlinks);
$pm="/((?<=\s|^)(?:" . implode('|',$wl) .")(?=\.|\!|\?|\,|\'|\s|$))/im";
foreach($posts as $key => $mainbody)
{
$mainbody=preg_replace_callback($pm, 'DoWordLink', $mainbody) ;
echo $mainbody;
}
}
}
?>
You can make it an actual method of that class and call it using this method:
http://www.php.net/manual/en/language.pseudo-types.php#language.types.callback
like:
preg_replace_callback($pm, array($this, 'DoWordLink'), $mainbody);
Change DoWordLink function so it is part of the class like:
class autolinkkeyword
{
function DoWordLink($match)
{
$rpl=$match[1];
if(isset($this->wordlinks[$rpl]))
{
$kword = $this->wordlinks[$rpl];
$rpl="<a class=\"keyword_link\" href=\"#\" onclick=\"popup('popUpDiv');
ajax_loadContent('kword', 'library.php?keyword=$kword')\">$kword</a>";
unset($this->wordlinks[$match[1]]);
}
return $rpl;
}
}
aren't you missing a "this->" construct here? if(isset($this->wordlinks[$rpl]))
Use the $this everywhere you refer to $wordlinks.
$this->wordlinks
You need to access the property in your linkkeywords-method with the object-accessor, too!
public function linkkeywords ($posts)
{
// Here use $this->wordlinks not $wordlinks
}