diff --git a/classes/core/PKPBladeViewServiceProvider.php b/classes/core/PKPBladeViewServiceProvider.php new file mode 100644 index 00000000000..85a241310f3 --- /dev/null +++ b/classes/core/PKPBladeViewServiceProvider.php @@ -0,0 +1,148 @@ +registerViewFinder(); + $this->registerBladeCompiler(); + $this->registerEngineResolver(); + $this->registerFactory(); + } + + /** + * Register the view environment. + * + * @return void + */ + public function registerFactory() + { + $this->app->singleton( + ViewFactory::class, + fn (PKPContainer $app) => $this->configureViewFactoryWithBindings($app) + ); + + $this->app->singleton( + 'view', + fn (PKPContainer $app) => $app->get(ViewFactory::class) + ); + } + + /** + * Register the view finder implementation. + * + * @return void + */ + public function registerViewFinder() + { + $this->app->singleton( + 'view.finder', + fn (PKPContainer $app) => new FileViewFinder( + $app->get('files'), + [ + $app->basePath('/templates'), + $app->basePath('/lib/pkp/templates'), + ] + ) + ); + } + + /** + * Register the Blade compiler implementation. + * + * @return void + */ + public function registerBladeCompiler() + { + $this->app->singleton('blade.compiler', function (PKPContainer $app) { + return tap(new BladeCompiler( + $app->get('files'), + BASE_SYS_DIR . '/compiled', + $app->get('config')->get('view.relative_hash', false) ? $app->basePath() : '', + $app->get('config')->get('view.cache', true), + $app->get('config')->get('view.compiled_extension', 'php'), + ), function (BladeCompiler $bladeCompiler) { + $bladeCompiler->component('dynamic-component', DynamicComponent::class); + + // Register component namespaces for PKP and APP Blade components + $bladeCompiler->componentNamespace('PKP\\components', 'pkp'); + $bladeCompiler->componentNamespace('APP\\components', 'app'); + + $this->app->instance(BladeCompiler::class, $bladeCompiler); + $this->app->alias( + BladeCompiler::class, + (new class extends \Illuminate\Support\Facades\Blade { + public static function getFacadeAccessor() { return parent::getFacadeAccessor(); } + })::getFacadeAccessor() + ); + }); + }); + } + + /** + * Register the Blade engine implementation. + * + * @param \Illuminate\View\Engines\EngineResolver $resolver + * @return void + */ + public function registerBladeEngine($resolver) + { + $resolver->register( + 'blade', + fn () => new CompilerEngine( + $this->app['blade.compiler'], + $this->app['files'] + ) + ); + } + + /** + * Configure the view factory with required bindings and setting the alias + * + * @param \PKP\core\PKPContainer $app + * @return \Illuminate\View\Factory + */ + protected function configureViewFactoryWithBindings(PKPContainer $app): ViewFactory + { + // Next we need to grab the engine resolver instance that will be used by the + // environment. The resolver will be used by an environment to get each of + // the various engine implementations such as plain PHP or Blade engine. + $resolver = $app->get('view.engine.resolver'); + + $finder = $app->get('view.finder'); + + $factory = $this->createFactory($resolver, $finder, $app->get('events')); + + // We will also set the container instance on this view environment since the + // view composers may be classes registered in the container, which allows + // for great testable, flexible composers for the application developer. + $factory->setContainer($app); + + $factory->share('app', $app); + + $app->instance(\Illuminate\Contracts\View\Factory::class, $factory); + $app->alias( + \Illuminate\Contracts\View\Factory::class, + (new class extends \Illuminate\Support\Facades\View { + public static function getFacadeAccessor() { return parent::getFacadeAccessor(); } + })::getFacadeAccessor() + ); + + return $factory; + } +} diff --git a/classes/core/PKPContainer.php b/classes/core/PKPContainer.php index 2283669131a..a438a71fd9c 100644 --- a/classes/core/PKPContainer.php +++ b/classes/core/PKPContainer.php @@ -30,6 +30,7 @@ use Illuminate\Support\Str; use Laravel\Scout\EngineManager; use PKP\config\Config; +use PKP\core\PKPBladeViewServiceProvider; use PKP\i18n\LocaleServiceProvider; use PKP\proxy\ProxyParser; use Throwable; @@ -57,6 +58,17 @@ public function __construct() $this->registerCoreContainerAliases(); } + /** + * Get the application namespace. + * Required by Laravel's ComponentTagCompiler for component discovery. + * + * @return string + */ + public function getNamespace(): string + { + return 'PKP\\'; + } + /** * Get the proper database driver */ @@ -83,6 +95,7 @@ protected function registerBaseBindings(): void static::setInstance($this); $this->instance('app', $this); $this->instance(Container::class, $this); + $this->instance(\Illuminate\Contracts\Foundation\Application::class, $this); $this->instance('path', $this->basePath); $this->instance('path.config', "{$this->basePath}/config"); // Necessary for Scout to let CLI happen $this->singleton(ExceptionHandler::class, function () { @@ -189,6 +202,7 @@ public function registerConfiguredProviders(): void $this->register(new ConsoleCommandServiceProvider($this)); $this->register(new ValidationServiceProvider($this)); $this->register(new \Illuminate\Foundation\Providers\FormRequestServiceProvider($this)); + $this->register(new PKPBladeViewServiceProvider($this)); $this->register(new \Laravel\Scout\ScoutServiceProvider($this)); } @@ -336,6 +350,9 @@ public function registerCoreContainerAliases(): void \Illuminate\Contracts\Encryption\Encrypter::class, \Illuminate\Contracts\Encryption\StringEncrypter::class, ], + 'view' => [ + \Illuminate\Support\Facades\View::class, + ], ] as $key => $aliases) { foreach ($aliases as $alias) { $this->alias($key, $alias); diff --git a/composer.json b/composer.json index 1e8208bc746..e8981d5da20 100644 --- a/composer.json +++ b/composer.json @@ -83,6 +83,8 @@ "APP\\pages\\": "../../pages/", "PKP\\": "classes/", "APP\\": "../../classes/", + "PKP\\components\\": ["templates/components/"], + "APP\\components\\": ["../../templates/components/"], "PKP\\plugins\\": "plugins/", "APP\\plugins\\": "../../plugins/", "PKP\\jobs\\": "jobs/", diff --git a/pages/about/AboutContextHandler.php b/pages/about/AboutContextHandler.php index c836cdf4362..2e0fcb402f1 100644 --- a/pages/about/AboutContextHandler.php +++ b/pages/about/AboutContextHandler.php @@ -25,6 +25,8 @@ use PKP\context\Context; use PKP\facades\Locale; use PKP\orcid\OrcidManager; +use Illuminate\Support\Facades\View; +use PKP\core\PKPContainer; use PKP\plugins\Hook; use PKP\security\authorization\ContextRequiredPolicy; use PKP\security\Role; @@ -57,9 +59,21 @@ public function authorize($request, &$args, $roleAssignments) */ public function index($args, $request) { - $templateMgr = TemplateManager::getManager($request); - $this->setupTemplate($request); - $templateMgr->display('frontend/pages/about.tpl'); + // Render template with page.blade.php + // we can also use View::make('TEMPLATE', [...]); + echo view('bladeTest.about', [ + 'title' => 'My Title', + 'text' => 'This is my text!', + ]); + + // echo \Illuminate\Support\Facades\View::make('about', [ + // 'title' => 'My Title', + // 'text' => 'This is my text!', + // ]); + + // $templateMgr = TemplateManager::getManager($request); + // $this->setupTemplate($request); + // $templateMgr->display('frontend/pages/about.tpl'); } diff --git a/templates/bladeTest/about.blade.php b/templates/bladeTest/about.blade.php new file mode 100644 index 00000000000..335632bbf6a --- /dev/null +++ b/templates/bladeTest/about.blade.php @@ -0,0 +1,6 @@ +Hello World -- from /lib/pkp/template +params : + title : {{$title}} + text : {{$text}} + + \ No newline at end of file diff --git a/templates/bladeTest/article.blade.php b/templates/bladeTest/article.blade.php new file mode 100644 index 00000000000..e9259f73db4 --- /dev/null +++ b/templates/bladeTest/article.blade.php @@ -0,0 +1,30 @@ + + + + @foreach($component->authors as $author) + + + + @foreach($component->affiliations as $affiliation) + + + + + @endforeach + + + + + + + + @foreach($component->creditRoles as $creditRole) + + + + + @endforeach + + + @endforeach + \ No newline at end of file diff --git a/templates/components/Author.php b/templates/components/Author.php new file mode 100644 index 00000000000..60eb6b4dd16 --- /dev/null +++ b/templates/components/Author.php @@ -0,0 +1,56 @@ +author = $author; + + // Get affiliations and credit roles from author object + if ($author) { + $this->affiliations = $author->affiliations ?? []; + $this->creditRoles = $author->creditRoles ?? []; + } + } + + /** + * Get the view / contents that represent the component. + * + * @return \Illuminate\Contracts\View\View|\Closure|string + */ + public function render() + { + // The component instance is available as $component in the view + return view('components.author')->with('component', $this); + } +} \ No newline at end of file diff --git a/templates/components/Authors.php b/templates/components/Authors.php new file mode 100644 index 00000000000..aa24206c29b --- /dev/null +++ b/templates/components/Authors.php @@ -0,0 +1,51 @@ +publication = $publication; + + // Get authors from publication's authors field + if ($publication && isset($publication->authors)) { + $this->authors = $publication->authors; + } else { + $this->authors = []; + } + } + + /** + * Get the view / contents that represent the component. + * + * @return \Illuminate\Contracts\View\View|\Closure|string + */ + public function render() + { + // The component instance is available as $component in the view + return view('components.authors')->with('component', $this); + } +} \ No newline at end of file diff --git a/templates/components/author.blade.php b/templates/components/author.blade.php new file mode 100644 index 00000000000..a76c8c7748e --- /dev/null +++ b/templates/components/author.blade.php @@ -0,0 +1,5 @@ +@props(['author']) + +
+ {{ $slot }} +
\ No newline at end of file diff --git a/templates/components/author/affiliation.blade.php b/templates/components/author/affiliation.blade.php new file mode 100644 index 00000000000..3b95dedaa65 --- /dev/null +++ b/templates/components/author/affiliation.blade.php @@ -0,0 +1,5 @@ +@props(['affiliation']) + +
+ {{ $slot }} +
\ No newline at end of file diff --git a/templates/components/author/affiliation/name.blade.php b/templates/components/author/affiliation/name.blade.php new file mode 100644 index 00000000000..b14f9542513 --- /dev/null +++ b/templates/components/author/affiliation/name.blade.php @@ -0,0 +1,3 @@ + + University Name + \ No newline at end of file diff --git a/templates/components/author/affiliation/ror.blade.php b/templates/components/author/affiliation/ror.blade.php new file mode 100644 index 00000000000..280dae4f6b0 --- /dev/null +++ b/templates/components/author/affiliation/ror.blade.php @@ -0,0 +1,3 @@ + + ROR-ID-123456 + \ No newline at end of file diff --git a/templates/components/author/affiliations.blade.php b/templates/components/author/affiliations.blade.php new file mode 100644 index 00000000000..a260a3e4502 --- /dev/null +++ b/templates/components/author/affiliations.blade.php @@ -0,0 +1,3 @@ +
+ {{ $slot }} +
\ No newline at end of file diff --git a/templates/components/author/credit-role.blade.php b/templates/components/author/credit-role.blade.php new file mode 100644 index 00000000000..3c2d0f4854a --- /dev/null +++ b/templates/components/author/credit-role.blade.php @@ -0,0 +1,5 @@ +@props(['creditRole']) + +
+ {{ $slot }} +
\ No newline at end of file diff --git a/templates/components/author/credit-role/degree.blade.php b/templates/components/author/credit-role/degree.blade.php new file mode 100644 index 00000000000..0c17dde85cd --- /dev/null +++ b/templates/components/author/credit-role/degree.blade.php @@ -0,0 +1,3 @@ + + Lead + \ No newline at end of file diff --git a/templates/components/author/credit-role/name.blade.php b/templates/components/author/credit-role/name.blade.php new file mode 100644 index 00000000000..5f2ac9fb355 --- /dev/null +++ b/templates/components/author/credit-role/name.blade.php @@ -0,0 +1,5 @@ +@props(['creditRole']) + + + Conceptualization + \ No newline at end of file diff --git a/templates/components/author/credit-roles.blade.php b/templates/components/author/credit-roles.blade.php new file mode 100644 index 00000000000..5e21ca8e9e3 --- /dev/null +++ b/templates/components/author/credit-roles.blade.php @@ -0,0 +1,3 @@ +
+ {{ $slot }} +
\ No newline at end of file diff --git a/templates/components/author/full-name.blade.php b/templates/components/author/full-name.blade.php new file mode 100644 index 00000000000..772cba47f0f --- /dev/null +++ b/templates/components/author/full-name.blade.php @@ -0,0 +1,3 @@ + + John Doe + \ No newline at end of file diff --git a/templates/components/author/orcid.blade.php b/templates/components/author/orcid.blade.php new file mode 100644 index 00000000000..e4c5cc33223 --- /dev/null +++ b/templates/components/author/orcid.blade.php @@ -0,0 +1,3 @@ +
+ {{ $slot }} +
\ No newline at end of file diff --git a/templates/components/author/orcid/icon.blade.php b/templates/components/author/orcid/icon.blade.php new file mode 100644 index 00000000000..0721ed28126 --- /dev/null +++ b/templates/components/author/orcid/icon.blade.php @@ -0,0 +1,3 @@ + + 📗 + \ No newline at end of file diff --git a/templates/components/author/orcid/value.blade.php b/templates/components/author/orcid/value.blade.php new file mode 100644 index 00000000000..510cbec69d0 --- /dev/null +++ b/templates/components/author/orcid/value.blade.php @@ -0,0 +1,3 @@ + + 0000-0002-1825-0097 + \ No newline at end of file diff --git a/templates/components/author/user-group.blade.php b/templates/components/author/user-group.blade.php new file mode 100644 index 00000000000..673b0eb1f42 --- /dev/null +++ b/templates/components/author/user-group.blade.php @@ -0,0 +1,3 @@ + + Author + \ No newline at end of file diff --git a/templates/components/authors.blade.php b/templates/components/authors.blade.php new file mode 100644 index 00000000000..ad31ccf2c10 --- /dev/null +++ b/templates/components/authors.blade.php @@ -0,0 +1,5 @@ +@props(['publication']) + +
+ {{ $slot }} +
\ No newline at end of file diff --git a/templates/components/authors/heading.blade.php b/templates/components/authors/heading.blade.php new file mode 100644 index 00000000000..28e02bfbad7 --- /dev/null +++ b/templates/components/authors/heading.blade.php @@ -0,0 +1,3 @@ +
+

Authors

+
\ No newline at end of file diff --git a/templates/components/hello-world.blade.php b/templates/components/hello-world.blade.php new file mode 100644 index 00000000000..de2fa6f9588 --- /dev/null +++ b/templates/components/hello-world.blade.php @@ -0,0 +1,4 @@ +
+

Hello, World!

+

This is a trivial Blade component example.

+
\ No newline at end of file