Can't get data from a static array in HelperAdmin - oop

I have a file/class::method (HelperAdmin.php/HelperAdmin::menuItem()) which extracts data from DB to generate main menu and submenu.
I have to get this data after the menu being generated but I don't want to call this method twice.
So I have created a static array in HelperAdmin class. It looks like this:
class HelperAdmin {
static $arrMenuItems;
...
public static function menuItem() {
....get $items....
self::$arrMenuItems = $items;
return $items;
}
....
}
But here is a problem. If I call the METHOD again:
$items=HelperAdmin::menuItem();
...I can get data.
In other hand if I try to get data through a static array:
$items=HelperAdmin::$arrMenuItems;
...it just returns null.
I hope to see some ideas. After all, if your opinion is that using static variable here (from Yii architecture view) is not the best solution, I'd like to get your advice!
#bool.dev:
OK, imagine the following scheme:
1. We have the main file
/modules/admin/views/layouts/admin.php
which is in essence our backend template.
2. We have the helper here:
/modules/admin/components/HelperAdmin.php
which contains:
* a class HelperAdmin,
* menuItem() method and
* a class static array $arrMenuItems.
A content of this ARRAY returned by calling HelperAdmin::menuItem().
We want get data from the HelperAdmin class twice:
1. While generating a menu in admin.php;
2. As part of content which we get with variable $content putting it at this file.
$content in turn is generated in another file:
/modules/admin/views/generator/index.php
So as you can see, our page compounds itself from the template file /modules/admin/views/layouts/admin.php and data ($content) getting from /modules/admin/views/generator/index.php.
First I get data for menu:
HelperAdmin::menuItem();
$items=HelperAdmin::$arrMenuItems;
$this->widget(....
'items'=>$items,
...),
));
That's OK. Notice that after this a static array $arrMenuItems already is generated in HelperAdmin.
Next I'm trying to get the same data ($arrMenuItems generated earlier) in file /modules/admin/views/generator/index.php to place it as $content:
$items=HelperAdmin::$arrMenuItems
And here I can't get it as described above.
Well, I hope it made a situation more clear (?).

Related

Trying to take some data from my file called "listing-card" which is is saved in the component folder

#foreach($listings as $listing)
<x-listing-card :listing="$listings" />
#endforeach
the listing card is in the component file
I was expecting to get results from 'listing-card' blade file. but I got this error
enter image description here
without a better understanding of your code, the first thing I see is the :listing=$listings
I would think you would want the individual item $listing from your foreach.
Secondly, The error states it can not find the class. Be wary of kabob-case vs CamelCase. It has bitten me a few times
Edit/Update addressing comment below:
You will have to go and look at your component blade file to check on your exact naming convention you are using. For example you have a class named SiteInfo and in the render section you would have it return something like : return view('components/site-info');
Your file and class being used will be SiteInfo.blade.php and the class in it will be: class SiteInfo extends Component
example:
#foreach($listings as $listing)
<x-listing-card :listing="$listing" />
#endforeach
Your Class file would be something similar to:
class Listing-card extends Component
{
public $listing;
}
/**
* Create a new component instance.
*
*
*/
public function __construct($listing)
{
$this->listing = $listing;
}
/**
* Get the view / contents that represent the component.
*
* #return \Illuminate\Contracts\View\View|\Closure|string
*/
public function render()
{
return view('components.listing-card');
}
}
You might have to enable some logging at key points in your app and pull data. The laravel log /storage/logs/laravel.log is invaluable in find your mistakes.

Laravel-8 Related data in a collection is lost

I am trying to get more familiar with laravel/livewire. I find myself struggling with collections with related data. In my component i get data from the database and store it in a variable, with related data. When i do a dd after the retrieval, i see a complete collection with the related data. In my bladefile i have a foreach loop to display all the lists and for each list i have a foreachloop to display all todos.
But when i want to edit a list, i want to show one of the lists in a modal with a form. I call a function 'edit_todo' and i want to extract the data from my collection to fill in a blade form.
But when i look at the same variable as before ($this->todolists) in that function, the related data is missing.
This is a part of the code.
class Dashboard extends Component
{
public $todolists, $list_id, $todolist;
public function render()
{
$this->todolists = TodoList::with('todos')->get();
//dd($this->todolists); //<-- relationsproperty shows all todos from each list
return view('livewire.dashboard');
}
/**
* The attributes that are mass assignable.
*
* #var array
*/
public function edit_todo($list_id)
{
dd($this->todolists); //<-- relationsproperty is empty
$this->todolist = $this->todolists->where('id',$list_id)->with('todos')->first()->toArray();
}
Any suggestions? What am i doing wrong?
Maybe i just have to get the data again from the database, but i'd like to understand why this isn't working.
Move the population of your $todoLists to the mount method:
public function mount()
{
$this->todolists = TodoList::with('todos')->get();
}
Have a look at https://laravel-livewire.com/docs/2.x/lifecycle-hooks and you'll notice that the render method is only requested at the very end. If you need your $todoLists populated as you wish, move it up in the list of lifecycle hooks.
Edit & extra: mount() in LiveWire is equal to __construct() in any other class as we are used to. Whatever you would like to 'construct', write it in the mount method.

Problems using successCallback in ag-grid

I have a vue component with ag-grid grid (infinite model). I want to access to its params to use successCallback, directly in another method in the component, after do the setDatasource.
In sum up, I can not find where the params are.
I have tried:
this.gridApi.params.successCallback(data, totalRows)
this.gridOptions.params.successCallback(data, totalRows)
this.params.successCallback(data, totalRows)
Any advice?
Basically, you have missed the full flow of how the ag-grid operating with dataSource.
So according to the official doc, IDatasource looks like that:
interface IDatasource {
/** If you know up front how many rows are in the dataset, set it here. Otherwise leave blank.*/
rowCount?: number;
/** Callback the grid calls that you implement to fetch rows from the server. See below for params.*/
getRows(params: IGetRowsParams): void;
destroy?(): void;
}
Let's go deeply to getRows and IGetRowsParams interface (only needed part of it)
/** Params for the above IDatasource.getRows() */
export interface IGetRowsParams {
....
successCallback(rowsThisBlock: any[], lastRow?: number): void;
...
}
So as you can see, successCallback only accessible via dataSource and exactly in getRows method, which means, that you don't have to get direct access via gridAPI. It should be defined once (as dataSource) and then, ag-grid will execute getRows only when it requires.
Possible solution (not recommended to use, cut dataSource mostly required for infinite scroll and auto-fill the new data)
You can bind params.successCallback to your own property and execute it whenever you want
here is a simple hack example (check successCallbackBinding)

Doctrine ODM: Cannot prime->(true) getSingleResult(); throws cursor error

I have a document that has a ReferenceMany attribute to another document. The reference is setup fine, and the data is returned from the query fine, but each document in the arraycollection is returned as a proxy. On this site, I saw it was mentioned I should add ->prime(true) in order to return the actual referenced documents.
When that ArrayCollection of documents is returned, I am running a loop of ids I have submitted to the server to remove them from the referenced collection. The removeElement method is not working b/c the returned documents are proxies, and I am comparing an actual document vs. those proxies. So basically I am trying to:
Look up a single document
Force all documents in the ReferenceMany attribute to be actual documents and not Proxy documents
Loop through my array of id's and load each document
Send the document to the removeElement method
On the first getSingleResult query method below, I am getting an error cannot modify cursor after beginning iteration. I saw a thread on this site mention you should prime the results in order to get actual documents back instead of proxies, and in his example, he used getSingleResult.
$q = $this->dm->createQueryBuilder('\FH\Document\Person')->field('target')->prime(true)->field('id')->equals($data->p_id);
$person = $q->getQuery()->getSingleResult();
foreach($data->loc_id as $loc) {
$location = $this->dm->createQueryBuilder('\FH\Document\Location')->field('id')->equals(new \MongoId($loc))->getQuery()->getSingleResult();
$person->removeTarget($location);
}
....
....
....
public function removeTarget($document)
{
$this->target->removeElement($document);
return $this;
}
If I remove ->prime(true) from the first query, it doesn't throw an error, yet it doesn't actually remove any elements even though I breakpoint on the method, compare the two documents, and the data is exactly the same, except in $this->target they are Location Proxy documents, and the loaded one is an actual Location Document.
Can I prime the single result somehow so I can use the ArrayCollection methods properly, or do I need to just do some for loop and compare ids?
UPDATE
So here is an update showing the problem I am having. While the solution below would work just using the MongoId(s), when I submit an actual Document class, it never actually removes the document. The ArrayCollection comes back from Doctrine as a PersistentCollection. Each element in $this->coll is of this Document type:
DocumentProxy\__CG__\FH\Document\Location
And the actual Document is this:
FH\Document\Location
The removeElement method does an array_search like this:
public function removeElement($element)
{
$key = array_search($element, $this->_elements, true);
if ($key !== false) {
unset($this->_elements[$key]);
return true;
}
return false;
}
So because the object types are not exactly the same, even though the proxy object should be inheriting from the actual Document I created, $key always returns 0 (false), so the element is not removed. Everything between the two documents are exactly the same, except the object type.
Like I said, I guess I can do it by MongoId, but why isn't it working by submitting the entire object?
Don't worry about the prime(true) stuff for just now. All that does is tell doctrine to pull the referenced data now, so it doesn't have to make multiple calls to the database when you iterate over the cursor.
What I would do is change your removeTarget method to do the following.
$this->dm->createQueryBuilder('\FH\Document\Person')->field('id')->equals($data->p_id);
$person = $q->getQuery()->getSingleResult();
$person->removeTargets($data->loc_id);
Person.php
public function removeTargets($targets)
{
foreach ($targets as $target) {
$this->removeTarget($target);
}
}
public function removeTarget($target)
{
if ($target instanceof \FH\Document\Location) {
return $this->targets->removeElement($target);
}
foreach ($this->targets as $t) {
if ($t->getId() == $target) {
return $this->targets->removeElement($t);
}
}
return $this;
}
This would mean you don't have to perform the second query manually as doctrine will know it needs to pull the data on that reference when you iterate over it. Then you can make this operation quicker by using the prime(true) call to make it pull the information it needs in one call rather than doing it dynamically when you request the object.

I can't load my SmartGWT Datasource

I'm modifying an example of the built-in-ds. The way this example works is that you need to select a datasource, and then a table gets filled with data from there. The idea is to show how the same component can adapt to multiple data sources. I've managed to run the example and it works, but I'm trying to modify it so you skip the first step - there's only one data source that gets loaded "into" the table. What puzzles me is that this should be trivial but for some reason it's not. I'll paste just the different parts of code, this one works:
// we create a list of datasources
ListGrid grid = new ListGrid();
grid.setLeft(20);
grid.setTop(75);
grid.setWidth(130);
grid.setLeaveScrollbarGap(false);
grid.setShowSortArrow(SortArrow.NONE);
grid.setCanSort(false);
grid.setFields(new ListGridField("dsTitle", "Select a DataSource"));
// I'm just loading the one I need
grid.setData(new ListGridRecord[] { new DSRecord("predmeti", "predmeti")});
grid.setSelectionType(SelectionStyle.SINGLE);
grid.addRecordClickHandler(new RecordClickHandler() {
public void onRecordClick(RecordClickEvent event) {
DSRecord record = (DSRecord) event.getRecord();
bindComponents(record.getDsName());
}
});
grid.draw();
and this is the bindComponents method:
private void bindComponents(String dsName) {
DataSource ds = DataSource.get(dsName);
boundList.setDataSource(ds);
boundViewer.setDataSource(ds);
boundForm.setDataSource(ds);
boundList.fetchData();
newBtn.enable();
saveBtn.disable();
}
and this works as it should. Now, since I only have one data source, I can skip the grid and just make the call to bindComponents:
bindComponents();
And bindComponents looks like this:
private void bindComponents() {
DataSource ds = DataSource.get("predmeti");
boundList.setDataSource(ds);
boundViewer.setDataSource(ds);
boundForm.setDataSource(ds);
boundList.fetchData();
newBtn.enable();
saveBtn.disable();
}
I can't see why the second doesn't work, it breaks on boundList.setDataSource(ds);. I inspected it in Debug mode, an object is returned and it looks "the same" in both cases but for some reason it doesn't work in the second example, so I'm guessing I'm instancing the data source too early or, somehow, just plain wrong :)
Everything was fine with the datasources, the problem is trivial and I must have just been tired - the boundList object at the time of this call boundList.setDataSource(ds); was not yet instantiated. I kept getting Null pointer exception, but I thought there was something wrong with the DataSource.