Call TYPO3 PHP function from outside TYPO3 - php

I try to open an extbase view in a different window.
For this I call the function
\typo3\sysext\extbase\Classes\Mvc\Controller\AbstractController->redirect().
But it fails, due to abstract class AbstractController implements ControllerInterface. It can not find ControllerInterface. It is in the folder, but the folder isn't included in the path get_include_path().
Is there any way to go arround this problem without changing the TYPO3 file?

On the surface this looks like a typical class loading issue, so I'll describe the pitfalls there in case someone comes searching for that type of error and finds this post.
If you installed TYPO3 via composer, make sure you load the composer autoload file from your external file. Composer paths do not appear in the PHP include paths, and you should never have to include any other file than the composer autoload file.
If you did not install via composer you will need to run your script in a TYPO3 context. Only then will class loading work.
That said: the fact that class loading is inactive indicates you are trying to use TYPO3 features completely outside TYPO3. It is no easy task to simply use TYPO3 classes outside of a TYPO3 context - especially not Extbase ones, and especially not controllers. There are so many dependencies on configuration, database and request handling. I would strongly discourage attempting to do this.
Even generating a link to a controller action involves calculating a request hash which in turn requires access to the TYPO3 configuration and database. So in all likelihood, what you are attempting is simply not possible - you need to do it from within a TYPO3 context.

Related

Use the same part of code in multiple WP plugins [duplicate]

I am developing a plugin that used composer.. meaning it has a vendor folder inside the plugin folder which includes Guzzle HTTP dependency
On wordpress site we installed this plugin, there is an existing plugin that has Guzzle HTTP
Now when we activate this plugin i am getting an error something like this:
Fatal error: Cannot redeclare GuzzleHttp\uri_template() (previously declared in /nas/content/staging/project/wp-content/plugins/my-plugin/vendor/guzzlehttp/guzzle/src/functions.php:17) in /nas/content/staging/project/wp-content/plugins/other-plugin/includes/lib/aws-sdk/GuzzleHttp/functions.php on line 31
I tried installing Plugins Load Order to force the 'other-plugin' to load first before 'my-plugin'
currently the error is happening on the other-plugin's resources.
this way, The error will yield in our autoload and we can catch that.
unfortunately.. Plugins Load Order did not work..
any ideas how to solve this?
Welcome to WordPress hell. We have 2018 and WordPress still does not have any dependency management and still didn't notice Composer existence.
WordPress ecosystem simply relies on assumption, that functions/classes names of plugins/themes should be unique. Obviously distributing popular 3rd-part Composer libraries with your plugin/theme is asking for trouble - it is easy to get names collision when other plugin is doing the same. There is no good way out of this situation.
If you want a bulletproof solution for standalone plugins, you should prefix namespaces of every package in your vendor directory with plugin prefix, for example myplygin\vendor. Then GuzzleHttp\Client becomes myplugin\vendors\GuzzleHttp\Client, so there is no risk of name collisions. This will require some work to write script for this (or you may use some existing solutions, like humbug/php-scoper), and you may get many duplicated dependencies (10 plugins may bring the same library 10 times, but with different namespaces), but this is the cost of integrating modern tools and patterns into outdated software.
If you're writing this plugin for yourself and you're controlling final installation, you may try to use Composer for installing WordPress and its plugins. You still may need to fix 3rd-party plugins (via forking) if they're have bundled some composer library, but in the long run it should simplify many things and you may avoid duplicating libraries for every plugin.
By design, PHP and Composer assume that you develop and distribute your code in a controlled environment. However, when you publish plugins on WordPress or modules on Joomla, you distribute the code on systems where you don't have control over what other authors install. This situation can result in name collisions such as Cannot redeclare GuzzleHttp\uri_template()....
To prepare your code for multi-vendor setups, you must prefix the PHP code to avoid name collisions or version collisions (the same library with a different version is loaded first). For instance, Guzzle is a well-known and widely used library, so if you publish a plugin including it, you must prefix it before distribution.
At first glance, you may think that prefixing only the namespaces would get the job done. But other named elements such as global functions and traits must also be prefixed to avoid all possible error types.
To prefix PHP code, there are tools or services to execute the task:
humbug/php-scoper. Prefixes all PHP namespaces in a file/directory to isolate the code bundled in PHARs.
Interfacelab/namespacer. Namespacer allows you to rename the namespace of any composer packages. It works by adding a namespace prefix to all of the namespaces. Namespacer also prefixes the package names. It then generates a folder called "lib" that you can safely include in your WordPress plugin.
coenjacobs/mozart. Developers tool for WordPress plugins: Wraps all your projects dependencies in your own namespace. This prevents conflicts with other plugins that load the same dependencies but in different versions.
PHP-Prefixer. It's an automated online service powered by a complex rule-based system to apply prefixes to Composer dependencies. In the composer.json, you just define the prefix to apply without worrying about the nitty-gritty details.
Disclaimer: I'm the lead PHP-Prefixer developer.
This is not suggested but use it if you must
function this_plugin_last() {
$wp_path_to_this_file = preg_replace('/(.*)plugins\/(.*)$/', WP_PLUGIN_DIR."/$2", __FILE__);
$this_plugin = plugin_basename(trim($wp_path_to_this_file));
$active_plugins = get_option('active_plugins');
$this_plugin_key = array_search($this_plugin, $active_plugins);
array_splice($active_plugins, $this_plugin_key, 1);
array_push($active_plugins, $this_plugin);
update_option('active_plugins', $active_plugins);
}
add_action("activated_plugin", "this_plugin_last");
I make use of this library which is a more maintained version of mozart: https://github.com/BrianHenryIE/strauss
It lets you set a namespace prefix for your vendor libaries of choice and add them to a separate library which you can then autoload into you project.
It also has a lot of other useful features.
I'm guessing there's a function at GuzzleHttp/functions.php on line 31 so you can use something like that:
if (function_exists('Do_Something')){
echo "Function Exists";
}else{
echo "Function Not Found, This name Can be used!";
}
or you can use is_plugin_active function to check if the plugin is already installed. In that case, you can ignore including the files
https://codex.wordpress.org/Function_Reference/is_plugin_active

How to determine which libraries were loaded by Composer autoload.php

Is there a way, within PHP, to get a list of all libraries loaded by Composer's /vendor/autoload.php file?
Example:
require_once("./composer/vendor/autoload.php");
// In some way, get a list of libraries that were loaded:
$libraries = composer_get_libraries(); // you get the idea
I can't seem to find this in the Composer docs or google...
It's easy to list the installed libraries ('composer show') but this doesn't show which ones are autoloaded in PHP. The reason I'm asking is that I just installed a new library with composer require [library name], but in PHP the library's class is not found. I'm trying to debug this problem and it would be helpful to ensure the autoload.php is actually loading this library.
Even enabling a "debugger" option that would dump the autoloader activity to a log file would be helpful.
Update: looking into the When unit test code, I see there must be a
use When\When;
before instantiating a When object.
PHP itself has no notion of a library or a package, only the functions, classes, etc, it defines.
Composer, in turn, has no notion of how the code is being used; it may register one or more autoloaders using the spl_autoload_register function, based on the configuration of the installed packages, but it can also include certain files on every page load, which might register their own autoloader, or just define classes and functions directly.
There is therefore no concept anywhere of "the autoloader loading that library" - there might be a combined PSR-4 autoloader built by Composer, plus a combined classmap autoloader, plus a bunch of custom autoloaders, none of which have any need to "remember" which package they belong to.
When you ask for the class, PHP runs all the autoloaders that are registered, and each has a chance to define the class, usually by including a file.
All of this happens in PHP code, so a debugger such as XDebug can be used to see what autoloaders are actually run, and what each does, but beware that they may be hard-to-read machine-generated code.
A class not being autoloaded suggests one of three things:
Composer has not generated the correct autoloader code. You might try running composer dump-autoload
The package contains incorrect autoload information in its composer.json. This is unlikely unless nobody else has installed it using Composer.
You have made a mistake in the way you referenced the class, for instance missing the namespace, or mistyping it in a use statement.

Add a custom PHP function to MAMP

I'm wondering what's the best way to extend the MAMP PHP core itself so that custom functions will be available globally without the need to import libraries.
A good example of what I want to do is to have a dd function (which is var_dump() + die(), inspired by Laravel) available in all my local projects.
These methods need to be available only on my local environement (where my version of MAMP is installed) and for debugging purposes only, so there is no fear of breaking PHP funcionality on end server.
Thanks for your help.
There are two approaches for this:
Adding a module to php which is loaded like all the other modules. Modules like database connectors, math libraries, translation functions, whatever. All those functions are not part of "the php core". The core implements only the language itself. You can see what modules are currently loaded and their configurations in your php setup by using the function phpinfo().
Implementing a module is possible, you need to know c or c++ langauge for this. An interesting project, you will learn a lot. But this is also a huge overhead to what you are looking for.
Implement your functions in a normal php file somewhere outside your normal project folder. Then register that file inside your http servers php configuration as "to be loaded for every executed script". That is exactly what the "auto_prepend_file" feature does. That way you can easily add global functions always available in all scripts on your local system.
Believe me, you want to give the second approach a try :-)
Without compiling your own extension to PHP, creating a global function that is automatically available to all scripts on the box without importing anything may be impossible.
You could create a file like "tools.php" that contains the dd function definition, and you do a call like require "tools.php" in your application. Put the development version of tools.php in a directory that is only available on the development server, in a path that is given highest priority in the include_path.
Then create a mirror tools.php in the codebase, with a lower priority in the include_path, that contains only stubs to your development methods. Therefore, on the dev box, the dev version of tools.php will be included. But on production, the production version of tools.php would be included.

Composer Namespace Collisions in WordPress Plugin Development

I'm encountering a wholly predictable yet incredibly annoying and tough to resolve problem.
I've been working on a PHP framework for developing WordPress plugins. It's using Composer for dependency management. Of course, the problem is if you have two instances of my framework in the same installation of WordPress, you have two vendor folders, and two copies of any packages required by the framework. Which leads to an error.
The framework functions as a separate plugin which is then inherited by any apps/plugins that are build on it.
Move the vendor folder to the core framework folder?
Problems: I don't know what would happen if I have two composer.json files and two composer.phar files writing to the same vendor folder and using the same autoloader. Presumably it wouldn't be good. Besides that, it doesn't solve the problem of collisions with composer packages that could be used by any other script or plugin outside of what I'm trying to handle.
So I'm stuck. Is this a problem that can be solved, or is it just inherent in PHP?
Composer is not really meant to be used multiple times in same project. On other hand there is nothing terribly wrong with it either, however you lose its dependencies features and need to treat this like generic case of dependencies in WordPress environment.
In other words - if you are not doing dependencies Composer way and WordPress is not doing dependencies at all, it becomes your personal problem how to deal with it.
I don't know what would happen if I have two composer.json files and two composer.phar files writing to the same vendor folder and using the same autoloader
I am not following why the vendor folder would be same if you are using multiple composer installs... Could you elaborate on how you structure it and is it meant for public or private use?
I'm not very familar with Composer or the plugin framework you are using, but in general - avoiding function/class name collisions in WordPress plugins is done in the following manner:
Assuming that your plugin (e.g. MyCoolPlugin) is written object-oriented, e.g. as a class named MyCoolPlugin, you may include the helper class/library as a subclass of MyCoolPlugin.
class_exists(), this is PHPs way of finding if a class has been defined. Assuming your helper class the following:
class MyHelperClass{
}
You may use the following check before declaring the class in each of your plugins:
if(!class_exists('MyHelperClass')){
class MyHelperClass{
}
}
Of course, there is a trade-off here, because only the first instance of the class will be used throughour WordPress. E.g. if you have two plugins with two different versions of the helper class - only one of them will be active and available at any given moment.
A global variable - e.g. define('MY_HELPER_IS_LOADED', true); in the helper files (in case you are including them via include() or require()). Then in the beginning of each included helper file check with if(defined('MY_HELPER_IS_LOADED')) return;, which will cause the currently requested file for include/require to NOT be included.
Again the tactics above are used in PHP in general, I am not sure how your plugin framework is set up exactly.

PHP 5.4 vs 5.3: Autoloading multiple classes in the same file

Firstly, this is a bit of a long one, so thank you for reading.
My issue is similar to this one:
Class not found in the same file
I have a custom-built framework originally written in 2008 for PHP 5 and it's been upgraded over the years to work with PHP 5.3. I've been looking at 5.4 compatibility and have hit a serious issue.
The ORM layer automatically generates classes for each DB table. These classes all sit in one file per table and our autoloader loads that file when required.
For example, a 'customer' table in the 'public' schema (postgresql) would have the following classes:
PublicCustomer, PublicCustomerDBReader, PublicCustomerDBWriter.
Now this may not be the ideal set up, but it is what we currently have.
In PHP 5.3, if PublicCustomer was required, the file would be included, parsed and all of the above classes would become available. So if, for example, a static method is called on PublicCustomer, and that method calls something in PublicCustomerDBReader, that would work fine, since that class is in the same file.
In PHP 5.4, it looks like some optimisations have been done in the core. In the above scenario:
A static method gets called in PublicCustomer.
The autoloader finds and loads the correct file.
The PHP parser only parses up to where it needs; the PublicCustomer class. It has not parsed or instantiated the PublicCustomerDBReader class. I can confirm this by testing if the class exists and by seeing if the parser reaches the end of the file when it gets included, when the method is called (it doesn't).
The method in PublicCustomer then tries to call a method in PublicCustomerDBReader. This fails, since our autoloader has already required the file once.
It seems to me that I have two solutions:
Separate these classes out so that there is one file for each (this will produce a huge number of files)
Redesign the ORM layer so that multiple classes are not required.
Have I understood the issue above properly?
Does anyone know if an optimisation or change was made in PHP 5.4 that would cause this behaviour?
Are there any other potential solutions to the problem that I have not considered?
Place the reader/writer classes at the head of the file. Also you might consider filing a bug report, since the parser should only halt on errors.
Referring to the PHP Framework Interop Group and their autoloading standards PSR-0 and PSR-4 each class must have its own file with a name ending in .php. Even if you have thousands of classes, this should't be a problem for the file system.
With more than one class in a file you have to consider following aspects:
For each class the autoloader must decide which file to load. If you have multiple classes in a file, each used class causes a load. Class files should be loaded once and not more, because classes cannot be redeclared. I do not recommend it, but you could handle this with your own autoloader, which remembers loaded files or tests for loaded classes.
Classes placed within the same file and using each other is problematic. The problem is described in Derived class defined later in the same file “does not exist”? and answered by Jon.

Categories