Giter Site home page Giter Site logo

riclep / laravel-storyblok Goto Github PK

View Code? Open in Web Editor NEW
58.0 3.0 15.0 521 KB

Make Laravel and Storyblok work together beautifully.

Home Page: https://ls.sirric.co.uk/

License: MIT License

PHP 98.79% Blade 1.21%
laravel storyblok storyblok-client storyblok-api content-management-system content-management headless-cms php headless

laravel-storyblok's Issues

Enable (rendering of) inline components within the RichText field

Hey, again thanks for the nice package!

Storyblok allows to insert components within the RichText field [1]. But from what i understood the provided storyblok/richtext-resolver for PHP does not handle them. Anyways, i needed to render inline components and came up with the following code. Maybe its a common enough use-case to be added to the core of this package.

I found no way to overwrite the existing RichText Field Class, so i added a Custom Field and named it accordingly in Storyblok. Maybe it would be nice if one could also overwrite the built-in fields to apply changes globally based on the field type vs the field name.

<?php

namespace App\Storyblok\Fields;

use Riclep\Storyblok\Fields\RichText as BaseRichText;
use Storyblok\RichtextRender\Resolver;
use Riclep\Storyblok\Block;

class Richtextfield extends BaseRichText
{
	/**
	 * Converts the data to HTML when printed
	 *
	 * @return string
	 */
	public function __toString()
	{
        $richtextResolver = new Resolver();

        $out = "";
        // Loop through all nodes from the RichText Field
        // Either Render them normally
        // Or if type is 'blok' create a block an add the rendered content to ouput
        foreach ($this->content['content'] as $node) {
            if ($node['type'] == 'blok' && isset($node['attrs']['body']) && is_array($node['attrs']['body'])){
                foreach ($node['attrs']['body'] as $blockContent) {
                    $block = new Block($blockContent, $this->block()->parent());
                    $out .= $block->render();
                }
            } else {
                $out .= $richtextResolver->render(["content" => [$node]]);
            }
        }
        return $out;
        // Original
		// return $richtextResolver->render($this->content);
	}
}

[1] https://www.storyblok.com/docs/richtext-field#components-inside-the-richtext-field

[Bug] Multi-option Parsing

Overview

Hello there 👋 .

We seem to be encountering a bug in one of the recent updates of your package. We upgraded from 2.15.0 to 2.19.2 and parsing of multi-option fields is no longer working.

After doing a bit more research the bug seems to have been introduced in 2.17.0.

Steps to Reproduce

  • Create a page
  • Add a new field that is a muti-option with a source as self
  • Add some options
  • Add field to page
  • Inspect draft response, and you should see something like:
{
    "story": {
        "content": {
            "_uid": "1515771c-3ec4-4922-8921-9607eda522e6",
            "body": [
                {
                    "_uid": "29914472-2a98-428d-868c-56c30207d608",
                    "component": "test-component",
                    "test_field": [
                        "20",
                        "10",
                        "30"
                    ],
                }
            ]
        }
    }
}

Expected Result

I expect in the component TestComponent to have access to a field called test_field that would be an array.

Actual Result

When accessing test_field, null is returned.

Question about serializing blocks

Question

Hey there 👋 .

This is more of a question than a feature request or bug ticket.

Let's say you have a block that you are going to serialize (via json_encode or the like). This package uses the magic __get() function to get attributes out of the private $fields array behind the scenes, so the JSON encoded object only has a few public properties (resolve relations and whatnot).

Is there a native way to get the full class serialized with all of the Storyblok attributes included? If there isn't, would that be something you want this package to handle?

Background

A lot of times we are using Storyblok to render our data, but then there are some frontend manipulations that we want to do as well. To accomplish our goals, sometimes we need to encode the Storyblok object into javascript to be used on the client.

Example

If I use the laravel @json directive on any component, the output will look similar to this:

{"_autoResolveRelations":false,"_resolveRelations":[],"_filterRelations":true,"_componentPath":["page","page","full-section","button"]}

But if I @dd that same instance, I get something like this:

App\Storyblok\Blocks\Button {[#1588 ▼]
  +_autoResolveRelations: false
  +_resolveRelations: []
  +_filterRelations: true
  +_componentPath: array:4 [[▶]()]
  #_casts: []
  -_fields: Illuminate\Support\Collection {[#1589 ▼]()
    #items: array:15 [[▼]()
      "url" => Riclep\Storyblok\Fields\UrlLink {[#1592 ▶]()}
      "size" => "normal"
      "text" => "Rawr"
    ]
    #escapeWhenCastingToString: false
    // other attributes
  }
}

Notice that the component has data like size and text in it, but it doesn't show up in the serialized instance.

Call to undefined method App\Storyblok\Block::flatten()

Overview

Looks like the latest version broke something in the editor-bridge. I see a function called flatten was removed, but not seeing any obvious references.

Error

Error
Call to undefined method App\Storyblok\Block::flatten() (View: /.../projectname/vendor/riclep/laravel-storyblok/src/resources/views/editor-bridge.blade.php)

Steps to Reproduce

  • Upgrade from previous version to version 2.6.0
  • Create a new piece of content inside Storyblok (or anything that enables the editor bridge)

Cache ignores $page in paginated fetching

Thanks for the awesome library.

Referring to line: https://github.com/RicLeP/laravel-storyblok/blob/master/src/Folder.php#L165

If we have the following two pages we get the same results back, the second from the cache.

// example.org/some-content?page=1
$requestSomeContent = new Folder();
$requestSomeContent->slug('some-content');
$requestSomeContent->perPage(10);
$requestSomeContent->settings([
    'is_startpage' => false,
    'filter_query' => [],
]);

// yields cache key:
// folder-some-content-4893ccccb8f122d63a21febbbb000000

// example.org/some-content?page=2
$requestSomeContent = new Folder();
$requestSomeContent->slug('some-content');
$requestSomeContent->perPage(10);
$requestSomeContent->settings([
  'is_startpage' => false,
  'filter_query' => [],
]);

// yields cache key:
// folder-some-content-4893ccccb8f122d63a21febbbb000000

Note on the second request (page=2), the cache key constructed doesn't account for the current page which gives it the same key, meaning we get the cached data back.

I believe the cache key should include $page in the cache key if set.

If I disable the cache (STORYBLOK_CACHE=false) it works as expected.
Looking through telescope I can confirm the cache keys aren't accounting for $page.

Dealing with pagination

Hi @RicLeP, I was wondering how you'd deal with paginating through the StoryBlok API when there's more than 100 articles in a 'collection'.

E.G. my client has a blog with several hundred articles - I couldn't see a process for iterating through all of the blog posts - just the first 100.

Detecting broken images to prevent calling transform()

A bit of an edge case here, but I've got a StoryBlok instance where we imported thousands of articles into the system, and we have a ton of broken images.

The client's gradually going through and fixing them, but we've gone live anyway - so there's a lot of older pages that just error out when we use $image->transform().

My current method of detecting if an image exists or not is to do a check on $story->image->filename.

However with broken images imported into Storyblok, there's still a filename (which is helping my client to figure out which images need to be added back in).

I could probably do a check on the $image->copyright or $image->alt fields - these are null on broken images, and if not utilised are empty.

But I thought it might be a better option to be able to check the transformer for the extension type - which will return null on these images.

As I said, very much an edge case, but I'd be interested to hear your thoughts on a solve.

Scaffolding Empty Components Errors

Overview

When generating new components that have no items in the schema, the command errors out.

Steps to Reproduce

  1. Create new component in Storyblok with no fields (an empty schema)
  2. Run command to scaffold component like so:
php artisan ls:block EmptyComponent

Expected

I expect a class representation of the component, but with no available attributes listed.

Actual

Command errors out with the following stack:

   ErrorException

  Trying to access array offset on value of type null

  at vendor/riclep/laravel-storyblok/src/Console/BlockSyncCommand.php:154
    150▕
    151▕ 			$component = $components->firstWhere('name', $name);
    152▕
    153▕ 			$fields = [];
  ➜ 154▕ 			foreach ($component['schema'] as $name => $data) {
    155▕ 				if ( ! $this->isIgnoredType($data['type'])) {
    156▕ 					$fields[$name] = $this->convertToPhpType($data['type']);
    157▕ 				}
    158▕ 			}

      +29 vendor frames
  30  artisan:37
      Illuminate\Foundation\Console\Kernel::handle(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))

Artisan command to create block template uses folder …/components while Block.php searches in …/blocks

Hey there, thanks for the package!

While following the documentation about Blocks i ran into an issue with my blocks not being rendered properly.

php artisan ls:block MyComponent -b
Creates a template in ressources/views/storyblok/components/my-component.blade.php.
This will not be found by the Block Class automatically. It expects the templates to reside in ressources/views/storyblok/blocks/ see

public function views() {

Once i renamed the folder the template gets used.

File Permission Issue with Console Commands

Overview

It appears that there is an issue when using the console commands that are using the replace method on files where it will actually update file permissions unnecessarily.

Steps to Reproduce

  1. Create a component in Storyblok
  2. Create class representation for said component php artisan ls:block <component>
  3. Add a new field to the component
  4. Run php artisan ls:sync

Expected Outcome

The new field will show up as a property for that block's class. File permissions should remain 644 (rw, r, r).

Actual Outcome

The new field will show up as a property for that block's class. File permissions are updated to 755 (rwx, rx, rx).

Fine tuning default configuration (public api key)

In a clean Laravel project if I try to install laravel-storyblok package i receive an error:

Storyblok\BaseClient::setApiKey(): Argument #1 ($apiKey) must be of type string, null given, called in /Users/roberto/Sites/composable-example/vendor/storyblok/php-client/src/Storyblok/BaseClient.php on line 81

I think this issue could be solved by setting the default as an empty string in the config/storyblok.php:

'api_public_key' => env('STORYBLOK_PUBLIC_API_KEY', ''),

Instead of:

'api_public_key' => env('STORYBLOK_PUBLIC_API_KEY'),

Undefined Variable after Generating Block

Looks like a recent change to the generator command stub changed the variable in the blade file from $content to $block. Now when generating a fresh block with the latest version of the library, you get this error:

Undefined variable: block (View: /projects/www.bankrate.com/resources/views/storyblok/blocks/teaser.blade.php)

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

composer
composer.json
  • php ^8.1|^8.2|^8.3
  • barryvdh/reflection-docblock ^2.0
  • embed/embed ^3.4|^4
  • illuminate/support ^9.0|^10.0|^11.0
  • imgix/imgix-php ^3.3|^4.0
  • ivopetkov/html5-dom-document-php 2.*
  • league/commonmark ^2.0
  • spatie/laravel-ignition ^2.8
  • spatie/schema-org ^3.3
  • storyblok/php-client ^2.3
  • storyblok/richtext-resolver ^2.2
  • mockery/mockery ^1.2
  • orchestra/testbench ^8.0|^9.0
  • phpunit/phpunit ^10
github-actions
.github/workflows/tests.yml
  • actions/checkout v3
  • php-actions/composer v6
  • php-actions/phpunit v3

  • Check this box to trigger a request for Renovate to run again on this repository

Having trouble with the basics

This is almost certainly down to a lack of experience with Laravel, but I'm having trouble getting started.

I've got a StoryBlok space setup with a ton of content imported into it.

I've got laravel and laravel-storyblok installed, and serving on localhost.

Environment variables are set, and by the errors I'm getting, it's definitely trying to hit the storyblok API. I've got the catch-all router in place.

I've gone back to basics, created the file /resources/views/storyblok/pages/page.blade.php which looks like this:

<main>
<header>
    <h1>@{{ $story->title }}</h1>
</header>

<section>
<?php dd($story); ?>
</section>
</main>

I've created a page called 'test' at the root of Storyblok, using the 'page' component, which has two fields defined - title and text.

But the @{{ $story->title }} just displays {{ $story->title}} in the browser.

The dd does give me a result:

App\Storyblok\Page {#1180 ▼
  +_componentPath: array:1 [▶]
  -block: App\Storyblok\Block {#1090 ▶}
  -story: array:22 [▼
    "name" => "test"
    "created_at" => "2021-11-17T10:41:40.966Z"
    "published_at" => "2021-11-17T10:42:25.116Z"
    "alternates" => []
    "id" => 86019624
    "uuid" => "761d11ac-c8bd-4eee-ae1f-6e3dbdc920bf"
    "content" => array:4 [▼
      "_uid" => "fbb0f60a-3c57-456e-84c3-8b86f02aeae0"
      "body" => array:1 [▼
        0 => array:4 [▼
          "_uid" => "62cd6c66-4d78-4ee5-af0f-e17b231fabda"
          "title" => "My big test"
          "component" => "text"
          "_editable" => "<!--#storyblok#{"name": "text", "space": "127485", "uid": "62cd6c66-4d78-4ee5-af0f-e17b231fabda", "id": "86019624"}-->"
        ]
      ]
      "component" => "page"
      "_editable" => "<!--#storyblok#{"name": "page", "space": "127485", "uid": "fbb0f60a-3c57-456e-84c3-8b86f02aeae0", "id": "86019624"}-->"
    ]
    "slug" => "test"
    "full_slug" => "test"
    "default_full_slug" => null
    "sort_by_date" => null
    "position" => -40
    "tag_list" => []
    "is_startpage" => false
    "parent_id" => 0
    "meta_data" => null
    "group_id" => "c3210eaf-a185-46ea-b7c5-a54424b3fcc9"
    "first_published_at" => "2021-11-17T10:42:25.116Z"
    "release_id" => null
    "lang" => "default"
    "path" => null
    "translated_slugs" => []
  ]
  +liveContent: []
  #_meta: array:5 [▶]
}

Only slugs in Storyblok root produce this kind of result, everything else errors out completely - usually because the API call is using the slug without the 'starts_with'. For example:

Storyblok\ApiException
An HTTP Error has occurred! - An HTTP Error has occurred! - Client error: `GET http://api.storyblok.com/v1/cdn/stories/blog?token=xxxxx&version=draft&cache_version=1637149023` resulted in a `404 Not Found` response: {"stories":["This record could not be found"]}

If I hit the API directly in the browser with a 'starts_with=blog/' parameter, then I get a full API response.

So definitely I'm missing something here, and if the answer is "learn more Laravel", then that's perfectly acceptable answer!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.