GithubHelp home page GithubHelp logo

brianhenryie / strauss Goto Github PK

View Code? Open in Web Editor NEW

This project forked from coenjacobs/mozart

128.0 4.0 21.0 3.18 MB

Prefix PHP namespaces and classnames to allow multiple versions of libraries to exist without conflict.

Home Page: https://brianhenryie.github.io/strauss/

License: MIT License

PHP 99.97% Shell 0.03%
composer namespaces

strauss's Introduction

PHPUnit PHPStan

Strauss – PHP Namespace Renamer

A tool to prefix namespaces and classnames in PHP files to avoid autoloading collisions.

A fork of Mozart. For Composer for PHP.

The primary use case is WordPress plugins, where different plugins active in a single WordPress install could each include different versions of the same library. The version of the class loaded would be whichever plugin registered the autoloader first, and all subsequent instantiations of the class will use that version, with potentially unpredictable behaviour and missing functionality.

⚠️ Sponsorship: I don't want your money. Please write a unit test to help the project.

Breaking Changes

  • v0.16.0 – will no longer prefix PHP built-in classes seen in polyfill packages
  • v0.14.0 – psr/* packages no longer excluded by default
  • v0.12.0 – default output target_directory changes from strauss to vendor-prefixed

Please open issues to suggest possible breaking changes. I think we can probably move to 1.0.0 soon.

Use

Require as normal with Composer:

composer require --dev brianhenryie/strauss

and use vendor/bin/strauss to execute.

Or, download strauss.phar from releases,

curl -o strauss.phar -L -C - https://github.com/BrianHenryIE/strauss/releases/latest/download/strauss.phar

Then run it from the root of your project folder using php strauss.phar.

To update the files that call the prefixed classes, you can use --updateCallSites=true which uses your autoload key, or --updateCallSites=includes,templates to explicitly specify the files and directories.

Its use should be automated in Composer scripts.

"scripts": {
    "prefix-namespaces": [
        "strauss"
    ],
    "post-install-cmd": [
        "@prefix-namespaces"
    ],
    "post-update-cmd": [
        "@prefix-namespaces"
    ]
}

or

"scripts": {
    "prefix-namespaces": [
        "@php strauss.phar"
    ]
}

‼️ Add composer dump-autoload to your scripts/strauss if you set target_directory to vendor or delete_vendor_packages/delete_vendor_files to true, i.e. if you are using require __DIR__ . '/vendor/autoload.php' and Strauss modifies the files inside vendor, you must tell Composer to rebuild its autoload index.

Configuration

Strauss potentially requires zero configuration, but likely you'll want to customize a little, by adding in your composer.json an extra/strauss object. The following is the default config, where the namespace_prefix and classmap_prefix are determined from your composer.json's autoload or name key and packages is determined from the require key:

"extra": {
    "strauss": {
        "target_directory": "vendor-prefixed",
        "namespace_prefix": "BrianHenryIE\\My_Project\\",
        "classmap_prefix": "BrianHenryIE_My_Project_",
        "constant_prefix": "BHMP_",
        "packages": [
        ],
        "update_call_sites": false,
        "override_autoload": {
        },
        "exclude_from_copy": {
            "packages": [
            ],
            "namespaces": [
            ],
            "file_patterns": [
            ]
        },
        "exclude_from_prefix": {
            "packages": [
            ],
            "namespaces": [
            ],
            "file_patterns": [
            ]
        },
        "namespace_replacement_patterns" : {
        },
        "delete_vendor_packages": false,
        "delete_vendor_files": false
    }
},

The following configuration is inferred:

  • target_directory defines the directory the files will be copied to, default vendor-prefixed
  • namespace_prefix defines the default string to prefix each namespace with
  • classmap_prefix defines the default string to prefix class names in the global namespace
  • packages is the list of packages to process. If absent, all packages in the require key of your composer.json are included
  • classmap_output is a bool to decide if Strauss will create autoload-classmap.php and autoload.php. If it is not set, it is false if target_directory is in your project's autoload key, true otherwise.

The following configuration is default:

  • delete_vendor_packages: false a boolean flag to indicate if the packages' vendor directories should be deleted after being processed. It defaults to false, so any destructive change is opt-in.

  • delete_vendor_files: false a boolean flag to indicate if files copied from the packages' vendor directories should be deleted after being processed. It defaults to false, so any destructive change is opt-in. This is maybe deprecated! Is there any use to this that is more appropriate than delete_vendor_packages?

  • include_modified_date is a bool to decide if Strauss should include a date in the (phpdoc) header written to modified files. Defaults to true.

  • include_author is a bool to decide if Strauss should include the author name in the (phpdoc) header written to modified files. Defaults to true.

  • update_call_sites: false. This can be true, false or an array of directories/filepaths. When set to true it defaults to the directories and files in the project's autoload key. The PHP files and directories' PHP files will be updated where they call the prefixed classes.

The remainder is empty:

  • constant_prefix is for define( "A_CONSTANT", value ); -> define( "MY_PREFIX_A_CONSTANT", value );. If it is empty, constants are not prefixed (this may change to an inferred value).
  • override_autoload a dictionary, keyed with the package names, of autoload settings to replace those in the original packages' composer.json autoload property.
  • exclude_from_prefix / file_patterns
  • exclude_from_copy
    • packages array of package names to be skipped
    • namespaces array of namespaces to skip (exact match from the package autoload keys)
    • file_patterns array of regex patterns to check filenames against (including vendor relative path) where Strauss will skip that file if there is a match
  • exclude_from_prefix
    • packages array of package names to exclude from prefixing.
    • namespaces array of exact match namespaces to exclude (i.e. not substring/parent namespaces)
  • namespace_replacement_patterns a dictionary to use in preg_replace instead of prefixing with namespace_prefix.

Autoloading

Strauss uses Composer's own tools to generate a classmap file in the target_directory and creates an autoload.php alongside it, so in many projects autoloading is just a matter of:

require_once __DIR__ . '/strauss/autoload.php';

If you prefer to use Composer's autoloader, add your target_directory (default vendor-prefixed) to your autoload classmap and Strauss will not create its own autoload.php when run. Then run composer dump-autoload to include the newly copied and prefixed files in Composer's own classmap.

"autoload": {
    "classmap": [
        "vendor-prefixed/"
    ]
},

Motivation & Comparison to Mozart

I was happy to make PRs to Mozart to fix bugs, but they weren't being reviewed and merged. At the time of writing, somewhere approaching 50% of Mozart's code was written by me with an additional nine open PRs and the majority of issues' solutions provided by me. This fork is a means to merge all outstanding bugfixes I've written and make some more drastic changes I see as a better approach to the problem.

Benefits over Mozart:

  • A single output directory whose structure matches source vendor directory structure (conceptually easier than Mozart's independent classmap_directory and dep_directory)
  • A generated autoload.php to include in your project (analogous to Composer's vendor/autoload.php)
  • Handles files autoloaders – and any autoloaders that Composer itself recognises, since Strauss uses Composer's own tooling to parse the packages
  • Zero configuration – Strauss infers sensible defaults from your composer.json
  • No destructive defaults – delete_vendor_files defaults to false, so any destruction is explicitly opt-in
  • Licence files are included and PHP file headers are edited to adhere to licence requirements around modifications. My understanding is that re-distributing code that Mozart has handled is non-compliant with most open source licences – illegal!
  • Extensively tested – PhpUnit tests have been written to validate that many of Mozart's bugs are not present in Strauss
  • More configuration options – allowing exclusions in copying and editing files, and allowing specific/multiple namespace renaming
  • Respects composer.json vendor-dir configuration
  • Prefixes constants (define)
  • Handles meta-packages and virtual-packages

Strauss will read the Mozart configuration from your composer.json to enable a seamless migration.

Alternatives

I don't have a strong opinion on these. I began using Mozart because it was easy, then I adapted it to what I felt was most natural. I've never used these.

Interesting

Changes before v1.0

  • Comprehensive attribution of code forked from Mozart – changes have been drastic and git blame is now useless, so I intend to add more attributions
  • More consistent naming. Are we prefixing or are we renaming?
  • Further unit tests, particularly file-system related
  • Regex patterns in config need to be validated
  • Change the name? "Renamespacer"?

Changes before v2.0

The correct approach to this problem is probably via PHP-Parser. At least all the tests will be useful.

Acknowledgements

Coen Jacobs and all the contributors to Mozart, particularly those who wrote nice issues.

strauss's People

Contributors

arjen-mediasoep avatar brianhenryie avatar coenjacobs avatar dartui avatar doekenorg avatar flickwire avatar kmgalanakis avatar konamiman avatar markjaquith avatar mikeill avatar nlemoine avatar schlessera avatar sovetski avatar spreeuw avatar stephenharris avatar szaleq avatar szepeviktor avatar timothybjacobs avatar uvlabs avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

strauss's Issues

Double namespacing issue when using nested namespace prefix

Hi @BrianHenryIE. I'm having issues with Strauss adding the namespace prefix twice on my files. There doesn't appear to be any way to fix it. I've removed the custom prefix and let it use the default, and that default doesn't get added twice.

See: https://www.loom.com/share/dd52ab3e791840bdbf25bd45fcdeecf3

Here's a couple samples from the autoloader.

'Dragon\Dependencies\Dragon\Dependencies\Ramsey\Uuid\FeatureSet' => $strauss . '/ramsey/uuid/src/FeatureSet.php',
'Dragon\Dependencies\Dragon\Dependencies\Doctrine\Common\EventArgs' => $strauss . '/doctrine/event-manager/lib/Doctrine/Common/EventArgs.php',

Here's the relevant chunk from my composer.json file.

"extra": {
	    "strauss": {
			"target_directory": "strauss",
	        "namespace_prefix": "Dragon\\Dependencies\\",
	        "classmap_prefix": "DRAGON_",
	        "constant_prefix": "DRAGON_CONST_",
	        "packages": [
				"guzzlehttp/guzzle",
				"dragon-public/framework"
	        ],
	        "override_autoload": {
	        },
	        "exclude_from_copy": {
	            "packages": [
	            ],
	            "namespaces": [
	            ],
	            "file_patterns": [
	            ]
	        },
	        "exclude_from_prefix": {
	            "packages": [
	            ],
	            "namespaces": [
	            ],
	            "file_patterns": [
	                "/^psr.*$/"
	            ]
	        },
	        "namespace_replacement_patterns" : {
	        },
	        "delete_vendor_files": false
	    }
    }

Update:
It seems to only happen with nested namespace prefixes. Here's a sample after changing it to a single namespace. I'll use that, but it might be worth documenting/fixing.

'DragonDependencies\Ramsey\Uuid\FeatureSet' => $strauss . '/ramsey/uuid/src/FeatureSet.php',
'DragonDependencies\Doctrine\Common\EventArgs' => $strauss . '/doctrine/event-manager/lib/Doctrine/Common/EventArgs.php',

Infinite loop

I am receiving an infinite loop with the recursiveGetAllDependencies() function when using the PHAR as reported by Xdebug. Attached is my composer.json.

It appears to be around the league/flysystem package. Multiple lines like so:

   45.3508   30967016  30. BrianHenryIE\Strauss\Console\Commands\Compose->recursiveGetAllDependencies($requiredPackageNames = [1 => 'league/flysystem-local', 2 => 'league/mime-type-detection']) phar:///Users/jonerickson/PhpstormProjects/wordpress-community-hive/strauss.phar/src/Console/Commands/Compose.php:173
   45.4071   25482912  31. BrianHenryIE\Strauss\Console\Commands\Compose->recursiveGetAllDependencies($requiredPackageNames = [2 => 'league/flysystem', 3 => 'league/mime-type-detection']) phar:///Users/jonerickson/PhpstormProjects/wordpress-community-hive/strauss.phar/src/Console/Commands/Compose.php:173
   45.4556   27192200  32. BrianHenryIE\Strauss\Console\Commands\Compose->recursiveGetAllDependencies($requiredPackageNames = [1 => 'league/flysystem-local', 2 => 'league/mime-type-detection']) phar:///Users/jonerickson/PhpstormProjects/wordpress-community-hive/strauss.phar/src/Console/Commands/Compose.php:173
   45.4996   28892624  33. BrianHenryIE\Strauss\Console\Commands\Compose->recursiveGetAllDependencies($requiredPackageNames = [2 => 'league/flysystem', 3 => 'league/mime-type-detection']) phar:///Users/jonerickson/PhpstormProjects/wordpress-community-hive/strauss.phar/src/Console/Commands/Compose.php:173
   45.5499   30601912  34. BrianHenryIE\Strauss\Console\Commands\Compose->recursiveGetAllDependencies($requiredPackageNames = [1 => 'league/flysystem-local', 2 => 'league/mime-type-detection']) phar:///Users/jonerickson/PhpstormProjects/wordpress-community-hive/strauss.phar/src/Console/Commands/Compose.php:173
   45.6173   25444520  35. BrianHenryIE\Strauss\Console\Commands\Compose->recursiveGetAllDependencies($requiredPackageNames = [2 => 'league/flysystem', 3 => 'league/mime-type-detection']) phar:///Users/jonerickson/PhpstormProjects/wordpress-community-hive/strauss.phar/src/Console/Commands/Compose.php:173
   45.6785   27153808  36. BrianHenryIE\Strauss\Console\Commands\Compose->recursiveGetAllDependencies($requiredPackageNames = [1 => 'league/flysystem-local', 2 => 'league/mime-type-detection']) phar:///Users/jonerickson/PhpstormProjects/wordpress-community-hive/strauss.phar/src/Console/Commands/Compose.php:173

Any help on how to diagnose would be great.

{
    "require": {
        "php": "^8.1",
        "roots/acorn": "^3.2",
        "guzzlehttp/guzzle": "^7.0",
        "web-token/jwt-framework": "^3.2"
    },
    "require-dev": {
        "spatie/laravel-ignition": "^1.6",
        "laravel/pint": "^v1.10.5",
        "fzaninotto/faker": "^1.5"
    },
    "autoload": {
        "psr-4": {
            "CommunityHive\\App\\": "src/app",
            "CommunityHive\\Database\\Factories\\": "src/database/factories/",
            "CommunityHive\\Database\\Seeders\\": "src/database/seeders/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "Tests\\": "src/tests/"
        }
    },
    "post-autoload-dump": [
        "Roots\\Acorn\\ComposerScripts::postAutoloadDump"
    ]
}

Namespaces of static methods not replaced inside array square brackets

Hi again,

I got another case in which the namespace replacements are currently not working yet: Inside array square brackets. Right now I avoid this issue by declaring a variable, but of course the better solution would be having this fixed.

The namespace replacement works for non-static methods, but not for static methods.

StraussTestPackage.php:

<?php
namespace ST;
class StraussTestPackage {
	public function __construct() {
		$arr = array();

		$arr[ ( new \ST\StraussTestPackage2() )->test() ] = true;

		$arr[ \ST\StraussTestPackage2::test2() ] = true;
	}
}

Result of StraussTestPackage.php

<?php
/**
 * @license proprietary
 *
 * Modified using Strauss.
 * @see https://github.com/BrianHenryIE/strauss
 */
namespace Prefix\ST;
class StraussTestPackage {
	public function __construct() {
		$arr = array();

		$arr[ ( new \Prefix\ST\StraussTestPackage2() )->test() ] = true;

		$arr[ \ST\StraussTestPackage2::test2() ] = true;
	}
}

StraussTestPackage2.php:

<?php
namespace ST;
class StraussTestPackage2 {
	public function __construct() {
	}
	public function test() {
		return 'Test';
	}
	public static function test2() {
		return 'Test';
	}
}

Backtrack limit exhausted

MPDF is a 27000 line file. Replacing classes in it is failing.

Error: Backtrack limit was exhausted!

{
  "name": "brianhenryie/strauss-backtrack-limit-exhausted",
  "minimum-stability": "dev",
  "require": {
    "afragen/wp-dependency-installer": "^3.1",
    "mpdf/mpdf": "*"
  },
  "require-dev": {
    "brianhenryie/strauss": "dev-master"
  },
  "extra": {
    "strauss": {
      "namespace_prefix": "BrianHenryIE\\Strauss_Backtrack_Limit_Exhausted\\",
      "target_directory": "/strauss/",
      "classmap_prefix": "BH_Strauss_Backtrack_Limit_Exhausted_"
    }
  }
}

Request: prefix global functions.

The strauss package is working perfectly for prefixing classes and constants. So far it helps us avoiding dependency hell within our custom WordPress plugin and we prevented a lot of compatibility issues with other plugins.

But I'm running into an issue. The illuminate\collections is being used and this package loads global functions in the helpers.php. Which is checking if a function exist like in this example:

if (! function_exists('collect')) {
    /**
     * Create a collection from the given value.
     *
     * @param  mixed  $value
     * @return \Custom\Prefix\Illuminate\Support\Collection
     */
    function collect($value = null)
    {
        return new Collection($value);
    }
} 

But when a different plugin is using the same package and this plugin is loaded first; we end up in the global function of that plugin. Which is not using my custom prefixed package and which is not using the same version as we do in our plugin.

This is resulting in this error:

#0 /home/user/public_html/wp-content/plugins/reviewx/vendor/jouleslabs/warehouse/src/Supports/common.php(58): explode()
#1 /home/user/public_html/wp-content/plugins/reviewx/vendor/jouleslabs/warehouse/src/Supports/common.php(50): array_get()
#2 /home/user/public_html/wp-content/plugins/our-custom-plugin/vendor/illuminate/collections/Arr.php(459): data_get()
#3 /home/user/public_html/wp-content/plugins/our-custom-plugin/vendor/illuminate/collections/Collection.php(688): Custom\Prefix\Illuminate\Support\Arr::pluck()

This is my composer.json:

{
    "name": "custom/plugin",
    "license": "GPL-2.0-or-later",
    "description": "WordPress plugin developed by Tussendoor.",
    "type": "wordpress-plugin",
    "require": {
        "php": "^8.0",
        "nesbot/carbon": "^2.66.0",
        "illuminate/database": "^8.0.0",
        "twbs/bootstrap": "^5.2.3",
        "fortawesome/font-awesome": "^6.4.0",
        "adbario/php-dot-notation": "^3.3.0",
        "woocommerce/action-scheduler": "^3.4.0",
        "yahnis-elsts/plugin-update-checker": "^4.13"
    },
    "autoload": {
        "psr-4": {
            "Custom\\Namespace\\": "app/"
        },
        "files": [
            "vendor/woocommerce/action-scheduler/action-scheduler.php"
        ],
        "classmap": [
            "vendor"
        ]
    },
    "config": {
        "optimize-autoloader": true,
        "sort-packages": true,
        "platform": {
            "php": "8.0.3"
        }
    },
    "scripts": {
        "pre-update-cmd": [
            "sh strauss-observer.sh"
        ],
        "post-install-cmd": [
            "sh strauss-prefixer.sh"
        ],
        "post-update-cmd": [
            "sh strauss-prefixer.sh"
        ]
    },
    "extra": {
        "strauss": {
            "target_directory": "vendor",
            "namespace_prefix": "Custom\\Prefix\\",
            "constant_prefix": "TSD_CUSTOM_PREFIX_",
            "include_modified_date": false,
            "include_author": false,
            "delete_vendor_packages": true,
            "exclude_from_prefix": {
                "packages": [
                    "yahnis-elsts/plugin-update-checker",
                    "woocommerce/action-scheduler"
                ]
            },
            "override_autoload": {
                "nesbot/carbon": {
                    "autoload": {
                        "psr-4": {
                            "Carbon\\": "src/Carbon/"
                        }
                    },
                    "classmap": [
                        "lazy"
                    ]
                }
            }
        }
    }
}

I'm using the strauss.phar at the moment. Is there a way to support prefixing global functions?

Add an option to copy non-php files (/folders)

When utilizing libraries that contain files like fonts (tecnickcom/tcpdf) or other non-php assets (composer/ca-bundle is a library built around a cacert.pem file), these assets are not copied over by Strauss. We currently resolve this with a bash script that runs after Strauss, but it would be nice to be able to tell Strauss which folders to copy over, or even to let it copy all the files/folders for a specific library?

Mismatch between extended class name and the actual class name

Hi @BrianHenryIE

We are facing an issue using your library with the symfony/polyfill-intl-normalizer, as the /Resources/stubs/Normalizer.php extended class shows like this:

class Normalizer_Test_Normalizer extends Normalizer_Test\Symfony\Polyfill\Intl\Normalizer_Test_Normalizer\Normalizer
{

when the actual Normalizer.php class name in the library root dir is:

namespace Normalizer_Test\Symfony\Polyfill\Intl\Normalizer_Test_Normalizer;

class Normalizer_Test_Normalizer
{

The error:

Uncaught Error: Class 'Normalizer_Test\Symfony\Polyfill\Intl\Normalizer_Test_Normalizer\Normalizer' not found in /lib/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php:9

You can easily test this using your phar.php and this JSON in a test directory:

{
    "require": {
        "symfony/polyfill-intl-normalizer": "^1.23"
    },
    "extra": {
        "strauss": {
            "target_directory": "lib",
            "namespace_prefix": "Normalizer_Test\\",
            "classmap_prefix": "Normalizer_Test_",
            "packages": [],
            "override_autoload": {
            },
            "exclude_from_copy": {
                "packages": [
                ],
                "namespaces": [
                ],
                "patterns": [
                ]
            },
            "exclude_from_prefix": {
                "packages": [
                ],
                "namespaces": [
                ],
                "patterns": [
                    "/^psr.*$/"
                ]
            },
            "namespace_replacement_patterns" : {
            },
            "delete_vendor_files": false
        }
    },
    "scripts": {
        "strauss": [
            "@php strauss.phar"
        ],
        "post-install-cmd": [
            "@strauss"
        ],
        "post-update-cmd": [
            "@strauss"
        ]
    }
}

Still works?

I'm running the library and it's only pulling and namespacing the dealerdirect/phpcodesniffer-composer-installer dependency which is actually a dev dependency..

Its totally ignoring a dependency not hosted on packagist and also one hosted there so it seems to just not be pulling my changes?

I also manually tried adding the packages to the "packages" array in the composer extra but it didn't have any effect.

My composer file:

{   
    "repositories": [
        {
            "type": "git",
            "url": "https://github.com/iconicwp/WordPress-Settings-Framework.git"
        }
    ],
    "scripts": {
        "prefix":  "vendor/bin/strauss"
    },
    "require-dev": {
        "dealerdirect/phpcodesniffer-composer-installer": "0.7.1",
        "wp-coding-standards/wpcs": "2.3",
        "suin/phpcs-psr4-sniff": "^3.0",
        "brianhenryie/strauss": "^0.13.0"
    },
    "autoload":{
        "psr-4": {
            "Namespace\\Subnamespace\\" : "includes/"
        },
        "classmap":[
            "vendor/iconicwp/wordpress-settings-framework/wp-settings-framework.php"
        ]
    },
    "require": {
        "iconicwp/wordpress-settings-framework": "dev-master",
        "freemius/wordpress-sdk": "^2.5"
    },
    "extra": {
        "strauss": {
            "target_directory": "vendor-prefixed",
            "packages": [
                "iconicwp/wordpress-settings-framework",
                "freemius/wordpress-sdk"
            ],
            "override_autoload": {
            },
            "exclude_from_copy": {
                "packages": [
                ],
                "namespaces": [
                ],
                "file_patterns": [
                ]
            },
            "exclude_from_prefix": {
                "packages": [
                ],
                "namespaces": [
                ],
                "file_patterns": [
                    "/^psr.*$/"
                ]
            },
            "namespace_replacement_patterns" : {
            },
            "delete_vendor_files": false
        }
    },
    "config": {
        "allow-plugins": {
            "dealerdirect/phpcodesniffer-composer-installer": true
        }
    }
    
}

When I run strauss this the vendor-prefixed library:

image

Troubles namespacing nesbot/carbon

When running the strauss.phar command after composer install all my dependencies get prefixed correctly except nesbot/carbon.

In short:
All classes in the vendor/nesbot/carbon/src directory get prefixed correctly. But the classes in the root vendor/nesbot/carbon directory doesnt and the classes inside vendor/nesbot/carbon/lazy does not get prefixed either.

My composer.json:

{
    "name": "custom/plugin",
    "license": "GPL-2.0-or-later",
    "description": "WordPress plugin developed by Tussendoor.",
    "type": "wordpress-plugin",
    "require": {
        "php": "^8.0",
        "nesbot/carbon": "^2.66.0",
        "illuminate/database": "^8.0.0",
        "twbs/bootstrap": "^5.2.3",
        "fortawesome/font-awesome": "^6.4.0",
        "adbario/php-dot-notation": "^3.3.0",
        "woocommerce/action-scheduler": "^3.4.0",
        "yahnis-elsts/plugin-update-checker": "^4.13"
    },
    "autoload": {
        "psr-4": {
            "Custom\\Namespace\\": "app/"
        },
        "files": [
            "vendor/woocommerce/action-scheduler/action-scheduler.php"
        ],
        "classmap": [
            "vendor"
        ]
    },
    "config": {
        "optimize-autoloader": true,
        "sort-packages": true,
        "platform": {
            "php": "8.0.3"
        }
    },
    "scripts": {
        "post-install-cmd": [
            "sh prefixer.sh"
        ],
        "post-update-cmd": [
            "sh prefixer.sh"
        ]
    },
    "extra": {
        "strauss": {
            "target_directory": "vendor",
            "namespace_prefix": "Custom\\Namespace\\Vendor\\",
            "constant_prefix": "TSD_CUSTOM_VENDOR_",
            "include_modified_date": false,
            "include_author": false,
            "delete_vendor_packages": true,
            "exclude_from_prefix": {
                "packages": [
                    "yahnis-elsts/plugin-update-checker",
                    "woocommerce/action-scheduler"
                ]
            }
        }
    }
}

As you can see I am running a custom shell script after the regular composer commands like install and update. The shell script is looking like this:

#!/bin/bash

printf "\n"
printf "Composer action is completed! Wait for the new actions. \n"
printf "\n"
printf "Starting Strauss to prefix all dependencies \n"

php strauss.phar

printf "\n"
printf "Strauss action is completed! \n"
printf "Dumping the composer autoload to prevent errors. \n"

composer dump-autoload

printf "\n"
printf "Autoload has been dumped. \n"
printf "Cleaning the empty folders in the vendor directory. \n"

find vendor -type d -empty -delete

printf "\n"
printf "All done! \n"

So everything works fine after running the script. The plugin gets loaded correctly and thus I thought everything worked fine :) Except I encountered the following error on a specifc page where I use the Carbon class. This fatal error is showing:

Fatal error:
Uncaught Error: Class "Carbon\AbstractTranslator" not found in /vendor/nesbot/carbon/lazy/Carbon/TranslatorStrongType.php:17

Upon investigation I found that not all classes from vendor/nesbot/carbon are getting prefixed. All classes in the vendor/nesbot/carbon/src directory get prefixed correctly. But the classes in the root vendor/nesbot/carbon directory doesnt and the classes inside vendor/nesbot/carbon/lazy does not get prefixed either. The error is originated from the lazy directory.

Its not a very big directory so I tried prefixing them manually and running composer dump-autoload afterwards. This fixes the issue.

I am wondering if this is a bug or due to misconfiguration on my end.

Thanks again for this project!

Add warning about using composer packages installed with symlink

Quite a few operations will change or delete files. When packages are installed by symlink these operations will break other projects also using the packages.

It would be great to have a warning before any dangerous operations are performed, and a warning in the docs.

delete_vendor_packages deletes needed composer files

First of all; thank you for this package. It works wonderfull.

Although I'm running into an issue when using delete_vendor_packages in the config. The reason I want to use this is to cleanup my vendor directory so only specific dependencies stay there and only those will be autoloaded using composer. That is because I use the composer autoloader for some packages that are not using namespaces and I also use the composer autoloader to load my custom plugin classes.

That means I include both of the autoloaders in my plugin like so:

/**
 * Autoload non prefixed- and plugin classes using Composer.
 * @see https://getcomposer.org/doc/01-basic-usage.md#autoloading
 */
require_once __DIR__ . '/vendor/autoload.php';

/** 
 * Autoload prefixed classes using Strauss.
 * @see https://github.com/BrianHenryIE/strauss
 */ 
require_once __DIR__ . '/vendor/prefixed/autoload.php';

This is my config in the composer.json:

"scripts": {
    "post-install-cmd": [
        "sh prefixer.sh"
    ],
    "post-update-cmd": [
        "sh prefixer.sh"
    ]
},
"extra": {
    "strauss": {
        "target_directory": "vendor/prefixed",
        "namespace_prefix": "Tussendoor\\Bol\\Vendor\\",
        "constant_prefix": "TSD_BOL_VENDOR_",
        "include_modified_date": false,
        "include_author": false,
        "delete_vendor_packages": true,
        "exclude_from_copy": {
            "packages": [
                "yahnis-elsts/plugin-update-checker",
                "woocommerce/action-scheduler"
            ]
        }
    }
}

As you can see I am running a custom shell script after the regular composer commands like install and update. The shell script is looking like this:

#!/bin/bash

printf "\n"
printf "Composer action is completed! Wait for the new actions. \n"
printf "\n"
printf "Starting Strauss to prefix all dependencies \n"

vendor/bin/strauss

printf "\n"
printf "Strauss action is completed! \n"
printf "Dumping the composer autoload to prevent errors. \n"

composer dump-autoload

printf "\n"
printf "Autoload has been dumped. \n"
printf "Cleaning the empty folders in the vendor directory. \n"

find vendor -type d -empty -delete

printf "\n"
printf "All done! \n"

So after running vendor/bin/strauss my vendor directory is looking like this. (leaving some stuff out for simplicity):

- vendor
    - bin
        - composer
        - strauss
    - composer
        - (no directories only files like autoload.php)
    - excluded-package 
    - moved-package-directories-that-are-now-empty
    - prefixed
        - (all packages except excluded) 
        - composer
            - src
                - Composer
                - (some folders and some files)

All good until now. But the next step is to dump the composer autoload by composer dump-autoload and this is where I run into the following errors:

PHP Warning:  include(/vendor/bin/../composer/composer/bin/composer): Failed to open stream: No such file or directory in /vendor/bin/composer on line 120

Warning: include(/vendor/bin/../composer/composer/bin/composer): Failed to open stream: No such file or directory in /vendor/bin/composer on line 120
PHP Warning:  include(): Failed opening '/vendor/bin/../composer/composer/bin/composer' for inclusion (include_path='.:/opt/homebrew/Cellar/[email protected]/8.1.19/share/[email protected]/pear') in /vendor/bin/composer on line 120

Warning: include(): Failed opening '/vendor/bin/../composer/composer/bin/composer' for inclusion (include_path='.:/opt/homebrew/Cellar/[email protected]/8.1.19/share/[email protected]/pear') in /vendor/bin/composer on line 120

This is originating from vendor/bin/composer on line 120. That is the following:
include __DIR__ . '/..'.'/composer/composer/bin/composer';

This file isnt present anymore after using delete_vendor_packages and it also is not in the new vendor/prefixed/composer directory. I've tried excluding the composer/composer package by adding it to the exclude_from_copy config but that resulted in even more errors.

I believe this error could be resolved when the composer directory would not be copied to the target_directory. This directory should also not be cleaned so the file that is being searched for will still be present.

I've got the following questions:

  • Is this something anybody else is running into?
  • Should I change my config?
  • Should composer be moved to my target_directory at all?
  • Any other tips would be welcome.

v0.14.1 no longer parses `<?php namespace ...`

As of v0.14.1, PHP files with an inline namespace ( i.e. <?php namespace MyNamespace; instead of <?php \nnamespace MyNamespace;) are no longer parsed and instead the class is renamed to a global prefix.

E.g.: Source file.
image

(Left: 0.14.0 | Right: v0.14.1 )
image

#[\ReturnTypeWillChange] becomes #[\MY_CUSTOM_PREFIX_ReturnTypeWillChange]

#[\ReturnTypeWillChange] is a special atribute provided by PHP to silence deprecation errors for return values. Strauss changes that very specific attribute name to add a prefix, and that leads to huge amounts of deprecation notices from Laravel while using phpunit.

Is there any way to stop this issue?

Namespaced use function declarations aren't prefixed

Currently any package that declares & uses namespaced functions via the use function ... method, those function's namespaces do not get properly prefixed.

Example package you can try is code-atlantic/chophper on the develop branch:
https://github.com/code-atlantic/chophper/tree/develop.

Currently the main branch has them hard coded for each usage which does get properly prefixed and didn't throw errors.

Basically if you have the following in a package, it won't translate and results in fatals.

namespace Chophper; // This works fine.

use function Chophper\some_func; // This doesn't get prefixed properly.
some_func();  // Resulting in errors.

\Chophper\some_func(); // This works fine.

Good idea to set `target_directory`to 'vendor'?

Thanks for the tool, like it so far!

I wonder if it's ok to set the output directory to 'vendor' to not have 'vendor_prefix' or simliar.

Currently I run rm -rf vendor;mv vendor_prefix vendor after the strauss command to only have one vendor folder which is also in my .gitignore.

Also I like to keep brianhenryie/strauss dependency in the 'require-dev' but that would bot work if running composer update --no-dev for the production build. What's the expected approach here?

Thanks!

Error when "exclude-from-classmap"

Hi,

I'm trying to use your package in a plugin where I make use of some Symfony components.

When running strauss, I'm having the following error:
/full/path/to/project/vendor/symfony/process//Tests/" directory does not exist

The "exclude-from-classmap" key doesn't seem to be handled in strauss. Could you have a look?

Distribute through PHIVE

phive install strauss would be nice :)

Needs a published GPG key and a signature per release.

Fatal error: Uncaught Error: Class "BrianHenryIE\Strauss\Console\Application" not found

When using strauss via the phar file I get the following error:

PHP Warning:  include(phar://strauss.phar/vendor/autoload.php): Failed to open stream: phar error: invalid url or non-existent phar "phar://strauss.phar/vendor/autoload.php" in phar:///Users/kodiegrantham/www/strauss.phar/bin/strauss on line 23

Warning: include(phar://strauss.phar/vendor/autoload.php): Failed to open stream: phar error: invalid url or non-existent phar "phar://strauss.phar/vendor/autoload.php" in phar:///Users/kodiegrantham/www/strauss.phar/bin/strauss on line 23
PHP Warning:  include(): Failed opening 'phar://strauss.phar/vendor/autoload.php' for inclusion (include_path='.:/usr/local/Cellar/php/8.1.2/share/php/pear') in phar:///Users/kodiegrantham/www/strauss.phar/bin/strauss on line 23

Warning: include(): Failed opening 'phar://strauss.phar/vendor/autoload.php' for inclusion (include_path='.:/usr/local/Cellar/php/8.1.2/share/php/pear') in phar:///Users/kodiegrantham/www/strauss.phar/bin/strauss on line 23
PHP Fatal error:  Uncaught Error: Class "BrianHenryIE\Strauss\Console\Application" not found in phar:///Users/kodiegrantham/www/strauss.phar/bin/strauss:26
Stack trace:
#0 phar:///Users/kodiegrantham/www/strauss.phar/bin/strauss(28): {closure}('0.8.1')
#1 /Users/kodiegrantham/www/strauss.phar(12): require('phar:///Users/k...')
#2 {main}
  thrown in phar:///Users/kodiegrantham/www/strauss.phar/bin/strauss on line 26

Fatal error: Uncaught Error: Class "BrianHenryIE\Strauss\Console\Application" not found in phar:///Users/kodiegrantham/www/strauss.phar/bin/strauss:26
Stack trace:
#0 phar:///Users/kodiegrantham/www/strauss.phar/bin/strauss(28): {closure}('0.8.1')
#1 /Users/kodiegrantham/www/strauss.phar(12): require('phar:///Users/k...')
#2 {main}
  thrown in phar:///Users/kodiegrantham/www/strauss.phar/bin/strauss on line 26

Feature: Change WordPress translation domain

I'm getting ready to use this on the new Validation library, and realized we have a need that I think Strauss would be a great fit for.

In the library we're using the WordPress __() translation function. The trick with that function is that the domain can't be a variable, it has to be a plain string for generating the POT file. That would mean the domain would need to be changed from some placeholder to whatever it ought to be during the build process.

The crew at Modern Tribe recently threw a script together that accomplishes this task. But it feels like something that would be a great fit for Strauss to handle.

Thanks!

using composer autoload and strauss autoload

After adding strauss, it seems that I need to use both the composer autoload and the strauss autoload.

include_once('strauss/autoload.php');
include_once('vendor/autoload.php');

The staruss process doesn't generate autoload data for my own classes / namespace.

  "autoload": {
    "psr-4": {
      "MyPlugin\\": "src/php"
    }
  },

Is there a setting I need add so that I only need to use one autoloader? Or am I missing something ?

Thanks

Error on call to undefined WP function

So switching from Mozart to this, has been fantastic as this is all working out of the box without the need for patches, or figuring out which versions of a composer package I need. However, when I made a new class with an admin notice add_action, just to test and ensure this is all properly working, I get the following error. Am I missing something, do I need to somehow wrap the wp core as well? I know the way I'm calling to the action is fine, but not sure why this error would trigger when calling to a default WP function.

PHP Fatal error:  Uncaught Error: Call to undefined function add_action() in /home/user/Sites/functionplayground/web/app/plugins/rap-site-reset/rap-site-reset.php:34
Stack trace:
#0 /home/user/Sites/functionplayground/web/app/plugins/rap-site-reset/vendor/composer/autoload_real.php(78): require()
#1 /home/user/Sites/functionplayground/web/app/plugins/rap-site-reset/vendor/composer/autoload_real.php(61): composerRequire9a0dc73fcbf3506c717760c1fe787923()
#2 /home/user/Sites/functionplayground/web/app/plugins/rap-site-reset/vendor/autoload.php(7): ComposerAutoloaderInit9a0dc73fcbf3506c717760c1fe787923::getLoader()
#3 /home/user/Sites/functionplayground/web/app/plugins/rap-site-reset/vendor/brianhenryie/strauss/bin/strauss(5): require('/home/user/Site...')
#4 /home/user/Sites/functionplayground/web/app/plugins/rap-site-reset/vendor/brianhenryie/strauss/bin/strauss(28): {closure}()
#5 /home/user/Sites/functionplayground/web/app/plugins/rap-site-reset/vendor/bin/strauss(112): include('/home/user/Site...')
#6 {main}
  thrown in /home/user/Sites/functionplayground/web/app/plugins/rap-site-reset/rap-site-reset.php on line 34

Here's my composer.json

{
	"name": "kupoback/rap-site-reset",
	"description": "",
	"type": "wordpress-muplugin",
	"require": {
		"composer/installers": "^2.0",
		"ext-json": "*",
		"php": "^7.4|^8.0.0",
		"phpseclib/phpseclib": "dev-master",
		"wp-cli/db-command": "^2.0",
		"wp-cli/extension-command": "^2.0",
		"wp-cli/maintenance-mode-command": "2.x-dev",
		"illuminate/support": "^8.0"
	},
	"require-dev": {
		"squizlabs/php_codesniffer": "4.0.x-dev",
		"roave/security-advisories": "dev-master",
		"brianhenryie/strauss": "dev-master"
	},
	"config": {
		"optimize-autoloader": true,
		"preferred-install": "dist",
		"allow-plugins": {
			"composer/installers": true,
			"cweagans/composer-patches": true
		}
	},
	"license": "MIT",
	"scripts": {
		"strauss": [
			"vendor/bin/strauss"
		],
		"post-root-package-install": [
			"@strauss"
		],
		"post-root-package-update": [
			"@strauss"
		],
		"test": [
			"phpcs"
		]
	},
	"authors": [
		{
			"name": "kupoback",
		}
	],
	"autoload": {
		"files": [ "rap-site-reset.php" ],
		"psr-4": {
			"RapReset\\": "src/"
		}
	},
	"minimum-stability": "dev",
	"extra": {
		"strauss": {
			"classmap_prefix": "RapReset",
			"constant_prefix": "RR_",
			"delete_vendor_files": false,
			"namespace_prefix": "RapReset\\Vendor",
			"target_directory": "vendor_prefix"
		}
	}
}

Here's my rap-site-reset.php file:

use RapReset\RapReset;

require_once __DIR__ . '/vendor_prefix/autoload.php';

add_action('admin_notices', [RapReset::class, 'adminNotice']);

And my Class

namespace RapReset;

class RapReset
{
    public static function adminNotice()
    {
        echo "Hello World";
    }
}

Namespace prefix added multiple times in strings

As you wished @BrianHenryIE, here's another one:

In some cases, the namespace prefix is added two or three times in strings. I couldn't find a simple code example where the prefix is added three times, but here's one where it's added two times.

Hint: If the content of the file StraussTestPackage.php is removed or the namespace in StraussTestPackage2.php is changed from ST\Namespace to ST everything works as expected.

Thanks again and keep up the good work!

StraussTestPackage.php:

<?php
namespace ST;
class StraussTestPackage {
	public function __construct() {
	}
}

StraussTestPackage2.php:

<?php
namespace ST\Namespace;
class StraussTestPackage2 {
	public function __construct() {
		$one = '\ST\Namespace';
		$two = '\ST\Namespace\StraussTestPackage2';
	}
}

Result of StraussTestPackage2.php:

<?php
/**
 * @license proprietary
 *
 * Modified by __root__ on 02-July-2021 using Strauss.
 * @see https://github.com/BrianHenryIE/strauss
 */
namespace StraussTest\ST\Namespace;
class StraussTestPackage2 {
	public function __construct() {
		$one = '\StraussTest\StraussTest\ST\Namespace';
		$two = '\StraussTest\StraussTest\ST\Namespace\StraussTestPackage2';
	}
}

Troubles Namespacing WPGraphQL

Attempting to solve depedency conflicts with https://github.com/wp-graphql/wp-graphql

composer.json


"require": {
	"wp-graphql/wp-graphql": "^1.12"
},
"extra": {
	"strauss": {
		"target_directory": "Dependencies",
		"namespace_prefix": "MyProject\\Dependencies\\",
		"classmap_prefix": "Prefix_",
		"constant_prefix": "Prefix_",
		"packages": [
			"wp-graphql/wp-graphql"
		],
		"delete_vendor_packages": true,
		"delete_vendor_files": true
	}
},

results in a whole lot of weirdness with the WPGraphQL package ultimately not working.

The main WPGraphQL class is not namespaced, the top of the file DOES have the following commented out line added:

// Global. - namespace MyProject\Dependencies\WPGraphQL;

but the actual class declaration remains untouched:

final class WPGraphQL {

whereas the expectation was for the class to either be namespaced via the namespace keyword or via the classmap_prefix prefix specified in composer.json.

Either way, autoloading does not work and results in errors like:

[26-Apr-2023 23:08:28 UTC] 
PHP Fatal error:  Uncaught Error: 
Class "MyProject\Dependencies\WPGraphQL" not found 
in /path/to/project/Dependencies/wp-graphql/wp-graphql/src/Registry/Utils/PostObject.php:181

which appears to be expecting the WPGraphQL to be namespaced like MyProject\Dependencies\WPGraphQL

PLease note that the autoload file generated by straus is loaded during the very first few steps of my bootstrapping process:

require_once __DIR__ . '/Dependencies/autoload.php';

Anyways, not sure whether my problems are caused by a bug, or due to misconfiguration, or if there is something else i failed to do.

Thank you in advance for all of your time, effort, and talent you have commited to this project. I'll gladly help write unit tests if any fix is needed to get this working.

Strauss Fail when a namespace is mapped to an array of paths

when multiple directories are add for the same namespace as specified in Composer documentaion:

{
    "autoload": {
        "psr-4": { "Monolog\\": ["src/", "lib/"] }
    }
}

it results in the error:

PHP Fatal error:  Uncaught TypeError: trim(): Argument #1 ($string) must be of type string, array given in [REDACTED]/vendor/brianhenryie/strauss/src/Composer/Extra/StraussConfig.php:235

it seems like the problem is strauss always expect the configuration to be a string and try to trim() it.

Deprecated: Return type of MyCLabs\Enum\Enum::jsonSerialize() should...

Running into these errors while running strauss:

PHP Deprecated:  Return type of MyCLabs\Enum\Enum::jsonSerialize() should either be compatible with JsonSerializable::jsonSerialize(): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /Users/kodiegrantham/.composer/vendor/myclabs/php-enum/src/Enum.php on line 246

Deprecated: Return type of MyCLabs\Enum\Enum::jsonSerialize() should either be compatible with JsonSerializable::jsonSerialize(): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /Users/kodiegrantham/.composer/vendor/myclabs/php-enum/src/Enum.php on line 246

I have it installed as a global package due to a conflict with the version of flysystem that strauss uses and the one my package uses.

It hangs there for a while and then ultimately fails with this error:

PHP Fatal error:  Uncaught TypeError: BrianHenryIE\Strauss\Licenser::addChangeDeclarationToPhpString(): Return value must be of type string, null returned in /Users/kodiegrantham/.composer/vendor/brianhenryie/strauss/src/Licenser.php:270

Incorrect binary name when installed using composer

When installing this via composer the binary is called mozart and not strauss as mentioned in the documentation.

I get this:
vendor/bin/mozart

Instead of this:
vendor/bin/strauss

Have I missed something or is this a mistake?

Suggestion: stop using DIRECTORY_SEPARATOR

I do my development primarily on Windows and have had various path issues with Mozart and Strauss before but it keeps regressing.
The current release does not work on Windows either. I've hacked together a quick fix here, but it feels like a patch at best.

The recurring theme is simple: code assumes forward slashes when in fact the path (on Windows) could have both forward and backward slashes, mainly due to inconsistent usage of DIRECTORY_SEPARATOR.

I propose to stop using DIRECTORY_SEPARATOR altogether and exclusively use forward slashes. PHP itself handles this fine on Windows, and as long as there are no things shell commands where you really need the correct separator, it's simply much easier to work with.

At the same time I think we could benefit from a simple Path helper class, with a few simple functions that replace a lot of recurring operations throughout Strauss (which at the moment also have slightly differing syntaxes, making it harder to debug path related issues):

  • Path::normalize( $path ) to replace all backward slashes with forward slash. For performance I would suggest using a simple str_replace rather than preg_replace. (similar to wp_normalize_path in WordPress).
  • Path::ensureTrailingSlash( $path ) to append a trailing slash if not present. (similar to trailingslashit in WordPress, which is actually referenced in some of the comments!)
  • Path::join( [ $path_1, $path_2 ] ) joining one or more paths with a /, avoiding ugly . '/' . string concatenations.
  • Path::getRelativePath( $path, $basePath ) get the relative path of $path to $basePath.

Function names, class structure etc. don't really matter, but I think this would make all path/file related code a lot more readable and more resistant to OS related issues. I looked for existing libraries handling this but couldn't find something that fits the bill, and also realized that it's pretty simple stuff to begin with.

Missing namespace prefixes since migrating from "coenjacobs/mozart": "dev-rewrite" and url in composer

Hi, Brian.

I migrated my composer file from

"repositories": [
    {
      "url": "https://github.com/brianhenryie/mozart",
      "type": "git"
    },
  ],
  "require-dev":{
    "coenjacobs/mozart": "dev-rewrite",
    "squizlabs/php_codesniffer": "*",
     "wp-coding-standards/wpcs": "*"
  },

to


With config:


    "strauss": {
      "dep_namespace": "MZoo\\MBO_Sandbox\\Dependencies\\",
      "dep_directory": "/src/Mozart/",
      "packages": [
        "htmlburger/carbon-fields",
        "ericmann/wp-session-manager",
        "ericmann/sessionz"
      ],
      "delete_vendor_files": false,
      "override_autoload": {
        "htmlburger/carbon-fields": {
          "psr-4": {
            "Carbon_Fields\\": "core/"
          },
          "files": [
            "config.php",
            "templates",
            "assets",
            "build"
          ]
        }
      }
    }
  }

I'm not quite sure how you are achieving the namespace prefixes, but it seems ones within Carbon Fields are breaking.

It breaks:

Uncaught Error: Class 'Carbon_Fields\Provider\Container_Condition_Provider' not found in path/to/src/Mozart/htmlburger/carbon-fields/core/Carbon_Fields.php:392

Then when I update that namespace to:

\MZoo\MBO_Sandbox\Dependencies\Carbon_Fields\Provider\Container_Condition_Provider

It breaks at:

Uncaught Error: Class 'Carbon_Fields\Carbon_Fields' not found in path/to/src/Mozart/htmlburger/carbon-fields/core/Loader/Loader.php:6

I have of course removed vendor and re-installed with re-running vendor/bin/strauss (Cool name, BTW.)
Am I missing a configuration or a step?

Diffs I see in the rendered files are, significantly:

# src/Mozart/htmlburger/carbon-fields/core/Carbon_Fields.php

And

  •   $ioc->register( new \MZoo\MBO_Sandbox\Dependencies\Carbon_Fields\Provider\Container_Condition_Provider() );
    
  •   $ioc->register( new \Carbon_Fields\Provider\Container_Condition_Provider() );
    
# src/Mozart/htmlburger/carbon-fields/core/Container.php
  * Container proxy factory class.
  * Used for shorter namespace access when creating a container.
  *
- * @method static \MZoo\MBO_Sandbox\Dependencies\Carbon_Fields\Container\Comment_Meta_Container make_comment_meta( string $id, string $name = null )
- * @method static \MZoo\MBO_Sandbox\Dependencies\Carbon_Fields\Container\Nav_Menu_Item_Container make_nav_menu_item( string $id, string $name = null )
- * @method static \MZoo\MBO_Sandbox\Dependencies\Carbon_Fields\Container\Network_Container make_network( string $id, string $name = null )
- * @method static \MZoo\MBO_Sandbox\Dependencies\Carbon_Fields\Container\Post_Meta_Container make_post_meta( string $id, string $name = null )
- * @method static \MZoo\MBO_Sandbox\Dependencies\Carbon_Fields\Container\Term_Meta_Container make_term_meta( string $id, string $name = null )
- * @method static \MZoo\MBO_Sandbox\Dependencies\Carbon_Fields\Container\Theme_Options_Container make_theme_options( string $id, string $name = null )
- * @method static \MZoo\MBO_Sandbox\Dependencies\Carbon_Fields\Container\User_Meta_Container make_user_meta( string $id, string $name = null )
+ * @method static \Carbon_Fields\Container\Comment_Meta_Container make_comment_meta( string $id, string $name = null )
+ * @method static \Carbon_Fields\Container\Nav_Menu_Item_Container make_nav_menu_item( string $id, string $name = null )
+ * @method static \Carbon_Fields\Container\Network_Container make_network( string $id, string $name = null )
+ * @method static \Carbon_Fields\Container\Post_Meta_Container make_post_meta( string $id, string $name = null )
+ * @method static \Carbon_Fields\Container\Term_Meta_Container make_term_meta( string $id, string $name = null )
+ * @method static \Carbon_Fields\Container\Theme_Options_Container make_theme_options( string $id, string $name = null )
+ * @method static \Carbon_Fields\Container\User_Meta_Container make_user_meta( string $id, string $name = null )

Thank you and if this is a bug, please feel free to let me know how I can help.

Local symlinked repositories fail

Given a package that is in a directory on the local filesystem

"repositories": [
    {
        "type": "path",
        "url": "../bh-pdf-helpers"
    },
    ...
],
"require": {
    "brianhenryie/pdf-helpers": "dev-master",
    ...    

Error:

The "/Users/brianhenry/Sites/my-project/vendor/Sites/bh-pdf-helpers/src/" directory does not exist.

The problem is in ComposerPackage constructor.

This was introduced when supporting packages that install themselves to a folder different to their package name.

Edit: Fix written but needs testing and thinking about.

Files autoloader for symlinked package not copied or referenced correctly

bootstrap.php

  "autoload": {
    "classmap": ["src"],
    "files": ["bootstrap.php"]
  },

in a symlinked package

 "repositories":{
    "brianhenryie/bh-wp-plugin-meta-kit":{
      "type": "path",
      "url":  "../bh-wp-plugin-meta-kit/"
    }

was not copied to the destination directory.

And the generated autoload-files.php referenced the original path:

require_once __DIR__ . '/Sites/bh-wp-plugin-meta-kit/bootstrap.php';

Issue bundling AWS S3 package

I'm attempting to bundle the aws-sdk-php package in my plugin (specifically the S3 component) and am running into an odd issue.

Basically these files:

vendor/aws/aws-sdk-php/src/Endpoint/UseDualstackEndpoint/Configuration.php
vendor/aws/aws-sdk-php/src/Endpoint/UseFipsEndpoint/Configuration.php
vendor/aws/aws-sdk-php/src/S3/UseArnRegion/Configuration.php

all have a line that looks similar to this:

$this->useFipsEndpoint = Aws\boolean_value($useFipsEndpoint);

and after prefixing, they become something like this:

$this->useFipsEndpoint = MyPlugin\Vendor\Aws\boolean_value($useFipsEndpoint);

Which results in this error:

PHP Fatal error:  Uncaught Error: Call to undefined function MyPlugin\Vendor\Aws\Endpoint\UseFipsEndpoint\MyPlugin\Vendor\Aws\boolean_value() in /app/content/plugins/my-plugin/vendor-prefixed/aws/aws-sdk-php/src/Endpoint/UseFipsEndpoint/Configuration.php:20

If I manually add a backslash at the begining of these classes, like this:

$this->useFipsEndpoint = \MyPlugin\Vendor\Aws\boolean_value($useFipsEndpoint);

The issue goes away and everything works as expected.

Any ideas?

Strings are being namespaced

The namespace being updated is TrustedLogin, a word which is also used in strings. After running Strauss, the strings get modified:

  • Before: esc_html__( 'Learn about TrustedLogin', 'trustedlogin' )
  • After: esc_html__( 'Learn about GravityView\TrustedLogin', 'trustedlogin' )

Namespace issues with static methods

Hi, I'm coming from coenjacobs#124 and wanted to give Strauss a go to fix my issues with mPDF & Mozart.

But Strauss is not replacing the old namespace with the new one when a static method is called. The are some cases in my codebase where also static methods get the updated namespace, but most of the times they do not.

I've created a simplified gist where I also attached the resulting file in which the non-static method gets the updated namespace and the static method does not. Is there something wrong with my composer.json or is Strauss not working correctly here? Thanks in advance!

Windows: File already exists at path

This seems to be a regression, which I believe was fixed in Mozart by either coenjacobs#91 or coenjacobs#103

on Windows, the directory separator is not cleaned for the files to be copied in the enumerator here:

$relativeFilepath = str_replace($prefixToRemove, '', $packagePath . $namespace_relative_path);

adding this below that line fixes the issue:

$relativeFilepath = preg_replace('#[\\\/]+#', DIRECTORY_SEPARATOR, $relativeFilepath);

to replicate, simply use:

    "require": {
        "iio/libmergepdf": "^4.0"
   },

Problem with package name `"Blockchain/Blockchain"`

"/Users/brianhenry/Sites/woocommerce-gateway-bitcoin/vendor/blockchain/blockchain/composer.json" does not match the expected JSON schema:
 - name : Does not match the regex pattern ^[a-z0-9]([_.-]?[a-z0-9]+)*/[a-z0-9](([_.]?|-{0,2})[a-z0-9]+)*$Script vendor/bin/strauss handling the post-update-cmd event returned with error code 1
{
    "name": "Blockchain/Blockchain",
    "description": "Blockchain API client library",
    "keywords": ["bitcoin", "blockchain"],
    "homepage": "https://github.com/blockchain/api-v1-client-php",
    "license": "MIT",
    "autoload": {
        "psr-4": {
            "Blockchain\\": "src/"
        }
    },
    "require": {
        "php": ">=5.3.0",
        "ext-curl": "*"
    }
}

Manually editing the package name to "blockchain/blockchain" fixed it.

Trips up when presented with non-standard packages

As metapackages do not follow the standard directory structure, Strauss has trouble dealing with them, as it cannot find their composer.json. An example of this can be seen by requiring league/omnipay. A workaround for this is to require the packages from the metapackage separately, but it would be more elegant if Strauss could handle this gracefully.

This also applies to other non-standard package types. For instance, if requiring composer/installers such that we can declare our package as a wordpress-plugin, rather than a library, strauss is unable to locate the package 'composer-plugin-api' and fails to compose dependencies.

I am unsure the best way to deal with these special cases - Perhaps at least in the case of composer-plugin-api we simply exclude this package by default

docblock comment "class object" resulting in prefixed "object"

using just this:

    "require": {
        "iio/libmergepdf": "^4.0"
   },

results in object being prefixed in all files. This appears to be caused by the following docblock (in: tecnickcom/tcpdf/include/tcpdf_static.php#L326-L332)

	/**
	 * Creates a copy of a class object
	 * @param $object (object) class object to be cloned
	 * @return cloned object
	 * @since 4.5.029 (2009-03-19)
	 * @public static
	 */

If I change that first line to Creates a copy of a classy object, the issue is resolved

Not prefixing all classes?

Hi Brian,

I spent sometime tonight figuring out how to make this work, including setting up a composer package at https://packagist.org/packages/qriouslad/codestar-framework for the library I needed to prefix.

I've successfully executed the strauss script via composer to prefix that package, however, I noticed not all classes are properly prefixed.

For example, in setup.class.php, while if ( class_exists( 'CSF_Options' )) is successfully prefixed into if ( class_exists( 'Prefix_CSF_Options' )), the if (class_exists( 'CSF_Metabox' )) part remains the same, not getting prefixed, as well as other classes in that file.

Since this library is not using namespaces yet, I needed to use this in the package composer.json:

"autoload": { "classmap": ["src/"] },

...where the library files are inside the /src/ folder. Could this be a method that is not yet fully supported by strauss?

Configuration option include_modified_date doesn't work

Hi,

when I add "include_modified_date": false to the extra/strauss object it doesn't take any effect, the date is still added to the header.

I also want to get rid of the author in the header, because I don't want git to include all files again after running strauss when actually the only change is the author in the header who ran strauss.

So a second option like "include_author": false would be much appreciated.

If both options are set to false the text would then be "Modified using Strauss.", which would not change if multiple authors run strauss on multiple dates.

Thank you!

Bug? Issue with composer 'static' loading

Hey,

I'm not sure if this a bug or just not a supported functionality. I'm using strauss and it's copying over the libraries fine and generating an autoload for the classes except for the /guzzlehttp/psr7/src/functions_include.php I'm aware that this file is being deprecated but I'm just not sure if this should work or not.

Thanks,

Workflows are referencing vulnerable actions

Hello, there!

As part of the university research we are currently doing regarding the security of Github Actions, we noticed that one or many of the workflows that are part of this repository are referencing vulnerable versions of the third-party actions. As part of a disclosure process, we decided to open issues to notify GitHub Community.

Please note that there are could be some false positives in our methodology, thus not all of the open issues could be valid. If that is the case, please let us know, so that we can improve on our approach. You can contact me directly using an email: ikoishy [at] ncsu.edu

Thanks in advance

  1. The workflow codecoverage.yml is referencing action shivammathur/setup-php using references 1.3.7. However this reference is missing the commit 7163319 which may contain fix to the vulnerability.
  2. The workflow release.yml is referencing action shivammathur/setup-php using references 1.3.7. However this reference is missing the commit 7163319 which may contain fix to the vulnerability.

The vulnerability fix that is missing by actions' versions could be related to:
(1) CVE fix
(2) upgrade of vulnerable dependency
(3) fix to secret leak and others.
Please consider updating the reference to the action.

If you end up updating the reference, please let us know. We need the stats for the paper :-)

Unprefixed static function call in ternary operation

guzzlehttp/guzzle/src/BodySummarizer.php:24

/**
 * Returns a summarized message body.
 */
public function summarize(MessageInterface $message): ?string
{
    return $this->truncateAt === null
        ? \GuzzleHttp\Psr7\Message::bodySummary($message)
        : \GuzzleHttp\Psr7\Message::bodySummary($message, $this->truncateAt);
}
PHP Fatal error:  Uncaught Error: Class "GuzzleHttp\Psr7\Message" not found in /path/to/wp-content/plugins/bh-wp-autologin-urls/strauss/guzzlehttp/guzzle/src/BodySummarizer.php:31
Stack trace:
#0 /path/to/wp-content/plugins/bh-wp-autologin-urls/strauss/guzzlehttp/guzzle/src/Exception/RequestException.php(113): BrianHenryIE\WP_Autologin_URLs\GuzzleHttp\BodySummarizer->summarize(Object(BrianHenryIE\WP_Autologin_URLs\GuzzleHttp\Psr7\Response))
#1 /path/to/wp-content/plugins/bh-wp-autologin-urls/strauss/guzzlehttp/guzzle/src/Middleware.php(75): BrianHenryIE\WP_Autologin_URLs\GuzzleHttp\Exception\RequestException::create(Object(BrianHenryIE\WP_Autologin_URLs\GuzzleHttp\Psr7\Request), Object(BrianHenryIE\WP_Autologin_URLs\GuzzleHttp\Psr7\Response), NULL, Array, NULL)
#2 /path/to/wp-content/plugins/bh-wp-autologin-urls/strauss/guzzlehttp/promises/src/Promise.php(210): BrianHenryIE\WP_Autologin_URLs\GuzzleHttp\Middleware::BrianHenryIE\WP_Autologin_URLs\GuzzleHttp\{closure}(Object(BrianHenryIE\WP_Autologin_URLs\GuzzleHttp\Psr7\Response))
#3 /path/to/wp-content/plugins/bh-wp-autologin-urls/strauss/guzzlehttp/promises/src/Promise.php(159): BrianHenryIE\WP_Autologin_URLs\GuzzleHttp\Promise\Promise::callHandler(1, Object(BrianHenryIE\WP_Autologin_URLs\GuzzleHttp\Psr7\Response), NULL)
#4 /path/to/wp-content/plugins/bh-wp-autologin-urls/strauss/guzzlehttp/promises/src/TaskQueue.php(54): BrianHenryIE\WP_Autologin_URLs\GuzzleHttp\Promise\Promise::BrianHenryIE\WP_Autologin_URLs\GuzzleHttp\Promise\{closure}()
#5 /path/to/wp-content/plugins/bh-wp-autologin-urls/strauss/guzzlehttp/promises/src/Promise.php(254): BrianHenryIE\WP_Autologin_URLs\GuzzleHttp\Promise\TaskQueue->run(true)
#6 /path/to/wp-content/plugins/bh-wp-autologin-urls/strauss/guzzlehttp/promises/src/Promise.php(230): BrianHenryIE\WP_Autologin_URLs\GuzzleHttp\Promise\Promise->invokeWaitFn()
#7 /path/to/wp-content/plugins/bh-wp-autologin-urls/strauss/guzzlehttp/promises/src/Promise.php(275): BrianHenryIE\WP_Autologin_URLs\GuzzleHttp\Promise\Promise->waitIfPending()
#8 /path/to/wp-content/plugins/bh-wp-autologin-urls/strauss/guzzlehttp/promises/src/Promise.php(232): BrianHenryIE\WP_Autologin_URLs\GuzzleHttp\Promise\Promise->invokeWaitList()
#9 /path/to/wp-content/plugins/bh-wp-autologin-urls/strauss/guzzlehttp/promises/src/Promise.php(68): BrianHenryIE\WP_Autologin_URLs\GuzzleHttp\Promise\Promise->waitIfPending()
#10 /path/to/wp-content/plugins/bh-wp-autologin-urls/strauss/guzzlehttp/guzzle/src/Client.php(129): BrianHenryIE\WP_Autologin_URLs\GuzzleHttp\Promise\Promise->wait()
#11 /path/to/wp-content/plugins/bh-wp-autologin-urls/strauss/klaviyo/sdk/lib/API/ProfilesApi.php(157): BrianHenryIE\WP_Autologin_URLs\GuzzleHttp\Client->send(Object(BrianHenryIE\WP_Autologin_URLs\GuzzleHttp\Psr7\Request), Array)
#12 /path/to/wp-content/plugins/bh-wp-autologin-urls/strauss/klaviyo/sdk/lib/API/ProfilesApi.php(135): BrianHenryIE\WP_Autologin_URLs\Klaviyo\API\ProfilesApi->exchangeWithHttpInfo(Array)
#13 /path/to/wp-content/plugins/bh-wp-autologin-urls/strauss/klaviyo/sdk/lib/Subclient.php(57): BrianHenryIE\WP_Autologin_URLs\Klaviyo\API\ProfilesApi->exchange(Array)
#14 /path/to/wp-content/plugins/bh-wp-autologin-urls/API/Integrations/class-klaviyo.php(36): BrianHenryIE\WP_Autologin_URLs\Klaviyo\Subclient->__call('exchange', Array)
#15 /path/to/wp-content/plugins/bh-wp-autologin-urls/WP_Includes/class-login.php(236): BrianHenryIE\WP_Autologin_URLs\API\Integrations\Klaviyo->get_email('3GJUdebm1Z28U02...')
#16 /path/to/wp-content/plugins/bh-wp-autologin-urls/WP_Includes/class-login.php(79): BrianHenryIE\WP_Autologin_URLs\WP_Includes\Login->klaviyo()
#17 /path/to/wp-includes/class-wp-hook.php(307): BrianHenryIE\WP_Autologin_URLs\WP_Includes\Login->process_querystring('')
#18 /path/to/wp-includes/class-wp-hook.php(331): WP_Hook->apply_filters(NULL, Array)
#19 /path/to/wp-includes/plugin.php(476): WP_Hook->do_action(Array)
#20 /path/to/wp-settings.php(461): do_action('plugins_loaded')
#21 /path/to/wp-config.php(95): require_once('/chroot/home/ab...')
#22 /path/to/wp-load.php(50): require_once('/chroot/home/ab...')
#23 /path/to/wp-blog-header.php(13): require_once('/chroot/home/ab...')
#24 /path/to/index.php(17): require('/chroot/home/ab...')
#25 {main}
thrown in /path/to/wp-content/plugins/bh-wp-autologin-urls/strauss/guzzlehttp/guzzle/src/BodySummarizer.php on line 31

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.