Issue installing Filament 3.2 for Laravel 11

I want to install filemanet in fresh laravel 11, then I facing this issue.

  1. I started by creating a new Laravel project using the following command:

composer create-project laravel/laravel example-app

  1. Then, I tried to install Filament 3.2 using this command:

composer require filament/filament:"^3.2" -W

Error:
After running the above command, I’m seeing an error:
showing this error after run filament installation command

Problem with function IOFactory::load(”)->getSheetByName(”)

Hi I am using the class IOFactory to read the pages of an xlsx file. I wrote these instructions:

$spreadsheet = IOFactory::load($filePath);
$sheetMale = $spreadsheet->getSheetByName('man');
$sheetFemale = $spreadsheet->getSheetByName('woman');
$sheetMale->toArray();
$sheetFemale->toArray();

Now the problem is that after creating with success the first array, the creation of the second blocks the code infinitly without genereting errors or messages. I want to precise that the ‘names’ and $filePath are correct

If it can be helpful I share the complete code too

<?php
namespace AppConsoleCommands;
use Exception;
use IlluminateConsoleCommand;
use PhpOfficePhpSpreadsheetIOFactory;

class ExtractExcelData extends Command
{
    public function extractDataFromExcel($filePath)
    {
        $spreadsheet = IOFactory::load($filePath);
        $sheetMale = $spreadsheet->getSheetByName('man');
        $sheetFemale = $spreadsheet->getSheetByName('woman');
        $rows = $sheetMale->toArray();
        $sheetFemale->toArray();
    }
    public function handle()
    {
        try {
            $filePath = storage_path('works.xlsx');
            $this->extractDataFromExcel($filePath);
            $this->info('Made well!');
        } catch (Exception $e) {
            $this->error("Error: " . $e->getMessage());
        }
    }
}

FilamentPHP / Laravel – Sub pages using the Tabs component

I have a custom page, which I’ve created called “CompanyOverview”. It’s a simple page, with a blade view like so:

<x-filament-panels::page>
    <div class="flex flex-col gap-4" x-data="{ tab: 'shipments' }">
        <x-filament::tabs label="Content tabs">
            <x-filament::tabs.item @click="tab = 'shipments'" :alpine-active="'tab === 'shipments''">
                Shipments
            </x-filament::tabs.item>
            <x-filament::tabs.item @click="tab = 'summary'" :alpine-active="'tab === 'summary''">
                Summary
            </x-filament::tabs.item>

        </x-filament::tabs>    

        <div>
            <div x-show="tab === 'shipments'" x-cloak>
                <livewire:intercompany.table-shipment :filters="$filters" />
            </div>
            <div x-show="tab === 'summary'" x-cloak>
                
            </div>

        </div>
        
    </div>
</x-filament-panels::page>

As you can see, on this page, I simply include a Livewire component in my first tab. This component just renders a standard Filament table:

//table-shipments.blade.php
<div>
    {{ $this->table }}
</div>

Now, I want to add some other content under the Summary tab. Under here, I would like to render a lot of different widgets (it’s basically an analytics page). So, I was thinking that it would be nice to be able to utilize just another custom page (or dashboard even), so I could just add the widgets using the getHeaderWidgets() method, and don’t worry about the Blade / HTML part.

I have tried to create a custom page CompanySummary.php:

use FilamentPagesPage;

class CompanySummary extends Page
{
    protected static ?string $navigationIcon = 'heroicon-o-document-text';

    protected static string $view = 'filament.app.pages.company-summary';

    protected function getHeaderWidgets(): array
    {
        return [
           //I will place my widgets here.
        ];
    }

}

<div x-show="tab === 'summary'" x-cloak>
    @include('filament.app.pages.company-summary')
</div>

It renders the new page, however, it includes it as a new page within my existing page (e.g., two titles and filter actions) – where I essentially, would also like to use my original page filters’.

Is this possible?

Symfony 6.4: Bazinga JS Translation Files Not Found in Production

I recently upgraded my Symfony application from version 5.4 to 6.4. My project uses Webpack Encore and the BazingaJsTranslationBundle to manage translations in JavaScript. In my Twig templates, I load translation files like this:

<script src="{{ path('bazinga_jstranslation_js', { 'domain': 'api' }) }}"></script>`

This works perfectly in all environments except for production (APP_ENV=prod). When APP_ENV is set to prod, the JavaScript translation files are not found, and the request to the bazinga_jstranslation_js route results in a 404 error. Everything works as expected when APP_ENV is set to anything else, such as dev, test, or prod2.

Here are some details about my setup:

  • Symfony version: 6.4
  • willdurand/js-translation-bundle version: 6.1
  • bazinga-translator version: 6.1
  • Webpack Encore for asset management.

How to Optimize Large JSON Files for Use with ChatGPT API?

I am trying to use ChatGPT as the chatbot for my Magento 2 website, and I want to pass product data to it. To do this, I collected all the products and stored them in a JSON file, which I then read to embed the data in the systemRoleContent of the system role. However, the issue I am facing is that the JSON file is quite large.

{
    "bot_response": "Error: ChatBot Error: Unexpected API response structure: {n    "error": {n        "message": "Request too large for gpt-4o on tokens per min (TPM): Limit 30000, Requested 501140. The input or output tokens must be reduced in order to run successfully. Visit https://platform.openai.com/account/rate-limits to learn more.",n        "type": "tokens",n        "param": null,n        "code": "rate_limit_exceeded"n    }n}n"
}

I noticed that there is a function that needs to be added to the API configuration, which allows you to run a query to select products based on keywords found in their names or descriptions that match keywords in the user’s message. The challenge is that users initially may not know the names of the products; they come to the chatbot to discover them. How can I address this issue?

This is the code that I am working with right now:

<?php

namespace MetaCaresChatbotModel;

use MagentoFrameworkAppObjectManager;

class ChatBot
{
    private $authorization;
    private $endpoint;
    private $conversationHistory = [];
    private $productsFile;
    private $fetchingDateFile;
    private $didFetchProducts = false;

    public function __construct()
    {
        $this->authorization = 'sk-proj-';
        $this->endpoint = 'https://api.openai.com/v1/chat/completions';

        $this->productsFile = __DIR__ . '/products.json';
        $this->fetchingDateFile = __DIR__ . '/fetching_date.json';

        $currentTime = time();
        $timeDifferenceSeconds = 24 * 3600;

        if (!file_exists($this->fetchingDateFile)) {
            file_put_contents($this->fetchingDateFile, json_encode(['last_fetch_time' => 0]));
        }

        $fetchingData = json_decode(file_get_contents($this->fetchingDateFile), true);
        $lastFetchTime = $fetchingData['last_fetch_time'] ?? 0;

        if ($currentTime - $lastFetchTime > $timeDifferenceSeconds) {
            $products = $this->fetchProductsUsingModel();
            $productsJson = json_encode($products);
            file_put_contents($this->productsFile, $productsJson);
            $fetchingData['last_fetch_time'] = $currentTime;
            file_put_contents($this->fetchingDateFile, json_encode($fetchingData));
            $this->didFetchProducts = true;
        }

        $jsonSampleData = file_get_contents($this->productsFile);

        $systemRoleContent = <<<EOT
Nom:
    Meta Cares Bot
Description
    BOT Meta Cares répond aux questions sur les produits du site et fournit des conseils santé fiables.
    Tu aides les clients de Meta Cares à faire des choix éclairés tout en offrant un accompagnement personnalisé, sécurisé et adapté à leurs besoins.

catalogue Meta Cares
{$jsonSampleData}

Liste des Sites Référencés :
- PubMed : [https://pubmed.ncbi.nlm.nih.gov/](https://pubmed.ncbi.nlm.nih.gov/)
- ScienceDirect : [https://www.sciencedirect.com/](https://www.sciencedirect.com/)
---
- Génération d’images DALL·E : Désactivée

EOT;

        $this->conversationHistory[] = [
            'role' => 'system',
            'content' => $systemRoleContent
        ];

        if (session_status() == PHP_SESSION_NONE) {
            session_start();
        }
        if (isset($_SESSION['chat_history'])) {
            $this->conversationHistory = $_SESSION['chat_history'];
        }
    }

    public function fetchProductsUsingModel(): array
    {
        return $products;
    }

    private function getCategoryNames(array $categoryIds): array
    {
        return $categoryNames;
    }

    public function sendMessage(string $message): array
    {
        try {
            $this->conversationHistory[] = [
                'role' => 'user',
                'content' => $message
            ];

            $data = [
                'model' => 'gpt-4o',
                'messages' => array_map(function ($msg) {
                    return [
                        'role' => $msg['role'] === 'bot' ? 'assistant' : $msg['role'],
                        'content' => $msg['content']
                    ];
                }, $this->conversationHistory)
            ];

            $response = $this->makeApiRequest($data);
            $arrResult = json_decode($response, true);

            if (json_last_error() !== JSON_ERROR_NONE) {
                throw new Exception('Invalid API response format');
            }

            if (!isset($arrResult['choices']) || !isset($arrResult['choices'][0]['message']['content'])) {
                throw new Exception('Unexpected API response structure: ' . $response);
            }

            $assistantResponse = $arrResult['choices'][0]['message']['content'];
            $this->conversationHistory[] = [
                'role' => 'bot',
                'content' => $assistantResponse
            ];

            $_SESSION['chat_history'] = $this->conversationHistory;
            return [
                "conversationHistory" => $_SESSION['chat_history'],
                'didFetchProducts' => $this->didFetchProducts,
                'response' => $assistantResponse,
            ];
        } catch (Exception $e) {
            throw new Exception('ChatBot Error: ' . $e->getMessage());
        }
    }

    private function makeApiRequest(array $data): string
    {
        $ch = curl_init();
        curl_setopt_array($ch, [
            CURLOPT_URL => $this->endpoint,
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => json_encode($data),
            CURLOPT_HTTPHEADER => [
                'Content-Type: application/json',
                'Authorization: Bearer ' . $this->authorization,
            ],
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_SSL_VERIFYHOST => 0
        ]);

        $response = curl_exec($ch);

        if (curl_errno($ch)) {
            $error = curl_error($ch);
            curl_close($ch);
            throw new Exception('API request failed: ' . $error);
        }

        curl_close($ch);
        return $response;
    }
}

Logo not displayed in quotes generated by TCPDF with Perfex

I am using Perfex to generate my quotes and invoices. Perfex utilizes the TCPDF library to create PDF documents. However, since this morning, the logo of my company no longer appears in the generated quotes.

Here are some details:

  • The logo URL is valid and accessible via a web browser.
  • I have checked the permissions on the image file.
  • I tried embedding the logo using an image tag in the TCPDF code, but it still doesn’t work.
  • I also used the pdf_logo_url() function provided by Perfex, which generates an image URL, but the logo is still not displayed.

Here is an example of the code I used to display the logo:

$pdf->Image('https://example.com/logo.png', 10, 10, 50);

Despite this, the logo does not appear in the PDF. No errors are reported by TCPDF.

What I have tried:

  • Using a PNG.
  • Using an absolute path.
  • Using Perfex function pdf_logo_url()
  • Testing with a local image instead of a remote URL.

admin-ajax.php form data submission error

I am making a timesheet system as a class project, and I have stumbled into some issues with the admin_class.php and ajax.php files. When I submit what I want to submit it gives me this error as a response:

Fatal error: Uncaught Error: Call to a member function real_escape_string() on null in C:xampphtdocsrbaaadmin_class.php:430 Stack trace: #0 C:xampphtdocsrbaaajax.php(160): Action->save_timesheet(Array) #1 {main} thrown in C:xampphtdocsrbaaadmin_class.php on line 430

ajax.php:

if ($action == 'save_timesheet') {
    require_once 'admin_class.php';
    
    $admin = new Action(); // Change Admin to Action

    // Receive data from form
    $data = [
        'id' => $_POST['id'],
        'client_id' => $_POST['client_id'],
        'audit_members' => $_POST['audit_members'],
        'date_started' => $_POST['date_started'],
        'start_time' => $_POST['start_time'],
        'end_time' => $_POST['end_time']
    ];

    $response = $admin->save_timesheet($data);

    echo $response;  // Return success or error message
}

admin_class.php:

public function save_timesheet($data) {
    global $conn;

    $client_id = intval($data['client_id']);
    $audit_members = implode(',', array_map('intval', $data['audit_members']));
    $date_started = $conn->real_escape_string($data['date_started']);
    $start_times = json_encode($data['start_time']);
    $end_times = json_encode($data['end_time']);
    
    // Insert into timesheets table
    $sql = "INSERT INTO timesheets (client_id, audit_members, date_started, start_time, end_time)
            VALUES (?, ?, ?, ?, ?)";
    
    $stmt = $conn->prepare($sql);
    $stmt->bind_param("iisss", $client_id, $audit_members, $date_started, $start_times, $end_times);
    
    if ($stmt->execute()) {
        return 1;  // Success
    } else {
        return $stmt->error;  // Error
    }
}

I need help creating a webpage application like the one I have attached? [closed]

I have a wordpress website built on wood mart I want a similar system to the one on this page?

https://www.mobilityhouse.com/de_de/elektroautos.html?page=2

In which I can select just the vehicle name and model and in similar boxes the output is displayed, also when they click on a vehicle model it goes to a actual page of just the vehicle.

How could I achieve this?

Regards

I have tried custom coding the calculator but I have not attempted this as I would like some direction before I do attempt.

Issues Connecting to Oracle Database Using PHP (TNS: Connect Timeout/No Listener) [duplicate]

I’m encountering an issue trying to connect to an Oracle database using Visual Studio PHP Server on my Windows . I’ve installed the oci8 extension, and I know it works correctly because PHP doesn’t throw any errors related to the extension and i can see the extension in phpinfo. I tried to connect with this code:

$host = "iacademy2.oracle.com";         
$port = "1521";              
$service_name = "orclpdb";   
$username = "username";      
$password = "password";      

$dsn = "(DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = $host)(PORT = $port))
    (CONNECT_DATA =
        (SERVER = DEDICATED)
        (SERVICE_NAME = $service_name)
    )
)";

$conn = oci_connect($username, $password, $dsn);

if (!$conn) {
    $e = oci_error();
    echo "Connection error: " . $e['message'];
    exit;
}

echo "Successfully connected to Oracle!";

However, despite the extension being correctly installed and activated, I am facing issues with the connection. The errors I receive are:

ORA-12170: TNS: Connect timeout occurred
ORA-12541: TNS: No listener

How can I resolve this Oracle database connection issue from PHP, considering that the oci8 extension is already installed and functioning correctly, and I can access the Oracle database in the browser? Do you have any ideas? I would be very grateful. I need this for my faculty.

Additionally, I am able to access the Oracle database through the browser (via https://iacademy2.oracle.com/ords/), so I know that the Oracle instance is up and running. However, I am having trouble connecting to it through PHP.

I’ve tried modifying the HOST value in the connection string to different addresses, but that didn’t resolve the issue. The connection still fails. I used 192.168.0.1 as host but it says:

Warning: oci_connect(): ORA-12541: TNS:no listener in D:frontendpagestest.php on line 16
Connection error: ORA-12541: TNS:no listener.

I also have the XAMPP turned on. One more thing is that from cmd I tried to use C:\Users\Lenovo>telnet iacademy2.oracle.com 1521

Connecting To iacademy2.oracle.com…Could not open connection to the host, on port 1521: Connect failed

Laravel RouteServiceProvider missing in app/Providers directory

I’m working on a Laravel project, and I’ve noticed that the RouteServiceProvider.php file is missing from the app/Providers directory. In the Laravel documentation and tutorials I’ve followed, it is typically present by default. I want to understand why it might be missing and how to restore it.

In addition to the AppServiceProvider, FortifyServiceProvider, and JetstreamServiceProvider, the RouteServiceProvider.php is supposed to be there, but it seems like it was never created in my project. How can I generate the missing RouteServiceProvider.php file and restore its functionality in my Laravel application?

I tried searching for a solution online and also checked if there is any Laravel Artisan command to regenerate this specific provider. I expected to find an easy way to either regenerate it using a command or instructions on restoring it without affecting my current setup.

What I expected to happen:

I expected to find a straightforward solution to restore the missing RouteServiceProvider.php file—either through an Artisan command or by manually creating it with the correct structure.

Yii2 ActiveForm Model doesn’t exist

I’m a newbie, so please excuse the stupid question:
I have a controller in Yii2 app with the following actions:

private function actionPagination($query)
    {
        $count = $query->count();

        $pagination = new Pagination([
            'defaultPageSize' => 10,
            'totalCount' => $count,
        ]);

        $books = $query
            ->orderBy('id')
            ->offset($pagination->offset)
            ->limit($pagination->limit)
            ->all();

        return [$books, $pagination];
    }


    public function actionIndex()
    {
        $query = Books::find();

        list($books, $pagination) = $this->actionPagination($query);

        return $this->render('index', [
            'books' => $books,
            'pagination' => $pagination,
            'totalPages' => max(1, ceil($pagination->totalCount / $pagination->pageSize)),
        ]);
    }


    public function actionFilter()
    {

        $query = Books::find();
        $genres = Genres::find()->select(['genre_name', 'id'])->orderBy('genre_name')->indexBy('id')->column();
        $authors = Authors::find()->select(['concat(first_name, " ", last_name)', 'id'])->orderBy('id')->column();
        $authors = array_combine(range(1, count($authors)), $authors);

        $searchModel = new Books();
        $requestParams = Yii::$app->request->queryParams;

        if ($searchModel->load($requestParams)) {
            if ($searchModel->year_filter) {
                $query->andWhere(['year' => $searchModel->year_filter]);
            }
            if ($searchModel->genre_filter) {
                $query->andWhere(['genre_id' => $searchModel->genre_filter]);
            }

            if ($searchModel->author_filter) {
                $query->joinWith('links')
                    ->andWhere(['links.author_id' => $searchModel->author_filter]);
            }
        }

        return $this->render('index', [
            'authors' => $authors,
            'genres' => $genres,
            'searchModel' => $searchModel,
        ]);
    }

and i have a form:

  <?php $form = ActiveForm::begin([
    'action' => ['filter'],
    'method' => 'get',
    'options' => ['id' => 'filter-form']
  ]); 
  ?>

  <?= $form->field($searchModel, 'year_filter')->textInput(['id' => 'year-filter-input']) ?>

  <?= $form->field($searchModel, 'genre_filter')->dropDownList(
    $genres,
    [
      'prompt' => 'All genres',
      'id' => 'genre-filter-select'
    ]
  ) ?>

<?= $form->field($searchModel, 'author_filter')->dropDownList(
    $authors,
    [
        'prompt' => 'All authors',
        'id' => 'author-filter-select'
    ]

) ?>

  <div class="form-group">
    <?= Html::submitButton('Filtering', ['class' => 'btn btn-primary']) ?>
    <?= Html::button('Reset filter', [
      'class' => 'btn btn-outline-secondary reset-filter',
      'type' => 'button'
    ]) ?>
  </div>

  <?php ActiveForm::end(); ?>

So when i try to load the page im getting the following error:
Undefined variable $searchModel
I want to create $searchModel only after im pressing ‘Filtering’.(
Or should i use another method?

i tried the code that i listed.

User in routes/web.php is not syncronized with User in app/Http/Controllers/AuthControllers.php

I really don’t know why, when I log Auth::user() in web.php, it will get the wrong auth user. But when I try to log in AuthController.php, it actually fine. I think there is a problem with sync or something else that must be frustating.

This is web.php

<?php

use IlluminateSupportFacadesRoute;
use AppHttpControllersAuthController;
use AppHttpControllersPantiController;
use AppHttpControllersProductController;
use AppHttpMiddlewareCheckRole;
use IlluminateSupportFacadesAuth;
use IlluminateSupportFacadesLog;

Route::get('/register', [AuthController::class, 'showRegisterForm'])->name('register');
Route::get('/login', [AuthController::class, 'showLoginForm'])->name('login');

Route::post('/register', [AuthController::class, 'register']);
Route::post('/login', [AuthController::class, 'login']);

Route::get('/product/{id}', [ProductController::class, 'show'])->name('product.detail');
Route::get('/panti/{id}', [PantiController::class, 'show'])->name('panti.detail');

Route::middleware('auth')->group(function () {
    Route::get('/', function (){
        $user = Auth::user();

        Log::info('Currently User logged in:', ['user' => $user]);

        if($user->role == 'donor'){
            return view('page.home.home-donor', ['user' => $user]);
        }else if($user->role== 'panti'){
            return view('page.home.home-panti', ['user' => $user]);
        }else if($user->role == 'admin'){
            return view('page.home.home-admin', ['user' => $user]);
        }
    })->name('home');

    Route::get('/catalog', function () {
        return view('page.catalog');
    })->name('catalog');
    
    Route::get('/panti', function () {
        return view('page.panti');
    })->name('panti');
    
    Route::get('/about', function () {
        return view('page.about');
    })->name('about');

    Route::get('/product/{id}', [ProductController::class, 'show'])->name('product.detail');
    
    Route::get('/panti/{id}', [PantiController::class, 'show'])->name('panti.detail');

    Route::get('/profile', function () {
        $user = Auth::user(); // Get the authenticated user
        return view('page.profile', ['user' => $user]);
    })->name('profile');

    Route::post('/logout', [AuthController::class, 'logout']);
});

This is AuthController.php

<?php

namespace AppHttpControllers;

use AppModelsUser;
use IlluminateHttpRequest;
use IlluminateSupportFacadesAuth;
use IlluminateSupportFacadesHash;
use IlluminateSupportFacadesLog;
use IlluminateSupportFacadesValidator;

class AuthController extends Controller
{
    // Show the registration form
    public function showRegisterForm()
    {
        return view('auth.register');
    }

    // Show the login form
    public function showLoginForm()
    {
        return view('auth.login');
    }

    // Register user
    public function register(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'username' => 'required|string|max:100|unique:users',
            'name' => 'required|string|max:100',
            'email' => 'required|string|email|max:100|unique:users',
            'password' => 'required|string|min:8|confirmed',
            'role' => 'required|in:donor,panti,admin',
        ]);

        if ($validator->fails()) {
            return redirect()->back()->withErrors($validator)->withInput();
        }

        User::create([
            'username' => $request->username,
            'name' => $request->name,
            'email' => $request->email,
            'password' => Hash::make($request->password),
            'role' => $request->role,
        ]);

        return redirect('/login')->with('success', 'Registration successful! Please login.');
    }

    // Login user
    public function login(Request $request)
    {
        $credentials = $request->only('username', 'password');

        $user = User::where('username', $credentials['username'])->first();

        if (!$user || !Hash::check($credentials['password'], $user->password)) {
            return redirect()->back()->withErrors(['login_error' => 'Invalid username or password.']);
        }
        
        Auth::login($user, true);
        $request->session()->regenerateToken();

        Log::info('User logged in:', ['user' => $user]);
        
        if (Auth::check()) {
            return redirect('/')->with('success', 'Login successful!');
        } else {
            return redirect('/login')->withErrors(['login_error' => 'Authentication failed.']);
        }        
    }

    // Logout
    public function logout(Request $request)
    {
        Auth::logout();
        $request->session()->invalidate();  // Invalidates the session
        $request->session()->regenerateToken();  // Regenerates the CSRF token to prevent CSRF attacks
        return redirect('/login')->with('success', 'Logged out successfully!');
    }
}

Here’s the log:

[2024-12-22 03:32:27] local.INFO: User logged in: {"user":{"App\Models\User":{"user_id":0,"username":"handphone","name":"handphone","email":"[email protected]","role":"donor","user_image":null,"remember_token":"fcvFDZa6WaOlVZTeVbEkLZN078B9RWR1jULhQZGzyHWCEsoZKRnQ7SLMzvYs","created_at":"2024-12-14T13:20:00.000000Z","updated_at":"2024-12-14T20:51:41.000000Z"}}} 
[2024-12-22 03:32:27] local.INFO: Currently User logged in: {"user":{"App\Models\User":{"user_id":0,"username":"sandwich","name":"sandwich","email":"[email protected]","role":"admin","user_image":null,"remember_token":"pZCLwvv2aMwnRwJPzULk403cTwWuYUcYPjvNi4EL8p7yVzMle7nC2gYP3Pho","created_at":"2024-12-15T13:48:17.000000Z","updated_at":"2024-12-15T20:48:23.000000Z"}}}

Look at the log, these are resulting different user. The correct user must be the “User logged in:” from AuthController.php and the wrong user is “Currently User logged in:” from web.php

I want to get login user attributes from web.php

I want to run simple php with frankenphp inside docker

I want to run my simple PHP script. like return phpinfo() with frankenphp inside docker.
But I have a problem for this simple script. Always not resolve when accessing localhost:8080.

This my Dockerfile

FROM dunglas/frankenphp:latest

RUN apt-get update && apt-get install -y 
    git 
    unzip 
    vim 
    && rm -rf /var/lib/apt/lists/*

WORKDIR /var/www/public_html

COPY ./app .

EXPOSE 80

CMD ["frankenphp", "php-server", "-r", "/var/www/public_html"]

and this my docker-compose

version: '3.8'
services:
  app:
    container_name: therapy_app
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "8080:80"
    volumes:
      - ./app:/var/www/public_html
    environment:
      - APP_ENV=local
      - APP_DEBUG=true
    networks:
        - therapy_nt

networks:
    therapy_nt:
      driver: bridge

This my index.php file

<?php
phpinfo();

after I run docker compose up -d succeeded running the container.
But, when I access localhost:8080 it doesn’t work.

Folder structure :

- app
  + index.php
- Dockerfile
- docker-compose.yml 

Is there something missing from my steps?

How to return blob in Joomla 5 API

I am writing a custom plugin API that should return PDF, I am using Joomla 5 but I see that it only supports JSON as a return via the View, not only that, but it also requires you to be working with Full MVC structure, is there a away to not do that? I want the flexibility to return a blob or text or whatever from inside the Controller.

class ProductsController extends ApiController
{
 protected $contentType = '';
 protected $default_view = '';

 public function displayList()
 {
 // I need to be able to return here a blob or whatever i want, right now if i return anything the content type in postmen is always "text/html; charset=UTF-8"
 }
}

And this is the view that I don’t really need, but it’s mandatory by Joomla:

class JsonapiView extends BaseApiView
{
        protected $fieldsToRenderList = [];

        protected $fieldsToRenderItem = [];
}

For reference, these are the docs: https://docs.joomla.org/J4.x:Adding_an_API_to_a_Joomla_Component/en

I did try to just return inside the displayList method but it’s not working.