DoubleClickDesignLtd's avatar

DoubleClickDesignLtd wrote a reply+100 XP

2mos ago

Hi @silveira, I've read about a similar issue in another post when upgrading to Livewire 4 and Filament. They fixed it by deleting the node_modules directory and installed the nodes packages again. I suggest giving it a try.

DoubleClickDesignLtd's avatar

DoubleClickDesignLtd liked a comment+100 XP

2mos ago

Latest update.

After trying different things I deleted the node_modules directory and installed the nodes packages again. It solved the problem - as far as I can see

DoubleClickDesignLtd's avatar

DoubleClickDesignLtd wrote a reply+100 XP

2mos ago

@troccoli I'm not 100% sure why your doing the persistent cache from what your describing.

However to answer your test fail issue, I believe this happens because Laravel’s test environment fakes the cache store, so the value you put() in the test is not available when the Livewire request runs.

Livewire component actions (->call('completeProfile')) are executed through a separate HTTP request lifecycle.

In your test, when you do the below, that value is stored in the cache instance for the current test lifecycle.

Cache::store('persistent')->put(key: $cacheKey, value: new SignUpAttempt(...));

During the Livewire call, Laravel boots a new request and the cache store is resolved again. In tests, Laravel commonly swaps cache stores with an array / fake store (or otherwise non-persistent store), so your “persistent” store isn’t actually hitting your persistent_cache DB table during the Livewire request.

That why the test is failing from my understand. To fix try forcing Laravel to use the real cache store in tests, not the fake/array one.

Question: Have you ensure cache tables exist in test DB and you set up the phpunit.xml to use your cache driver?

Let me know how you get on.

All the best

Mark

DoubleClickDesignLtd's avatar

DoubleClickDesignLtd wrote a reply+100 XP

2mos ago

If you need to get your head round the backend I would suggest your start by doing the Level 1 The Fundamentals.

https://laracasts.com/path

It a good base line and will help you moving forward.

DoubleClickDesignLtd's avatar

DoubleClickDesignLtd wrote a reply+100 XP

2mos ago

No problem I wish you the best with your learning

DoubleClickDesignLtd's avatar

DoubleClickDesignLtd liked a comment+100 XP

2mos ago

Thank you very kindly.

DoubleClickDesignLtd's avatar

DoubleClickDesignLtd liked a comment+100 XP

3mos ago

@yumna12-coder You might not be ready for this series. Can you describe precisely what you found difficult, and we can point you to a place to learn more?

DoubleClickDesignLtd's avatar

DoubleClickDesignLtd wrote a reply+100 XP

3mos ago

First don't be too hard on yourself. Everything you stated as challenging are very large areas of programming in general. Everyone finds them challenging. The good news is their are various courses on Laracasts that can help you.

I had difficulty with Testing and I'm still not great a it. I found watch this course help me a lot.

https://laracasts.com/series/php-testing-jargon

Also I recommend reading the Laravel documentation. I know it sound scary but the documentation is very human friendly to read and understand.

If you just struggling with the PHP in general I would recommend "PHP For Beginners" and the "PHP Crash Course" on Laracasts.

Authorisation is a massive topic and even after all my 20+ years as a developer I'm still learning on this subject. The best way to pick it up is to create a simple app yourself.

Start with a Laravel start kit. Use something like Laravel Breeze starter kit and learn to use the existing Auth process. By doing this you will learn the basics and you can look at the start kit codebase and start reading it to understand what going on.

Here a very good Laracasts course on the subject

https://laracasts.com/series/laravel-authentication-options

If you still don't understand I suggest copying the script into chatGPT and asking it to explain in detail what each line does and why, it can be a helpful exercise if you don't understand something.

Gate and Policies sound more complex than they really are. They are just layers you can add to system security. You don't have to master everything all at once. Just learn to get comfortable with Authorisation then once your good start playing with Gate...then Policies. Before long you will start feeling comfortable with everything.

Just remember programming is creative exercise and you learn through play. So just have fun and play.

As far as Vite and UI I would recommend watching.

https://laracasts.com/series/laravel-and-vite

I hope the above helps you and if you have any particular questions just let me know and I've tried and explain it to you.

All the best :-)

DoubleClickDesignLtd's avatar

DoubleClickDesignLtd wrote a comment+100 XP

3mos ago

@ojiminy really??? Has the AI been prompt to make sure it only uses PHP 8.4 syntax?

DoubleClickDesignLtd's avatar

DoubleClickDesignLtd wrote a comment+100 XP

3mos ago

I kind of understand what @JeffreyWay is saying but I'm left wondering why the readonly approach was not mention on the refactor of this code example.

Let me explain.... using the same example we could achieve the same functionality with less code and be more readable (in my opinion).


// notice the use of the readonly on the $email

class User {
    public function __construct(
        public readonly string $email
    ) {
        // Validate email before assigning
        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            throw new InvalidArgumentException('Email must be valid.');
        }
    }
}

$user = new User('[email protected]');
echo $user->email; // Outputs: [email protected]

The above code does the following :-

  1. public readonly string $email
    • Can be read publicly ($user->email)
    • Can only be assigned once, in the constructor
    • Prevents accidental modification after creation
  2. Email validation
    • Done in the constructor before assignment
    • Guarantees object is always in a valid state
  3. No property hooks are needed for $email
    • Since it’s immutable, you don’t need a setter
    • Getter is automatic with public readonly

Where I'm sitting the above gives all the same functionality and safety that the original does. The only thing I'm wondering is why the readonly was not mention in the video.

I understand my example does not make use of the new way to do the property hooks but I'm not seeing a case where the property hooks be a better approach. Maybe I'm missing something if so please can someone enlighten me.

DoubleClickDesignLtd's avatar

DoubleClickDesignLtd wrote a reply+100 XP

3mos ago

Thanks for sharing this information @martinbean

DoubleClickDesignLtd's avatar

DoubleClickDesignLtd liked a comment+100 XP

3mos ago

A vulnerability has been discovered that affects Livewire 3 versions up to and including 3.6.3 (https://nvd.nist.gov/vuln/detail/CVE-2025-54068). If you’re running a vulnerable version, you’re advised to upgrade immediately. This includes if you’re using a package (such as Filament) that relies on affected versions.

DoubleClickDesignLtd's avatar

DoubleClickDesignLtd liked a comment+100 XP

4mos ago

you need to adopt the standards of the project unless you can jointly agree to change the approach.

DoubleClickDesignLtd's avatar

DoubleClickDesignLtd wrote a reply+100 XP

4mos ago

@eddieace can you post the Livewire and blade code please. I think it will be something simple for example the wire:key has to be on the root element DIRECTLY inside the foreach loop.

DoubleClickDesignLtd's avatar

DoubleClickDesignLtd liked a comment+100 XP

4mos ago

@sharkblue58 Why not use an actual authorisation standard such as OAuth?

JWT isn’t great for stateful authentication because tokens contain the claims and are self-signed. Once they’re issued, there’s no way to revoke them.

For token-based authentication, I’ll always used a widely-accepted standard such as OAuth before I use something JWT-based or hand-rolled. There’s just no point in re-inventing the wheel.

DoubleClickDesignLtd's avatar

DoubleClickDesignLtd wrote a reply+100 XP

4mos ago

Sorry I did your last reply before ending for the day. Looking over what I wrote to your post you are correct. Envoy does NOT automatically load your Laravel .env file, and your test result is correct.

I've done it like this in the past in command line

envoy run deploy --env=production --branch=main

Then in your envoy file.

@task('deploy', ['env', 'branch'])
    echo "Deploying {{ $branch }} to {{ $env }}"
@endtask 

This should work for you.

If you export variables in your shell, Envoy can read them I believe you can do something like this below but I've not tried it this way.

export APP_ENV=production
export DEPLOY_PATH=/var/www/app
envoy run deploy
@task('deploy')
    echo "{{ getenv('APP_ENV') }}"
    cd {{ getenv('DEPLOY_PATH') }}
@endtask

Try this and let me know how you get on.

DoubleClickDesignLtd's avatar

DoubleClickDesignLtd wrote a reply+100 XP

4mos ago

@snapey just trying to explain the life-cycle as he wanted to know why his private values where empty.

Regarding this feature being used by others that don't understand it as a negative. Yes, you can create heavy system loads if you don't understand the life-cycle by sending far to many request but their are plenty of ways to work smarter and have large scale TALL stack application run smoothly.

DoubleClickDesignLtd's avatar

DoubleClickDesignLtd wrote a reply+100 XP

4mos ago

@vincent15000 Yes but with important caveats.

Laravel’s configuration system is the correct layer to expose values to Blade.

create new file in the config folder. For example config/services.php


<?php

return [
    'per_page' => env('PER_PAGE', 15),
];

In your blade you can now do the following

{{ config('services.per_page') }}

DO NOT DO THE FOLLOWING IN YOUR BLADE!!!

{{ env('APP_ENV') }} 

The above is how you do it correctly in Laravel.

However your question was about Envoy and that works differently.

Envoy work differently let me explain

Envoy runs outside the Laravel HTTP runtime, essentially as a standalone PHP script for deployment tasks.

Here, env() works fine because Envoy is not using cached configs.

Envoy reads the .env file directly when it runs, so there’s no “config caching” problem like in Laravel Blade.

For example

@task('deploy')
    echo "{{ env('APP_ENV') }}"
@endtask
DoubleClickDesignLtd's avatar

DoubleClickDesignLtd wrote a reply+100 XP

4mos ago

Hi @sean2025, that’s a great question and one I can definitely relate to. I’ve been working in software design and development for about 30 years, across many different projects, teams, and technologies.

The first thing to understand is that every company and team has its own way of working, so what I’m sharing here isn’t “the” way just a set of general principles based on my experience. Over time, and by working with other designers and developers, you’ll naturally develop your own workflow. Also, don’t be too hard on yourself when things don’t go as planned; you often learn the most when something goes wrong.

Below is a very rough outline of how I typically approach a project when working with a small team (around five developers).

It starts with the idea. Most of the projects I work on are about solving a real problem either for a client or as internal tooling for a team.

Write a short project brief. I start with a simple text document describing the idea and listing the project goals as bullet points. I keep this intentionally short no more than one page, ideally half a page.

Pitch and discuss the idea. I share the idea with the team and gather feedback. If you don’t have a team, friends or peers are a great substitute. The goal here is to understand whether it’s a good idea, what the pros and cons are, and to let others build on the original concept. Two heads really are better than one.

Refine the brief and explore architecture. Based on feedback, I update the document and start thinking about system architecture and the tech stack. I consider infrastructure and application choices together, because each decision has trade-offs that need to balance out.

Review as a team (iteration). Once the document is more fleshed out, we review it together. This iteration helps surface key issues early and aligns everyone on the direction.

Create rough wireframes. I usually use Balsamiq to sketch very rough wireframes that focus on user journeys rather than visuals. Alongside each screen, I list the required functionality. This often takes a couple of days things always look better with fresh eyes the next day, and logic issues tend to appear during revision.

Gather feedback and iterate again. I present the wireframes to the team, gather feedback, and refine them.

Write functional specifications per screen. For each screen, I create a more detailed functional document: high-level bullet points, followed by happy paths, error states (“sad paths”), and required functionality. I send this, along with the wireframes, to the developers for review. Don’t be afraid of having others check your work it’s how you grow.

Finalise infrastructure planning. Once the application scope is agreed upon, we design the infrastructure: diagrams, services, micro-services (if applicable), networking, and deployment considerations. This is also iterative.

Security and compliance review. We do a security and QA pass across the whole project, covering both technical and legal aspects authentication, authorisation, data governance, GDPR, etc.

Project planning and task breakdown. We create the project in Jira (or Trello for very small teams), define phases, create epics, and assign work.

Design work begins. The designer creates the brand identity and UI direction. For small projects, this might just be a logo and UI theme derived from the wireframes. Again, this is iterative.

Build reusable UI components. Design templates are broken down into reusable UI building blocks. Once these are coded, pages can be assembled by composing these components.

Application development (Phase 1). We build toward clearly defined Phase 1 objectives.

QA, review, and learning. After Phase 1, we stop to test, review results as a team, and feed lessons learned back into the design, architecture, or process.

There’s a lot more that could be said, I’ve probably skipped another 15 steps in between but I hope this gives you a realistic sense of how experienced teams often move from concept to design to code.

I hope this give you some insight into a project. It not the complete set of stages but I just wanted to give you a flavour of the process.

Best of luck and happy coding

Regards

Mark

DoubleClickDesignLtd's avatar

DoubleClickDesignLtd wrote a reply+100 XP

4mos ago

If you read the document it say it. Also you can test it yourself. I know it to be so but I understand why you are saying this.

DoubleClickDesignLtd's avatar

DoubleClickDesignLtd wrote a reply+100 XP

4mos ago

Yes that is correct.

DoubleClickDesignLtd's avatar

DoubleClickDesignLtd wrote a reply+100 XP

4mos ago

@snapey thanks was just about to say the same thing.

DoubleClickDesignLtd's avatar

DoubleClickDesignLtd wrote a reply+100 XP

4mos ago

@sean2025 this is hard to answer as everyone journey is different as I would have to say it depends on your experience in development.

For me I started with a very basic Laravel Course years ago which taught the me about the basic feature of the framework and then using my previous experience in PHP and software development I went from there.

If you can give me some idea of your experience level I'll try and direct you.

All the Best

Mark :-)

DoubleClickDesignLtd's avatar

DoubleClickDesignLtd wrote a reply+100 XP

4mos ago

This is a classic Google Drive ownership transfer limitation issue and it’s not really a bug in the PHP client library. It’s a hard constraint imposed by Google Drive API and Workspace policies.

When you try to transfer ownership of a file from a service account to a user, Google Drive enforces these rules:

  1. Consent from the recipient is required for ownership transfer unless the service account and the target user are under the same Google Workspace domain and the Workspace admin has enabled ownership transfer without consent.
  2. Personal Gmail accounts cannot be direct owners of files created by a service account in another domain; manual acceptance is mandatory.
  3. The sendNotificationEmails parameter cannot be silently bypassed in some older client library versions. Your error "unknown parameter: 'sendNotificationEmails'" is just the PHP client rejecting the field, not Drive itself.

So essentially, you’re hitting a Google policy limitation, not a client bug.

DoubleClickDesignLtd's avatar

DoubleClickDesignLtd wrote a reply+100 XP

4mos ago

There are definite risks in rolling your own refresh token logic with Tymon/JWT (or any JWT library) compared to using a framework that handles refresh tokens natively.

JWTs themselves are stateless, meaning once issued, the server doesn’t track them unless you implement some mechanism yourself. This brings a few common pitfalls.

Rolling your own refresh token logic with Tymon/JWT can work, but it’s risky. The most common mistakes involve revocation, rotation, storage, and concurrency. If security and reliability are critical (as in production), using a framework or managed solution is strongly recommended.

DoubleClickDesignLtd's avatar

DoubleClickDesignLtd wrote a reply+100 XP

4mos ago

@darkdawg I've also done a lot of work in Livewire 2 and 3 with Image upload admin panels including image chunking of large file etc. Can you post some code and bullet point your goals and I'll see if I can help you.

DoubleClickDesignLtd's avatar

DoubleClickDesignLtd wrote a reply+100 XP

4mos ago

@vincent15000, @snapey is right because it to do with how Livewire life-cycle works.

Let me step you through the logic so it clear for you, then I'll suggest 2 alternative ways of doing it rather than putting it in the render method.

In Livewire 3, when you type into an input with wire:model.live (or wire:model), Livewire performs AJAX requests on each keystroke. Each request:

  1. Sends the public properties to the server.
  2. Re-renders the component on the server.
  3. Sends back the updated DOM.

Private properties are not part of the payload because Livewire only syncs public properties with the frontend.

So, if you initialise your private arrays in mount() method, example like this:

private array $myArray;

public function mount()
{
    $this->myArray = ['a', 'b', 'c'];
}

Then as soon as Livewire sends a request from wire:model.live. Livewire creates a new instance of your component on the server and only hydrates public properties from the previous state. Private properties are not restored, so $myArray is now empty unless reinitialised

@snapey suggested reinitialising the private arrays in the render() method. This works because render() is called on every request, so your private arrays are reset each time.

Remember: ** In Livewire 3, private properties are never persisted across requests, so you always need to reinitialize them somewhere (render(), hydrate(), or make them public and control dehydration)**

Now you could do something very similar to @snapey using the hydrate method like this example

use Livewire\Component;

class MyComponent extends Component
{
    private array $myArray;

    // Initialize once on first mount
    public function mount()
    {
        $this->myArray = ['a', 'b', 'c'];
    }

    // Ensure private data exists on every Livewire request
    public function hydrate()
    {
        if (empty($this->myArray)) {
            $this->myArray = ['a', 'b', 'c'];
        }
    }

    public function render()
    {
        return view('livewire.my-component');
    }
}

The above works but I think it looks a bit messy.

What I normally do is use Livewire computed properties. No need for private + hydrate() trick and data stays server-only, computed each request. Here an example

use Livewire\Component;

class MyComponent extends Component
{
    public int $userId;

    #[Computed]
    public function myArray(): array
    {
        // Computed each render; never sent to frontend directly
        return ['a', 'b', 'c', 'user' => $this->userId];
    }

    public function render()
    {
        return view('livewire.my-component');
    }
}

Now if the Computed is a database query and you don't want to keep looking up the same information again and again, I normally use the cache facade something like this for example.

class MyComponent extends Component
{
    public int $userId = 1; // example public property

    #[Computed]
    public function user(): ?User
    {
        // Cache the result for 10 minutes
        return Cache::remember("user_{$this->userId}", now()->addMinutes(10), function () {
            return User::find($this->userId);
        });
    }

    public function render()
    {
        return view('livewire.my-component');
    }
}

Important

  • Computed methods cannot be private. They must be public to be recognized by Livewire.
  • They are read-only. You cannot bind wire:model to them.
  • Good for static arrays, derived data, server-only calculations, etc.

#[Computed] is cleaner replacement for private arrays used only on the server if your array doesn’t need to be modified by Livewire requests.

If you need to store state that changes and must survive requests, then you still need public properties + hydrate().

DoubleClickDesignLtd's avatar

DoubleClickDesignLtd liked a comment+100 XP

4mos ago

As Lary says, data that is not exchanged with the frontend MUST be reinitialised on every request.

I usually do this in the render method.