Propel and Composer in PHP: no connection - php

I've problem in configuring Propel with Composer in my php project.
this is how appears my tree directory:
project/
|--/public_html/index.php
|--/app/
| |--data/
| | |--propel.json
| | |--schema.xml
| |--vendor/
| |--composer.json
In /data/ folder I would store all my propel files, that is generated-classes/ , generated-conf/ and generated-sql/ .
To realize this purpose, with a terminal in /data/ folder, I put the commands in the following sequence:
$ propel sql:build
$ propel model:build
$ propel config:convert
and all go right.
To make more suitable work, in composer.json I've added this extra feature:
"autoload": {
"classmap": ["./data/generated-classes/"]
}
so that, almost in theory, putting
require '../app/vendor/autoload.php';
inside index.php should be enough. Unfortunately, when I try to use one propel classes inside this page, returns the error
Type: Propel\Runtime\Exception\RuntimeException
Message: No connection defined for database "my_api". Did you forget to define a connection or is it wrong written?
File: 'C:\pathToMyProject'\project\app\vendor\propel\propel\src\Propel\Runtime\ServiceContainer\StandardServiceContainer.php
Line: 279
I thought that propel doesn't find the propel.json file stored in /data/folder.
As extra, if in index.php I simply add
require_once '../app/data/generated-conf/config.php';
all goes right.
There's a trick to autoload propel without use this last require_once? (obviously keep the tree as is).
Thanks for reading.

The order of CLI commands is important:
composer install or update to fetch propel
then the commands to generate the models with propel
then re-scan / re-generate the autoloading files with composer dump-autoload --optimize
You could include the configuration file in the bootstrap process of your application - like you already have.
Or you could use the files directive in Composers autoload section
to define file(s), which should be included on every request.
Referencing: https://getcomposer.org/doc/04-schema.md#files
"autoload": {
"files": ["./data/generated-conf/config.php"],
"classmap": ["./data/generated-classes/"]
}

Related

How write a Symfony Flex recipe for a new bundle?

I tried to find any documentation about using Symfony Flex but so far no luck.
Almost all docs point to installing a bundle that uses symfony Flex, not how to create a bundle that is using it.
I even tried to reverse engineer some of the packages but again, no luck.
My goal is to generate a default configuration file for my bundle in config/packages/my_bundle.yaml.
What I need to know is where do I need to put it and what env variables (if any) will I have available?
What is a Flex Recipe?
Keep in mind that the flex recipe is a separate repository from your package repository, that needs to be hosted separately from the Bundle package.
In the most likely scenario that your is a public bundle/recipe, you'll have to submit your recipe to the "contrib" repository, get it approved and merged, so it's available as a community recipe.
Additionally, it's important to remember that most users will not have the contrib repository enabled by default. So if this is important for installing this bundle, you should tell your users how to do so before they install your recipe (e.g. in your bundle's readme file).
Private Recipes
The other option would be having a private Flex recipe, as described here. The easiest way to generate a private recipe is to follow the same steps that Symfony does. Check this question and its answers for more details: How to generate a private recipe JSON from the contents of a recipe directory?
With that out of the way: Basically, a Flex recipe is a repository with a manifest.json file with specific keys to enable certain "configurators".
The available manifest.json configurators are:
Bundles
Which bundles should be enabled on bundles.php. These are added when the recipe is installed, and removed when the recipe is uninstalled.
{
"bundles": {
"Symfony\\Bundle\\DebugBundle\\DebugBundle": ["dev", "test"],
"Symfony\\Bundle\\MonologBundle\\MonologBundle": ["all"]
}
}
Configuration
The "configuration" configurator deals with two keys: copy-from-recipe and copy-from-package. The first one can copy files from the recipe repository, the second one copies files from the package repository.
{
"copy-from-package": {
"bin/check.php": "%BIN_DIR%/check.php"
},
"copy-from-recipe": {
"config/": "%CONFIG_DIR%/",
"src/": "%SRC_DIR%/"
}
}
In this example, a file bin/check.php in the package will be copied to the projects %BIN_DIR%, and the contents of config and src on the recipe package will be copied the corresponding directory.
This is the typical use case to provide default configuration files, for example. From what you ask, this is your stated purpose for wanting to create a flex recipe.
Env Vars
This configurator simply adds the appropriate environment variable values to the project's .env and .env.dist. (Again, these would be removed if you uninstalled the recipe)
{
"env": {
"APP_ENV": "dev",
"APP_DEBUG": "1"
}
}
Composer Scripts
This configurator adds tasks to the scripts:auto-scripts array from the project's composer.json. The auto-scripts are tasks that are executed every time composer update or composer install are executed in the project.
{
"composer-scripts": {
"vendor/bin/security-checker security:check": "php-script",
"make cache-warmup": "script",
"assets:install --symlink --relative %PUBLIC_DIR%": "symfony-cmd"
}
}
The second part on each line specifies what kind of command it is: a regular PHP script (php-script), a shell script (script), or a Symfony command (symfony-cmd, executed via bin/console).
Gitignore
This will add entries to the project's .gitignore file.
{
"gitignore": [
"/phpunit.xml"
]
}
A complete example of a manifest.json (lifted from here, as most other examples on this post):
{
"bundles": {
"Symfony\\Bundle\\FrameworkBundle\\FrameworkBundle": ["all"]
},
"copy-from-recipe": {
"config/": "%CONFIG_DIR%/",
"public/": "%PUBLIC_DIR%/",
"src/": "%SRC_DIR%/"
},
"composer-scripts": {
"make cache-warmup": "script",
"assets:install --symlink --relative %PUBLIC_DIR%": "symfony-cmd"
},
"env": {
"APP_ENV": "dev",
"APP_DEBUG": "1",
"APP_SECRET": "%generate(secret)%"
},
"gitignore": [
".env",
"/public/bundles/",
"/var/",
"/vendor/"
]
}
Additional configurators
There are two configurators which do not rely on the manifest.json file:
Post-install output.
If a file named post-install.txt exists in the recipe's package, its content is displayed when installation is complete. You can even use styles as defined here, for additional prettiness/obnoxiousness.
Example:
<bg=green;fg=white> </>
<bg=green;fg=white> Much success!! </>
<bg=green;fg=white> </>
* <fg=yellow>Next steps:</>
1. Foo
2. <comment>bar</>;
3. Baz <comment>https://example.com/</>.
This will be presented to the user after the installation is complete.
Makefile
If a file named Makefile exists in the recipe's repository, the tasks defined here would be added to the project's Makefile (creating the Makefile if it didn't exist).
cache-clear:
#test -f bin/console && bin/console cache:clear --no-warmup || rm -rf var/cache/*
.PHONY: cache-clear
Simple as that. I guess than most packages would not need a makefile command, so this would have much less use than other configurators.
You can read the full documentation here.

Changing vendor directory can't find files anymore using Symfony 3.4

I'm trying to change the directory of my dependencies on a Symfony 3.4 application.
I need that because I'm working on macOS with Docker and I'd rather have them not shared with the host since the file synchronization is too slow.
The related documentation, says:
The change in the composer.json will look like this:
{
"config": {
"bin-dir": "bin",
"vendor-dir": "/some/dir/vendor"
},
}
That I did
Then, update the path to the autoload.php file in app/autoload.php:
// app/autoload.php
// ...
$loader = require '/some/dir/vendor/autoload.php';
I don't have any autoload.php file in my app directory.
Am I missing something in the doc ?
The application generates the following fatal error:
Warning: require(/some/dir/vendor/symfony/symfony/src/Symfony/Component/VarDumper/Resources/functions/dump.php): failed to open stream: No such file or directory in /vendor/composer/autoload_real.php on line 66
Fatal error: require(): Failed opening required '/some/dir/vendor/symfony/symfony/src/Symfony/Component/VarDumper/Resources/functions/dump.php' (include_path='.:/usr/local/lib/php') in /vendor/composer/autoload_real.php on line 66
I originally created the application with:
$ composer create-project symfony/framework-standard-edition test "3.*"
Open your composer.json file in editor.
Look for "autoload-dev" section
Remove whole "files" part (if exist)
Save file
Run composer install once again
Enjoy the party.
Sample code:
"autoload-dev": {
"psr-4": {
"App\\Tests\\": "tests/"
},
"files": [
"vendor/symfony/symfony/src/Symfony/Component/VarDumper/Resources/functions/dump.php"
]
},
In Symfony 3.4, the file app/autoload.php is removed so you should:
replace old vendor path by the new vendor path directly in web/app.php, web/app_dev.php, bin/console and var/SymfonyRequirements.php files
Rerun the command $ composer install
I had the same issue and it was resolved doing the next.
Follow these 3 steps
1. First of all, modify composer.json to use the new vendor path:
"config": {
...,
"vendor-dir": "/app-vendor"
},
And remove the next line:
"files": ["vendor/symfony/symfony/src/Symfony/Component/VarDumper/Resources/functions/dump.php"]
2. Secondly, if you are using docker-compose add a new volume where you'll put your vendors.
volumes:
...
- /app-vendor
PD: /app-vendor is a mounted volume which is now empty directory.
3. Lastly, write require '/app-vendor/autoload.php'; to:
my_project_name/bin/console
my_project_name/web/app.php
my_project_name/web/app_dev.php
PD1: Simply, this line is pointing to the new vendor path.
PD2: It's not necessary to modify any other file (like var/SymfonyRequirements.php as I could read).
Check your changes
Once the changes are ready, remove vendor/ and also remove the containers to avoid future problems.
Start your new containers and execute composer install. Now, /vendor will be /app-vendor, it won't be in the root folder of the project anymore.
For more details, I'd recommend you to go to my docker-symfony repository and check the commits. You'll see a benchmark progression and another tips like cached volumes and non-shared /cache && /logs folders.
All for Symfony 3.4.

Symfony4 Error loading classes custom folder "Expected to find class... but it was not found"

Problem
I'm trying to setup a custom directory structure
for some shared classes in my Symfony project. I
want to create a custom folder in the root of my
project and I want to use the Symfony auto-load
feature to automatically register services from
that folder.
So I added a custom services namespace to the
services.yaml file:
# src ./config/services.yaml
services:
...
TestNamespace\:
resource: '../TestNamespace/*'
...
And I added an empty class in the custom folder:
# src ./TestNamespace/TestClass.php
namespace TestNamespace;
class TestClass
{
}
When I run the app I get the following error:
(1/2) InvalidArgumentException
Expected to find class "TestNamespace\TestClass" in file
"/path/to/ClassLoadErrorDemo/demo/TestNamespace/TestClass.php"
while importing services from resource
"../TestNamespace/*", but it was not found! Check the
namespace prefix used with the resource.
(2/2) FileLoaderLoadException
Expected to find class "TestNamespace\TestClass" in file
"/path/to/ClassLoadErrorDemo/demo/TestNamespace/TestClass.php" while
importing services from resource "../TestNamespace/*", but it was not
found! Check the namespace prefix used with the resource in
/path/to/ClassLoadErrorDemo/demo/config/services.yaml (which is loaded
in resource "/path/to/ClassLoadErrorDemo/demo/config/services.yaml").
I double checked the paths, namespace and the class
name multiple times and everything seems fine and I
don't understand why I still get the error.
Controllers in the ./src folder seem to load fine.
What am I doing wrong here?
Steps to reproduce
I created a demo repo to isolate the problem.
git clone https://github.com/smoelker/SymfonyClassLoadErrorDemo.git
cd SymfonyClassLoadErrorDemo/demo
composer install
mv TestNamespace/TestClass.php_ TestNamespace/TestClass.php
php bin/console server:start
Update your composer.json autoload setup
{
[...]
"autoload": {
"psr-4": {
"TestNamespace\\": "TestNamespace/",
"": "src/"
}
},
[...]
}
After run: composer dump-autoload and try again.
composer dump-autoload --classmap-authoritative will only work if your src directory is present at the time you run the command.
This can be an issue with multi-stage Docker builds in particular, when you are normally only copying the composer.json/composer.lock into the build image.

Making Legacy Application PSR-4 Compatible

I have a question with regards to refactoring a legacy PHP application to be compatible with PHP's PSR-4 standards. I have some classes located at app/classes/ folder which are not yet namespaced properly and I want them to be autoloaded directly when I call composer's vendor/autoload.php. I added a name space according to \<NamespaceName>(\<SubNamespaceNames>)*\<ClassName> and I have tried creating a vendor/myapp/classes/src/ directory under the vendor folder of composer, and executed a dump-autoload command but to no avail. The class doesn't get loaded up and composer can't figure out where to find it. Any pointers on how to do this?
Thanks,
Jan
Thing/s to Note:
-> I don't want to upload the source code to any repository that can be publicly searchable like Packagist as the code is for internal use only.
EDIT:
Here is my composer.json:
...
"autoload":{
"psr-4": {
"Myapp\\" : "Myapp"
}
},
...
But now the structure looks like:
->Myapp
-->Classes
--->Module1
---->submodule.php
--->Module2
---->submodule2.php
--->Module3
---->submodule3.php
--->Config
---->config.db.php
->vendor
-->autoload.php
Here are my issues/questions:
When I try to load submodule.php, which in turn would load submodule2.php and submodule3.php, it would tell me that submodule3.php is not found. The namespace of submodule3.php is Myapp\Classes\Module3 but it says its not found.
I want to include forcibly, config.db.php, on every call of autoload.php
I now figured it out. But the source files will not reside in the /vendor folder, which is okay for my case. If you want to make your files be autoloaded automatically no matter which folder, just add it to the psr-4 block in the composer.json, or create it if it's not yet there. In my composer.json, I have this block on the top level object, which adds the folder I want to get autoloaded and includes also the specific file I want to include, like a config file of some sorts:
...
"autoload":{
"files": [
"somefolder/somefile.php"
],
"psr-4": {
"MyApp\\" : "MyApp"
}
},
...
Which simply means that composer should autoload files residing in the MyApp directory which will also have a namespace of MyApp.
So my folder structure looks like this now:
->MyApp
-->Classes
--->MyClass1.php --> namespace MyApp\Classes classname: MyClass1
-->Components
--->MyClass2.php --> namespace MyApp\Classes classname: MyClass2
->somefolder
-->somefile.php
->vendor
-->autoload.php
->index.php
So if I want to include the file MyClass1.php in index.php, I will just add it like:
include_once( __DIR__ . "/vendor/autoload.php");
use \MyApp\Classes\MyClass1;
$foo = new MyClass1();
$foo->bar();
Hope it helps.
You could approach this by creating your own composer package, adding it to your private git repository, and adding the package to your project's composer.json file:
"require": {
"{your-vendor}/{package-name}": "dev-master"
},
"repositories": [
{
"type": "vcs",
"url": "git#bitbucket.org:{your-vendor}/{package-name}.git"
}
],
Once this is done, run composer update.

One shared vendor with two projects

I'm working on 2 applications right now. The first one is a CMS, and the second is a shop. I want to move my vendor one level above and the share it between projects.
So my structure will be something like this:
project1/
project2/
shared_vendor/
I read about this.
I have changed the app/autoload.php loader variable from:
$loader = require __DIR__.'/../vendor/autoload.php';
to:
$loader = require __DIR__.'/../../vendor/autoload.php';
And I have also changed vendor-dir in my composer.json from:
"config": {
"bin-dir": "bin",
"vendor-dir": "vendor"
},
to:
"config": {
"bin-dir": "bin",
"vendor-dir": "/../vendor"
},
And after this I'm getting this error:
ClassNotFoundException in AppKernel.php line 20: Attempted to load
class "CmsUserBundle" from namespace "Cms\UserBundle".
Did you forget a "use" statement for another namespace?
What am I doing wrong? Did I forget to change something?
Thanks in advance.
Composer works on a per project basis.
One project - one vendor folder. Not, two projects and one "shared" vendor folder.
We had the "shared" vendor folder approach with PEAR long enough and it simply didn't work out. Managing different project requirements with a global vendor folder is a pain, because every project has different requirements.
Anyway...
if you like the "shared vendor folder" setup, i would suggest to create something like a "wrapper" or "super" project, which acts as container repository for the two other projects. The wrapper project will contain the composer.json file with the requirements for both(!) projects. That means that you are working against the same set of dependencies in both sub-projects.
This allows to define requirements for both sub-projects (cms and shop)
in the "wrapper" repo. Basically, i'm suggesting the following structure:
|-container-project
+-CMS
|-src
+-tests
+-Shop
|-src
+-tests
+-vendors // contains dependencies for both projects (CMS + Shop)
|-composer.json // define requirements for both projects
This setup allows to introduce composer.json files for the subprojects, too.
You just have to transfer the requirements from the composer.json file of the super-project to the composer.json file of a subproject.
Now, it's also possible to tweak the autoloading behavior of the sub-projects by registering autoloaders in a specific order.
For Laravel 5, 6 and 7+
After adding the new vendor folder config:
...
"config": {
...,
"vendor-dir": "../vendor"
},
...
Then run composer update
Then you need to change two files:
For your app: public/index.php
require __DIR__.'/../../vendor/autoload.php';
Your artisan command in the root folder: artisan
require __DIR__.'/../vendor/autoload.php';
Package auto-discovery in Illuminate\Foundation\PackageManifest:
$this->vendorPath = $basePath.'/../vendor'; //Change this line in constructor
and rerun
php artisan package:discover --ansi
I know this is an old question but I run into the same problem. I'm using Laravel 7 and I solved the problem with the following method.
I wrote a shellscript (my-vendor.sh) at the root of my project with the following code :
#!/bin/bash
MY_VENDOR_DIRECTORY=my-vendor
VENDOR_DIRECTORY=vendor
if [ ! -d "$MY_VENDOR_DIRECTORY" ]
then
echo "Le dossier $MY_VENDOR_DIRECTORY n'existe pas : on le crée."
mkdir "$MY_VENDOR_DIRECTORY"
else
echo "Le dossier $MY_VENDOR_DIRECTORY existe : on le vide."
rm -rf "$MY_VENDOR_DIRECTORY/*"
fi
echo "Copie des fichiers autoload généré depuis $VENDOR_DIRECTORY vers $MY_VENDOR_DIRECTORY."
cp "$VENDOR_DIRECTORY/autoload.php" "$MY_VENDOR_DIRECTORY"
cp -R "$VENDOR_DIRECTORY/composer" "$MY_VENDOR_DIRECTORY"
cd "$MY_VENDOR_DIRECTORY/composer"
echo "Remplacement de 'require \$file' par \str_replace(\"$MY_VENDOR_DIRECTORY\/composer\/..\", \"vendor\", \$file)"
sed -i "s/require \$file/require \\str_replace('$MY_VENDOR_DIRECTORY\/composer\/..', 'vendor', \$file)/" autoload_real.php
echo "Remplacement de 'include \$file' par \str_replace(\"$MY_VENDOR_DIRECTORY\/composer\/..\", \"vendor\", \$file) "
sed -i "s/include \$file/require \\str_replace('$MY_VENDOR_DIRECTORY\/composer\/..', 'vendor', \$file)/" ClassLoader.php
Then, I replace the following code in public/index.php :
require __DIR__.'/../vendor/autoload.php' => by require __DIR__.'/../my-vendor/autoload.php';
After that, I add my-vendor.sh command in the post-autoload-dump scripts.
I made this modifications in my two projects, launch composer dump-autoload and it work like a charm :)
A link to the gist : https://gist.github.com/flibidi67/7c2cfdc1ff1b977b48204be0bee5eb76
Hope this can help someone else ;)
Based on your requirements and if the only thing you need/want to share between your multiple projects is the vendor directory, you could just create symlinks in each project except whatever the main one which already has the the vendor directory.
For example:
cd /var/www/SiteA
composer install
# git clone new project into /var/www/SiteB
cd ../SiteB
# If vendor directory is already there, delete it: rm -rf vendor
# create symlink to Site A's vendor directory
ln -s /var/www/SiteA/vendor
Unless you know for sure that all projects are definitely going to need exactly the same versions of your dependancies, this maybe not a good plan.

Categories