How to do multi level self join in laravel 5.4
i have table like this.
ID name ParentId
1 abc 0
2 acd 1
3 ads 1
4 xyz 2
5 xxy 2
6 plm 3
7 ytr 4
8 lks 6
Now i need:
# if i call id 1 it will return full tree under it.
# if i call it empty it will return full tree
# i did this
public function getParent() {
return $this->belongsTo(self::class, 'ParentId','id');
}
public function getChild(){
return $this->hasMany(self::class, 'ParentId','id');
}
its giving me single brunch but i need full of them.
some one plz help.
public function chartLedgre($headId) {
$mainHead = self::where('id',$headId)->get();
if(count($mainHead[0]->childs) > 0){
foreach ($mainHead[0]->childs as $child){
if($child->chart_type == 'L'){
$this->data[] = $child->id;
}else{
$this->chartLedgre($child->id);
}
}
}else{
if($mainHead[0]->chart_type == 'L'){
$this->data[] = $mainHead[0]->id;
}
}
return $this->data;
}
Related
Hi i'm just started to learn laravel and i have 2 database tables that i want to modify, the first one is the main table which is products and the other table is upsells which will connect two entity from products table:
products
id
name
price
1
Bag
300
2
Belt
100
3
ring
120
4
Hat
250
5
Scarf
125
upsells
id
product_id_1
product_id_2
1
2
1
2
2
4
3
2
5
4
5
4
5
5
1
the idea is product enitty can be connected to the one or more product using the upsells table. the product_id_1 will be the main product that will point to the product_id_2
Currently i'm using this method to retrieve the relationship:
public function getUpsells($mainProductId){
$upsells = Upsell::where('product_id_1', $mainProductId);
$results = array();
foreach($upsells as $upsell){
$results[] = $upsell->product_id_2;
}
return $results;
}
$mainProductId = 5;
$relatedProducts = array(2,3);
public function updateUpsells($mainProductId,$relatedProducts){
foreach($relatedProducts as $relatedProduct){
//create if not exists
$upsell = Upsell::where('product_id_1', $mainProductId)->
where('product_id_2', $relatedProduct)->first();
if(empty($upsell->id)){
$upsell = new Upsell;
$upsell->product_id_1 = $mainProductId;
$upsell->product_id_2 = $relatedProduct;
}
}
//delete if not in the array input
Upsell::where('product_id_1', $mainProductId)->
whereNotIn('product_id_2', $relatedProducts)->delete();
}
Is there any simplified method or any method that i'm missing based on laravel best practice ?
You can use eloquent relationships. Based on your code I think you have these relationships between your models:
Products hasMany upSells,
so in your Products.php you will have to add relation like this:
public function upSells(){
return $this->hasMany(UpSells::class, 'product_id_1', 'id');
}
This way you can fetch upsells from products like this:
$products = Product::with('upSells')->find(1);
The same thing you can do with your other relationships. You just have to define which will be the parent and which will be the child in the relationship.
For more information, you can go through this.
CURRENT SOLUTION WHICH IS NOT RECOMMENDED
public function getUpsells($mainProductId)
{
return Upsell::where('product_id_1', $mainProductId)->pluck('product_id_2'); //This will give you array of product_id_2.
}
$mainProductId = 5;
$relatedProducts = [2, 3];
public function updateUpsells($mainProductId, $relatedProducts)
{
Upsell::where('product_id_1', $mainProductId)->delete();
foreach($relatedProducts as $relatedProduct){
$upsells = [
[
'product_id_1' => $mainProductId,
'product_id_2' => $relatedProduct
]
];
}
Upsell::insert($upsells);
}
RECOMMENDED SOLUTION
Important docs,
https://laravel.com/docs/8.x/eloquent-relationships
https://laravel.com/docs/8.x/migrations
You have to make a relation in the product model make migration of pivot table.
public function upsells()
{
return $this->hasMany(Upsell::class, 'product_id_1', 'id')
}
then getUpsells() and updateUpsells() be like,
public function getUpsells($mainProductId)
{
$products = Product::with('upsells')->findOrFail($mainProductId);
return $products->upsells->product_id_2;
}
$mainProductId = 5;
$relatedProducts = [2, 3];
public function updateUpsells($mainProductId, $relatedProducts)
{
$product = Product::findOrFail($mainProductId);
$product->upsells()->sync($relatedProducts);
}
I'm trying to find a way to do \App\Goal::find(1)->children and get returned all children, and childrens children.
With the database pasted below I want
\App\Goal::find(1)->children
to return
2, 4 and 5. Currently I can only do \App\Goal::find(1)->goals, which returns only 2 and 4
I have a database like this:
id user_id goal_id objective
1 1 NULL Get rich
2 1 1 Save $5
3 1 NULL Learn to cook
4 1 1 Save $10,000
5 1 4 Buy stocks
6 1 5 Buy 5x Intel
7 1 5 Buy 5x AMD
How would you go about creating the children() function in the Goal model?
Please ask if any important info is missing from this
Edit:
Goal.php:
public function user()
{
return $this->belongsToUser(User::class);
}
public function goals()
{
return $this->hasMany(Goal::class, 'goal_id')
}
When I run \App\Goals::find(1)->goals in the GoalController it returns the children of itself (with id 2 and 4 from the example db table), but not its grandchildren...
ID 5 from the example table has a parent of id 4, which itself has a parent id of 1.
So how could I get \App\Goal::find(1)->children or \App\Goal::find(1)->goals to return its grandchildren, and their children etc?
So, assuming the table you've posted is the goals table, related to App\Goal...
If you have these two relationships set up on the model:
public function children()
{
return $this->hasMany(Goal::class, 'parent_id');
}
public function childrenRecursive()
{
return $this->children()->with('children');
}
You can call Goal::with('childrenRecursive')->get() which will return a nested collection of all the children and children's children.
If you'd like all of the children in a flat array, you could do something like this:
public function getFamilyAttribute()
{
$family = collect([]);
$children = $this->children;
while (!is_null($children )) {
$family->push($children);
$children = $children->children;
}
return $family;
}
I have 4 models:
Stream
Field
Document
Result
I then have below relationships defined:
Stream.php:
public function fields()
{
return $this->hasMany(Field::class);
}
public function documents()
{
return $this->hasMany(Document::class);
}
Field.php:
public function stream()
{
return $this->belongsTo(Stream::class);
}
public function result()
{
return $this->hasOne(Result::class);
}
Document.php:
public function stream()
{
return $this->belongsTo(Stream::class);
}
Result.php:
public function field()
{
return $this->hasOne(Field::class);
}
Now, my users can upload documents to a stream, and my users can create many fields on a stream.
When a document is uploaded to a stream,for each field defined, the document content will be parsed according to some logic I have created.
The end result of this parsing, should be saved to the database (results).
I can do this now, by:
$document = Document::find(1);
foreach($stream->fields as $field)
{
$content = myParseFunction($document->content);
$field->save(['content' => $content]);
}
This will create a result for each field on the stream. Like, if my Stream had 2 fields:
results table:
id | field_id | content
1 | 1 | Lorem ipsum
2 | 2 | Another ipsum
Whenever I upload a new document however, the result will be overwritten.
As each uploaded documents content is unique, how can I save the result for the field and specific document.
Like, if my Stream still have 2 fields, but I upload 2 documents:
results table:
id | field_id | document_id | content
1 | 1 | 1 | Lorem ipsum
2 | 2 | 1 | Another ipsum
3 | 1 | 2 | Another unique content
4 | 2 | 2 | Yet another unique content
I think the result is also determined by the document, as you are parsing a document for a for a field.
I would also link the documents to theuse the Result table ans store the results there.
One result would be determinded by the document id and the field id.
Result
public function fields()
{
return $this->hasMany(Field::class);
}
public function documents()
{
return $this->hasMany(Document::class);
}
Document
public function results()
{
return $this->hasMany(Result::class);
}
Field
public function stream()
{
return $this->belongsTo(Stream::class);
}
public function result()
{
return $this->hasOne(Result::class);
}
And then:
$document = Document::find(1);
$result = new Result();
foreach($stream->fields as $field)
{
$content = myParseFunction($document->content);
$result->save(['field_id' => $field->id, 'document_id'=>$document->id, 'content' => $content]);
}
I am working with Laravel 5.6 with MySql database in My web app.
and I have following function method to add order,
public function addOrder()
{
$input = Input::all();
$subscribed= false;
if(isset($input['subscribed']))
{
$subscribed= true;
}
and In My system I have table name as vehicles as following,
**vehicles table**
id name number adtype
1 car 123 0
2 van 159 0
3 car 258 0
4 lorry 147 0
5 van 298 0
etc..
Now I need update above table adtype values from 0 to 1 when click submit button regarding to above addorder function. then how can write code to update code in side above function????
My url as following....
http://localhost:8000/myads/1/edit/payment
route is,
Route::post('add-order', 'PaymentController#addOrder');
If you are using a model then try the following code:
public function addOrder()
{
$input = Input::all();
$subscribed= false;
if(isset($input['subscribed'])){
$subscribed= true;
}
$vehicle= App\Vehicles::find($input[id]);
$vehicle->adtype = $subscribed;
$vehicle->save();
}
If you are using Query Builder (add use DB;)
public function addOrder()
{
$input = Input::all();
$subscribed= false;
if(isset($input['subscribed'])){
$subscribed= true;
}
DB::table('vehicles')
->where('id', $input[id])
->update(['adtype' => $subscribed]);
}
You must pass the id of a table row to edit each of them(this is must for any method).
I have tabel like this
id name parent_id order_id
1 software 0 1
2 hardware 0 2
3 windows 1 3
4 linux 1 4
5 mouse 2 5
6 keyword 2 6
And I use Laravel 5.1 Eloquent
How to get data in model like this
[{"id":1,"children":[{"id":3},{"id":4}]},{"id":2,"children":[{"id":5},{"id":6}]}]
There is a best way to do this.
The package etrepat/baum is so awesome and easy. It has everything you need about nesting elements. Just add it to your composer dependencies and enjoy.
You can also add these methods to your Model and use them as relations.
public function parent() {
return $this->belongsTo(self::class, 'parent_id');
}
public function children() {
return $this->hasMany(self::class, 'parent_id');
}
Then you will simply say:
$results = MyModel::with('children')->get();
Update for comment:
$results = Category::select('id','name')->with([
'children' => function($query) {
$query->select('id', 'parent_id');
// You can customize the selected fields for a relationship like this.
// But you should select the `key` of the relationship.
// In this case it's the `parent_id`.
}
])->get();