Extend Existing Controller #5134

Closed
opened 2026-02-05 09:42:19 +03:00 by OVERLORD · 4 comments
Owner

Originally created by @RobinNiemann on GitHub (Jan 20, 2025).

Attempted Debugging

  • I have read the debugging page

Searched GitHub Issues

  • I have searched GitHub for the issue.

Describe the Scenario

I want to add a custom feature (on the Book-Page). I use the Logical Theme System for this.

What would work: Copy the BookController to my theme folder (themes/mytheme/app/Entities/Controllers/BookController.php) and then implement my feature in between the copied code.

Since a don't want to adjust existing features but add a new one, it would seem cleaner to me to extend the BookController and just overwrite what I need.

What I tried so far

First approach was to create MyBookController extends BookController. Then I would have to overwrite the web.php. I both tried a web.php at the same folder position and a my-web.php, both included in the functions.php but doesn't work. I either get a "Sorry, this page was not found" result or an exception ViewException: Undefined variable $cspNonce.

Second approach was

namespace BookStack\Entities\Controllers;
use BookStack\Entities\Controllers\BookController as BookstackBookController;
class BookController extends BookstackBookController
...

wich lead to local.ERROR: Failed loading theme functions file at "/app/themes/mytheme/functions.php" with error: Class "BookStack\Entities\Controllers\BookController" not found {"exception":"[object] (BookStack\\Exceptions\\ThemeException(code: 0): Failed loading theme functions file at \"/app/themes/mytheme/functions.php\" with error: Class \"BookStack\\Entities\\Controllers\\BookController\" not found at /app/app/Theming/ThemeService.php:79) plus a lot of Undefined variable $cspNonce exceptions.

Is there a chance that this will work in some way or do I have to do the way of copiing the whole Controller?

Exact BookStack Version

24.02.2

Log Content

No response

Hosting Environment

Local development environment with Docker

Originally created by @RobinNiemann on GitHub (Jan 20, 2025). ### Attempted Debugging - [x] I have read the debugging page ### Searched GitHub Issues - [x] I have searched GitHub for the issue. ### Describe the Scenario I want to add a custom feature (on the Book-Page). I use the Logical Theme System for this. What would work: Copy the BookController to my theme folder (themes/mytheme/app/Entities/Controllers/BookController.php) and then implement my feature in between the copied code. Since a don't want to adjust existing features but add a new one, it would seem cleaner to me to extend the BookController and just overwrite what I need. ## What I tried so far First approach was to create `MyBookController extends BookController`. Then I would have to overwrite the [web.php](https://github.com/BookStackApp/BookStack/blob/development/routes/web.php). I both tried a `web.php` at the same folder position and a `my-web.php`, both included in the `functions.php` but doesn't work. I either get a "Sorry, this page was not found" result or an exception `ViewException: Undefined variable $cspNonce`. Second approach was ``` namespace BookStack\Entities\Controllers; use BookStack\Entities\Controllers\BookController as BookstackBookController; class BookController extends BookstackBookController ... ``` wich lead to `local.ERROR: Failed loading theme functions file at "/app/themes/mytheme/functions.php" with error: Class "BookStack\Entities\Controllers\BookController" not found {"exception":"[object] (BookStack\\Exceptions\\ThemeException(code: 0): Failed loading theme functions file at \"/app/themes/mytheme/functions.php\" with error: Class \"BookStack\\Entities\\Controllers\\BookController\" not found at /app/app/Theming/ThemeService.php:79)` plus a lot of `Undefined variable $cspNonce` exceptions. Is there a chance that this will work in some way or do I have to do the way of copiing the whole Controller? ### Exact BookStack Version 24.02.2 ### Log Content _No response_ ### Hosting Environment Local development environment with Docker
OVERLORD added the 🐕 Support label 2026-02-05 09:42:19 +03:00
Author
Owner

@ssddanbrown commented on GitHub (Jan 21, 2025):

Hi @RobinNiemann,

Here's a full commented (and quickly tested) example which should hopefully help:

Code

<?php

use BookStack\Activity\ActivityQueries;
use BookStack\Entities\Controllers\BookController;
use BookStack\Facades\Theme;
use BookStack\Theming\ThemeEvents;
use Illuminate\Http\Request;
use Illuminate\Routing\Router;

class CustomBookController extends BookController
{
    /**
     * Custom show route
     */
    public function show(Request $request, ActivityQueries $activities, string $slug)
    {
        // Get the default response from the original show method
        /** @var \Illuminate\Contracts\View\View $defaultResponse */
        $defaultResponse = parent::show($request, $activities, $slug);

        // Alter some existing data passed to the view
        $defaultResponse->with('referenceCount', 1000333);

        // Return the altered response
        return $defaultResponse;
    }
}

// Override the route with our custom route by listening to the theme event
// which allows us to register custom authed web routes.
Theme::listen(ThemeEvents::ROUTES_REGISTER_WEB_AUTH, function (Router $router) {
    $router->get('/books/{slug}', [CustomBookController::class, 'show']);
});

Note that much of the contents here has potential to break on updates, and the ability to override existing controller routes is kind of luck and based upon the ordering of when things run, so not something intentional but seems to work. Can't imagine it's too likley to break, but not something assured nor tested either.

Edit: Also, you might not need to override the existing controller at all, depending on what you're needing, it might be simpler just to define a custom simpler standalone controller. It's the route it's registered at which really matters for access at the same URL.

@ssddanbrown commented on GitHub (Jan 21, 2025): Hi @RobinNiemann, Here's a full commented (and quickly tested) example which should hopefully help: <details><summary>Code</summary> <p> ```php <?php use BookStack\Activity\ActivityQueries; use BookStack\Entities\Controllers\BookController; use BookStack\Facades\Theme; use BookStack\Theming\ThemeEvents; use Illuminate\Http\Request; use Illuminate\Routing\Router; class CustomBookController extends BookController { /** * Custom show route */ public function show(Request $request, ActivityQueries $activities, string $slug) { // Get the default response from the original show method /** @var \Illuminate\Contracts\View\View $defaultResponse */ $defaultResponse = parent::show($request, $activities, $slug); // Alter some existing data passed to the view $defaultResponse->with('referenceCount', 1000333); // Return the altered response return $defaultResponse; } } // Override the route with our custom route by listening to the theme event // which allows us to register custom authed web routes. Theme::listen(ThemeEvents::ROUTES_REGISTER_WEB_AUTH, function (Router $router) { $router->get('/books/{slug}', [CustomBookController::class, 'show']); }); ``` </p> </details> Note that much of the contents here has potential to break on updates, and the ability to override existing controller routes is kind of luck and based upon the ordering of when things run, so not something intentional but seems to work. Can't imagine it's too likley to break, but not something assured nor tested either. Edit: Also, you might not need to override the existing controller at all, depending on what you're needing, it might be simpler just to define a custom simpler standalone controller. It's the route it's registered at which really matters for access at the same URL.
Author
Owner

@RobinNiemann commented on GitHub (Jan 23, 2025):

Thank you! I got the overwritten Controller working and also tried a standalone controller approach :-)

So you'd prefer something like this?

CustomController.php
<?php

namespace custom\Controllers;

class CustomController
{
    public function getStuff()
        // ...
        return $stuff;
    }
}
my_theme/books/show.blade.php
// ...
@php
   $customController= app(custom\Controllers\CustomController::class);
   $stuff= $customController->getStuff();
@endphp
{{ $stuff }}
// ...

This also works but raises another problem: I need the book context.
In CustomController->getStuff I want to depend on the current book, thus I need at least string $slug as parameter. Do you have an idea how to get the book context into the CustomController?

@RobinNiemann commented on GitHub (Jan 23, 2025): Thank you! I got the overwritten Controller working and also tried a standalone controller approach :-) So you'd prefer something like this? <details> <summary>CustomController.php</summary> ```php <?php namespace custom\Controllers; class CustomController { public function getStuff() // ... return $stuff; } } ``` </details> <details> <summary>my_theme/books/show.blade.php</summary> ```php // ... @php $customController= app(custom\Controllers\CustomController::class); $stuff= $customController->getStuff(); @endphp {{ $stuff }} // ... ``` </details> This also works but raises another problem: I need the book context. In `CustomController->getStuff` I want to depend on the current book, thus I need at least `string $slug` as parameter. Do you have an idea how to get the book context into the CustomController?
Author
Owner

@ssddanbrown commented on GitHub (Jan 23, 2025):

So you'd prefer something like this?

No, I just meant you may not have to extend the original BookController, but instead just the app default controller, then copy over methods/lines needed, but just do whatever works best for what you need, it's not a big deal.

@ssddanbrown commented on GitHub (Jan 23, 2025): > So you'd prefer something like this? No, I just meant you may not have to extend the original BookController, but instead just the [app default controller](https://github.com/BookStackApp/BookStack/blob/development/app/Http/Controller.php), then copy over methods/lines needed, but just do whatever works best for what you need, it's not a big deal.
Author
Owner

@RobinNiemann commented on GitHub (Jan 24, 2025):

Ah, okay.
Overwriting the BookController seems to be cleaner to me and it works quite nicely :-)
Thanks again for your help!

@RobinNiemann commented on GitHub (Jan 24, 2025): Ah, okay. Overwriting the BookController seems to be cleaner to me and it works quite nicely :-) Thanks again for your help!
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/BookStack#5134