I am having a problem with attempting to batch load ACLs for a specific object (in the example below it is the Account class.)
If I am using the following code, even though acl_object_identities is populated, the returning array that should be populated is empty. What am I missing?
$oids = array();
foreach ($accounts as $account) {
$oid = ObjectIdentity::fromDomainObject($account);
$oids[] = $oid;
}
$aclProvider->findAcls($oids);
$accounts holds the array of entities found with a findAll().
Well, it looks like the ACLs are pulled after all with the key being an iterative follow-up to see what permissions are in place.
foreach ($accounts as $account) {
if ($securityContext->isGranted('EDIT', $account)) {
// Granted, do something with it
} else {
// Not Granted
}
}
So, it seems that everything is working a designed.
Related
I'm working with a Mongo database, and i have a Reading List with a BelongsToMany Relationship to a Stories table, it seems like this:
public function stories()
{
return $this->belongsToMany(Story::class, null);
}
Then, on the controller, i want to return a list of them, which contains only the id and title of the story list, i searched, and found many ways, but all them caused the same error, this is one of them:
$user = auth()->user();
$readingList = ReadingList::where('user_id', $user->id)->with(["stories"=> function ($query) {
$query->select("title");
}])->paginate(10);
And causes: Invalid argument supplied for foreach().
I took out the filter to verify it works, and answered correctly.
[
{
"_id": "6148dc2a23ef6d0e6838h123",
"name": "MyReadingList",
"stories": [
{
"_id": "611a64f5f735f32dcc5ab657",
"title": "Lorem",
"blurb": "Ipsum"
}
]
}
]
Am i doing this wrong, or how do you filter the fields with Jensseger library and BelongsToMany?
UPDATE
After a little debugging, seems like i found the cause, but i'm not sure how to solve it, in the Jensseger BelongsToMany file, there is a function like this:
protected function buildDictionary(Collection $results)
{
$foreign = $this->foreignPivotKey;
// First we will build a dictionary of child models keyed by the foreign key
// of the relation so that we will easily and quickly match them to their
// parents without having a possibly slow inner loops for every models.
$dictionary = [];
foreach ($results as $result) {
foreach ($result->$foreign as $item) {
$dictionary[$item][] = $result;
}
}
return $dictionary;
}
Here, $result is equal to {"_id":"6148dc2a23ef6d0e6838h123"}, which is my filtered result, but then it tries to access $result->$foreign, where $foreign is 'reading_list_ids', the pivot column, but is not here, hence returning a null and launching that error.
I tried adding reading_list_ids(And removing it from hidden) like $readingList = ReadingList::where('user_id', $user->id)->with("stories:title,reading_list_ids")->get();, still didn't work. Interestingly, i tried testing this without the filter, but with reading_list_ids hidden, it showed something like this {"_id":"6148dc2a23ef6d0e6838h123","title":"Lorem","blurb":"Ipsum","completed":"1"}, still not that field there, but it doesn't launch that error and works.
Does anyone knows how to bypass this, or make it work?
I've got two tables: step and links joined 1:n. I'm aiming to maintain the links through the step objects. I retrieve all steps from the database and populate the relation with the links table. I persist the step object containing a collection of links to JSON and return it to the front end using REST.
That means that if a step is linked or unlinked to another step in the front end I send the entire step back to the backend including a collection of links. In the back end I use the following code:
public function put($processStep) {
if (isset($processStep['Processesid']) && isset($processStep['Coordx']) && isset($processStep['Coordy'])) {
$p = $this->query->findPK($processStep['Id']);
$p->setId($processStep['Id']);
$p->setProcessesid($processStep['Processesid']);
if (isset($processStep['Flowid'])) $p->setFlowid($processStep['Flowid']);
if (isset($processStep['Applicationid'])) $p->setApplicationid($processStep['Applicationid']);
$p->setCoordx($processStep['Coordx']);
$p->setCoordy($processStep['Coordy']);
$links = $p->getLinksRelatedByFromstep();
$links->clear();
foreach ($processStep['Links'] as $link) {
if (!isset($link['Linkid'])) {
$newLink = new \Link();
$newLink->setFromstep($link['Fromstep']);
$newLink->setTostep($link['Tostep']);
$links->prepend($newLink);
}
}
$p->save();
return $p;
} else {
throw new Exceptions\ProcessStepException("Missing mandatory fields.", 1);
}
}
I'm basically deleting every link from a step and based upon the request object I recreate the links. This saves me the effort to compare what links are deleted and added. The insert work like a charm Propel automatically creates the new links. Thing is it doesn't delete like it inserts. I've checked the object that is being persisted ($p) and I see the link being deleted but in the MySQL log there is absolutely no action being performed by Propel. It looks like a missing member from the link collection doesn't trigger a dirty flag or something like that.
Maybe I'm going about this the wrong way, I hope someone can offer some advice.
Thanks
To delete records, you absolutely always have to use delete. The diff method on the collection is extremely helpful when determining which entities need added, updated, and deleted.
Thanks to Ben I got on the right track, an explicit call for a delete is not needed. I came across a function called: setRelatedBy(ObjectCollection o) I use this function to provide a list of related objects, new objects are interpreted as inserts and omissions are interpreted as deletes.
I didn't find any relevant documentation regarding the problem so here's my code:
$p = $this->query->findPK($processStep['Id']);
$p->setId($processStep['Id']);
$p->setProcessesid($processStep['Processesid']);
$p->setCoordx($processStep['Coordx']);
$p->setCoordy($processStep['Coordy']);
if (isset($processStep['Flowid'])) $p->setFlowid($processStep['Flowid']);
if (isset($processStep['Applicationid'])) $p->setApplicationid($processStep['Applicationid']);
//Get related records, same as populaterelation
$currentLinks = $p->getLinksRelatedByFromstep();
$links = new \Propel\Runtime\Collection\ObjectCollection();
//Check for still existing links add to new collection if so.
//This is because creating a new Link instance and setting columns marks the object as dirty creating an exception due to duplicate keys
foreach ($currentLinks as $currentLink) {
foreach ($processStep['Links'] as $link) {
if (isset($link['Linkid']) && $currentLink->getLinkid() == $link['Linkid']) {
$links->prepend($currentLink);
break;
}
}
}
//Add new link objects
foreach ($processStep['Links'] as $link) {
if (!isset($link['Linkid'])) {
$newLink = new \Link();
$newLink->setFromstep($link['Fromstep']);
$newLink->setTostep($link['Tostep']);
$links->prepend($newLink);
}
}
//Replace the collection and save the processstep.
$p->setLinksRelatedByFromstep($links);
$p->save();
Using eloquent, I am querying two sets of data like so:
$all_perms = Permission::all(); //all permissions
$role_perms = Auth::user()->roles()->permissions; //permissions belonging to a role
$role_perms is a subset of $all_perms and what I want is to loop both arrays and come out with a new array containing all permissions already assigned to a role together with those not yet assigned to a role.
What I have done is loop through both arrays in a foreach loop and if any one array belongs to both sets, I mark it by adding a check key with corresponding value 1 to the array so that I can identify is as a permission already assigned to a role.
foreach ($role_perms as $role_perm) {
foreach ($all_perms as $key => $value ) {
if (array_diff_assoc($all_perm, $role_perm)) {
$all_perm['check'] = 1;
}
}
}
but it keeps throwing the error:
array_diff_assoc(): Argument #1 is not an array
Are they better ways of doing this? Or what can I do on this one to make it work?
Thanks for any help
That's because it's a collection, not an array. If you want to get an array, try to use toArray():
$all_perms = Permission::all()->toArray();
Also, is this a typo here:
array_diff_assoc($all_perm, $role_perm);
It should be $all_perms
Try using the wonderful contains method that is available on all your collections:
foreach ($role_perms as $role_perm) {
if($all_perms->contains($role_perm))
{
// do whatever is needed
}
}
Checkout the docs for help with the contains method.
I consider myself as a php beginner, so it may be possible that this question is too easy for someone, but I got really confused on how to solve it. I am trying to loop something from the database in my views. So, in a quick way I solved it like this:
I've created a function in my model that does the loop and in the same time is creating the html and saves it in a variable. Then, I get that variable from my controller and I pass it in my view. But, it seems that this is not a good way to solve it, since if I want to change my html I need to enter my model function instead some of the view files.
Then, I've created another function in my model that looks like this:
function displayUsers() {
$sql = $this->pdo->prepare('select * from user');
$sql->execute();
while($row = $sql->fetch())
$results[] = $row;
return $results;
}
Now... I take the result in my controller, and send it in the view, but then... I don't know how to extract the results from my variable. I have done something like this:
while($output) {
foreach($output[$i] as $key => $value)
$data[$key] = $value;
echo $data['email'];
$i++;
}
But then, in the end it says to me undefined offset, which means I am referring to an array key that doesn't exist. Can anyone help me on how to solve this issue?
Proper MVC shouldn't have any output in the model or the controller.
Ideally you would have a model that just gets the raw data and returns it in the controller. The controller can then build up an array of values that we'll call data. For example:
Controller
$data['users'] = $this->MyModel->getusers(); // Getting the users from your model
$data['posts'] = $this->MyModel->getposts(); // Getting the posts from your model
$this->getTemplate('userdisplay', $data); // Get the template userdisplay and pass data
This gets the data from the model, and then assigns it to a key within the "data" variable. You can then pass the data variable into the template. You'll then have two variables to work with in the template, $users and $posts.
You'll need a "getTemplate" function that properly maps the data array to individual variables for use in the template, but all of the display should be located in the template.
To answer your specific question at the end, something like this should work in the template:
if (count($users) > 0) {
foreach ($users as $person) {
echo $person['email'];
}
}
You should be able to do this:
foreach($output as $row) {
echo $row['email'];
}
I have a problem i can't even name properly. Here is the situation.
I'm using php framework (kohana3 but it's not important i think) to write a simple cms with entries and uploads. The relations are:
Entries -> has_many -> Uploads
Uploads -> belongs_to -> Entries
To display all entries with their uploads, i'm using this code in view file:
foreach( $entries as $entry )
{
foreach( $entry->upload->find_all() as $uploads )
{
foreach( $uploads->find_all() as $upload )
{
echo $upload->file;
}
}
}
Now i want to create a method in Entry model called find_first_upload() which will return first uploaded element. Here is the future usage of it:
foreach( $entries as $entry )
{
echo $entry->find_first_upload()->file;
}
and the important thing is that i don't want to pass any variables to find_first_upload() method like for example $entry object or currently looped entry id.
What i want to achieve is to be able to get currently looped entry object inside find_first_upload method - it'll allow me to make a foreach's inside of it.
Have you any ideas how can i code that?
If you have any questions, feel free to ask them here.
Thanks,
Mike
public function find_first_upload() {
$result = 0;
foreach( $this->upload->find_all() as $uploads )
{
foreach( $uploads->find_all() as $upload )
{
if(empty($result))
$result = $upload;
}
}
return $result;
}
Sorry for reviving this old topic, but I was googling something and stumbled on this. In case anyone has a similar issue, ignore the accepted answer, this is the correct way:
public function find_first_upload()
{
return $this->uploads->find();
}