How to get data from intermediate table in eloquent, silex - php

I created database tables users, groups, and group_user (MySQL).And group_user table (intermediate table) contains the user_id and role_id. users and groups relationship is many to many. I want to delete a group in groups table. Before deleting a group, I want to check if there is any user belongs to that group.
I tried to do it this way.
Group.php (Model)
public function users()
{
return $this->belongsToMany('\Modules\User\Models\User');
}
Service.php
public function deleteGroup($data) {
if (!isset($data['groupID']))
return ['error' => 'Failed to delete group. Group id is required'];
$group = Group::find($data['groupID']);
if (!$group)
return ['error' => 'Failed to delete group. Group not found'];
// check any user belongs to group.
$result = $group->users()->pivot->user_id;
if(!$result){
$group->delete();
return ['success' => 'Successfully delete group.'];
}
return ['error' => 'Failed to delete group. Group not found'];
}
But this doesn't work.

I find it out.
service.php
public function deleteGroup($data) {
$group = Group::find($data['groupID']);
if (!$group){
return [
"msg" => "Failed to delete group. Group not found."
];
}
// find out any one belongs to the group.
$result = $group->users->first()->userID;
if ($result){
return [
"msg" => "Failed to delete group. Group has users."
];
}
$result = $group->delete($data['groupID']);
if(!$result){
return [
"msg" => "Failed to delete group."
];
}
return [
"msg" => "Successfully deleted group."
];
}
This is how I do it. If there is another way please tell me. Thanks.

Related

How to validate pivot table in Laravel?

In the admin panel, I have something called Group that an admin can make a group of users so my scheme is:
groups table contains:
id
name
1
group1
group_user table contains:
id
group_id
user_id
1
1
2
2
1
3
My logic is: if a user belongs to a group, that user cannot be added again to the same group:
In update, when I add a user that already exists in group, it added it again:
public function update($id, Request $request)
{
$request->validate([
'name' => 'sometimes|nullable|string',
'user_ids' => 'sometimes|array',
]);
$group = Group::findOrFail($id);
$group->update($request->only('name'));
if ($ids = $request->user_ids) {
$group->users()->attach($ids);
}
return $this->apiRespone(null, 'group updated successfully', null, 200);
}
Just check if user already is in the group before attaching to it:
public function update($id, Request $request)
{
$request->validate([
'name' => 'sometimes|nullable|string',
'user_ids' => 'sometimes|array',
]);
$group = Group::findOrFail($id);
$group->update($request->only('name'));
foreach($request->user_ids as $user_id) {
if (!$group->users()->where('id', $user_id)->exists()) {
$group->users()->attach($user_id);
}
}
return $this->apiRespone(null, 'group updated successfully', null, 200);
}
Update:
To get the list of already existing members, apply this in your loop logic:
$existingUsers = [];
foreach($request->user_ids as $user_id) {
if (!$group->users()->where('id', $user_id)->exists()) {
$group->users()->attach($user_id);
} else {
$existingUsers[] = $user_id;
}
}
// now you can use $existingUsers

How to add and update in one api in laravel

I am trying to add and update using the same API, currently, I can add but I am not clear about how to update using the same API.
I am adding folders against id and my body response looks like this:
{
"id": "2",
"folder_detail": [1,3,4]
}
I can add folders with id 1,3 and 4 against id 2 but next time when I hit the same API with folder[1,3,5] it should update folders details not should add again, I can do that by making separate API but I want to do that in one API.
My Controller code:
try {
$folder = Doctor::where('id', $request->get('id'))->first();
$folder->doctor()->attach($request->get('folder_detail', []));
DB::commit();
return response([
'status' => true,
'message' => 'Folder detail added',
], 200);
} catch (\Exception $ex) {
DB::rollback();
return response([
'status' => false,
'message' => __('messages.validation_errors'),
'errors' => $ex->getMessage(),
], 500);
}
}
public function doctor()
{
return $this->belongsToMany('App\Folder', 'folder_details');
}
Your help will be highly appreciated?
Okay so after our back and forth in the comments I think you are looking for something like this:
$folders = $request->get('folder_detail', []);
foreach($folders as $folder) {
$record = Folder::firstOrNew(['id', $folder]);
$record->doctor_id = $request->id;
// You can add your own records here, or use the 'fill' function
}
So, this way, you loop through all your folders. Check if the folder with the specific ID already exists, if it does not, it creates a new one. The doctor is linked through the doctor_id on your record.
Find record if exist then update otherwise create
$post = $request->all();
$doctor = Doctor::find($post['id']);
if($doctor){
$doctor->update([
//your data for update doctor model
]);
//remove old folders which is related with this doctor
Folder::where('doctor_id', $doctor->id)->delete();
//add current data of folder
if(!empty($post['folder_detail'])){
foreach($post['folder_detail'] as $folder){
Folder::create([
'doctor_id' => $doctor->id,
'folder_detail' => $folder
]);
}
}
//return your response here
} else {
$doctor = Doctor::create([
//data for create doctore
]);
//add current data of folder
if(!empty($post['folder_detail'])){
foreach($post['folder_detail'] as $folder){
Folder::create([
'doctor_id' => $doctor->id,
'folder_detail' => $folder
]);
}
}
//return your response here
}

laravel auth() is not allowing a user to make a post request

A user should be able to set a rating for more than one book, it allows a user to set a rating for ONLY one book, but not any other.
The problem
the user is not able to make another rating for
another book. However, another user
can make a rating for the same book, but cant make another rating for
other books. Not even if the user logged out.
I'm using rateYo and laravel-ratable
The way i have it set up, a rating type is set to false by default, enabling a user to set stars and make a rating pretty much.
And once again, once a user makes a rating for any book doesn't matter which, the rating type is set to true which disables a user to set a star.
Here is what i have
here is how the html setup is like
HTML
<div id="rateYo" data-rateyo-rating="{{ $book->userSumRating or 0}}" data-rateyo-read-only="{{ $book->rated ? 'true' : 'false' }}"></div`>
BookController.php
public function rate(Request $request, $book_id)
{
$book = Book::find($book_id);
$rating = $book->ratings()->where('user_id', auth()->user()->id)->first();
if(is_null($rating)){
$ratings = new Rating();
$ratings->rating = $request['rating'];
$ratings->user_id = auth()->user()->id;
$ratings->type = Book::RATED;
$book->ratings()->save($ratings);
return json_encode($book);
}
else{
return response()->json(['status' => 'You already left a review']);
}
}
public function show($book_name)
{
$books = Book::GetBook($book_name)->get();
$data = $books->map(function(Book $book){
$book['rated'] = $book->type;
return $book;
});
return view('books.show', compact('data', $data));
}
Book.php(relevant code) On default if a rating has not been set, type is equal to false enabling the user to make a rating, if a rating is set, type is equal to true disabling the star feature/read mode.
use Rateable;
const RATED = "true";
const NOT_RATED = "false";
protected $fillable = [ 'user_id', 'title', 'description'];
protected $appends = ['rated'];
public function getRatedAttribute()
{
return Rate::where('type', $this->owl() )->where('user_id', auth()->user()->id )->first();
}
public function owl(){
foreach($this->rate as $rates){
if ($rates->type != "true"){
return self::NOT_RATED;
}
}
return self::RATED;
}
public function rate()
{
return $this->hasMany('App\Rate', 'type', 'user_id');
}
You need to add the book id in the where clause to check if the user has left a rating for that particular book. As you have it it will find the first rating a user has left for any book.
$constraints = [
'user_id' => auth()->id(),
'book_id' => $book_id
];
// checks if the user has not left a rating for this particular book
if ($book->ratings()->where($constraints)->doesntExist()) {
// create new rating...
} else {
// user has already rated this book...
}
i need to change my Book model to the following, thank you digital for steering me into the right direction
Book.php
public function getRatedAttribute()
{
$this->constraints = [
'user_id' => auth()->id()
];
if(Rating::where($this->constraints)->exists()){
return Rating::where(['type' => self::RATED, 'book_id' => $this->getKey()])->first();
}else{
return Rating::where('type' ,self::NOT_RATED)->first();
}
}

Trying to update attribute result in mass-update [Laravel 5]

I'm trying to change a value in my DB for a single item, I use first() to get an item, but for some reason when I try this function, every entry with the same primary key has the authenticated user gets the attribute 'AreFriend' updated at 1, why?
public function acceptrequest($id)
{
$user = app('Dingo\Api\Auth\Auth')->user();
if (!$targetuser = User::find($id)) {
return response()->json(['status' => "The requested resource does not exists!"], 403);
}
if ($relation = $user->requestspending()->where('user_id', $targetuser->user_id)->first()) {
Friend::unguard();
$relation->AreFriend = 1;
$relation->save();
Friend::unguard();
Friend::reguard();
return response()->json(['status' => "Request accepted!"], 200);
} else {
return response()->json(['status' => "You do not have an invitation from this user!"], 403);
}
}
In my database, relations with the $user id are updated. The variable $relation is an item, not a collection.

How to set multi select value from array object in yii2 while updating

I have table which have multiple reference to ohter tables like
user
id name email
categories
id title
user_categories
user_id category_id
Here a user will have multiple category associated with him/her
I am able to save these successfully with new records like following
View File:
echo $form->field($package_categories, 'category_id')->dropDownList( ArrayHelper::map(
StudyMaterialCategories::find()->all(), 'id', 'title'),
['multiple' => true]
);
Save New record:
$model = new Packages();
$package_categories = new PackageCategories();
$request = Yii::$app->request;
if ($request->isPost) {
$transaction = Yii::$app->db->beginTransaction();
try {
$post = $request->post();
$model->load($post);
$model->save();
foreach ($post['PackageCategories']['category_id'] as $key => $value) {
$package_categories = new PackageCategories();
$package_categories->category_id = $value;
$package_categories->package_id = $model->id;
$package_categories->save();
}
$transaction->commit();
return $this->redirect(['view', 'id' => $model->id]);
} catch (Exception $ex) {
$transaction->rolback();
Yii::$app->session->setFlash("error", $ex->getMessage());
}
}
Till now It's running successfully.
But I'm stuck when going to update the table. The problem part is dropdown list. How to set multiple selected option as per database if I'm coming with array of object.
Have a look on the following code
$package_categories = PackageCategories::find()
->where('package_id=:package_id', ['package_id' => $id])->all();
if (count($package_categories) < 1) {
$package_categories = new PackageCategories();
}
$request = Yii::$app->request;
if ($request->isPost) {
$transaction = Yii::$app->db->beginTransaction();
try {
$post = $request->post();
$model->load($post);
$model->save();
$package_categories = new PackageCategories();
$package_categories->deleteAll(
"package_id=:package_id",
[':package_id' => $model->id]
);
foreach ($post['PackageCategories']['category_id'] as $key => $value) {
$package_categories = new PackageCategories();
$package_categories->category_id = $value;
$package_categories->package_id = $model->id;
$package_categories->save();
}
$transaction->commit();
return $this->redirect(['view', 'id' => $model->id]);
} catch (Exception $ex) {
$transaction->rolback();
Yii::$app->session->setFlash("error", $ex->getMessage());
}
}
if I try to get first object of the array $package_categories of only able to set selected one option
This is an example code of a model class Permit which has a many to many relationship with Activity through PermitActivity (pivot table model).
Model Class Activity
public class Permit extends \yii\db\ActiveRecord {
public $activities_ids;
...
public function rules() {
return [
...
[['activities_ids'], 'safe'],
...
];
}
...
// Method called after record is saved, be it insert or update.
public function afterSave($insert, $changedAttributes) {
// If this is not a new record, unlink all records related through relationship 'activities'
if(!$this->isNewRecord) {
// We unlink all related records from the 'activities' relationship.
$this->unlinkAll('activities', true);
// NOTE: because this is a many to many relationship, we send 'true' as second parameter
// so the records in the pivot table are deleted. However on a one to many relationship
// if we send true, this method will delete the records on the related table. Because of this,
// send false on one to many relationships if you don't want the related records deleted.
}
foreach($this->activities_ids as $activity_id) {
// Find and link every model from the array of ids we got from the user.
$activity = Activity::findOne($activity_id);
$this->link('activities', $activity);
}
parent::afterSave($insert, $changedAttributes);
}
...
// Declare relationship with Activity through the pivot table permitActivity
public function getActivities(){
return $this->hasMany(Activitiy::className(), ['id' => 'activity_id'])
->viaTable('permitActivity',['permit_id' => 'id']);
}
...
public function afterFind(){
parent::afterFind();
$this->activities_id = ArrayHelper::getColumn($this->activities, 'id');
}
}
This way the model class is the one responsible for creating and updating the relationship using the pivot table.
The most important thing is to have the relationship method declared correctly.
Edit
This is an example of the view using kartikv\widgets\Select2. I don't really know if dropDownList supports multiple select, however Select2 has so many useful features i usually use it over other options.
echo $form->field($model, 'activities')->widget(Select2::classname(), [
'data' => $data,
'options' => [
'placeholder' => '...'
],
'pluginOptions' => [
'allowClear' => true,
'multiple' => true,
],
]);

Categories