Skip to content

[6.x] Remove vendor from namespace if it exists#14100

Open
indykoning wants to merge 1 commit intostatamic:6.xfrom
indykoning:patch-5
Open

[6.x] Remove vendor from namespace if it exists#14100
indykoning wants to merge 1 commit intostatamic:6.xfrom
indykoning:patch-5

Conversation

@indykoning
Copy link
Contributor

I've run into this issue when using https://github.com/statamic-rad-pack/runway
Th blueprint edit page does have the correct url and handles set.
Once the save button is used a 404 gets thrown. Why?

Because the url is like follows /cp/fields/blueprints/vendor.runway/category
Meaning it will look for a blueprint with the handle vendor.runway::category

Bringing it to code, calling Blueprint::find('runway::category')->namespace() returns vendor.runway
(the full path to the file is /resources/blueprints/vendor/runway/category.yaml)

I'm not sure wether this should be moved to runway, but i did not seem to see a way for runway to add a path to remove to resolve the namespace.

@jasonvarga
Copy link
Member

jasonvarga commented Mar 2, 2026

I'm hesitant to just chop off parts of a string. Seems weird that the word vendor made it into the url in the first place.

@indykoning
Copy link
Contributor Author

The word vendor ending up in the url can be made sense of by going through the following functions

public function getNamespaceAndHandleFromPath($path)
{
    $namespace = collect($this->directories) // No directory is mapped so we end up with 'default'
        ->search(function ($directory) use ($path) {
            return Str::startsWith($path, $directory);
        });

    if ($namespace === 'default') {
        // When we're given $path of "/resources/blueprints/vendor/runway/category.yaml"
        // $this->directory() ("/resources/blueprints") gets stripped.
        // We end up with `vendor/runway/category.yaml`
        // Then we remove the .yaml suffix and end up with `vendor/runway/category` getting passed to `getNamespaceAndHandle`
        return $this->getNamespaceAndHandle(Str::after(Str::before($path, '.yaml'), $this->directory().'/'));
    }

    $directory = $this->directories[$namespace];
    $handle = Str::after(Str::before($path, '.yaml'), $directory.'/');

    return [$namespace, $handle];
}

protected function getNamespaceAndHandle($blueprint)
{
    // $blueprint is received as `vendor/runway/category`
    $blueprint = str_replace('/', '.', $blueprint);
    // $blueprint = "vendor.runway.category"
    $parts = explode('.', $blueprint);
    // $parts = ['vendor', 'runway', 'category']
    $handle = array_pop($parts);
    // $handle = "category" & $parts = ['vendor', 'runway']
    $namespace = implode('.', $parts);
    // $namespace = `vendor.runway`
    $namespace = empty($namespace) ? null : $namespace;

    return [$namespace, $handle];
}

An alternative would be to require each package utilising blueprints/vendor/.../ to add their blueprint directory with vendor
This support would need to be added though, as currently you are unable to append a directory to the list.
You can only overwrite them:

public function setDirectories(string|array $directories)

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants