I, using the Graphaware Neo4j-php-OGM. I would like to access the 2nd level relationship. I can't seen to get it to work. What am i doing wrong?
I'm trying to execute the following:
public function allowToContinue($userUuid, $permissionUuid)
{
$userRepo = $this->entityManager->getRepository(User::class);
$permRoleRepo = $this->entityManager->getRepository(PermRole::class);
$permissionRepo = $this->entityManager->getRepository(Permission::class);
$user = $userRepo->findOneBy(['uuid' => $userUuid]);
$permission = $permissionRepo->findOneBy(['uuid' => $permissionUuid]);
$allowed = false;
foreach ($user->getPermrole() as $userRole)
{
var_dump($userRole);
$role = $permRoleRepo->findOneBy(['uuid' => $userRole->getUuid()]);
var_dump($role);
foreach ($role->getPermissions() as $perm)
{
var_dump($perm->getUuid());
if($perm->getUuid() === $permissionUuid){
$allowed = true;
}
}
}
return $allowed;
}
Stacktrace:
Error:
Call to a member function isCollection() on null
at vendor/graphaware/neo4j-php-ogm/src/Hydrator/EntityHydrator.php:107
at GraphAware\Neo4j\OGM\Hydrator\EntityHydrator->hydrateSimpleRelationshipCollection('permissions', object(Result), object(neo4j_ogm_proxy_App_Entity_Generic_PermRole))
(vendor/graphaware/neo4j-php-ogm/src/Persisters/BasicEntityPersister.php:104)
at GraphAware\Neo4j\OGM\Persisters\BasicEntityPersister->getSimpleRelationshipCollection('permissions', object(neo4j_ogm_proxy_App_Entity_Generic_PermRole))
(vendor/graphaware/neo4j-php-ogm/src/Proxy/NodeCollectionInitializer.php:22)
at GraphAware\Neo4j\OGM\Proxy\NodeCollectionInitializer->initialize(object(Node), object(neo4j_ogm_proxy_App_Entity_Generic_PermRole))
(vendor/graphaware/neo4j-php-ogm/src/Proxy/LazyCollection.php:52)
at GraphAware\Neo4j\OGM\Proxy\LazyCollection->doInitialize()
(vendor/doctrine/collections/lib/Doctrine/Common/Collections/AbstractLazyCollection.php:332)
at Doctrine\Common\Collections\AbstractLazyCollection->initialize()
(vendor/doctrine/collections/lib/Doctrine/Common/Collections/AbstractLazyCollection.php:274)
at Doctrine\Common\Collections\AbstractLazyCollection->getIterator()
(src/Security/RoleChecker.php:45)
at App\Security\RoleChecker->allowToContinue('8d88d920-5ab0-11e8-a371-001c42dff143', 'd93370b0-585d-11e8-a371-001c42dff143')
(src/Controller/Generic/UserController.php:146)
at App\Controller\Generic\UserController->destroy('c34f1380-5ab5-11e8-a371-001c42dff143')
(vendor/symfony/http-kernel/HttpKernel.php:149)
at Symfony\Component\HttpKernel\HttpKernel->handleRaw(object(Request), 1)
(vendor/symfony/http-kernel/HttpKernel.php:66)
at Symfony\Component\HttpKernel\HttpKernel->handle(object(Request), 1, true)
(vendor/symfony/http-kernel/Kernel.php:188)
at Symfony\Component\HttpKernel\Kernel->handle(object(Request))
(public/index.php:37)
It throws the error on the 2nd foreach loop on line:
foreach ($role->getPermissions() as $perm)
It's strange, working the first time correctly and not the 2nd time. Also after fetching the object again to be sure. Without this it throws the exact same notice.
Thanks in advance!
All code is at github: https://github.com/djkevino/Support4Neo
Honestly, pretty confused by this code. The var_dump() die() stuff in destroy()... Also, took me a while to realize we are talking about code in the library, not your code that interacts with this library.
Can you avoid the issue like so?
//add this next line
if (!is_iterable($user->getPermrole())) continue;
foreach ($role->getPermissions() as $perm)
If you are not on PHP version 7.1 or greater you could simply check if the returned value is_null or test for instance of \Traversable and is_array...
is_array($foo) || (is_object($foo) && ($foo instanceof \Traversable ));
As stated in my comment, not sure if that role having no "permissions" is considered a valid state or not.
It looks like $role->getPermissions() can return a null result. So, make sure the result is not null before executing the inner foreach loop.
Since you seem to be testing if any of the user's roles has the desired permission, you do not need the $allowed variable at all. The inner foreach loop can just immediately return true once a match is found, avoiding unnecessary processing.
That is, try this:
public function allowToContinue($userUuid, $permissionUuid) {
$userRepo = $this->entityManager->getRepository(User::class);
$permRoleRepo = $this->entityManager->getRepository(PermRole::class);
$permissionRepo = $this->entityManager->getRepository(Permission::class);
$user = $userRepo->findOneBy(['uuid' => $userUuid]);
$permission = $permissionRepo->findOneBy(['uuid' => $permissionUuid]);
foreach ($user->getPermrole() as $userRole) {
var_dump($userRole);
$role = $permRoleRepo->findOneBy(['uuid' => $userRole->getUuid()]);
var_dump($role);
$rolePerms = $role->getPermissions();
if (!is_null($rolePerms)) {
foreach ($rolePerms as $perm) {
var_dump($perm->getUuid());
if ($perm->getUuid() === $permissionUuid) {
return true;
}
}
}
}
return false;
}
Related
PHP/Laravel
Hey, I'm moving into abstraction in php and am attempting to validate and store values based on whatever has been submitted, where I expect that the methods should neither know what to validate against and/or which class and method to use to do so -
What I've got works but I can see that there would be issues where classes/methods do not exist. Here lays my question.
If I were to call a method in the following format, which way would be best to 'check' if class_exists() or the method exists()?
public function store(Request $request)
{
$dataSet = $request->all();
$inputs = $this->findTemplate();
$errors = [];
$inputValidators = [];
foreach ($inputs as $input) {
$attributes = json_decode($input->attributes);
if (isset($attributes->validate)) {
$inputValidators[$input->name] = $input->name;
}
}
foreach ($dataSet as $dataKey => $data) {
if (array_key_exists($dataKey, $inputValidators)) {
$validate = "validate" . ucfirst($dataKey);
$validated = $this->caseValidator::{$validate}($data);
if ($validated == true) {
$inputValidators[$dataKey] = $data;
} else {
$errors[$dataKey] = $data;
}
} else {
$inputValidators[$dataKey] = $data;
}
}
if (empty($errors)) {
$this->mapCase($dataSet);
} else {
return redirect()->back()->with(['errors' => $errors]);
}
}
public function mapCase($dataSet)
{
foreach($dataSet as $dataKey => $data) {
$model = 'case' . ucfirst($dataKey);
$method = 'new' . ucfirst($dataKey);
$attribute = $this->{$model}::{$method}($dataKey);
if($attribute == false) {
return redirect()->back()->with(['issue' => 'error msg here']);
}
}
return redirect()->back->with(['success' => 'success msg here'])'
}
For some additional context, an input form will consist of a set of inputs, this can be changed at any time. Therefore I am storing all values as a json 'payload'.
When a user submits said form firstly the active template is found, which provides details on what should be validated $input->attributes, once this has been defined I am able to call functions from caseValidator model as $this->caseValidator::{$validate}($data);.
I do not think that any checks for existence will be needed here as the validation parameters are defined against an input, thus if none exist this check will be skipped using if (array_key_exists($dataKey, $inputValidators))
However, I am dispersing some data to other tables within the second block of code using mapCase(). This is literally iterating over all array keys regardless of if a method for it exists and thus the initial check cannot be made as seen in the first block. I've attempted to make use of class_exists() and method_exists but logically it does not fit and I cannot expect them to work as I'd like, perhaps my approach in mapCase is not correct? I guess if I'm defining a class for each key I should instead use one class and have methods exist there, which would remove the need to check for the class existing. Please advise
Reference:
$attribute = $this->{$model}::{$method}($dataKey);
Solved the potential issue by using class_exists(), considering I know the method names as they are the same as the $dataKey.
public function mapCase($dataSet)
{
foreach($dataSet as $dataKey => $data) {
$model = 'case' . ucfirst($dataKey);
if (class_exists("App\Models\CaseRepository\\" . $model)) {
$method = 'new' . ucfirst($dataKey);
$attribute = $this->{$model}::{$method}($dataKey);
}
if($attribute == false) {
return redirect()->back()->with(['issue' => 'error msg here']);
}
}
return redirect()->back->with(['success' => 'success msg here'])'
}
I have had this app developed for over two years, and nothing has changed on it. But all of a sudden this week, it started throwing out this error.
Trying to get property 'conversation_interlocutors' of non-object
at HandleExceptions->handleError('8', 'Trying to get property 'conversation_interlocutors' of non-object', '/home/admin/web/365onlinework.com/public_html/app/Services/MessageService.php', '47', array('collection' => object(WebsiteUser))) in MessageService.php line 47
So, the script in questions is here.
public function getConversations()
{
$websites = Website::orderBy('created_at', 'desc')->get();
$conversations = collect();
foreach ($websites as $website) {
if (auth()->user()->can('view', $website)) {
$this->tenant->connect($website);
$collections = $website->managed_users()
->with(['user.conversation_interlocutors' => function ($query) {
$query
->select('id', 'read', 'initiatorId', 'interlocutorId')
->where('read', 0)
->orWhere('read', 1)
->has('initiator')
->has('interlocutor')
->has('messages')
->with(['flagged', 'interlocutor.website',
'initiator' => function ($i) {
$i->select('id', 'username');
}])
->withCount('messages');
}])->get();
$filtered = $collections->filter(function ($collection) {
return $collection->user->conversation_interlocutors;
});
foreach ($filtered as $filter) {
$conversations->push($filter->user->conversation_interlocutors);
}
}
}
$conversations = $conversations->flatten()->sortBy('lastMessageTimestamp')->values();
return $conversations;
}
Line 47 is:
return $collection->user->conversation_interlocutors;
I tried to do an if isset to check if it's nulled and it goes through, but then it shows nothing on the output at all. Normally it shows the list of conversations.
As well we already do a check if it has a value while doing the query, this has been running for a long time already, and I am not sure what is causing the error.
This happens because $collection->user is null. To fix it use this code:
$collection->user->conversation_interlocutors ?? null;
or
!empty($collection->user->conversation_interlocutors)
? $collection->user->conversation_interlocutors
: null;
I have one PHP class as below (part of the code):
class myclass{
private static $arrX = array();
private function is_val_exists($needle, $haystack) {
if(in_array($needle, $haystack)) {
return true;
}
foreach($haystack as $element) {
if(is_array($element) && $this->is_val_exists($needle, $element))
return true;
}
return false;
}
//the $anInput is a string e.g. Michael,18
public function doProcess($anInput){
$det = explode(",", $anInput);
if( $this->is_val_exists( $det[0], $this->returnProcess() ) ){
//update age of Michael
}
else{
array_push(self::$arrX, array(
'name' => $det[0],
'age' => $det[1]
));
}
}
public function returnProcess(){
return self::$arrX;
}
}
The calling code in index.php
$msg = 'Michael,18';
myclass::getHandle()->doProcess($msg);
In my webpage says index.php, it calls function doProcess() over and over again. When the function is called, string is passed and stored in an array. In the next call, if let's say same name is passed again, I want to update his age. My problem is I don't know how to check if the array $arrX contains the name. From my own finding, the array seems to be re-initiated (back to zero element) when the code is called. My code never does the update and always go to the array_push part. Hope somebody can give some thoughts on this. Thank you.
There is a ) missing in your else condition of your doProcess() function, it should read:
else{
array_push(self::$arrX, array(
'name' => $det[0],
'age' => $det[1]
)); // <-- there was the missing )
}
Here is a complete running solution based on your code:
<?php
class myclass{
private static $arrX = array();
private function is_val_exists($needle, $haystack) {
if(in_array($needle, $haystack)) {
return true;
}
foreach($haystack as $element) {
if(is_array($element) && $this->is_val_exists($needle, $element))
return true;
}
return false;
}
//the $anInput is a string e.g. Michael,18
public function doProcess($anInput){
$det = explode(",", $anInput);
if( $this->is_val_exists( $det[0], $this->returnProcess() ) ){
//update age of Michael
for ($i=0; $i<count(self::$arrX); $i++) {
if (is_array(self::$arrX[$i]) && self::$arrX[$i]['name'] == $det[0]) {
self::$arrX[$i]['age'] = $det[1];
break;
}
}
} else{
array_push(self::$arrX, array(
'name' => $det[0],
'age' => $det[1]
));
}
}
public function returnProcess(){
return self::$arrX;
}
}
$mc = new myclass();
$mc->doProcess('Michael,18');
$mc->doProcess('John,23');
$mc->doProcess('Michael,19');
$mc->doProcess('John,25');
print_r($mc->returnProcess());
?>
You can test it here: PHP Runnable
As I said in comments, it looks like you want to maintain state between requests. You can't use pure PHP to do that, you should use an external storage solution instead. If it's available, try Redis, it has what you need and is quite simple to use. Or, if you're familiar with SQL, you could go with MySQL for example.
On a side note, you should read more about how PHP arrays work.
Instead of array_push, you could have just used self::$arrX[] = ...
Instead of that, you could have used an associative array, e.g. self::$arrX[$det[0]] = $det[1];, that would make lookup much easier (array_key_exists etc.)
Can you try updating the is_val_exists as follows:
private function is_val_exists($needle, $haystack) {
foreach($haystack as $element) {
if ($element['name'] == $needle) {
return true;
}
return false;
}
I have a static method 'findAll' on a model which basically gets all rows with certain criteria. This method works fine and I can call it using:
$m::findAll();
Where $m is the model name as a variable. I can output this and it returns correct results. However, when assigning this to a variable in the Zend_View object, as:
$this->view->viewvariable = $m::findAll();
I get the error:
Zend_Db_Table_Exception: Too many
columns for the primary key
Any ideas why?
Find all function:
final public static function findAll($where = false, array $options = array()) {
$object = new static();
if (!empty($options)) $options = array_merge($object->options, $options);
else $options = $object->options;
$run = $object->buildDefaultSelect($where, $options);
$rows = $run->fetchAll();
if ($options['asObject'] == true) {
$result = array();
foreach ($rows as $r) {
$class = new static();
$class->setInfo($r);
$result[] = $class;
}
return $result;
} else {
if (count($rows) > 0) return $rows;
else return array();
}
}
Note: This function works fine everywhere apart from when assigning to a view variable. If I run the below (not assigning it to a view variable), it shows the correct array data.
var_dump($m::findAll($module['where'], $module['options']));
exit;
In my view (I have replaced the actual name with viewvariable for the sake of this post):
<?php foreach($this->viewvariable as $item) { ?>
//Do some echoing of data in $item
//Close foreach
I doubt the issue is with Zend_View. It's hard to tell without seeing your code, but my guess is that findAll() is using the Zend_Table_Db find() function incorrectly.
To my knowledge, the only place that throws that exception is the find() function on Zend_Db_Table_Abstract.
Perhaps, inside the findAll() function (or in a function it calls) you're doing one of these:
$zendDbTable->find(1,2) //is looking for a compound key
$zendDbTable->find(array(1,2)) //is looking for two rows
When you really want the opposite.
how can I get a object from an array when this array is returned by a function?
class Item {
private $contents = array('id' => 1);
public function getContents() {
return $contents;
}
}
$i = new Item();
$id = $i->getContents()['id']; // This is not valid?
//I know this is possible, but I was looking for a 1 line method..
$contents = $i->getContents();
$id = $contents['id'];
You should use the 2-line version. Unless you have a compelling reason to squash your code down, there's no reason not to have this intermediate value.
However, you could try something like
$id = array_pop($i->getContents())
Keep it at two lines - if you have to access the array again, you'll have it there. Otherwise you'll be calling your function again, which will end up being uglier anyway.
I know this is an old question, but my one line soulution for this would be:
PHP >= 5.4
Your soulution should work with PHP >= 5.4
$id = $i->getContents()['id'];
PHP < 5.4:
class Item
{
private $arrContents = array('id' => 1);
public function getContents()
{
return $this->arrContents;
}
public function getContent($strKey)
{
if (false === array_key_exists($strKey, $this->arrContents)) {
return null; // maybe throw an exception?
}
return $this->arrContents[$strKey];
}
}
$objItem = new Item();
$intId = $objItem->getContent('id');
Just write a method to get the value by key.
Best regards.