Love Fuel?    Donate

FuelPHP Forums

Ask your question about FuelPHP in the appropriate forum, or help others by answering their questions.
Twig Autoloader not found
  • I added twig to composer.json then installed it. I can confirm it's installed because there's a folder called twig inside fuel/vendor.

    I then enabled parser inside config.php but I keep getting Class Twig_Autoloader not found.


    BTW why can't I insert images on my device?
    image
  • I'm using Fuel PHP 1.8
  • After a little digging I discovered that fuel php's parser is looking for a class Twig_Autoloader which used to be located inside ..../lib/Twig/Autoloader.php and that has been deprecated in Twig's version 2.x which I was using.

    After removing 2.x and installing 1.x no more errors.


    The parser needs to be worked on to make it compatible with twig 2.x.
  • HarroHarro
    Accepted Answer
    Hmm... Thought that was already addressed.

    Added a ticket for it: https://github.com/fuel/parser/issues/91

    And no idea why images don't work, I'll pass that on to the server admin.
  • Great. Well done guys.
  • Support has been added to 1.9/develop.

    A new hotfix release for 1.8 is planned for this weekend, it will be automatically installed if you run a "composer update" after release.
  • I hope the update won't break my code
  • Please I have two slight issues.

    1. In php I can call Asset::img and pass it attributes e.t.c how can I do the same thing in Twig? I saw asset_img() on a website but I don't know how to pass it attributes and it's not in the documentation.

    2. Is there a way to get an image asset without knowing the extension? i.e I know it must be named logo but it can be logo.jpg, logo.png, logo.svg e.t.c
  • The code defaults to 2.x, but has a fallback to 1.x, so it shouldn't break anything.

    If you want to test it, just change the composer.json to load

        "fuel/parser": "dev-1.9/develop"

    and run a composer update. After testing, put the old line back again, and run another update to go back to the 1.8 release code.

    The functions are defined in the parser package, in Twig_Fuel_Extension. These are the only Fuel internal functions that are available in your templates.

    In twig, you call a function like you would do in PHP, so in this case something like:

    {{ asset_img('myimages.png') }}

    No, there is no way to "guess" an extension. If you want to do that, you need to do that in your controller (or preferrable, your presenter as it is not really controller code):

    // untested, from the top of my head
    $logo = '';
    foreach (array('jpg', 'png', 'svg' as $ext)
    {
        if ($logo = Asset::find_file('logo.'.$ext, 'img'))
        {
            break;
        }
    }

    and pass $logo as a variable to your template. Or extend the parser class, and add your own custom extensions so you can do this using a template function.
  • Thanks. I think I'll prefer the second option of extending the parser class, please how can I go about this?
  • Under app/classes I created twig/fuel/extension.php (how it was created in the parser package) then I created a class Twig_Fuel_Extension

    class Twig_Fuel_Extension extends \Parser\Twig_Fuel_Extension {
    public function getFunctions() {
    return array();
    }
    }

    Then I created a config/parser.php which contains

    return array(
    'View_Twig' => array(
    'extensions' => array(
    'Twig_Fuel_Extension'
    )
    )
    );


    But this doesn't work as I'm still able to use all functions defined. How can I easily override any part of the parser class without having to modify the core code?
  • HarroHarro
    Accepted Answer
    You also need to define the existence of this class in your app bootstrap:

    Autoloader::add_classes(array(
        // overload the Twig fuel extension
        'Twig_Fuel_Extension'        => APPPATH.'classes/twig/fuel/extension.php',
    ));

    So the autoloader knows to load your class instead of the original one.
  • It works. Thanks a lot.
  • I have another issue though. I routed /admin/country/:num/state/:num to admin/state

    1. How can I get the country_id and state_id?
    2. admin/state still works which is not what I want. How can I disable this?
  • Assuming that is Controller_Admin::action_state(), additional URI segments are passed on as method arguments, so define it like so

    public function action_state($country_id, $state_id)

    if the arguments are required (if not given in the URI, you will get a 404), or

    public function action_state($country_id = null, $state_id = null)

    if they are optional (give them any default value you want),

    If you want to block access to a route, route it to your 404 action.
  • It's a different controller. I have Controller_Admin_Country which extends Controller_Admin. It includes every thing necessary to interact with countries. Since states will also have more than one methods I decided to split it into it's own controller (Controller_Admin_State) instead of creating action_state inside Controller_Admin_Country.

    I'll still have urls like admin/country/1/state/delete/1, /admin/country/1/state/edit/1 e.t.c. I wish routing can be as flexible as in django and express js. Probably you can consider having that sort of option in future versions.


    In the meantime how can I go about this?
  • I'm not sure I understand what your problem is. Why wouldn't you be able to have url's like that?
  • My problem is how can I get the country_id and state_id parameters?

    My route looks like this 'admin/country/:num/state/:num' => 'admin/state'
  • Okay I figured it out.

    I changed my route to 'admin/country/(?P<country_id>\d+)/state/(?P<state_id>\d+)' => 'admin/state',

    so inside the controller I can use $this->param('country_id) to get the country_id.


    I got the hint from router class section of the docs, it would have been nice if the routing section also include the same kind of example.
  • That also works.

    But it is a lot easier to define it like this:

    'admin/country/(:num)/state/(:num)' => 'admin/state/$1/$2'

    and use the method definition I posted earlier.

    or like this:

    'admin/country/:country_id/state/:state_id' => 'admin/state'

    and use the param() method, or like this:

    'admin/country/(:country_id)/state/(:state_id)' => 'admin/state/$1/$2'

    and have both options.

    In general, there is no need to define your own regex, unless you're trying to do something very complicated.
  • Oh! I see where my mistake is during my first routes. I didn't add /$1/$2.

    Thanks a lot.
  • I noticed a problem with using 'admin/country/(:num)/state/(:num)' => 'admin/state/$1/$2' though. If I navigate to /admin/state/1/2 It also works.
  • Yeah, I mentioned that before.

    Fuel has dynamic routing to controllers for URL's like /controller/method or /namespace/controller/method.

    If you don't want that, you need to block dynamic routes to those controllers, either by using specific routes like:

    'admin' => 'welcome/404'

    or

    'admin/state' => 'welcome/404'

    or even as catch-all

    '.*' => 'welcome/404'

    (or whatever your 404 handler is). Note that routes are processed in sequence, so make sure that if you use these routes, you add them BELOW the more specific routes you have, and if you use the catch-all, make sure it is the last route defined.
  • Thanks.

    I'm having issues, making ajax call to a controller method which returns json.

    public function post_fetch_sub_category() {
    $category_id = self::sanitize(Input::post('category_id'));
    $sub_categories = DB::select()->from('qc_sub_categories')->where('category_id', $category_id)->execute();
    return $this->response($sub_categories, 200);
    }


    $('#id_product_category').on('change', function() {
    data = new FormData();
    data.append('category_id', this.value);
    $.ajax({
    data: data,
    type: "POST",
    url: "/admin/category/fetch_sub_category",
    dataType: "json",
    cache: false,
    contentType: false,
    processData: false,
    success: function(sub_categories) {
    console.log(sub_categories);
    }
    });
    });



    If I change the method to action_fetch_sub_category($category_id), when I navigate from browser I get a json response with a text at the beginning saying 'This REST page returned array or object.' But with ajax call I keep getting Internal Server Error.
  • Is this a standard controller, or a REST controller?

    A standard controller returns HTML, you have to do the json conversion of your data structure yourself.
  • Controller_Admin extends Controller_Hybrid and Controller_Admin_Category extends Controller_Admin so I guess that should give it REST functionality.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

In this Discussion