BKWLD / decoy

A Laravel model-based CMS
http://docs.decoy.bukwild.com/
MIT License
303 stars 44 forks source link

How to check if Element exists? #64

Closed SomosAMambo closed 7 years ago

SomosAMambo commented 7 years ago

I did this as a helper:

function elementExists($key)
{
    foreach (app('decoy.elements')->getConfig() as $page => $page_data) {
        foreach (isset($page_data['sections']) ? $page_data['sections'] : $page_data as $section => $section_data) {
            foreach (isset($section_data['fields']) ? $section_data['fields'] : $section_data as $field => $field_data) {
                $field_parts = explode(',', $field);
                $field = $field_parts[0];

                if ($key == "{$page}.{$section}.{$field}") return true;
            }
        }
    }
    return false;
}

But it doesn't check for another elements files, and I think it's kind weird.

weotch commented 7 years ago

Do you wanna know if a value was set in the admin as opposed to just being defined in yaml? Or do you wanna check that the yaml key exists too?

eminos commented 7 years ago

I'm having a similar issue where I need to fetch an Element that might not exist. I thought I solved it with this code:

@php
    try {
        $title = Decoy::el(Route::currentRouteName() . '.header.heading') . ' | ';
    } catch (Exception $e) {
        $title = '';
    }
@endphp

Works on dev, but on the production server I get this error:

Method Bkwld\Decoy\Models\Element::__toString() must not throw an exception, caught LogicException: Relationship method must return an object of type Illuminate\Database\Eloquent\Relations\Relation

Any clues? Is there a smarter way to achieve what I'm trying to do?

weotch commented 7 years ago

When you say it may not exist, you mean not even in the yaml file right? LIke it's not been defined?

In your case @eminos, where you are fine with a default, you should be able to do:

Decoy::el(Route::currentRouteName() . '.header.heading', '') // Note default param

See: https://github.com/BKWLD/decoy/blob/master/classes/Collections/Elements.php#L80-L112

eminos commented 7 years ago

Hmm. I'm still getting that error, even when using no try/catch but the default value on the Element fetch.

weotch commented 7 years ago

Huh, ok, I'll dig more into later.

eminos commented 7 years ago

Also, I can not really just use a default value if the Element is not found, since I need to add that string ' | ' if the Element IS found. Is there a better way to achieve that (in one line?), or is try/catch the best way? I guess this is more of a laravel/php question, but I'm sure you have a good solution for it :)

SomosAMambo commented 7 years ago

@eminos Try my code... if the element to check existence is in the default yaml, the code works. @weotch the use case is exactly the one you showed Decoy::el(Route::currentRouteName() . '.header.heading', '') but without a default value. Lets say... there is some route without a name that uses the view with this code... or you have a default value for the posts route, but not for post.

eminos commented 7 years ago

@SomosAMambo Honestly I don't really understand your code. And I'm not sure it should be needed for such a simple thing that I'm trying to achieve. It should be a one-liner. Get Element value if it exist (+ concat string), else default (nothing). And it's suposed to be simple (as @weotch showed), but I'm getting a Decoy related error. Might be a bug...

eminos commented 7 years ago

I just realized another thing @weotch, the Element might not exist in the yaml at all, that's why the default value might not work at all... I just get an error (on dev).

Element key 'home.header.heading' is not declared in elements.yaml.

SomosAMambo commented 7 years ago

@eminos, our code is a helper function to achieve just what you described. Even if the element was not declared. Just one line of code: elementExists($key)

E.g.:

@if (elementExists('seo.home.description'))
<meta name="description" content="{{ Decoy::el('seo.home.description') }}">
@endif

You can even use string interpolation or concatenation to use a variable in the key parameter. E.g.:

$where = Request()->route()->getName();
if (elementExists("seo.$where.description"))

All you have to do is declare the elementExists function globally. In my case, I use a helper file where I declare all my helper functions. I hope this helps.