I was wondering if there is a way to load different folder based on php version. I could do it writing my own autoloader, but i was wondering if there is a way of using composer for that?
Ps. I have seen this in use before in module / plugin application that where redistributed globally to work with wide range of env. Those scripts where using own autoloading classes.
I am curios is there a way to use composer in similar way.
Scenario: class / folder structure:
class >
php5.6 >
- SomeClass.php
...
php7.x >
- SomeClass.php
...
php8.x >
- SomeClass.php
...
Compare php version and do something:
$classPathForAutoloader = '';
if (version_compare(PHP_VERSION, '8.0.0') >= 0) {
$classPathForAutoloader = 'php8.x';
// do something to composer autoload or
// use declaration
}else if(version_compare(PHP_VERSION, '7.0.0') >= 0){
$classPathForAutoloader = 'php7.x';
// do something to composer autoload or
// use declaration
}else if(version_compare(PHP_VERSION, '5.6.0') >= 0{
$classPathForAutoloader = 'php5.6';
// do something to composer autoload or
// use declaration
}else{
// throw Exception ...
}
standard composer setup:
{
"name": "some/name",
"require": {
},
"authors": [
{
"name": "Some Name",
"email": "some#email.com"
}
],
"autoload": {
"psr-4": {
"Devwl\\": "class/",
"Tools\\": "tools/"
},
"classmap": [
"class/"
],
"exclude-from-classmap": []
}
}
I don't think Composer provides a way to dynamically autoload different paths.
Can you use version_compare in a single SomeClass.php class only where the functionality differs by PHP version? Or write the entire SomeClass.php to be backwards compatible?
To me loading different classes depending on the PHP version is asking for trouble when it comes to reproducibility across environments.
Another option would be to use require_once to load the different classes, but for maintainability I'd really lean towards a single class with version checks only when absolutely necessary.
So i have created a class which does what I need. It can laso work alongside Composer autoloader.
<?php
class PhpVersionAutoloader{
private $baseClassesDirPath = null;
private $phpVersionArr = [];
private $phpDir = null;
private $classes = []; /** Keep a record of all loaded classes */
/**
* Allows to change base dir path.
* If not set the path will be set to file _DIR_
*
* #see $this->baseClassesDirPath
*
* #param string $path
* #return void
*/
public function setBaseClassesDirPath($path)
{
$this->baseClassesDirPath = $path;
}
/**
* Map available dir name and php version
*
* #see $this->phpVersionArr
*
* #param string $directory name
* #param string $phpVersion
* #return void
*/
public function registerPhpDir($dir, $phpVersion){
$this->phpVersionArr[] = [$dir => $phpVersion];
}
/**
* Compare curent php version with $this->phpVersionArr to determin the right path for class load
*/
public function selectPhpDir(){
foreach ($this->phpVersionArr as $key => $phpVDir) {
$this->position = $key;
foreach($phpVDir as $key => $value){
if (version_compare(PHP_VERSION, $value) >= 0){
$this->phpDir = $key;
break 2;
}
}
}
}
/**
* Register autloader
*
* #return void
*/
public function register(){
spl_autoload_register(function($className)
{
$namespace = str_replace("\\","/",__NAMESPACE__);
$className = str_replace("\\","/",$className);
$this->baseClassesDirPath = ($this->baseClassesDirPath === null) ? str_replace("\\","/",__DIR__) : $this->baseClassesDirPath;
$class = $this->baseClassesDirPath."/classes/".$this->phpDir.'/'. (empty($namespace)?"":$namespace."/")."{$className}.php";
$this->classes[] = $class;
if (file_exists($class)){
include_once($class);
}else{
// ... if not exsist try to load lower php version file?
// ... or throw new Error("Error Processing Request", 1);
}
});
}
}
Use the PhpVersionAutoloader object like this:
/**
* Use example
*/
$loader = new PhpVersionAutoloader(); // init PhpVersionAutoloader object
$loader->setBaseClassesDirPath('C:/xampp/htdocs/blog/blog autoloading'); // if not used will use _DIR_ to create path
$loader->registerPhpDir('php8.x', '8.0.0'); // as "folder name" => "php version"
$loader->registerPhpDir('php7.x', '7.0.0'); // ...
$loader->registerPhpDir('php5.6', '5.6.0'); // ...
$loader->selectPhpDir(); // compare system php version and selects the correct phpX.X subfolder
$loader->register(); // register autoloader
I also created more functional class of this loader which allow to force specific directory to load from or even allow to load classes from older version of PHP if not found in selected version.
See github [here]
Related
I've developed a Scheduler task in TYPO3 which basically generates files while accessing each class repository. If a certain record, which has a dependency with a record of another class is being deleted in the BE i want the task to also remove this corresponding record from the repository as well. For that i thought of using repository methods.
Here i define the repositories (there are more, but those two are relevant for my problem):
/** #var CustomerRepository $apprep */
$apprep = $objectManager->get(\Cjk\Icingaconfgen\Domain\Repository\HostRepository::class);
/** #var Typo3QuerySettings $querySettings */
$querySettings = $objectManager->get('TYPO3\\CMS\\Extbase\\Persistence\\Generic\\Typo3QuerySettings');
$querySettings->setRespectStoragePage(FALSE);
$apprep->setDefaultQuerySettings($querySettings);
$hosts = $apprep->findAll();
/** #var CustomerRepository $apprep2 */
$apprep2 = $objectManager->get(\Cjk\Icingaconfgen\Domain\Repository\ServicesRepository::class);
/** #var Typo3QuerySettings $querySettings */
$querySettings = $objectManager->get('TYPO3\\CMS\\Extbase\\Persistence\\Generic\\Typo3QuerySettings');
$querySettings->setRespectStoragePage(FALSE);
$apprep2->setDefaultQuerySettings($querySettings);
$services = $apprep2->findAll();
$srvrep = $apprep2;
Farther down in my code i have the following block:
foreach($services as $service){
$validate2 = false;
foreach($hosts as $host){
if($host->getUid() == $service->getHost()){
$validate2 = true;
break;
}
}
if($validate2 == false){
foreach($kunden as $kunde){
$name = $kunde->getName();
$files = array_filter(scandir('/etc/icinga2/conf.d/hosts/'.$name.'/'), function($item) {
return !is_dir('/etc/icinga2/conf.d/hosts/'.$name.'/'. $item);
});
foreach($files as $fileval){
if($fileval == 'Service_' . $service->getServicename(). '_'. $kunde->getKundennummer().'.conf'){
unlink('/etc/icinga2/conf.d/hosts/'.$kunde->getName().'/'.$fileval);
}
}
}
$srvrep->remove($service);
}
}
So as you can see, i check if a corresponding service has any host (the getter getHost() of the $service object returns basically the Uid of the specific corresponding host object (getUid()) if there is a dependency. If there is no dependency it first removes the file and then i want it to remove the record from the repository. but the line
$srvrep->remove($service);
Doesn't seem to work as i want it to.
When using the Extbase persistence layer in any context besides an Extbase ActionController, you need to manually flush the PersistenceManager to persist your changes.
$persistenceManager = $objectManager->get(\TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager::class);
$persistenceManager->persistAll();
With Symfony 2 & Doctrine on a Windows machine I'm trying to
generate entities from an existing schema:
php app/console doctrine:mapping:import --force CoreBundle annotation
generate getters/setters on them:
php app/console doctrine:generate:entities --path=/path/to/codebase/src/MyProject/CoreBundle/Entities CoreBundle
generate REST CRUD controllers on them using Voryx:
php app/console voryx:generate:rest --entity="CoreBundle:User"
The first steps works fine and I can find the entities in my CoreBundle/Entity folder with the correct namespace:
MyVendor\MyProject\CoreBundle\Entity
Good so far.
However, running the other 2 commands will fail:
[RuntimeException]
Can't find base path for "CoreBundle" (path:
"\path\to\codebase\src\MyProject\CoreBundle", destination:
"/path/to/codebase/src/MyProject/CoreBundle").
The autoload in my composer.json looks like this:
"autoload": {
"psr-4": {
"MyVendor\\": "src/"
}
},
I found out that Doctrine can't deal with PSR-4 namespaces, that's probably what makes it fail.
I would really like the entities to live in the PSR-4 CoreBundle though - is there a workaround for it?
I tried this, but it doesn't work, either:
"autoload": {
"psr-0": {
"MyVendor\\MyProject\\CoreBundle\\Entity": "src/MyProject/CoreBundle/Entity/"
},
"psr-4": {
"MyVendor\\": "src/"
}
},
Thank you.
User janvennemann on GitHub fixed Doctrine for PSR-4. You can find the patch on Gist, or linked here below
Step to fix it
mkdir -p app/VendorOverride;
cp vendor/doctrine/doctrine-bundle/Mapping/DisconnectedMetadataFactory.php app/VendorOverride/DisconnectedMetadataFactory.php;
apply the DisconnectedMetadataFactory patch;
add app/VendorOverride to the classmap section in composer.json;
run composer dump-autoload.
Then almost all scaffolding command works.
DisconnectedMetadataFactory PSR-4 patch
/**
* Get a base path for a class
*
* #param string $name class name
* #param string $namespace class namespace
* #param string $path class path
*
* #return string
* #throws \RuntimeException When base path not found
*/
private function getBasePathForClass($name, $namespace, $path)
{
$composerClassLoader = $this->getComposerClassLoader();
if ($composerClassLoader !== NULL) {
$psr4Paths = $this->findPathsByPsr4Prefix($namespace, $composerClassLoader);
if ($psr4Paths !== array()) {
// We just use the first path for now
return $psr4Paths[0];
}
}
$namespace = str_replace('\\', '/', $namespace);
$search = str_replace('\\', '/', $path);
$destination = str_replace('/'.$namespace, '', $search, $c);
if ($c != 1) {
throw new \RuntimeException(sprintf('Can\'t find base path for "%s" (path: "%s", destination: "%s").', $name, $path, $destination));
}
return $destination;
}
/**
* Gets the composer class loader from the list of registered autoloaders
*
* #return \Composer\Autoload\ClassLoader
*/
private function getComposerClassLoader() {
$activeAutloaders = spl_autoload_functions();
foreach($activeAutloaders as $autoloaderFunction) {
if (!is_array($autoloaderFunction)) {
continue;
}
$classLoader = $autoloaderFunction[0];
if ($classLoader instanceof \Symfony\Component\Debug\DebugClassLoader) {
$classLoader = $classLoader->getClassLoader()[0];
}
if (!is_object($classLoader)) {
continue;
}
if ($classLoader instanceof \Composer\Autoload\ClassLoader) {
return $classLoader;
}
}
return NULL;
}
/**
* Matches the namespace against all registered psr4 prefixes and
* returns their mapped paths if found
*
* #param string $namespace The full namespace to search for
* #param \Composer\Autoload\ClassLoader $composerClassLoader A composer class loader instance to get the list of psr4 preixes from
* #return array The found paths for the namespace or an empty array if none matched
*/
private function findPathsByPsr4Prefix($namespace, $composerClassLoader) {
foreach ($composerClassLoader->getPrefixesPsr4() as $prefix => $paths) {
if (strpos($namespace, $prefix) === 0) {
return $paths;
}
}
return array();
}
If somebody comes across this issue.. I got it finally working. I'm not quite sure what exactly fixed it, so here are all the steps I did:
As I was running Symfony 2.3, first I upgraded to 2.7
I re-generated the bundle from scratch... I changed the location of the bundle to MyProject\CoreBundle and renamed the bundle class to MyProjectCoreBundle.
I can now run all of these commands successfully:
php app/console doctrine:mapping:import --force MyProjectCoreBundle annotation
php app/console doctrine:generate:entities MyProjectCoreBundle
php app/console doctrine:generate:form MyProjectCoreBundle:User
php app/console voryx:generate:rest --entity=MyProjectCoreBundle:User
(Note that the call of doctrine:generate:form was not in the OP.)
My best guess is that one step of the upgrade was to change the composer autoload - this, or the 2.7 autoloader, seems to have fixed it:
"autoload": {
"psr-4": { "": "src/", "SymfonyStandard\\": "app/" }
},
I am having problems getting my sparks install to work with my codeigniter install
here are the steps I took which were as follows:
I went to my root of my codeigniter project folder through my PHPCLI to install sparks using the below command
php -r "$(curl -fsSL http://getsparks.org/go-sparks)"
i installed the active record library using the spark command below
php tools\spark install -v0.0.2 php-activerecord
2a. this command gave me the follwing folder structure
-application
-sparks
-php-activerecord
-0.0.2
-config
-variables
-vendor
-system
-tests
-tools
-lib
-spark
-sparktypes
-test
-user_guide
2b. this command generates a sparks containing php active record folder that makeup the necessary components of php-activerecord, the command using generates a MY_Loader.php file which looks like this
<?php if (! defined('BASEPATH')) exit('No direct script access allowed');
/**
* Sparks
*
* An open source application development framework for PHP 5.1.6 or newer
*
* #package CodeIgniter
* #author CodeIgniter Reactor Dev Team
* #author Kenny Katzgrau <katzgrau#gmail.com>
* #since CodeIgniter Version 1.0
* #filesource
*/
/**
* Loader Class
*
* Loads views and files
*
* #package CodeIgniter
* #subpackage Libraries
* #author CodeIgniter Reactor Dev Team
* #author Kenny Katzgrau <katzgrau#gmail.com>
* #category Loader
* #link http://codeigniter.com/user_guide/libraries/loader.html
*/
class MY_Loader extends CI_Loader
{
/**
* Keep track of which sparks are loaded. This will come in handy for being
* speedy about loading files later.
*
* #var array
*/
var $_ci_loaded_sparks = array();
/**
* Is this version less than CI 2.1.0? If so, accomodate
* #bubbafoley's world-destroying change at: http://bit.ly/sIqR7H
* #var bool
*/
var $_is_lt_210 = false;
/**
* Constructor. Define SPARKPATH if it doesn't exist, initialize parent
*/
function __construct()
{
if(!defined('SPARKPATH'))
{
define('SPARKPATH', 'sparks/');
}
$this->_is_lt_210 = (is_callable(array('CI_Loader', 'ci_autoloader'))
|| is_callable(array('CI_Loader', '_ci_autoloader')));
parent::__construct();
}
/**
* To accomodate CI 2.1.0, we override the initialize() method instead of
* the ci_autoloader() method. Once sparks is integrated into CI, we
* can avoid the awkward version-specific logic.
* #return Loader
*/
function initialize()
{
parent::initialize();
if(!$this->_is_lt_210)
{
$this->ci_autoloader();
}
return $this;
}
/**
* Load a spark by it's path within the sparks directory defined by
* SPARKPATH, such as 'markdown/1.0'
* #param string $spark The spark path withint he sparks directory
* #param <type> $autoload An optional array of items to autoload
* in the format of:
* array (
* 'helper' => array('somehelper')
* )
* #return <type>
*/
function spark($spark, $autoload = array())
{
if(is_array($spark))
{
foreach($spark as $s)
{
$this->spark($s);
}
}
$spark = ltrim($spark, '/');
$spark = rtrim($spark, '/');
$spark_path = SPARKPATH . $spark . '/';
$parts = explode('/', $spark);
$spark_slug = strtolower($parts[0]);
# If we've already loaded this spark, bail
if(array_key_exists($spark_slug, $this->_ci_loaded_sparks))
{
return true;
}
# Check that it exists. CI Doesn't check package existence by itself
if(!file_exists($spark_path))
{
show_error("Cannot find spark path at $spark_path");
}
if(count($parts) == 2)
{
$this->_ci_loaded_sparks[$spark_slug] = $spark;
}
$this->add_package_path($spark_path);
foreach($autoload as $type => $read)
{
if($type == 'library')
$this->library($read);
elseif($type == 'model')
$this->model($read);
elseif($type == 'config')
$this->config($read);
elseif($type == 'helper')
$this->helper($read);
elseif($type == 'view')
$this->view($read);
else
show_error ("Could not autoload object of type '$type' ($read) for spark $spark");
}
// Looks for a spark's specific autoloader
$this->ci_autoloader($spark_path);
return true;
}
/**
* Pre-CI 2.0.3 method for backward compatility.
*
* #param null $basepath
* #return void
*/
function _ci_autoloader($basepath = NULL)
{
$this->ci_autoloader($basepath);
}
/**
* Specific Autoloader (99% ripped from the parent)
*
* The config/autoload.php file contains an array that permits sub-systems,
* libraries, and helpers to be loaded automatically.
*
* #param array|null $basepath
* #return void
*/
function ci_autoloader($basepath = NULL)
{
if($basepath !== NULL)
{
$autoload_path = $basepath.'config/autoload'.EXT;
}
else
{
$autoload_path = APPPATH.'config/autoload'.EXT;
}
if(! file_exists($autoload_path))
{
return FALSE;
}
include($autoload_path);
if ( ! isset($autoload))
{
return FALSE;
}
if($this->_is_lt_210 || $basepath !== NULL)
{
// Autoload packages
if (isset($autoload['packages']))
{
foreach ($autoload['packages'] as $package_path)
{
$this->add_package_path($package_path);
}
}
}
// Autoload sparks
if (isset($autoload['sparks']))
{
foreach ($autoload['sparks'] as $spark)
{
$this->spark($spark);
}
}
if($this->_is_lt_210 || $basepath !== NULL)
{
if (isset($autoload['config']))
{
// Load any custom config file
if (count($autoload['config']) > 0)
{
$CI =& get_instance();
foreach ($autoload['config'] as $key => $val)
{
$CI->config->load($val);
}
}
}
// Autoload helpers and languages
foreach (array('helper', 'language') as $type)
{
if (isset($autoload[$type]) AND count($autoload[$type]) > 0)
{
$this->$type($autoload[$type]);
}
}
// A little tweak to remain backward compatible
// The $autoload['core'] item was deprecated
if ( ! isset($autoload['libraries']) AND isset($autoload['core']))
{
$autoload['libraries'] = $autoload['core'];
}
// Load libraries
if (isset($autoload['libraries']) AND count($autoload['libraries']) > 0)
{
// Load the database driver.
if (in_array('database', $autoload['libraries']))
{
$this->database();
$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));
}
// Load all other libraries
foreach ($autoload['libraries'] as $item)
{
$this->library($item);
}
}
// Autoload models
if (isset($autoload['model']))
{
$this->model($autoload['model']);
}
}
}
}
i modify my autoload.php to include php active record as below
$autoload['sparks'] = array('php-activerecord/0.0.2');
when i run my codeigniter site i get the following error
A PHP Error was encountered
Severity: Notice
Message: Use of undefined constant EXT - assumed 'EXT'
Filename: core/MY_Loader.php
Line Number: 174
Backtrace:
File: C:\xampp\htdocs\orm\application\core\MY_Loader.php
Line: 174
Function: _exception_handler
File: C:\xampp\htdocs\orm\application\core\MY_Loader.php
Line: 154
Function: ci_autoloader
File: C:\xampp\htdocs\orm\application\core\MY_Loader.php
Line: 67
Function: initialize
File: C:\xampp\htdocs\orm\index.php
Line: 274
Function: require_once
I am curious as to what could be causing this error? Please let me know if there is any other configuration that I am missing or if theres a mistake that I have made.
The EXT is defined in your root index.php file.
// The PHP file extension
// this global constant is deprecated.
define('EXT', '.php');
See if it's still there or not?
IN case that constant is not there, you can also define the autoload.php without using the constant.
I know this is an old post but hopefully this will save someone some time... I had the same issue and the above fix did not work. I finally fixed the issue in the htaccess file by removing the RewriteBase although I am not sure why this caused the issue in the first place.
just commented out the line as follows:
RewriteBase /
to
#RewriteBase /
Problem: rendering barcodes in CodeIgniter via Zend library barcode.
I googled, and also tried all tutorials on first 2 pages. I stackoverflowed and found quiet a few topics on my problem, even few are marked as answered but no luck.
Finally I tried this https://stackoverflow.com/a/15480779/1564365 but yet another error message.
error:
Fatal error: Class 'Zend\Barcode\ObjectPluginManager' not found
that means it is actually loading Barcode library but with error.
sidenote: ZF 2.2 fresh download (today), CI 2.1.3 fresh download (today)
To solve this, I am forced to use ZF1.
step by step:
Download (Zend Framework 1.12.3 Full) from here
Unzip files and locate folder Zend in ./libraries folder copy it to CI application/libraries
Create new file inside (CI) application/libraries/Zend.php "loader for ZF"
with code as follows
<?php if (!defined('BASEPATH')) {exit('No direct script access allowed');}
/**
* Zend Framework Loader
*
* Put the 'Zend' folder (unpacked from the Zend Framework package, under 'Library')
* in CI installation's 'application/libraries' folder
* You can put it elsewhere but remember to alter the script accordingly
*
* Usage:
* 1) $this->load->library('zend', 'Zend/Package/Name');
* or
* 2) $this->load->library('zend');
* then $this->zend->load('Zend/Package/Name');
*
* * the second usage is useful for autoloading the Zend Framework library
* * Zend/Package/Name does not need the '.php' at the end
*/
class CI_Zend
{
/**
* Constructor
*
* #param string $class class name
*/
function __construct($class = NULL)
{
// include path for Zend Framework
// alter it accordingly if you have put the 'Zend' folder elsewhere
ini_set('include_path',
ini_get('include_path') . PATH_SEPARATOR . APPPATH . 'libraries');
if ($class)
{
require_once (string) $class . EXT;
log_message('debug', "Zend Class $class Loaded");
}
else
{
log_message('debug', "Zend Class Initialized");
}
}
/**
* Zend Class Loader
*
* #param string $class class name
*/
function load($class)
{
require_once (string) $class . EXT;
log_message('debug', "Zend Class $class Loaded");
}
}
and controllers method should be as follows
function barcode() {
$this->load->library('zend');
$this->zend->load('Zend/Barcode');
$test = Zend_Barcode::draw('ean8', 'image', array('text' => '1234565'), array());
var_dump($test);
imagejpeg($test, 'barcode.jpg', 100);
}
I would like to use YUI compressor with minify PHP rather than the default JSmin. Does anyone have experience setting this up?
Right now I am using the groupsConfig.php to combine the JS.
return array(
'jsAll' => array('//contenido/themes/bam/assets/js/jquery.js', '//contenido/themes/bam/assets/js/modernizr.js','//contenido/themes/bam/assets/js/imgpreload.js', '//contenido/themes/bam/assets/js/imgpreload.js', '//contenido/themes/bam/assets/js/history.js','//contenido/themes/bam/assets/js/ajaxify.js', '//contenido/themes/bam/assets/js/isotope.js'),
'jsHome' => array('//contenido/themes/bam/assets/js/easing.js','//contenido/themes/bam/assets/js/scrollable.js', '//contenido/themes/bam/assets/js/home.js'),
'cssAll' => array('//contenido/themes/bam/bam.css'),
);
As it says on the homepage:
Uses an enhanced port of Douglas Crockford's JSMin library and custom classes to minify CSS and HTML
I have the following code in config.php, but I get a 500 error when trying to view the combined js file:
function yuiJs($js) {
require_once '/lib/Minify/YUICompressor.php';
Minify_YUICompressor::$jarFile = '/lib/yuicompressor-2.4.2.jar';
Minify_YUICompressor::$tempDir = '/temp';
return Minify_YUICompressor::minifyJs($js);
}
$min_serveOptions['minifiers']['application/x-javascript'] = 'yuiJs';
It also appears that there are several lines in lib/Minify/YUICompressor.php that need to be configured, and I'm not sure if I'm doing it right:
class Minify_YUICompressor {
/**
* Filepath of the YUI Compressor jar file. This must be set before
* calling minifyJs() or minifyCss().
*
* #var string
*/
public static $jarFile = '../yuicompressor-2.4.2.jar';
/**
* Writable temp directory. This must be set before calling minifyJs()
* or minifyCss().
*
* #var string
*/
public static $tempDir = '../../temp/';
/**
* Filepath of "java" executable (may be needed if not in shell's PATH)
*
* #var string
*/
public static $javaExecutable = 'java';
I had the same problem on windows. It seems jar file needs to be executable in order to run yui compressor. So, i have to remove excutable check from YUICompressor.php
#132
private static function _prepare()
{
if (! is_file(self::$jarFile)) {
throw new Exception('Minify_YUICompressor : $jarFile('.self::$jarFile.') is not a valid file.');
}
// if (! is_executable(self::$jarFile)) {
// throw new Exception('Minify_YUICompressor : $jarFile('.self::$jarFile.') is not executable.');
// }
if (! is_dir(self::$tempDir)) {
throw new Exception('Minify_YUICompressor : $tempDir('.self::$tempDir.') is not a valid direcotry.');
}
if (! is_writable(self::$tempDir)) {
throw new Exception('Minify_YUICompressor : $tempDir('.self::$tempDir.') is not writable.');
}
}
and that works fine.