Im passing the id of an user to a controller. This id is used to fill a field of another Entity so this entity can know where it belongs to. The code of the controller is
public function nuevamedidaAction($id, Request $peticion){
$em = $this->get('doctrine')->getEntityManager();
$medida = new \Goodday\PreditBundle\Entity\Medida;
$medida->setHijo($id);
$form = $this->createForm(new \Goodday\PreditBundle\Form\MedidaType(), $medida);
$form->handleRequest($peticion);
if ($form->isValid()) {
$em->persist($medida);
$em->flush();
return $this->render('PreditBundle:Default:test2.html.twig');
}
return $this->render('PreditBundle:Medida:newmedida.html.twig', array('form' => $form->createView(), 'error' => $form->getErrors()));
}
now the field "hijo" in my entity looks like:
/**
* #ORM\ManyToOne(targetEntity="Hijo", inversedBy="medidas", cascade={"remove"})
* #ORM\JoinColumn(name="hijo_id", referencedColumnName="id")
*/
protected $hijo;
It returns me the following error
"Catchable Fatal Error: Argument 1 passed to Goodday\PreditBundle\Entity\Medida::setHijo() must be an instance of Goodday\PreditBundle\Entity\Hijo, string given, called in C:\Users\Diego\Desktop\Practicas\predit\src\Goodday\PreditBundle\Controller\HijoController.php on line 74 and defined in C:\Users\Diego\Desktop\Practicas\predit\src\Goodday\PreditBundle\Entity\Medida.php line 461"
Thanks for all your answers
The error is clear: Argument 1 passed to Goodday\PreditBundle\Entity\Medida::setHijo() must be an instance of Goodday\PreditBundle\Entity\Hijo, string given
You must pass an Hijo object to the method setHijo
$hijo = $em->getRepository('GooddayPreditBundle:Hijo')->find($id);
$medida->setHijo($hijo);
Hope it's helpful.
Best regard.
Related
I have entity User with field roles:
/**
* #ORM\Column(name="roles", type="json")
*/
private $roles = [];
public function getRoles(): array
{
return $roles = $this->roles;
}
public function setRoles($roles): self
{
$this->roles[] = $roles;
return $this;
}
I want to add functionality to update user role from ROLE_ADMIN to ROLE_USER. I tried this in my controller but instead of replacing ROLE_ADMIN with ROLE_USER it inerts this: "ROLE_ADMIN""ROLE_USER". This is my controller:
public function updateuser(Request $request, $id) {
$entityManager = $this->getDoctrine()->getManager();
$usr = $this->getDoctrine()->getRepository(User::class)->find($id);
$usr->setRoles("ROLE_USER");
$entityManager->persist($usr);
$entityManager->flush();
First of all its best practice that every users has at least a default role like ROLE_USER. If you want to give users extra roles then you add them with beside ROLE_USER, like for example ROLE_ADMIN.
Now take a close look how arrays work in PHP. Let's take the code of you setter function setRoles.
When you write the value assignment like this $this->roles[] = $roles, then a value is added to the array . Thats why you in you code you have both roles inside you array now. The already existing ROLE_ADMIN and after the function call you added ROLE_USER.
When you write the value assignment like this $this->roles = $roles, then the whole array is overwritten with the new value.
Conclusion:
Thats how you code should look like if you want a simple solution:
public function setRoles(array $roles): self
{
$this->roles = $roles;
return $this;
}
Then you can call it like this:
$user->setRoles(['ROLE_USER']);
The setRoles function only accepts array.
So your code should change accordingly:
$usr->setRoles(["ROLE_USER"]);
Furthermore, if you want to store it as json, you can use json_encode:
$usr->setRoles(json_encode(["ROLE_USER"]));
I have these union in my controller :
$expression = new Expression('"News"');
$featuredNews2= news::find()
->alias('ne')
->select(['ne.title', 'ne.content','ne.featuredOrder', 'category'=>$expression])
->innerJoinWith('featuredOrder1');
$expression2 = new Expression('"Event"');
$featuredEvents2 = event::find()
->select(['ev.title', 'ev.content','ev.featuredOrder','category'=>$expression2])
->from('event ev')
->innerJoinWith('featuredOrder2');
$union = $featuredNews2->union($featuredEvents2);
The relation in model :
news model
public function getFeaturedOrder1()
{
return $this->hasOne(Featured::className(), ['featuredOrder' => 'featuredOrder']);
}
event model
public function getFeaturedOrder2()
{
return $this->hasOne(Featured::className(), ['featuredOrder' => 'featuredOrder']);
}
I need to return the query as an Active Query because I need to access my model's method e.g : $model->featuredOrder1->preview in my view.
The following works but it returns an array, as the result I can't access my model's method :
$unionQuery = (new \yii\db\Query)->select('*')
->from($union)
->orderBy('featuredOrder')->all(\Yii::$app->db2);
I have two questions :
How to return the equivalent $unionQuery above but as an active query object? I have googled and search on SO but what I found is how to return it as array.
This is out of curiosity, I wonder why I should provide my db connection as argument in my $unionQuery all() method above. If I didn't use an argument that point to db2, it will look for table name inside my db database instead ( db is my parent database, this db2 is my module's database/the correct one). This only happen with a union. My news and event model already have this in getdb() function:
return Yii::$app->get('db2');
update
I've tried this too :
$unionProvider = (new ActiveQuery(Featured::className()))->select('*')
->from(['union' => $featuredEvents2->union($featuredNews2)])
->orderBy('featuredOrder');
With this relation in featured model:
public function getNews()
{
return $this->hasOne(News::className(), ['featuredOrder' => 'featuredOrder']);
}
public function getEvents()
{
return $this->hasOne(Event::className(), ['featuredOrder' => 'featuredOrder']);
}
and in the view, I tried this :
foreach($unionProvider as $key=>$model){
echo $model->news->title;
}
but get this error : Trying to get property of non-object
Update 2
I forgot to add ->all() in my $unionProvider, but after that I got this error instead : PHP Fatal Error – yii\base\ErrorException
Allowed memory size of 134217728 bytes exhausted (tried to allocate 12288 bytes)
Might be something wrong with my query? Can't figure it out
You can try using pure SQL. Plus you can test to see if it is returning the correct results and then add it in the statement below.
$customers = Customer::findBySql('SELECT * FROM customer')->all();
Learn more in yii docs
In Laravel After recording last row to a DB table, can I safely access same recorded data right after recording it by calling latest() queries? Because transactions by other users may occur at the same time, and it may not really be the last record anymore?
Edit:
For example:
Public function StoreNotif($data){
auth()->user()->Notif()->create(store $data here..)
}
Public function SendNotif(){
$data="123";
$this->StoreNotif($data)
event(new Notification(stored Notif instance?));
}
No, you cannot rely on the database to return the record from your current script.
The ->latest() method will always sort the records with the most recent created_at date first.
https://laravel.com/docs/6.x/queries#ordering-grouping-limit-and-offset
But you haven't provided any code or explanation as to why this is a concern. If you just created a new record, why do you need to query it again? You should already have access to an instance of the model.
EDIT: I've made a few edits to demonstrate how you would pass the model from a controller to an event as referenced in the comments. Please post your code if you want more specific help.
SomeController.php
function store()
{
$model = Model::create([
'some_data' => 1
]);
// fire an event with the newly created model
event(new SomeEvent($model));
dd($model);
}
------------------------
Model {
// ...
attributes: [
'id' => 101,
'some_data' => 1
'created_at' => '2019-10-06 12:48:01',
'updated_at' => '2019-10-06 12:48:01',
]
// ...
}
SomeEvent.php
<?php
namespace App\Events;
use App\Model;
use Illuminate\Queue\SerializesModels;
class SomeEvent
{
use SerializesModels;
public $model;
public function __construct(Model $model)
{
$this->model = $model;
// ...
}
}
EDIT: Per your newly added code, you just need to pass the new model back to the original method. You could do something like this.
Public function StoreNotif($data)
{
// add a return statement
return auth()->user()->Notif()->create(store $data here..);
}
Public function SendNotif()
{
$data="123";
// store the returned data to a variable
$model = $this->StoreNotif($data);
// call the event with the model instance
event(new Notification(model));
}
I'm not sure what 'latest' is but I do know that MySQL uses SELECT LAST_INSERT_ID as the query to get the 'per-connection' id of the last inserted item. Under the covers it's using mysql_insert_id so if you are in a language that supports it, you could use that too.
I'm having trouble with Yii2 Role Based Access Control. In the usual set-up, the authentication rule takes place when the identity of the current user. Like written in the docs. Authorization
In my case, how can I set up the authorization (aside from the basic feature) using another set of models.? Here is my set up.
Table auth_assignment [item_name, user_id] from rbac migration,
user [id] from the yii2 migration.
I created a new table assignment [user_id related to user, rec_id related to recognition of an organization].
This is the scenario. I have the roles admin, organization-head, member. How can I check if the organization-head, or member belongs to their own Recognition module; not the other modules from other organization-heads?
I used also the context access control filter by peixoto.
Here is my code for checking. RecognitionRule checks if there is a user user_id equal to the identity of the user; and account_id equal to rec_id. The second condition tells if he is belong to the organization
/**
* Checks if ID matches user passed via params
*/
class RecognitionRule extends Rule
{
public $name = 'isRecognition';
/**
* #param string|integer $user the user ID.
* #param Item $item the role or permission that this rule is associated with
* #param array $params parameters passed to ManagerInterface::checkAccess().
* #return boolean a value indicating whether the rule permits the role or permission it is associated with.
*/
public function execute($user, $item, $params)
{
if(isset($params['recognition'])){ //Directly specify the model you plan to use via param
$model = $params['recognition'];
}else{ //Use the controller findModel method to get the model - this is what executes via the behaviour/rules
$id = Yii::$app->request->get('id'); //Note, this is an assumption on your url structure.
$model = Yii::$app->controller->findModel($id); //Note, this only works if you change findModel to be a public function within the controller.
}
return \common\models\Assignment::find()->where(['rec_id' => $model->id, 'user_id' => $user])->exists();
}
}
Still, I am not allowed to perform the action. Any clues?
I got the answers. I based my answer on AccessRule behavior and rbac\Rule $params
snippet of the RecognitionRule
/**
* #param string|integer $user the user ID.
* #param Item $item the role or permission that this rule is associated with
* #param array $params parameters passed to ManagerInterface::checkAccess().
* #return boolean a value indicating whether the rule permits the role or permission it is associated with.
*/
public function execute($user, $item, $params)
{
if(isset($params['recognition'])){ //Directly specify the model you plan to use via param
$model = $params['recognition'];
} else{ //Use the controller findModel method to get the model - this is what executes via the behaviour/rules
$id = Yii::$app->request->get('id'); //Note, this is an assumption on your url structure.
}
return \common\models\Assignment::find()->where(['rec_id' => $id, 'user_id' => $user])->exists();
}
}
?>
RecognitionController
[
'class' => 'common\rbac\ContextAccessRule',
'modelClass' => 'frontend\models\recognition',
'allow' => true,
'actions' => ['view','update'],
'roles' => ['viewOwnRecognition', 'updateOwnRecognition'],
],
],
],
];
I have the following code
public function findAccessible(Query $query, array $options){
return $this->findPublic($query, $options)
->union($this->findMyAdmin($query, $options));
}
public function findPublic(Query $query, array $options){
return $query
->where(['public' => true]);
}
public function findMyAdmin(Query $query, array $options){
return $query
->where(['admin_user_id' => $options['User.id']]);
}
The findAccessible call gives me this error message in Chrome: ERR_EMPTY_RESPONSE
No other error message, no entry in error log. I am sure that is because of the union call. How to do it?
What I want to achieve:
groups hasAndBelongsTo users
groups: id, name, admin_user_id, public
I would like to get groups
1) what are public groups (This is ok, findPublic method)
2) where admin_user is the given user (This is ok, findMyAdmin method)
3) in where the given user is a member (This is ok, I could do it with an other find()->matching call)
4) which are accessible for the user, eg. public OR the given user is admin OR a member - meaning the union of 1), 2) and 3) - that is with what I am struggling. If I put all these to one find method I can not define OR relationship for the membership, as that is done by matching what is translated into an inner join.
I found a really ugly but working solution.
public function findAccessible(Query $query, array $options){
$qq = $this->query($query);
$memberships = $qq->matching('Users', function($q) use ($options){
return $q->where(['Users.id' => $options['User.id']]);
});
foreach($memberships as $m){
$memberInGroup[] = $m->id;
}
return $query
->where(['public' => true])
->orWhere(['admin_user_id' => $options['User.id']])
->orWhere(['Groups.id IN' => $memberInGroup]);
}
I hope somebody will find a better solution and post here.