1

I becmoe this error

Fatal error: Uncaught Error: Call to undefined method Closure::index() in C:\xampp\htdocs\projects\mBv\public\index.php:45
Stack trace: #0 {main} thrown in C:\xampp\htdocs\projects\mBv\public\index.php on line 45

I have a Container class, that includes all other classes as array in its __construct, which I need to use it.

Container.php

<?php
namespace App\Core;

use PDO;
use Exception;
use PDOException;

use App\Post\Container\PostContainer;
use App\User\Container\UserContainer;
use App\Post\Repository\PostsRepository;
use App\Post\Repository\CommentsRepository;
 
class Container
{

    private $receipts = [];
    private $instances = [];

    public function __construct()
    {
        $this->receipts = [
               
            'postsRepository' => function() {
                $postContainer= $this->make('postContainer');
                $postsRepository= $postContainer->postReceipts['postsRepository'];
                return $postsRepository;
            },
            'commentsRepository' => function() {
                $postContainer= $this->make('postContainer');
                $commentsRepository= $postContainer->postReceipts['commentsRepository'];
                return $commentsRepository;
            },
       
            'pdo' => function() {
                try {
                    $pdo = new PDO(
                        'mysql:host=XXXX;dbname=XXXX;charset=utf8',
                        'XXXX',
                        'XXXX'
                        );
                } catch (PDOException $e) {
                    echo "ERROR";
                    die();
                }
                $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
                return $pdo;
            }
            ];
    }

    public function make($name)
    {
        if (!empty($this->instances[$name]))
        {
            return $this->instances[$name];
        }
        if (isset($this->receipts[$name])) {
            $this->instances[$name] = $this->receipts[$name]();
        }
        return $this->instances[$name];
    }
}
?>

i made for the Post, its own Container, which include the comments and post repository.

The reason for that it's when I want to change the structure of the classes later (comments or post) then i have to change it just from their own container. So their own Container of post and comments seems like this

PostContainer.php

<?php
namespace App\Post\Container;
 
use App\Post\Repository\PostsRepository;
use App\Post\Repository\CommentsRepository;
 

//admin - postsController -  post and comments Repository

class PostContainer
{
    public $postReceipts = [];
    public function __construct() {

        $this->postReceipts = [
            'postsRepository' => function() {
                return new PostsRepository(
                    $this->make("pdo")
                    );
            },
            'commentsRepository' => function() {
                return new CommentsRepository(
                    $this->make("pdo")
                    );
            },
            ];
    }
}
?>

when i run it i become the error, that I already mentioned it at the beginning.

Here ist the index file, where the error is in the line 45.

<?php
session_start();


require __DIR__ . "/../init.php";

$pathInfo = $_SERVER['PATH_INFO'];

$routes = [
    '/index' => [
        'controller' => 'postsController',
        'method' => 'index'
        ],
    '/post' => [
        'controller' => 'postsController',
        'method' => 'show'
        ]
    ];

if (isset($routes[$pathInfo])) {
    $route = $routes[$pathInfo];
    $controller = $container->make($route['controller']);
    $method = $route['method'];
  
    $controller->$method(); // the error place is in this line
}
?>

here is the init file, which includes the $container init.php

<?php
require __DIR__ . "/autoload.php";
function  ePreventXss($str)
  {
  return htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
  }
$container = new App\Core\Container();
?>

postController.php

<?php
namespace App\Post\Controller;
use App\Core\Controller\AbstractController;
use App\Post\Repository\PostsRepository;
use App\Post\Repository\CommentsRepository;
class PostsController extends AbstractController
{
  public function __construct(PostsRepository $postsRepository,CommentsRepository $commentsrepository)
        {
            $this->postsRepository = $postsRepository;
            $this->commentsrepository =  $commentsrepository;
        }

  public function index()
      {
          $posts = $this->postsRepository->showPostsIndex();
          $this->render("post/index", [
            'posts' => $posts
          ]);
      }

  public function show()
      {
            $postId= $_GET['id'];
            $this->deleteComments($postId);
            $this->setkommentar($postId);
            $this->getAllComments($postId);
      }

  private function getAllComments($postId)
      {
           $post= $this->postsRepository->loadPostById($postId);
           $comments= $this->commentsrepository->getAllCommentsByPost($postId);
           $this->render("post/show",[
             'post'=>$post,
             'comments'=>$comments
           ]);
      }


  private function setkommentar($postId)
      {
          if(isset($_POST['content']))
          {
                $contentKommentar= $_POST['content'];
                $this->commentsrepository->insertKommentar($postId,$contentKommentar);
          }
      }

      public function deleteComments($postId)
          {
            if(isset($_POST['commentId']))
            {
              $commentId= $_POST['commentId'];
              $this->commentsrepository->loadKommentarToDelete($postId, $commentId);
            }
          }



}
?>

i invoke the code from PostContainer into the Container class as you can see in the examples , so I use the Container class to produce the obejcts of the post and comment repository.

I tried already to solve it, unfortunately i did't can.

I read that sometime this error will happen, when the version of php less than 7, my php version is: 8.0.2

BasharIT
  • 51
  • 4
  • Where do you set `$container`? – Barmar Mar 06 '21 at 22:21
  • in the init file, i will edit the post one more time and write the init file their, in order you can see it :) – BasharIT Mar 06 '21 at 22:23
  • Can you reduce this to a [mcve]? We don't need to see multiple versions of the class, just the one with the problem. And which class are you using, `Container` or `PostContainer`? – Barmar Mar 06 '21 at 22:24
  • i use container, yes i can reduce the code – BasharIT Mar 06 '21 at 22:27
  • @BasharIT, Could you show us the code in `postsController`?. It's likely that it lucks the method `index()` – steven7mwesigwa Mar 06 '21 at 23:16
  • And can you `var_dump($controller)` on line `$controller->$method(); // the error place is in this line` in `index file`? – steven7mwesigwa Mar 06 '21 at 23:20
  • @BasharIT, I believe the `make()` method is flawed in `Container.php`. It continuously accesses items in the member variable array `instances` yet there is no code that pushes values to it hence most likely always empty. – steven7mwesigwa Mar 06 '21 at 23:54
  • I believe your `$controller` instance isn't being created as you expect in _index file_. Dump/print the variable and verify your expectations. – steven7mwesigwa Mar 07 '21 at 00:03
  • the var_dump of this ` $controller = $container->make($route['controller']);` is that – BasharIT Mar 07 '21 at 00:12
  • ``` object(Closure)#14 (1) { ["this"]=> object(App\Post\Container\PostContainer)#13 (1) { ["postReceipts"]=> array(4) { ["postsController"]=> *RECURSION* ["adminController"]=> object(Closure)#15 (1) { ["this"]=> *RECURSION* } ["postsRepository"]=> object(Closure)#16 (1) { ["this"]=> *RECURSION* } ["commentsRepository"]=> object(Closure)#17 (1) { ["this"]=> *RECURSION* } } } } ``` – BasharIT Mar 07 '21 at 00:13
  • @steven7mwesigwa you can see now the code of postController in my question, i edit it – BasharIT Mar 07 '21 at 00:15
  • @BasharIT, try this, please. `$controller()->$method();` – steven7mwesigwa Mar 07 '21 at 00:18
  • Does this answer your question? [Call to undefined method Closure::query()](https://stackoverflow.com/questions/35458502/call-to-undefined-method-closurequery) – steven7mwesigwa Mar 07 '21 at 00:21
  • unfortunately i can't var_dump this ``` $controller()->$method();``` because the code cannot be done. – BasharIT Mar 07 '21 at 00:22
  • The dump you provided is a `Closure` instead of `postsController`. Doesn't that sound weird to you? – steven7mwesigwa Mar 07 '21 at 00:23
  • 1
    yes that's weird – BasharIT Mar 07 '21 at 00:25
  • @BasharIT, There is one **big** flaw I've noticed in your code. In both `PostContainer.php` and `Container.php` your assign array values as `closures` yet you _never_ call them. Define them as [IIFEs( Immediately Invoked Function Expressions)](https://stackoverflow.com/questions/35044452/iife-immediately-invoked-function-expression-in-php) instead. – steven7mwesigwa Mar 07 '21 at 01:07
  • @steven7mwesigwa see my answer :). – BasharIT Mar 08 '21 at 22:36
  • i used your suggestion to use IIFES, that was good. from this website: [link](https://www.amitmerchant.com/immediately-invoked-function-expression-php/) – BasharIT Mar 08 '21 at 23:07

1 Answers1

0

that is the answer, the problem was that i had in the PostContainer no arrays one to save the objects in it and the second two check and to make certain that no objects will be returned twice in the same array.

public $receipts = []; public $instances = []; and I had either to write the make function in the two classes PostContainer and the Container or to let the classes to extend it from an abstract class, but i choosed the simplest way, which is to write the make() in both. In addition i had to make a function, that make an object of the PostContainer class in the Container class, in order to have access to the calss and its elements and methods. So the problem was just in (PostContainer - Contianer) classes. And as @steven7mwesigwa suggested, that i should to use IIFEs( Immediately Invoked Function Expressions).– I used it in the Container class, without IIFEs the code it's not able to be executed.
I hope, that i could to explain my answer clearly. When you have questions about my situation, you are welcome.

so the final answer for the question as the following:

PostContainer.php

<?php
namespace  App\Post\Container;
use PDO;
use Exception;
use PDOException;

use App\Post\Repository\PostsRepository;
use App\Post\Repository\CommentsRepository;
use App\Post\Controller\PostsController;
use App\Core\Container\AbstractContainer;

class PostContainer  
{
  public $receipts = [];
  public $instances = [];

  public function __construct()
    {
      $this->receipts=[

        "postsController" =>  function (){
          return new PostsController(
            $this->make('postsRepository'),
            $this->make('commentsRepository')
          );
        } ,
        "commentsRepository" => function (){
          return new CommentsRepository(
            $this->make('pdo')
          );
        }  ,

        "postsRepository" =>  function (){
          return new PostsRepository(
            $this->make('pdo')
          );
        } ,
        'pdo' =>  function() {
        try {
          $pdo = new PDO(
            'mysql:host=localhost;dbname=XXXX;charset=utf8',
            'XXXXX',
            'XXXXX'
          );
        } catch (PDOException $e) {
          echo "Verbindung zur Datenbank fehlgeschlagen";
          die();
        }
        $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
        return $pdo;
      }
    ];
  }
  public function make($name)
       {
        if (!empty($this->instances[$name]))
        {
          return $this->instances[$name];
        }
        if (isset($this->receipts[$name])) {
          $this->instances[$name] = $this->receipts[$name]();
        }
        return $this->instances[$name];
      }

}

?>

Container.php

<?php
namespace  App\Core;
use App\Post\Container\PostContainer;
use App\Core\Container\AbstractContainer;

class Container

{
  private $receipts = [];
  private $instances = [];
  private $postContainer;
  public function __construct()
  {
    $this->receipts=[
    "postsRepository" => (function(){
    return $this->makePostContainer()->receipts['postsRepository'];
    })(),
    "commentsrepository" => (function(){
      return $this->makePostContainer()->receipts['commentsRepository'];
    })(),
    "postsController" => (function(){
      return $this->makePostContainer()->receipts['postsController'];
    })(),
    "pdo" => (function(){
      return $this->makePostContainer()->receipts['pdo'];
    })()
      ];
  }

  public function make($name)
       {
        if (!empty($this->instances[$name]))
        {
          return $this->instances[$name];
        }
        if (isset($this->receipts[$name])) {
          $this->instances[$name] = $this->receipts[$name]();
        }
        return $this->instances[$name];
      }
      private function makePostContainer()
      {
         $this->postContainer= new PostContainer;
          return $this->postContainer;
      }
}
?>


BasharIT
  • 51
  • 4