twig: How to add Twig extension file whilst NOT using symfony - php

I am currently using v1.12.2 Twig as a standalone templating engine.
I wrote a Twig extension called Utility_Twig_Extension in a file called UtilityExtension.php
and an index.php
//index.php
require_once '../vendor/twig/twig/lib/Twig/Autoloader.php';
Twig_Autoloader::register();
$loader = new Twig_Loader_Filesystem(OEBPS);
$twig = new Twig_Environment($loader, array(
'cache' => APP . DS . 'cache',
));
require_once '../vendor/twig/twig/ext/utility/UtilityExtension.php';
$twig->addExtension(new Utility_Twig_Extension());
Here is the UtilityExtension.php
//UtilityExtension.php
namespace UtilityTwigExtension;
class Utility_Twig_Extension extends Twig_Extension
{
public function getName()
{
return "utility";
}
}
Here is my directory structure:
src
|__app
| |__ index.php
|__vendor
|__twig
|__twig
|__ext
|__lib
I cannot even load the file properly.
I have traced the issue to the fact that the extension class tries to extend Twig_Extension.php.
So I require_once the Twig_Extension which is the Extension.php file in UtilityExtension.php. However, still not working.
Most documentation talks about adding a custom Twig Extension in the context of Symfony.
I am using Twig standalone, so I have yet to find any documentation on that.
Please advise.
UPDATE1:
By not working, I meant that I get the 500 server error. I ran error_reporting(E_ALL) was to no avail.
The error was relieved the moment I removed the words extends Twig_Extension from the extension class.
UPDATE2:
I realized it was a namespace issue. because I removed the namespace UtilityTwigExtension; from the UtilityExtension.php and the server 500 error was gone.
So I put the namespace UtilityTwigExtension; back and then call
require_once '../vendor/twig/twig/ext/utility/UtilityExtension.php';
$twig->addExtension(new UtilityTwigExtension\Utility_Twig_Extension());
the error came back.
Question: How do I call the TwigExtension if I insist on using the namespace? Is there a better way of using namespace?
UPDATE3:
I still get server 500 after trying Luceos answer.
error_reporting(E_ALL);
require_once 'constants.php';
require_once 'ZipLib.php';
require_once '../vendor/twig/twig/lib/Twig/Autoloader.php';
Twig_Autoloader::register();
$loader = new Twig_Loader_Filesystem(OEBPS);
$twig = new Twig_Environment($loader, array(
'cache' => APP . DS . 'cache',
));
require_once '../vendor/twig/twig/ext/utility/UtilityExtension.php';
use UtilityTwigExtension\Utility_Twig_Extension;
$twig->addExtension(new Utility_Twig_Extension());
the UtilityExtension.php
namespace UtilityTwigExtension;
class Utility_Twig_Extension extends Twig_Extension
{
/**
* Returns the name of the extension.
*
* #return string The extension name
*/
public function getName() {
return 'utility';
}
}

So let's put the comments in an answer and move on from there without crowding the comments:
First of call the extension from the correct namespace:
use UtilityTwigExtension\Utility_Twig_Extension;
$twig->addExtension(new Utility_Twig_Extension());
Use and namespaces calls are normally placed at the top of the file.
You can also try calling the namespace + object directly by using:
$twig->addExtension(new UtilityTwigExtension\Utility_Twig_Extension());
Update 3
The Utility_Twig_Extension extends Twig_Extension from the namespace UtilityTwigExtension, which does not exist. I assume Twig_Extension is not in any namespace so you'll use \Twig_Extension:
namespace UtilityTwigExtension;
class Utility_Twig_Extension extends \Twig_Extension
{
/**
* Returns the name of the extension.
*
* #return string The extension name
*/
public function getName() {
return 'utility';
}
}

Related

Unable to load vendor classes from other namespace

I'm having some hard time wrapping around namespaces in PHP, especially when you code needs to interact with scripts residing in another namespace. I downloaded a Shopify API toolkit and trying to get it working. Everything was fine before I started adding namespaces to my code (which is required or threre is script collisition with other Wordpress plugins on my site). Also, the weird namespace {} bit at the top is because in this same file I want a globally accessible function for making the class a singleton.
Looking forward to learning more about how this works.
#### FILE BEING CALLED
namespace {
function SomeFunctionToBeAccessedGlobally() {
return 'Hello';
}
}
namespace MySpecialApp {
class ShopifyImport {
public function __construct() {
// Do Whatever
$this->doImport();
}
public function doImport() {
require __DIR__ . '/vendor/autoload.php';
$credential = new Shopify\PrivateAppCredential('standard_api_key', 'secret_api_key', 'shared_api_key');
$client = new Shopify\Client($credential, 'shop_url', [ 'metaCacheDir' => './tmp' ]);
}
}
}
#### FILE '/vendor/autoload.php'
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit73503f8de5d68cdd40a9c0dfd8a25b44::getLoader();
I do noice that some of the files which where part of the repository cloned into vendor have namespace Slince\Shopify; declarations. I tried to do a use with that namespace within my original namespace but it also didn't work.
The PHP Error being reported is:
Fatal error: Uncaught Error: Class
'MySpecialApp\Shopify\PrivateAppCredential' not found in
/.../ShopifyImporter.php:139 Stack trace: #0 (Blah Blah Blah)
Your code tries to create a new Shopify\PrivateAppCredential() object in the current namespace. However, this class does not exist in your namespace since it is part of the "vendor" namespace.
You can "reset" (read fallback) to the global namespace for your object creations by adding a \ in front of them, as described in the documentation:
$credential = new \Shopify\PrivateAppCredential('standard_api_key', 'secret_api_key', 'shared_api_key');
You can check the difference here without \ and with \.

Phalcon php namespaces cant use

So I have Users model namespaced:
namespace App\Models;
use Phalcon\Mvc\Model;
class Users extends Model
{
And Controller:
use \Phalcon\Mvc\Controller;
use \App\Models\Users;
class LoginController extends Controller
{
...
public function postLoginAction() {
$user = Users::findFirst([ ...
}
...
Always getting error Fatal error: Uncaught Error: Class 'App\Models\Users' not found in no matter what, tried every variation no idea what's wrong with it. even my IDEA resolving this class correctly.
Everything is working if I remove my namespacing.
UPDATE:
So if you generated project with phalcon dev tools and then started generate other things (model, controllers) you will need to provide namespace for model and it will not work, you will also need to update app/config/loader.php like this:
<?php
$loader = new \Phalcon\Loader();
/**
* We're a registering a set of directories taken from the configuration file
*/
$loader->registerDirs(
[
$config->application->controllersDir,
$config->application->modelsDir
]
)->register();
$loader->registerNamespaces(
[
'App\Controller' => $config->application->controllersDir,
'App\Model' => $config->application->modelsDir,
]
)->register();
In other words register namespace, I don't know why this not clearly stated in documentation but it seams this framework have many such "black holes" or I don't understand this framework fundamentals (came from codeigniter and Laravel background).
Try this in your bootstrap file:
// registers namespaces
$loader = new Loader();
$loader->registerNamespaces([
'App\Controllers' => APP_PATH . '/controllers/',
'App\Models' => APP_PATH . '/models/'
]);
$loader->register();
Btw, APP_PATH could be a constant to your app's directory, or whatever you want/need.

How to register a twig extension in PHP

I am currently using twig standalone (not with symphony or composer) and am not finding in the documentation on how to register an extension in php.
My index.php file looks like this
<?php
include 'exts/ext.php';
require_once 'Twig/Autoloader.php';
Twig_Autoloader::register();
$loader = new Twig_Loader_Filesystem('views');
$twig = new Twig_Environment($loader);
$twig->addExtension(new Test_Twig_Extension())
echo $twig->render('index.twig');
?>
My extension class looks like this (ext.php)
<?php
//require_once 'Twig/Extension.php';
//require_once 'Twig/ExtensionInterface.php';
class Test_Twig_Extension extends Twig_Extension {
public function getFunctions() {
return array(
new Twig_SimpleFunction('my_function', array($this,'my_function'))
);
}
public function my_function($arg1, $arg2) {
echo "Arg1: {$arg1} and Arg2: {$arg2}";
}
public function getName(){
return 'my_function';
}
}
?>
I get the following error:
Fatal error:
Interface 'Twig_ExtensionInterface' not found in
C:\xampp\htdocs\Twig\Extension.php on line 12
I have found tones of articles with setting it up with yaml but I am not using yaml.
I am sure I am not registering this properly or do not have something set up just right.
So what I figured out is is the following:
When autoloading you do not need to require/include the class file
The name of your extension should start with Twig_Extension_ (for example i had to rename mine to Twig_Extension_Test rather than Test_Twig_Extension like the docs some time show)
Make sure your Twig_Extension_Test class has the getName method in it.
Name your extension file to be last part of class name. So mine had to be called Test.php. I believe this is case sensative as well.
Place this file into the Twig/Extension/ folder
Call $twig->addExtension(new Twig_Extension_Text());
I have updated my code in the Question to reflect these steps

Composer autoload not work properly

I have following problem: I have class Router (in project/connection/api/callbacks) and TestRouter (in project/tests/api).
Class Router is only Example and I don't want psr-0 or 4.
Router has this code on the beginning:
<?php
namespace Connection\Api\Callbacks;
class Router
{
Test class start with this code:
<?php
$loader = require __DIR__ . '/../../vendor/autoload.php';
$loader->add('Connection\\Api\\Callbacks', __DIR__ . '/../../connection/api/callbacks');
class TestRouter extends PHPUnit_Framework_TestCase
{
function test() {
$variable = new \Connection\Api\Callbacks\Router();
}
Then I got error class not found. Please where is the problem?
You don't want PSR-0, but you are using exactly that function. The code comment for the add() method you are using to add your class to the autoloader:
/**
* Registers a set of PSR-0 directories for a given prefix, either
* appending or prepending to the ones previously set for this prefix.
*
* #param string $prefix The prefix
* #param array|string $paths The PSR-0 root directories
* #param bool $prepend Whether to prepend the directories
*/
public function add($prefix, $paths, $prepend = false)
I wonder what keeps you from simply using PSR-4 in this case. Just add the necessary declaration to your composer.json file.
When it comes to PHPUnit, add require "vendor/autoload.php" to the bootstrap file or use it as the full bootstrap file if you don't have to do anything else there. It will make writing tests easier because you don't have to take care of the autoloading and adding the individual class to the autoloader. Also, you won't end up instantiating multiple autoloaders that don't get removed from the autoloader stack.

how can I solve "Cannot redeclare class" error in zf2?

I'm developing a personal finance application with ZF2 in ZendStudio 11. I'm getting the following fatal error after adding a new controller from New Zend Item wizard. Here's a screenshot.
Error:
_Fatal error: Cannot redeclare class Application\Controller\OutcomeController in **C:\wamp\www\PersonalFinance\module\Users\src\Users\Controller\OutcomeController.php** on line 33_
OutcomeController class code is as follow:
<?php
namespace Application\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
/**
* OutcomeController
*
* #author
*
* #version
*
*/
class OutcomeController extends AbstractActionController
{
/**
* The default action - show the home page
*/
public function indexAction()
{
// TODO Auto-generated OutcomeController::indexAction() default action
return new ViewModel();
}
public function fooAction()
{
// This shows the :controller and :action parameters in default route
// are working when you browse to /income/income/foo
return array();
}
}
I've also added the below line to the autoload_classmap.php file:
'Users\Controller\OutcomeController' => __DIR__ . '/src/Users/Controller/OutcomeController.php',
So:
I've added the controller using the wizard
I've added the needed
controller configs to the module.config.php
I've added the
autoloading config line to the autoload_classmap.php
Any ideas why the error happens?
As the error message suggests, the class Application\Controller\OutcomeController is already defined somewhere else in your application.
This has nothing to do with using the wizard of ZendStudio, configuring correctly ZF2 or with autoloading. This is a PHP thing: you can't have in your application two classes with the same name (considering the namespace).
To avoid the problem you could either change the name of the class or change the namespace where you declare it.

Categories