laravel 5 update in database - laravel

I created a row in my 'movies' table called 'slug' where i want to store the slug of the titles of my movies.the problem is i already have 250 movies and i don't want to manually enter the slug to each one of them so i am trying to make a script to automatically update all the slugs.But i failed to do that:
This is my code in FilmController.php:
class FilmController extends Controller {
public function film()
{
$title = DB::table('movies')->select('title');
$slug = str_replace(" ","-",$title);
DB::table('movies')->update(array('slug' => $slug));
}
}
And this is in my routes:
Route::get('update','FilmController#film');
This is the error that pops up when i go to localhost/update:
Object of class Illuminate\Database\Query\Builder could not be converted to string
Can somebody tell me how could i change my code so i can put in my slug field in all the movies the title of the movie with '-' insted of space between the words?

$title is an object containing all titles, and not a string,so str_replace will not work on it
you can try using a loop to update each record according to its title
something like
$titles = DB::table('movies')->select('title','id')->get();
foreach ($titles as $title){
$slug = str_replace(" ","-",$title->title);
DB::table('movies')->where('id',$title->id)->update(array('slug' => $slug));
}

I recomend use a seeder if you want to make a script that update or create default info on your database.
Laravel Database Seeding doc
And title have a collection of titles not a single title.

Related

Get laravel relations value as attribute

I have two models, Portal and Tag and relation many-to-many between them with extra database portal_tag. All working great and I can access to portal->tag without problem.
But my goal is to get this model like "all values from model" and all relations value as one attribute, between commas. Is it possible?
Because I need it inside PortalsExport class in this form to use in export into CSV libary.
Now its look like this:
Portal::with('tags')
->select('url','type','topic','description','prohibited','visits','facebook_url','twitter_url','instagram_url')
->where('user_id', Auth::id())->get();
I have no idea how to make tags.name same as all other options from select.
If you want to get tags relations as comma separated string then One approach is, You will need to define a accessor in your Portal model which will append you tags array into string. like once I was did in one of my project:
Step 1:
public function getTagsAsStringAttribute(): string
{
$array = $this->tags->pluck('name')->all();
return implode(", ",
array_map(function ($k, $v) {
return $k;
}, array_keys($array), array_values($array))
);
}
In above closure functions, plz verify yourself that you tag name value is available in $k or $v variable.
Step 2:
add that accessor in Portal model append array like that:
protected $appends = [
'tags_as_string',
];
Step 3:
In the result of yours below query you will get tags_as_string attribute which contains comma separated tags as string.
Portal::with('tags')
->select('url','type','topic','description','prohibited','visits','facebook_url','twitter_url','instagram_url')
->where('user_id', Auth::id())->get();
If tags_as_string shown empty then try it above query without select() clause.

Get specific values from controller function

I started learning Laravel and I am trying to achieve the following:
Get data from database and display specific field.
Here is my code in the controller:
public function show()
{
$students = DB::select('select * from students', [1]);
return $students;
}
Here is my route code:
Route::get('', "StudentController#show");
That all works for me and I get the following displayed:
[{"id":1,"firstname":"StudentFirstName","lastname":"StudentLastName"}]
How can I get only the "lastname" field displayed?
Thanks in advance!
DB::select('select * from students')
is a raw query that returns an array of stdClass objects, meaning you have to loop through the array and access properties:
$students[0]->lastname
You can also use the query builder to return a collection of objects:
$collection = DB::table('students')->get();
$student = $collection->first();
$student->lastname;
Lastly, using the query builder, you can use pluck or value to get just the last name. If you only have one user, you can use value to just get the first value of a field:
DB::table('students')->where('id', 1)->value('lastname');
I strongly advise you to read the Database section of the Laravel docs.
$students[0]['lastname'] will return the last name field, the [0] will get the first student in the array.
I would recommend creating a model for Students, which would make your controller something like this:
$student = Students::first(); // to get first student
$student->lastname; // get last names
If you only want the one column returned, you can use pluck()
public function show()
{
$last_names= DB::table('students')->pluck('lastname');
return $last_names;
}
This will return an array of all the students' lastname values.
If you want just one, you can access it with $last_names[0]
As a side note, your show() method usually takes a parameter to identify which student you want to show. This would most likely be the student's id.
There are several ways you can accomplish this task. Firstly, I advise you to use the model of your table (probably Students, in your case).
Thus, for example,to view this in the controller itself, you can do something like this using dd helper:
$student = Students::find(1);
dd($student->lastname);
or, using pluck method
$students = Students::all()->pluck('lastname');
foreach($students as $lastName) {
echo $lastName;
}
or, using selects
$students = DB::table('students')->select('lastname');
dd($students);
Anyway, what I want to say is that there are several ways of doing this, you just need to clarify if you want to debug the controller, display on the blade...
I hope this helps, regards!

Laravel slug performance eloquent

I have setup a route like this:
Route::get('/prod/{id}/{title?}', 'Web\GetItemController#getItem')->where('id', '[0-9]+')->name('prod.item');
This is to retrieve a item based on the id the title is only a optional parameter in order to make the url look somewhat nicer.
Then in the controller I fetch the item like this:
class GetItemController extends Controller
{
public function getItem($id, $title = null)
{
$item = new product();
$data = $item->getProdInfo($id);
// Show view with data...
}
}
So I should be able to fetch the item with or without the title parameter.
So a call like this would trigger the route "https://www.x.com/prod/3/sonic-free-games"
But is there any difference in performance using slug like I do above?
/prod/{id}/{title?} vs /prod/{id}

Laravel 5 - relationships and handling data

I have a system whereby you can create Documents of different types. Initially, I had a new Model for each Document, but I don't think this is the best way because it can get messy fast. So what I wanted to do is make a generic Documents model, and have individual documents come from this. I have come up with the following type of design
So a Document can have one DocumentA and one DocumentB. DocumentA and DocumentB can only ever be created once per project which is why I have this relationship. Now each form for each document has an upload button, where supporting documents can be uploaded alongside the generated document. So Documents can have one to many FileUploads.
This is where I am confused. A person visits my portal and selects the option to create DocumentA. A form is now displayed to them which looks something like the following
So they enter the data for DocumentA, upload supporting documents, and then click submit.
Now I am thinking about how this can be handled within Laravel.
From what I understand, it will be something like the following
public function store(Request $request, Project $project)
{
$document = new Documents();
$document->documentName = 'Something';
$document->documentA = new DocumentA();
$document->documentA->startDate = Input::get('startDate');
$document->documentA->endDate = Input::get('endDate');
$document->documentA->notes = Input::get('notes');
if (Input::hasFile('filePath')) {
$files = Input::file('filePath');
foreach($files as $file) {
$fileString = "";
$file->move(public_path('uploads'), $file->getClientOriginalName());
$fileString .= public_path('uploads') . '/' . $file->getClientOriginalName();
$document->fileUpload = new FileUploads();
$document->fileUpload->filename = $file->getClientOriginalName();
$document->fileUpload->mime = $file->getClientOriginalExtension();
$document->fileUpload->filepath = $fileString;
$document->fileUpload->documentId = $document->id;
}
}
$document->save();
return Redirect::route('projects.documentA.edit', compact('project', 'documents'));
}
Really, looking for advice as to whether I am designing this correctly, and whether I am handling it correctly within Laravel. I am going to end up with many different Documents, each of them accepting different input.
Any advice appreciated.
Thanks
you want to create different tables for each doc? like you showed above for A and B. It will become messy. Why do not you just manage this in one table by using some identifier col?
If you create one table for documents, one for fileUploads then you would create relationship between them like so
File upload model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class File extends Model
{
/**
* each file belongs to a document
*/
public function document()
{
return $this->belongsTo('App\Document', 'foreign_key', 'primary_key');
}
}
Document model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Document extends Model
{
/**
* document has multiple files
*/
public function files()
{
return $this->hasMany('App\File', 'foreign_key', 'primary_key');
}
}
Then you can access the records like this
$documents->files()->where('id', 1)->get();
//gives file associated with document id 1

Laravel - CreateMany if not exists

I have a table that stores tags name as "tag"
tag
id->Integer(unique)
title->String;
url->string;(unique)
Also I have a table to store places named as place
place
id->Integer(unique)
title->string
latitude->string
longtitue->string
A place may have many tags, here is my place_tag table
place_tag
id->Integer(unique)
tag_id->Integer
place_id->Integer
when I try to update place I need to do this
1- check all tags posted.
2- add them to "tag" db if not created before
3- write relationship with tag and place
But I think Laravels ORM can handle it, I'm walking around but can't find a good solution.
Please see my update procedure what am I doing wrong.
public function update($id)
{
$place=Place::findOrFail($id);
$place->fill(Input::all());
$place->save();
$tags=explode(',',Input::get('tags'));
$tags_data=array();
foreach($tags as $tag) {
$tags_data[]=new Tag(array('title'=>$tag,'url'=>$tag));
}
$place->tags()->detach();
$place->tags()->saveMany($tags_data);
return Redirect::to('admin/places');
}
You can do it this way:
$tagIds = [];
foreach ($tags as $tag) {
$tag = trim($tag);
if ($tag == '') {
continue;
}
$fTag = Tag::firstOrCreate( [ 'title' => $tag, 'url' => $tag ] );
$tagIds[] = $fTag->id;
}
$place->tags()->sync($tagIds);
I assumed one Tag can be set to many Places (n:n relationship), so first you basically find tags and if it doesn't exist you create it and then using sync you synchronize relationship table (insert or remove data from pivot when necessary)

Resources