Is it possible to validate vendor folder integrity in composer? - php

I just inherited a composer project in a very bad shape. They sent me a zip file with the vendor directory in it and I suspect that the previous developer has edited files directly inside vendor.
Is there a way to "validate" the vendor folder to ensure that the files inside are unmodified?

Change the name of the old vendor to something else.
Execute composer install again.
Run diff to compare both directories.
E.g. for a sample project where I intentionally modified a single file inside vendor.
$ mv vendor vendor_old
$ composer install
### install output...
$ diff -rq vendor vendor_old
Files vendor/autoload.php and vendor_old/autoload.php differ
Files vendor/composer/autoload_files.php and vendor_old/composer/autoload_files.php differ
Files vendor/composer/autoload_real.php and vendor_old/composer/autoload_real.php differ
Files vendor/composer/autoload_static.php and vendor_old/composer/autoload_static.php differ
Files vendor/symfony/console/Terminal.php and vendor_old/symfony/console/Terminal.php differ
You can mostly ignore the changes to the autoload* files, but with this listing you can concentrate in those other files that report differences (and run a more exhaustive diff from them).
In the example, only vendor/symfony/console/Terminal.php was actually modified.

Copy the project into some other folder, and delete the vendor directory. Run composer install and compare two vendor files.

The easiest way to do this is by using composer status command.
The prerequisite is that package is installed from source (as described on the official Composer site):
If you often need to modify the code of your dependencies and they are installed from source, the status command allows you to check if you have local changes in any of them.

Related

How to exclude the unit test directory in Git

A large existing PHP project that is having Unit Tests retrofitted to it. I want to have a "tests" directory in the code on the development branch which contains these unit tests and perhaps the DB fixtures also. Naturally I don't want anything in there making its way onto the production environment so I want a way of automatically excluding this directory when it's deployed. Or ideally, a way to avoid anything in there that is committed from being merged into master in the first place.
How do I manage this? There will be frequent and unpredictable commits to the test directory so I can't simply skip certain commits manually.
EDIT: I've now got four answers telling me about .gitignore. I don't believe .gitignore is appropriate here because I want to exclude something that IS to be committed but only from a specific branch.
it's called .gitignore
From the docs:
A gitignore file specifies intentionally untracked files that Git should ignore. Files already tracked by Git are not affected
source: https://git-scm.com/docs/gitignore
For examples sake, let's say you have this working tree:
|-app
|-test
|-index.php
to exclude test/ the test directory add a .gitignore on the same level as the .git folder and in it just add:
test/
commit the git ignore and make a change/add a file to test/ and you'll notice it doesn't appear when you run
$ git status
You can use .gitignore. This is a file in your project root and you can list all files and directories you don't want to commit/push. They are separated by a new line.
I've found that the way to keep a part of a branch from being merged into another branch on a permanent basis is to use sub-modules.
I created my unit tests folder as its own repository and then included it in my mainline branch (which is not the production/master branch) as a sub-module.
https://git-scm.com/book/en/v2/Git-Tools-Submodules
By default when you clone a repository, sub-modules are not cloned with it. The sub-module directory is created but remains empty, unless you also execute
git submodule init
git submodule update
Therefore it's as simple as not including the above commands in your production git clone but including them when you clone the repository for testing or development. You can make any changes to the tests directory along with the codebase and commit both together. This means tests can be developed alongside the code base without risking them being deployed to production.
I found the following aliases useful to set up to streamline git operations:
$ git config alias.sdiff '!'"git diff && git submodule foreach 'git diff'"
$ git config alias.spush 'push --recurse-submodules=on-demand'
$ git config alias.supdate 'submodule update --remote --merge'
This seems to be the correct approach to solving the problem of wanting separation of code in a single repository to be different on a per-branch basis.

Symfony3 - creating a vendor-based bundle

We'd like to create a bundle which can deployed via composer/packagist for others to use. It'll wrap the logic created by the owners of MessageBird. Basically a kind of Service which will indeed be called with the container via ourvendor.messagebird.messaging.
Since it's a type of bundle (as per the docs of Sf3), we created a bundle while following the documentation:
http://symfony.com/doc/current/bundles/SensioGeneratorBundle/commands/generate_bundle.html
As the directory /src we used /vendor instead. That's when it all went wrong. Our namespace could not be located, loaded or even when we manually added it to the autoloading classes of Composer it failed all the same.
The question is, what is the best practice to go about this? We got it working right now and what we did was the following:
We created a bundle wit the following cmd:
bin/console generate:bundle --shared --namespace=OurVendor/MessageBird/MessageBirdBundle --bundle-name=MessageBirdBundle --format=yml
We moved the /src/OurVendor directory to /vendor/OurVendor as the only way to get a perfect generation was to use the default /src folder.
We manually updated the AppKernel.php
We did some debugging with namespaces for Composer but eventually we added "OurVendor\\":"vendor/" to the "autoload/psr-4" directive in root composer.json
We ran composer dumpautoload && bin/console cache:clear -e dev which resulted in an error.
We ran composer -o update which checked all dependencies and updated accordingly, including autogenerated autoload files
Strangely enough we had to add the Bundle to the AppKernel.php class and cleaned the cache again.
After all this it worked but the documentation said no such thing about developing a 3rd party vendor bundle.
http://symfony.com/doc/current/bundles/best_practices.html
So long story short, did we go about it the wrong way or what?
/vendor directory is managed by composer. Do not copy/move anything there. Don't even edit anything there, unless you understand all consequences.
When you create a shared bundle, you need to push it to a VCS of your choice, and add it as a dependency in composer.json of the project which uses it.
When you run composer update it will check-out your bundle into /vendor directory and generate correct autoload file.
Please read more how to use private repositories with composer.

Where should the composer.json and composer.lock files should be?

I've never used Composer before, but installed it so I could set twig up the recommended way.
I now have composer.json and composer.lock files in two separate directories. How do I determine where they SHOULD be? I assume they certainly shouldn't be in my public html root, as one of them has managed to be?
The composer.json file should be created at the topmost directory of your project, i.e. the top directory that is in version control. Subdirectories of this directory likely are for example the "public" or "htdocs" or "www" directory which is the document root for the web server.
By using Composer, this directory will also get a "vendor" directory where the packages are being placed, as well as the composer.lock file which records the exact versions being installed.
Do commit both composer.json and composer.lock. Don't commit the vendor folder, put it onto the ignore list.

I have PHP code I need to use—how do I install it?

I'm trying to get some code set up to use an particular company's API.
I have experience with Perl and if I need a module installed, I type cpan ModuleName and most of the time it Just Works. How does that work with PHP code of similar complexity?
The company in question have a github repository with PHP Client system to access their API, which looks much the same as a perl Module.
I can git clone it, I can download it, but then what? Do I have to install it? There are no installation instructions. Or do I just start using it? There's a composer.json file in there. Do I need to run a composer command so it can figure out and install its dependencies like a CPAN module would? Will it install into system folders or just right there in whatever directory it happens to be in? I feel like there ought be some kind of official installation process because there's a /tests/ folder in the files I downloaded.
Their example code literally starts like this:
<?php
/* #var $CompanyName \CompanyName_Api */
$CompanyName = new \CompanyName_Api();
/* do interesting stuff */
and that's it. Of course nothing works if I just do that because it doesn't know where the CompanyName_Api files are. It works if I add this:
<?php
include('/full/path/to/downloaded/files/CompanyName/src/Api.php');
is that all I need to do?
In order to install all dependencies defined in composer.json you would run the following command inside the project directory:
composer install
This will find and download the dependencies into the vendor directory and it will also generate an optimized autoloader.
To autoload your own source files you'll need to add it to the autoload section in the composer.json file:
First your need to install an PHP environment like PHP, Apache and all stuff, then you need to clone that file from the git repository or just download it, then navigate to the dir and fire the command composer install. It will install all of the dependencies required for that package. After that, run the code from the browser -- the package api code may have the auto loader file which you need to include in your current package and autoloader will do all the stuff for you. Add your folder structure and file structure so that you get a better answer on this.

Composer vendor/ folder FTP upload

I have a local project with loaded with Composer libs. I uploaded this project to my FTP and received errors, connected with not found classes from some libs.
Can I simply copy vendor/ folder to FTP or I missed something?
Error received:
Fatal error: Class 'AAA\Core\Tools' not found in /home/aaa/public_html/api.php on line 11
api.php:
<?php
use AAA\Core\Tools;
require_once("./vendor/autoload.php");
require_once("./api/" . Tools::getFieldValue('controller') . ".php");
All works fine on localhost!
Linux has a case sensitive file system. That means that files Alex.txt and alex.txt are the same thing in Windows, but not in Linux. Actually on Linux both can happily live in the same directory:
$ tree .
.
├── alex.txt
└── Alex.txt
0 directories, 2 files
Taking this into consideration, I would try to double check that the paths you are using in your namespace are actually identical to what is found at the file system level. (i.e: AAA directory with only uppercase letters ; Core directory capitalized and Tools.php file capitalized)
If you want to keep your existing file system layout, you can use PSR-4 to explicitly tell Composer how to map the namespace to the file system:
Change autoload section from your composer.json:
{
"autoload": {
"psr-4": {"AAA\\DB\\": "db/"}
}
}
where db/ is the actual path from the file system
Update the autoloader:
$ composer dump-autoload
This will take care of directory names, but doesn't apply for files. Meaning that any file inside db/ must be named exactly as used in namespace (for a usage as use AAA\DB\DBCore the file must be db/DBCore.php).
If your file is named dbcore.php and you want to reference it in your namespace as DBCore, you can use classmap feature from Composer:
"autoload": {
"classmap": [
"db/dbcore.php"
]
}
dbcore.php:
<?php
namespace AAA\DB;
class DBCore
{
}
And you can use it as usual:
<?php
require_once("./vendor/autoload.php");
$dbCore = new \AAA\DB\DBCore();
Firstly I would check the autoloader files composer has generated to make sure the paths are valid on your linux server.
Another simple but common issue is that on windows the folder and file names are not case sensitive however they are on Linux. Double check that the folders and files have the correct case as if not it won't find them to auto load.
Rather than trying to upload via FTP which I think is going to be tricky if not impossible to get right, I would suggest you explore getting composer working on your hosting environment.
Composer is entirely PHP based, so should run anywhere that PHP is running.
If you don't have command line access, you can use something like PHPShell which gives you a PHP based command line on which you can then run Composer.
See this other SO answer to get some tips on how to use PHPShell.
Another option is to build a little PHP wrapper that you actually run by visiting it in your browser, in the classic PHP way. See this other SO answer for some tips on how to do that.
Bottom line, you should really look at getting Composer running on your server rather than trying to bodge it another way.
Once you have done your composer process on the server, you must remove the PHPShell or composer wrapper you created so that you don't leave any security holes.
Did you tell the composer where your Class 'AAA\Core\Tools' is?
You can even add your own code to the autoloader by adding an autoload field > to composer.json.
{
"autoload": {
"psr-4": {"Acme\\": "src/"}
}
}
Composer is not meant to be used that way (i.e. you shouldn't be manually transferring vendor directories from one environment to another).
As you add dependencies to your project, the composer.json file will contain those dependencies. When you run composer install or update on your localhost, it "locks" the current version of those dependencies for your project and stores them in the composer.lock file. You should be transferring the composer.json and composer.lock files from your development environment to your production environment and then running composer install on your production environment as part of your deployment process. When you run composer install on your production environment, Composer will look at your composer.lock file and install the specified versions of the dependencies in the vendor directory of the production environment.
You may want to review the composer documentation regarding basic usage (https://getcomposer.org/doc/01-basic-usage.md) and command line options (https://getcomposer.org/doc/03-cli.md) for more details.

Categories