Skip to content

Conversation

@gwleuverink
Copy link
Collaborator

@gwleuverink gwleuverink commented Oct 28, 2025

This pull request adds the Conditionable trait to all Facades where it makes sense (omitted all that don't use fluent chaining)

  • Added the Conditionable trait to the following classes, allowing the use of when and unless methods for more expressive and concise conditional logic:
    • App
    • Alert
    • AutoUpdater
    • ChildProcess
    • Clipboard
    • Dock
    • Notification

Facade method annotations:

  • Updated Facade classes to include @method annotations for when and unless, ensuring IDEs and static analysis tools are aware of the new methods:
    • App
    • Alert
    • AutoUpdater
    • ChildProcess
    • Clipboard
    • Dock
    • Menu already conditionable, not annotated
    • Notification

@gwleuverink gwleuverink self-assigned this Oct 28, 2025
@gwleuverink gwleuverink added the enhancement New feature or request label Oct 28, 2025
Copy link
Member

@PeteBishwhip PeteBishwhip left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Worth a test to verify and assert the functionality remains and doesn't regress? :)

@gwleuverink
Copy link
Collaborator Author

Sure 👍🏻 What sort of test do you have in mind?

I'm only dropping in a trait here that is already covered by Laravel. So you must be meaning to test the integration with the existing logic?

We can't do a full end-to-end test with Electron for this. We can do assertions on a mock object to see if methods were called, but I don't think those will be very valuable. Do you have any suggestions on how to cover regressions @PeteBishwhip ? Keen to know your vantage point

@PeteBishwhip
Copy link
Member

To me, I think some tests don't have to test functionality as much as ensure certain traits.

For example, I have a test in my own repos which simply make sure that all classes in a specific namespace extend a specific class and fails if one doesn't.

In this case, if we can dynamically pull a list of registered facades, iterate through and ensure they include the Conditional trait... Or even just iterate the directory of Facades and just verify use Conditional; is present.

Just a small little failsafe that ensures we remain consistent. I'm happy to pop in a test for it on this PR if you're happy for me to? :)

@gwleuverink
Copy link
Collaborator Author

Ah check I get what you're saying! Perfect 👌 no worries I'm already at it

Copy link
Member

@simonhamp simonhamp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Beautiful! 😍

@gwleuverink
Copy link
Collaborator Author

@PeteBishwhip Is this what you had in mind?

800f055

@gwleuverink
Copy link
Collaborator Author

Hmm the test don't pass with prefer-lowest. Must be a incompatibility with the architecture testing api 🤔

Method "toUseTrait" does not exist in string.

pestphp/pest: 2.30.0
pestphp/pest-plugin: 2.1.1
pestphp/pest-plugin-arch: 2.5.0

@PeteBishwhip
Copy link
Member

@gwleuverink - That would work but doesn't protect against future additions. My thoughts were more to do a full scan of src/Facades and iterate through all, ensuring that the implement Conditionable.

This way, we can explicitly exclude a class if it should not include it, but by default, the test expects all and any newly created Facades to include it.

Something like:
tests/Pest.php:

use Symfony\Component\Finder\Finder;

/**
 * Get all concrete classes from facades in a namespace
 *
 * @param string $namespace The namespace to search (e.g., 'Native\Desktop\Facades')
 * @param string $path The directory path to search
 * @return Collection Collection of concrete class names from getFacadeAccessor()
 */
function getClassesInNamespace(string $namespace, string $path): Collection
{
    if (!is_dir($path)) {
        return [];
    }

    $classes = [];
    $finder = Finder::create()->files()->name('*.php')->in($path);

    foreach ($finder as $file) {
        $facadeClass = $namespace . '\\' . $file->getBasename('.php');
        
        if (class_exists($facadeClass) && method_exists($facadeClass, 'getFacadeAccessor')) {
            $concreteClass = $facadeClass::getFacadeAccessor();
            
            if (is_string($concreteClass) && class_exists($concreteClass)) {
                $classes[] = $concreteClass;
            }
        }
    }

    return collect($classes);
}

The test:

use Illuminate\Support\Traits\Conditionable;

it('ensures all facade concrete classes use Conditionable trait', function () {
    $excluded = [
        // Add explicitly excluded classes here
    ];

    arch()
        ->expect(
            getClassesInNamespace(
                'Native\\Desktop\\Facades',
                __DIR__ . '/../../src/Facades' // From tests/Architecture
            )->filter(fn ($value) => !in_array($value, $excluded))->toArray()
        )
        ->each
        ->toUseTrait(Conditionable::class);
});

I haven't tested this, and I took ages typing it in the comments box because I'm silly but it should work. Whats your thoughts?

@gwleuverink
Copy link
Collaborator Author

I see what you mean. Sure I can do that for the facades.

Not all of these in the list are facades though, I'll keep the others hardcoded.


})->skip(function () {
// Only run test when pest version is at least 3
return version_compare(version(), '3.0.0', '<');
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test was failing on prefer-lowest when using pest 2.

I admit that this workaround is a bit janky. But if this runs on the higher versions i think that is enough.

@PeteBishwhip
Copy link
Member

My understanding (albeit wrong looking back) was that we were adding Conditionable to all Facade insert faceplam emoji.

If it's specific ones, not really a way to dynamically ensure that things include it. In that case, your solution is okay.

@gwleuverink
Copy link
Collaborator Author

Most of these classes also have a facade so what you propose would work! We only also have to mix in some additional classes 👍 let me see if I can make it work

@gwleuverink
Copy link
Collaborator Author

Okay @PeteBishwhip i came to the same conclusion after writing it. I'll have to exclude about the same amount of classes I could remove using the 'dynamic' method. Maybe as it is is best in retrospect

@PeteBishwhip
Copy link
Member

Okay, no biggie. Was hoping for something to ensure standards moving forward but perhaps thats a project for the future :)

@gwleuverink gwleuverink merged commit ac3d6df into main Nov 6, 2025
30 checks passed
@gwleuverink
Copy link
Collaborator Author

I'm on board with the idea. It's just that about only half of these facades have a fluent api where the Conditionable trait makes sense. When I had the solution ready and done I reconsidered your previous comment 😅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants