elliotk

Member Since 4 Years Ago

Experience Points
21,510
Total
Experience

3,490 experience to go until the next level!

In case you were wondering, you earn Laracasts experience when you:

  • Complete a lesson — 100pts
  • Create a forum thread — 50pts
  • Reply to a thread — 10pts
  • Leave a reply that is liked — 50pts
  • Receive a "Best Reply" award — 500pts
Lessons Completed
177
Lessons
Completed
Best Reply Awards
1
Best Reply
Awards
  • start your engines Created with Sketch.

    Start Your Engines

    Earned once you have completed your first Laracasts lesson.

  • first-thousand Created with Sketch.

    First Thousand

    Earned once you have earned your first 1000 experience points.

  • 1-year Created with Sketch.

    One Year Member

    Earned when you have been with Laracasts for 1 year.

  • 2-years Created with Sketch.

    Two Year Member

    Earned when you have been with Laracasts for 2 years.

  • 3-years Created with Sketch.

    Three Year Member

    Earned when you have been with Laracasts for 3 years.

  • 4-years Created with Sketch.

    Four Year Member

    Earned when you have been with Laracasts for 4 years.

  • 5-years Created with Sketch.

    Five Year Member

    Earned when you have been with Laracasts for 5 years.

  • school-in-session Created with Sketch.

    School In Session

    Earned when at least one Laracasts series has been fully completed.

  • welcome-newcomer Created with Sketch.

    Welcome To The Community

    Earned after your first post on the Laracasts forum.

  • full-time-student Created with Sketch.

    Full Time Learner

    Earned once 100 Laracasts lessons have been completed.

  • pay-it-forward Created with Sketch.

    Pay It Forward

    Earned once you receive your first "Best Reply" award on the Laracasts forum.

  • subscriber Created with Sketch.

    Subscriber

    Earned if you are a paying Laracasts subscriber.

  • lifer Created with Sketch.

    Lifer

    Earned if you have a lifetime subscription to Laracasts.

  • evangelist Created with Sketch.

    Laracasts Evangelist

    Earned if you share a link to Laracasts on social media. Please email [email protected] with your username and post URL to be awarded this badge.

  • chatty-cathy Created with Sketch.

    Chatty Cathy

    Earned once you have achieved 500 forum replies.

  • lara-veteran Created with Sketch.

    Laracasts Veteran

    Earned once your experience points passes 100,000.

  • 10k-strong Created with Sketch.

    Ten Thousand Strong

    Earned once your experience points hits 10,000.

  • lara-master Created with Sketch.

    Laracasts Master

    Earned once 1000 Laracasts lessons have been completed.

  • laracasts-tutor Created with Sketch.

    Laracasts Tutor

    Earned once your "Best Reply" award count is 100 or more.

  • laracasts-sensei Created with Sketch.

    Laracasts Sensei

    Earned once your experience points passes 1 million.

  • top-50 Created with Sketch.

    Top 50

    Earned once your experience points ranks in the top 50 of all Laracasts users.

  • Community Pillar

    Earned once your experience points ranks in the top 10 of all Laracasts users.

Level 5
21,510 XP
May
10
15 hours ago
Activity icon

Replied to Transactional Email Providers

I am using SES in another app, so very familiar, it's a very cheap and reliable service.

Honestly. I find the console a nightmare to navigate. I don't like how easy it is to accidentally run up a bill too.

I'd rather pay more than the few cents it's costing now, but live without the extra burden.

Think Digital Ocean vs AWS - I'm looking for the same but for the emails

Activity icon

Started a new Conversation Transactional Email Providers

Hello,

Who would you recommend for sending Transactional Emails?

I have the following requirements..

No more than 2k emails per month Emails can come from domain1.com domain2.com domain3.com I would want to use a shared credential if possible and provide the sending from address I specifically don't want to use AWS I want to send transactional emails - eg sign up, reset password, new order Looking for someone with a free tier or a very low cost per month

Thanks

May
09
1 day ago
Activity icon

Replied to Optimising View Composer To Avoid N+1

Yep this is what I was trying to avoid. All good suggestions on the thread, I’ll certainly think over and see whether there is any refactor to be had

May
08
2 days ago
Activity icon

Replied to Alpine Component - EOF

Spot on, thank you

Activity icon

Replied to Optimising View Composer To Avoid N+1

Thank you both for your reply. I have not seen this share view before, so I will take a look.

On the cache perspective - how would I do this for something like a Basket which is unique to each visitor?

Activity icon

Started a new Conversation Alpine Component - EOF

Hello,

I need some help with my first Alpine / Blade Component. I have built a model component, which accepts a title and a body and displays the content to the user.

When a small body of text is passed, everything is working fine. When I try and pass a bigger body, I get an error as follows

Alpine Error: "SyntaxError: Unexpected EOF"

Perhaps I have completely misunderstood the architecture here, any guidance appreciated.

This is how I call my component

<x-simple-modal modelTitle="Terms and Conditions" modelBody="{{ $terms->text }}" />

Here is the Component Class

<?php

namespace App\View\Components;

use Illuminate\View\Component;

class SimpleModal extends Component
{
    public $modelTitle;
    public $modelBody;
    /**
     * Create a new component instance.
     *
     * @return void
     */
    public function __construct($modelTitle, $modelBody)
    {
        $this->modelTitle = $modelTitle;
        $this->modelBody = $modelBody;
    }

    /**
     * Get the view / contents that represent the component.
     *
     * @return \Illuminate\Contracts\View\View|\Closure|string
     */
    public function render()
    {
        return view('components.simple-modal');
    }
}

Finally, here is my component


<div
    x-data="{
        'showModal': false, 'modelTitle': '{{ $modelTitle }}', 'modelBody': '{{ $modelBody }}'
    }"
    
    @keydown.escape="showModal = false"
>
    <!-- User Clicks here to Launch Modal -->
    <a href="#" x-text="modelTitle" class="font-medium text-grey-700 text-sm underline" @click="showModal = true"></a>



    <div
        class="fixed z-10 inset-0 overflow-y-auto" aria-labelledby="modal-title" role="dialog" aria-modal="true"
        x-show="showModal"
    >
        <div class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">

            <div @click="showModal = false" class="fixed inset-0 bg-gray-400 bg-opacity-90 transition-opacity" aria-hidden="true"></div>
            <span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">&#8203;</span>

            <div
                class="inline-block align-bottom bg-white rounded-lg px-4 pt-2 pb-4 text-left shadow-xl transform transition-all sm:my-3 sm:align-middle sm:max-w-xl sm:w-full sm:p-6">
                <div>
                    <div class="mt-3 text-center sm:mt-1">
                        <h3 x-text="modelTitle"class="text-lg leading-6 font-medium text-gray-900" id="modal-title">
                            
                        </h3>
                        <div class="py-3 px-3 mt-2 border border-gray-300 overflow-auto max-h-96">
                            <p x-text="modelBody" class="text-sm text-gray-500">
                                
                            </p>
                        </div>
                    </div>
                </div>
                <div class="mt-5 sm:mt-6">
                    <button type="button"
                        @click="showModal = false"
                        class="inline-flex justify-center w-full rounded-md border border-transparent shadow-sm px-4 py-2 bg-indigo-600 text-base font-medium text-white hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:text-sm">
                        Close
                    </button>
                </div>
            </div>
        </div>
    </div>
</div>
Activity icon

Replied to Optimising View Composer To Avoid N+1

No, these are different views.

layouts.nav shows a small basket element in the navigation

store.basket shows the users basket in the checkout process.

May
04
6 days ago
Activity icon

Started a new Conversation Optimising View Composer To Avoid N+1

Hello,

I have a View Composer, which I wrongly thought would reduce query duplication (eg n+1)

I have the same $basket that I want available in 2 different views. I expected that this query would run just the once, but it runs twice. If I add a 3rd view, a 3rd query.

Is there a better way to do this to reduce the number of queries?

Each User has a single Basket - is it possible / wise to cache every users basket?

Should I just live with it?

Appreciate any thoughts.

        View::composer(['layouts.nav', 'store.basket'], function ($view) {
            if (Basket::cookieExists()) {
                $basket = Basket::retrieve();
            }
            $view->with('basket', $basket);
        });
May
03
1 week ago
Activity icon

Replied to Computed Properties

Thanks a lot

Activity icon

Started a new Conversation Computed Properties

Hello,

I want to build a computed property to return the value of a shopping basket.

The Basket contains Sku and each Sku has a price.

On the Basket Model I have the following working fine

    public function getTotalAttribute()
    {
        return $this->sku->sum('price');
    }

However, the Sku is associated to a Basket via a many to many with a pivot column for quantity.

So I was hoping to do something like

    public function getTotalAttribute()
    {
        return ($this->sku->sum('price') * $this->sku->pivot->sum('quantity'))
    }

This doesn't work due to the following error

Property [pivot] does not exist on this collection instance.

Any even if it did, each Basket will have many Sku all with different values, so how do you calculate the whole basket?

Basket
Sku 1, Price 10, Quantity 5 = 50
Sku 2, Price 100, Quantity 1 = 100
Sku 3, Price 3, Quantity 3 = 9

Basket Total = 159

Any help much appreciated.

Apr
30
1 week ago
Activity icon

Replied to Update Pivot Column

Thanks a lot!

Activity icon

Started a new Conversation Update Pivot Column

Hello,

I have a Basket with many SKU associated via a many to many relationship. On the Pivot I store the quantity.

What is the best way to update the Pivot Quantity?

I currently loop through all the existing SKU's on the basket to find the one I need. I then get the existing Quantity and combine it with the New Quantity. Then pass that new Quantity to updateExistingPivot

It's working fine, just seems a bit heavy for what it does.

Any recommended refactors?

            $newQuantity = 0;
            foreach($this->basket->sku as $basketSku)
            {
                if ($basketSku->id == $sku->id) {
                    $newQuantity = $basketSku->pivot->quantity + $quantity;
                }
            }
            $this->basket->sku()->updateExistingPivot($sku->id, ['quantity' => $newQuantity]);
Apr
29
1 week ago
Activity icon

Replied to Filtering Nightmare

@michaloravec that's incredible, thanks so much.

Activity icon

Started a new Conversation Filtering Nightmare

I am trying to filter some nested relationships to get down to a single item, I am having a nightmare.

I am sorry if this doesn't make sense, trying to explain the problem in the simplest way possible.

My query returns the following...

Illuminate\Database\Eloquent\Collection {#1567 ▼
  #items: array:3 [▼
    0 => App\Models\ProductAttributeValue {#1529 ▶}
    2 => App\Models\ProductAttributeValue {#1527 ▶}
    4 => App\Models\ProductAttributeValue {#1525 ▶}
  ]
}

There are 3 ProductAttributeValue models.

Each ProductAttributeValue model has a relationship to a sku

Illuminate\Database\Eloquent\Collection {#1567 ▼
  #items: array:3 [▼
    0 => App\Models\ProductAttributeValue {#1529 ▼
      #connection: "mysql"
      #table: "product_attribute_values"
      #primaryKey: "id"
      #keyType: "int"
      +incrementing: true
      #with: []
      #withCount: []
      #perPage: 15
      +exists: true
      +wasRecentlyCreated: false
      #attributes: array:7 [▶]
      #original: array:7 [▶]
      #changes: []
      #casts: []
      #classCastCache: []
      #dates: []
      #dateFormat: null
      #appends: []
      #dispatchesEvents: []
      #observables: []
      #relations: array:1 [▼
        "sku" => Illuminate\Database\Eloquent\Collection {#1517 ▼
          #items: array:2 [▼
            0 => App\Models\ProductSku {#1560 ▶}
            1 => App\Models\ProductSku {#1554 ▶}
          ]
        }
      ]
      #touches: []
      +timestamps: true
      #hidden: []
      #visible: []
      #fillable: []
      #guarded: array:1 [▶]
    }
    2 => App\Models\ProductAttributeValue {#1527 ▶}
    4 => App\Models\ProductAttributeValue {#1525 ▶}
  ]
}

In this example, there are 2 Sku in each ProductAttributeValue model

Each Sku has it's own ID

I basically want to find the common Sku across each ProductAttributeValue model.

Attribute A
Sku ID 1
Sku ID 4
Attribute B
Sku ID 4
Sku ID 9
Attribute C
Sku ID 2
Sku ID 4

As you can see the common Sku is ID 4, so I would want this Sku Model with ID 4 to be the return of the filter.

Hope that makes sense. Any ideas?

Activity icon

Started a new Conversation Binding To An Array

Hello,

I have a Product model which has many Attributes. It could be 1, 2, 5, an unknown number.

I display these options on a form, and I want to capture the users selection.

I have the following approach. On mount, I loop the attributes and create an item for each attribute ID.

	public Product $product;
    public $attributes = [];


    public function mount(Product $product)
    {
        $product->load('sku', 'attribute.value');

        foreach ($product->attribute as $attribute)
        {
            $this->attributes[$attribute->id] = '';
        }
    }

On the form, I have wire:model set to the same array index as the attribute ID (as above).

    @foreach($product->attribute as $attribute)
        <select wire:change="change" wire:model="attributes.{{ $attribute->id }}" id="{{ $attribute->name }}" name="{{ $attribute->name }}">
            <option>Please Select...</option>
            @foreach($attribute->value as $value)
                <option value="{{ $value->id }}">{{ $value->value }}</option>
            @endforeach
        </select>
    @endforeach

On change, i dump the array. If I have a product with 2 attributes, attribute ID 1 and 2 I get the following behavour.

Change Attribute 1

array:2 [▼
  1 => "5"
  2 => ""
]

If I then change Attribute 2, it forgets what is set in slot 1.

array:2 [▼
  1 => ""
  2 => "8"
]

I would have expected to see 5 and 8.

Where am I going wrong?

Apr
18
3 weeks ago
Activity icon

Replied to How Granular For Models?

Hello @martinbean I am having some trouble with the relationships, hoping you can give me a few pointers...

Here are the tables

products

+------------+---------------------+------+-----+---------+----------------+
| Field      | Type                | Null | Key | Default | Extra          |
+------------+---------------------+------+-----+---------+----------------+
| id         | bigint(20) unsigned | NO   | PRI | NULL    | auto_increment |
| name       | varchar(255)        | NO   |     | NULL    |                |
| url        | varchar(255)        | NO   |     | NULL    |                |
| enabled    | tinyint(1)          | NO   |     | NULL    |                |
| tenant_id  | bigint(20) unsigned | YES  | MUL | NULL    |                |
| created_at | timestamp           | YES  |     | NULL    |                |
| updated_at | timestamp           | YES  |     | NULL    |                |
+------------+---------------------+------+-----+---------+----------------+

skus

+------------+---------------------+------+-----+---------+----------------+
| Field      | Type                | Null | Key | Default | Extra          |
+------------+---------------------+------+-----+---------+----------------+
| id         | bigint(20) unsigned | NO   | PRI | NULL    | auto_increment |
| tenant_id  | bigint(20) unsigned | YES  | MUL | NULL    |                |
| product_id | bigint(20) unsigned | NO   | MUL | NULL    |                |
| sku        | varchar(255)        | NO   |     | NULL    |                |
| name       | varchar(255)        | NO   |     | NULL    |                |
| price      | decimal(8,2)        | YES  |     | NULL    |                |
| stock      | int(11)             | YES  |     | NULL    |                |
| enabled    | tinyint(1)          | NO   |     | NULL    |                |
| created_at | timestamp           | YES  |     | NULL    |                |
| updated_at | timestamp           | YES  |     | NULL    |                |
+------------+---------------------+------+-----+---------+----------------+

attributes

+------------+---------------------+------+-----+---------+----------------+
| Field      | Type                | Null | Key | Default | Extra          |
+------------+---------------------+------+-----+---------+----------------+
| id         | bigint(20) unsigned | NO   | PRI | NULL    | auto_increment |
| tenant_id  | bigint(20) unsigned | YES  | MUL | NULL    |                |
| name       | varchar(255)        | NO   |     | NULL    |                |
| enabled    | tinyint(1)          | NO   |     | NULL    |                |
| created_at | timestamp           | YES  |     | NULL    |                |
| updated_at | timestamp           | YES  |     | NULL    |                |
+------------+---------------------+------+-----+---------+----------------+

attribute_sku

+--------------+---------------------+------+-----+---------+-------+
| Field        | Type                | Null | Key | Default | Extra |
+--------------+---------------------+------+-----+---------+-------+
| attribute_id | bigint(20) unsigned | NO   | PRI | NULL    |       |
| sku_id       | bigint(20) unsigned | NO   | PRI | NULL    |       |
| value        | varchar(255)        | NO   |     | NULL    |       |
+--------------+---------------------+------+-----+---------+-------+

Then in my models, I have..

Product

With the following relationships

    public function sku()
    {
        return $this->hasMany(Sku::class);
    }

    public function attribute()
    {
        return $this->hasManyThrough(Attribute::class, Sku::class);
    }

Sku

With the following relationships

    public function product()
    {
        return $this->belongsTo(Product::class);
    }

    public function attribute()
    {
        return $this->hasMany(Attribute::class)->withPivot('value');
    }

And finally Attribute

With the following relationships

    public function sku()
    {
        return $this->belongsToMany(Sku::class);
    }

    public function product()
    {
        return $this->belongsToMany(Product::class);
    }

However, when I try and load the attributes off the Product

$product->load('attribute');

I get the following error

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'attributes.sku_id' in 'on clause' (SQL: select `attributes`.*, `skus`.`product_id` as `laravel_through_key` from `attributes` inner join `skus` on `skus`.`id` = `attributes`.`sku_id` where `skus`.`product_id` in (1) and `attributes`.`tenant_id` is null)

What I want to do is get a list of all the Attributes (Name and Value) for a given Product. I guess there are some relationship issues.

Apr
17
3 weeks ago
Activity icon

Replied to Binding Data

Thanks so much, works as expected now. So if you don't initialise those variables at mount, you can't then interact with them later?

Activity icon

Started a new Conversation Binding Data

Hello,

I am super new to Livewire, making my first component.

I can't seem to get the following part to work: wire:click="changeImage('{{ $media->getUrl() }}')"

A user should be able to click the small gallery image, and this will then update the Main Image. I don't understand why it's not working. I am sure it's an incredibly simple thing, maybe I missed something obvious.

When the component loads, everything is working as epected.

Component

<?php

namespace App\Http\Livewire\Store;

use App\Models\Product;
use Livewire\Component;

class ImageGallery extends Component
{
    public Product $product;
    public $mediaList = null;
    public $activeImage = null;

    public function mount(Product $product)
    {
        // Set the Model Assosiated with the Component 
        $this->product = $product;
    }

    public function changeImage($image)
    {
        // Listen for the new image click and set the Active Image 
        $this->activeImage = $image;
    }

    public function render()
    {
        // Get the Media Assosiated to the Product Model
        $this->mediaList = $this->product->getMedia();

        // Set a default first image
        $this->activeImage = $this->mediaList->first()->getUrl();

        // Render the view
        return view('livewire.store.image-gallery');
    }
}

And then in the blade

<div>
    <!-- Main Image -->
    <div class="mb-3" id="product-image" name="product-image">
        <img class="w-100 h-100 flex-shrink-0 bg-black " src="{{ $activeImage }}" alt="">
    </div>

    <!-- Gallery -->
    <div class="grid grid-flow-col grid-cols-3 grid-rows-{{ceil(count($mediaList)/3)}} gap-4">
        @foreach ($mediaList as $media)
            <div>
                <!-- When a user clicks on this image, it should update the main image view -->
                <img wire:click="changeImage('{{ $media->getUrl() }}')" class="w-100 h-100 flex-shrink-0 bg-black " src="{{ $media->getUrl() }}" alt="">
            </div>
        @endforeach
    </div>

</div>
Apr
15
3 weeks ago
Activity icon

Started a new Conversation Blade + Empty Relationship

Hello,

I have a Product which has a relationship to a ProductDescription model.

In my blade view I want to display a field from the ProductDescription model

{{ $product->description->body }}

How should I handle the fact that, in some cases a Product may not have a ProductDescription?

I tried putting a accessor on the ProductDescription model, but I am still getting Trying to get property 'body' of non-object

Apr
14
3 weeks ago
Activity icon

Replied to How Granular For Models?

That’s super helpful and exactly the kind of information I was looking for. I’ll take a similar approach.

Activity icon

Replied to How Granular For Models?

Thanks @bugsysha - my question wasn't on the mysql database - I am good with that. I was wondering about the Models structure in Laravel itself. It's all related to Products, but is it more desirable to have each table with its own corresponding model?

Activity icon

Started a new Conversation How Granular For Models?

If I have a Product

And a Product can have a number of options - Size and Colour

And a Size can have Small, Medium, Large

And a Colour can be Red, Green, Blue

From a Models perspective how does this work?

In my Database I have the tables - product, product_options and product_options_values

Should I have 3 corresponding Models? I would appreciate input.

Feb
28
2 months ago
Activity icon

Replied to Help Testing URL

I don't understand sorry - how can I make a request to an arbitrary domain?

In my factory I have 'domain' => $this->faker->domainName,

How do I make a request to whatever this returns?

Feb
26
2 months ago
Activity icon

Started a new Conversation Help Testing URL

Hello,

I am hoping to get some help writing a test.

I have a Domain model which holds a list of valid domains for a site.

I then have a middleware that checks whether the current $_SERVER['HTTP_HOST'] is in the Domain model and sets a session variable called domain_id which is then used throughout the site for other purposes.

I want to simulate adding a new domain, making a call to http://domain and then asserting that the session contains the correct domain_id

Any help would be greatly appreciated.

Thanks

Feb
16
2 months ago
Activity icon

Started a new Conversation Simplify Blade @Isset

Is there a better way to do this? I have around 40-50 fields so I am looking for something more readable.

@isset(json_decode($order->basket_payload, true)['billing_address']['recipient'])
<li>{{ json_decode($order->basket_payload, true)['billing_address']['recipient'] }}</li>
@endisset
Dec
16
4 months ago
Activity icon

Replied to Allow Multiple User Registrations For Same Email Address

Sorry for the delay in replying.

So the idea here was a user would be able to sign up independently to each site without realising that it was related to another site. Think along the lines of shopping / ecomm SaaS .

shop1.com shop2.co.uk shop3.net

I don't want to create a pseudo single sign on by allowing 1 username / password combination to work across all the sites.

So my idea was to extend the Registration Controller (which I can't find) and in the validation rule - make an allowance for combination or email + department/site ID being unique, rather than the email address alone.

Hope that makes sense.

Dec
14
4 months ago
Activity icon

Started a new Conversation Allow Multiple User Registrations For Same Email Address

Hello,

What is the correct way to allow the same email address to register (with its own user->id) based on a combination of email + user.dept_id

ID 1 email [email protected] dept_id 1 ID 2 email [email protected] dept_id 2

I don't see the Register Controller in Http/Controleers/Auth where I would expect it to be.

This is Laravel 8

Thanks