blade
blade copied to clipboard
How to use blade components with this package?
I second this issue. From what I've read in the Laravel docs, you're supposed to be able to use
Stack Trace: #0 C:\inetpub*\vendor\illuminate\container\Container.php(845): Illuminate\Container\Container->notInstantiable() #1 C:\inetpub*\vendor\illuminate\container\Container.php(717): Illuminate\Container\Container->build() #2 C:\inetpub*\vendor\illuminate\container\Container.php(655): Illuminate\Container\Container->resolve() #3 C:\inetpub*\vendor\illuminate\view\Compilers\ComponentTagCompiler.php(247): Illuminate\Container\Container->make() #4 C:\inetpub*\vendor\illuminate\view\Compilers\ComponentTagCompiler.php(211): Illuminate\View\Compilers\ComponentTagCompiler->componentClass() #5 C:\inetpub*\vendor\illuminate\view\Compilers\ComponentTagCompiler.php(144): Illuminate\View\Compilers\ComponentTagCompiler->componentString() #6 [internal function]: Illuminate\View\Compilers\ComponentTagCompiler->Illuminate\View\Compilers{closure}() #7 C:\inetpub*\vendor\illuminate\view\Compilers\ComponentTagCompiler.php(139): preg_replace_callback() #8 C:\inetpub*\vendor\illuminate\view\Compilers\ComponentTagCompiler.php(90): Illuminate\View\Compilers\ComponentTagCompiler->compileOpeningTags() #9 C:\inetpub*\vendor\illuminate\view\Compilers\ComponentTagCompiler.php(76): Illuminate\View\Compilers\ComponentTagCompiler->compileTags() #10 C:\inetpub*\vendor\illuminate\view\Compilers\BladeCompiler.php(334): Illuminate\View\Compilers\ComponentTagCompiler->compile() #11 C:\inetpub*\vendor\illuminate\view\Compilers\BladeCompiler.php(231): Illuminate\View\Compilers\BladeCompiler->compileComponentTags() #12 C:\inetpub*\vendor\illuminate\view\Compilers\BladeCompiler.php(150): Illuminate\View\Compilers\BladeCompiler->compileString() #13 C:\inetpub*\vendor\illuminate\view\Engines\CompilerEngine.php(55): Illuminate\View\Compilers\BladeCompiler->compile() #14 C:\inetpub*\vendor\illuminate\view\View.php(139): Illuminate\View\Engines\CompilerEngine->get() #15 C:\inetpub*\vendor\illuminate\view\View.php(122): Illuminate\View\View->getContents() #16 C:\inetpub*\vendor\illuminate\view\View.php(91): Illuminate\View\View->renderContents() #17 C:\inetpub*\Framework\Blade\BladeController.class.php(125): Illuminate\View\View->render() #18 C:\inetpub*\Framework\Core\CoreController.php(18): Blade\BladeController->loadView() #19 C:\inetpub*\App\Controllers\CMS\Home.php(22): Core\CoreController->view() #20 C:\inetpub*\Framework\Bootstrap\Api.php(192): Controllers\CMS\Home->Index() #21 C:\inetpub***\Public\index.php(38): Bootstrap\Api::__dispatch_routing() #22 {main}
Any help with this issue would be greatly appreciated.
Anonymous components ala 6.x work for me, fyi, like @component('alert')
. But I get the same issue for Blade <x-
templates. From quick cursory checks, it looks like Blade-x depends on several additional illuminate packages (cache/config, possibly even the entire illuminate/foundation).
Is there any way this is fixed in the future?
I was able to set up x-
components but it's very verbose (since I am trying to show multifile solution in one post) and probably not correct way to do this.
<?php
use Illuminate\Container\Container;
use Illuminate\Contracts\Foundation\Application as ApplicationContract;
use Illuminate\Contracts\View\Factory as ViewFactoryContract;
use Illuminate\Support\Facades\Facade;
use Illuminate\View\Component;
use Illuminate\View\View;
use Jenssegers\Blade\Blade as JenssegersBlade;
$app = Container::getInstance();
$app->bind(ApplicationContract::class, Container::class);
$app->alias('view', ViewFactoryContract::class);
$blade = new JenssegersBlade(
['views'],
'views/compiled',
$app
);
$viewFactory = Facade::getFacadeApplication()->get('view');
$blade->compiler()->components([
'media-image' => MediaImage::class,
'components.anonymous.breadcrumbs' => 'breadcrumbs' // yes, anonymous components with @props
]);
trait BladeViewComponent
{
public function view(string $name): View
{
global $viewFactory;
return $viewFactory->make("components.{$name}", $this->extractPublicProperties());
}
public function render(): View
{
return $this->view($this->template);
}
}
// Very rough example with some wordpress stuff
final class MediaImage extends Component
{
use BladeViewComponent;
public readonly WordPressMediaImage|bool $image;
private string $template = 'media-image';
/**
* @param string $wordpresstitle title of WP image attachment to process
* @param string $size size parameter for wp image functions
* @param string $class all the classes to assign to the img tag
* @param int $preload if the image needs to be preloaded
*/
public function __construct(
public readonly string $wordpresstitle,
public readonly string $size = 'full',
public readonly string $class = 'media-image',
public readonly int $preload = 0
) {
$this->image = $this->getWordPressMediaImage();
}
private function getAttachmentIdByTitle(): int|bool
{
$attachment = get_posts([
'numberposts' => 1,
's' => trim($this->wordpresstitle),
'lang' => pll_current_language('slug'),
'post_type' => 'attachment'
])[0];
if (!$attachment || !isset($attachment->ID)) {
error_log("Media image not found: {$this->wordpresstitle}", 1);
return false;
}
return $attachment->ID;
}
private function getWordPressMediaImage(): WordPressMediaImage|bool
{
if ($id = $this->getAttachmentIdByTitle()) {
return new WordPressMediaImage($id, $this->size);
}
return false;
}
}
Then in your blade template you can put this:
<x-media-image wordpresstitle="Background" class="home-bg-img" preload />
And components/media-image.blade.php
looks like this:
@if ($image === false)
<h1>There has been an error loading image "{{ $wordpresstitle }}"</h1>
@else
@if ($preload)
@push('preload')
<link
rel="preload"
as="image"
href="{{ $image->src }}"
imagesrcset="{{ $image->srcsetWebp ? $image->srcsetWebp : $image->srcset }}"
imagesizes="{{ $image->sizes }}"
/>
@endpush
@endif
<picture>
@if ($image->srcsetWebp)
<source
srcset="{{ $image->srcsetWebp }}"
sizes="{{ $image->sizes }}"
type="image/webp"
/>
@endif
<source
srcset="{{ $image->srcset }}"
sizes="{{ $image->sizes }}"
type="{{ $image->metaData['sizes']['medium']['mime-type'] }}"
/>
<img
src="{{ $image->src }}"
width="{{ $image->metaData['width'] }}"
height="{{ $image->metaData['height'] }}"
alt="{{ $image->alt }}"
title="{{ $image->caption }}"
class="{{ $class }}"
loading="lazy"
/>
</picture>
@endif
Ok, I forked this repo and made some updates to be able to use components (class-based and anonymous)
https://github.com/lexdubyna/blade
@lexdubyna how did you set this up in a WordPress theme? Is it possible to render from a given HTML string (that contains x-components)?
To be more specific, I'm calling the $blade->compileString( $html );
method which throws me the error PHP Fatal error: Uncaught Illuminate\Contracts\Container\BindingResolutionException: Target [Illuminate\Contracts\Foundation\Application] is not instantiable. in E:\github\spring-reveal-plugin\vendor\illuminate\container\Container.php:1089
.
This is the complete code used in my WordPress plugin:
<?php
/*
* Plugin Name: Spring reveal
*/
require plugin_dir_path( __FILE__ ) . '/vendor/autoload.php';
use Lexdubyna\Blade\Blade;
$blade = new Blade('views', 'cache');
add_action( 'init', function () {
ob_start();
} );
add_action( 'shutdown', function () {
global $blade;
$html = ob_get_clean();
echo $blade->compileString( $html );
exit;
}, 0 );
@kaspost You can check out how I implemented compileString
in my forked version of this package:
https://github.com/lexdubyna/blade/blob/master/src/Blade.php#L133
Also, I'm not sure whether it's a good idea to put ob_start
and ob_get_clean
in two different actions.
@lexdubyna Thank you and I'm using your forked version in composer. I boiled down the code to this bare minimum which still throws me the same error:
<?php
/*
* Plugin Name: X Components test
*/
$plugin_dir = plugin_dir_path( __FILE__ );
require $plugin_dir . '/vendor/autoload.php';
use Lexdubyna\Blade\Blade;
$blade = new Blade( $plugin_dir . '/views', $plugin_dir . '/cache' );
echo $blade->compileString( '<x-test />' );
The folder content is: plugin.php /cache /views/components/test.blade.php /views/test.blade.php
Is there something I'm missing here?
@lexdubyna Where do we put our components? I am getting an error that App\View\Components\Alert not found
@kaspost I have not yet tested x-components compiled from string. Will look into it.
@Marvellous890 This is my test folders structure that works:
app
Components
MediaImage.php
views
compiled
components
anonymous
alert.php
media-image.blade.php
and code:
$blade = new Lexdubyna\Blade\Blade(
[get_template_directory() . '/views'],
get_template_directory() . '/views/compiled'
);
$blade->compiler()->components([
'media-image' => App\Components\MediaImage::class,
'components.anonymous.alert' => 'alert'
]);