The Slim Framework support forum has moved to http://discourse.slimframework.com. This Tender forum is no longer maintained or monitored.

Call to a member function render() on a non-object

Jd Daniel's Avatar

Jd Daniel

30 Jul, 2012 06:33 PM

Hey So I'm setting up some classes to keep my Routes out of the eye of my index.php,

index.php

require 'library/Slim/Slim.php';

$app=new Slim();
$app->map('/api/:class/:method(/:args1(/:args2(/:args3)))', function ($class,$method) use ($app) {

    $args=array_slice(func_get_args(), 2);
    require_once('library/controllers/'.str_replace('.','/',$class).'.php');

        $Class=substr($class,strrpos($class,'.'));
        $controller=new $Class($app);

        if(method_exists($controller,$method)) $controller->{$method}($args);

})->via('GET', 'POST');

$app->run();

And am calling something like this
__http://domain.com/api/photos/recent/args/args/args

Test Class Photos

<?php

class photos {

    private $app;

    public function __contruct() {
        $this->app = Slim::getInstance();
    }

    public function recent() {

        $this->app->render('test.html');

    }

}

And am just trying to run an instance of Slim to render, but am not getting it for some reason?
What am I doing wrong? I'm dying with fatal error

PHP Fatal error: Call to a member function render() on a non-object in /library/controllers/photos.php on line 13

  1. Support Staff 1 Posted by Brian Nesbitt on 30 Jul, 2012 06:41 PM

    Brian Nesbitt's Avatar

    Away from computer at the moment but is it as simple as miss spelling
    the constructor?
    __contruct => __construct

    This would cause the private app to be undefined.

  2. Support Staff 2 Posted by Brian Nesbitt on 31 Jul, 2012 02:38 AM

    Brian Nesbitt's Avatar

    Also I'll mention that you call the controller constructor by passing in the slim application instance.

    $controller=new $Class($app);
    

    ... yet your photos class doesn't accept any parameters for the constructor. You are using the Slim static getInstance() function instead. Maybe try something like...

    class BaseController {
        protected $app;
        public function __construct($app = null) {
            $this->app = ($app instanceof Slim) ? $app : Slim::getInstance();
        }
    }
    
    class photos extends BaseController {
        public function recent() {
            $this->app->render('test.html');
        }
    }
    

    Now you can do $controller = new photos(); or $controller = new photos($app); and it will get set correctly. Will also make your testing of controllers easier :-)

  3. 3 Posted by dodomeki on 31 Jul, 2012 04:13 PM

    dodomeki's Avatar

    Actually my index.php ATM looks exctly like this. Does it still seem wonky to you? I still have a good day of refactorig left before it goes live.

    $app=new Slim();
    
        //wildcards to array 
        //anon.func man: http://php.net/manual/en/functions.anonymous.php
        $wildsToArr=function ($param_name) use ($app) {
           return function ($req, $res, $route) use ($param_name, $app) {
    
              $env=$app->environment();
              $params=$route->getParams();
    
              $env[$param_name.'_array']=array();
    
              //Is there a useful url parameter?
              if (!isset($params[$param_name])) return;
    
              $val=$params[$param_name];
    
              //Handle  /api/getitems/seafood//fruit////meat
              if (strpos($val, '//') !== false) $val=preg_replace("#//+#", "/", $val);
    
              //Remove the last slash
              if (substr($val, -1) === '/') $val=substr($val, 0, strlen($val) - 1);
    
              //explode or create array depending if there are 1 or many parameters
              if (strpos($val, '/') !== false)
              {
                 $values=explode('/', $val);
              }
              else
              {
                 $values=array($val);
              }
    
              $env[$param_name.'_array']=$values;
           };
        };
    
    
    //map all api call to associated classes or 404
    $app->map('/api/:class(/:method(/:args))', $wildsToArr('args'), function ($class,$method=null,$args=null) use ($app) {
    
        $env=$app->environment();
        if($app->request()->isPost() && in_array($class, array('photos','sweeps','audit'))) 
        {
            $env['args_array']=$app->request()->post();
            switch($class)
            {
                case('photos'): $method='upload'; break;
                case('sweeps'): $method='track';  break;
                case('audit'):  $method='audit';  break;
            }
        }
    
        require_once('library/controllers/'.str_replace('.','/',$class).'.php');
    
            $Class=substr($class,strrpos($class,'.'));
            $controller=new $Class($app);
    
            if(method_exists($controller,$method)) $controller->{$method}($env['args_array']);
    
    })->via('GET', 'POST')->conditions(array('args' => '.+'));
    
    
    //dynamic templating engine
    $app->get('/(:template)', function ($template=null) use ($app) {
    
        // Verify the template is valid or render home
        if(!file_exists("templates/{$template}.php")) $template='home';
    
        $app->render('includes/header.php');
        $app->render("{$template}.php");
        $app->render('includes/footer.php');
    
    })->name('templates');
    
    $app->run();
    

    And here's part of my photos class

    class photos

    {
    
        private $app;
        const   PAG=9;
    
        public function __construct() 
        {
            $this->app=Slim::getInstance();
        }
    
        //lazy autoloading
        //autloading man: http://php.net/manual/en/language.oop5.autoload.php
        public static function loadClass($class)
        {
            $files=array(
                $class . '.php',
                str_replace('_', '/', $class) . '.php',
            );
    
            foreach (explode(PATH_SEPARATOR, ini_get('include_path')) as $base_path)
            {
                foreach ($files as $file)
                {
                    $path="$base_path/$file";
                    if (file_exists($path) && is_readable($path))
                    {
                        include_once $path;
                        return;
                    }
                }
            }
        }
    
        public function recent($items) 
        {
    
  4. 4 Posted by dodomeki on 31 Jul, 2012 04:27 PM

    dodomeki's Avatar

    I just arranged it like you had above, very nice. ;) Thanks for all the help mate.

  5. Support Staff 5 Posted by Brian Nesbitt on 01 Aug, 2012 12:59 AM

    Brian Nesbitt's Avatar

    You can even improve your wildcard route middleware if you are using Slim 1.6.4. You can write the parsed parameter back to the argument list rather than having to write it to the $app->environment() as you do now and would simplify your code in several places.

    I blogged about it here http://nesbot.com/2012/7/3/slim-wildcard-routes-improved

  6. Support Staff 6 Posted by Andrew Smith on 01 Aug, 2012 09:42 AM

    Andrew Smith's Avatar

    Wildcard params have been added to Slim 1.6.5, now you can use it out of the box.

    http://www.slimframework.com/documentation/stable#wildcardrouteparameters

  7. Support Staff 7 Posted by Brian Nesbitt on 03 Aug, 2012 07:48 PM

    Brian Nesbitt's Avatar
  8. Brian Nesbitt closed this discussion on 03 Aug, 2012 07:48 PM.

Comments are currently closed for this discussion. You can start a new one.

Keyboard shortcuts

Generic

? Show this help
ESC Blurs the current field

Comment Form

r Focus the comment reply box
^ + ↩ Submit the comment

You can use Command ⌘ instead of Control ^ on Mac