Use entities from composer package in api platform - api-platform.com

As we use the entities in multiple projects we have required our entities via composer.
All the stuff that would normally be in the annotations I have written into a yaml file.
But I don't get any routes shown in the frontend or the swagger documentation.
I have found the following configuration: api_platform.resource_class_directories
But you have to set a directory there. I would not really like to have a hardcoded path like vendor/my-company/my-entity-package/src/Entity.
So how do I solve this issue?
Is there a magic variable in symfony like the %kernel.project_dir% which points to the vendor directory?
Did I forget to set some configuration?

I was able to get this working by extending the classes of my composer package.
So in api/src/Entity/Order.php I have the following:
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use Company\ComposerPackage\Entity\Order as ComposerOrder;
use Doctrine\ORM\Mapping as ORM;
/**
* #ApiResource()
* #ORM\Entity
*/
class Order extends ComposerOrder
{
/**
* #var int The id of this order entity.
*
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
}
For some reason api-platform was not recognizing the id property and it's annotations so I had to copy it to the child class.
The entity in the composer package also needed a change for this to work:
namespace Company\ComposerPackage\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\MappedSuperclass
*/
class Order
{
// all properties are defined here including the #ORM, #Assert etc. annotations
}
I had to add the #ORM\MappedSuperclass annotation.
The #ORM\HasLifecycleCallbacks annotation also had to be done in the childclass for some reason. Also if you have additional configuration for the table e.g. table name or unique constraints these also have to be added to the child class.

Related

"AuthenticatorInterface" not found on Security\Guard, Symfony 6.2

I'm trying to create a custom Token authenticator for my Symfony 6.2 and API Platform project
class TokenAuthenticator extends JWTTokenAuthenticator
{
/**
* #param PreAuthenticationJWTUserToken $preAuthToken
* #param UserProviderInterface $userProvider
* #return UserInterface
*/
public function getUser($preAuthToken, UserProviderInterface $userProvider): UserInterface
{
$user = parent::getUser($preAuthToken, $userProvider);
var_dump($preAuthToken->getPayload());exit;
}
}
But I always get this error:
Attempted to load interface "AuthenticatorInterface" from namespace "Symfony\Component\Security\Guard".
Did you forget a "use" statement for "Symfony\Component\Security\Http\Authenticator\AuthenticatorInterface"?
that means, there's no AuthenticatorInterface on Security\Guard and Http\Authenticator replaces it, so the LexikJWTAuthenticationBundle must be updated to include the new change.
This new class contains new functions so is there any documentation regarding them? Also, the purpose of establishing this class TokenAuthenticator is to make the old token invalid when changing the password, so is there a better way to do this?

Doctrine - Set $id as UUID instead of Integer when creating new entity

I am working on a new project in Symfony 5.3. I am using this command bin/console make:entity for creating entities.
This wizard automatically creates an entity with $id as primary key of type integer. I am prefering UUID instead of integer.
How I should change settings to get Entity like this?
Thank you
namespace App\Entity;
use App\Repository\EventRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
/**
* #ORM\Entity(repositoryClass=EventRepository::class)
*/
class Event
{
/**
* #ORM\Id
* #ORM\Column(type="uuid", unique=true)
* #ORM\GeneratedValue(strategy="CUSTOM")
* #ORM\CustomIdGenerator(class=UuidGenerator::class)
*/
private $id;
...
}
There is no option to set the generated identifier strategy on make entity.
You can see all available option using php bin/console make:entity -h
Also there are no configuration in doctrine.yaml file to define this.
It could be a good feature to add for current and next version
To request a new feature, you can create a new issue feature request type:
https://github.com/symfony/symfony/issues/new/choose
You will need a github account

How i can extend laravel translator (any other component)?

I want to implement some extra features to Illuminate\Translate\Translator.
So, i create my folder in ~/vendor directory, place there My/Traslator class, that will implement Symfony\Component\Translation\TranslatorInterface. Right?
Is it OK to extend laravel translator class (a lot of functionality will be duplicated otherwise) in my package?
If it is ok - it will be necessary to tie to current laravel version to keep code stable. But what will happen in case enduser laravel version will differ from one required in my package?
What should i do then to make laravel use my translator class in application (facades,etc)?
Make a Translator class and make it extend Illuminate\Translation\Translator
<?php
namespace App\Helpers;
use Illuminate\Translation\Translator as LaravelTranslator;
class Translator extends LaravelTranslator
{
// here you can overwrite any functions you want/need
}
Create your own TranslationServiceProvider inside app/providers (just copy the laravel translation service provider and change the line where it uses Translator with your own Translator class where you have overwritten what you needed)
<?php
namespace App\Providers;
use App\Helpers\Translator; // <= Your own class
use Illuminate\Translation\FileLoader;
use Illuminate\Support\ServiceProvider;
class TranslationServiceProvider extends ServiceProvider
{
/**
* Register the service provider.
*
* #return void
*/
public function register()
{
$this->registerLoader();
$this->app->singleton('translator', function ($app) {
$loader = $app['translation.loader'];
// When registering the translator component, we'll need to set the default
// locale as well as the fallback locale. So, we'll grab the application
// configuration so we can easily get both of these values from there.
$locale = $app['config']['app.locale'];
$trans = new Translator($loader, $locale);
$trans->setFallback($app['config']['app.fallback_locale']);
return $trans;
});
}
/**
* Register the translation line loader.
*
* #return void
*/
protected function registerLoader()
{
$this->app->singleton('translation.loader', function ($app) {
return new FileLoader($app['files'], $app['path.lang']);
});
}
/**
* Get the services provided by the provider.
*
* #return array
*/
public function provides()
{
return ['translator', 'translation.loader'];
}
}
Comment out or delete the Laravels translator service line inside config/app.php:
//Illuminate\Translation\TranslationServiceProvider::class,
Add your own Provider in that same array
App\Providers\TranslationServiceProvider::class,
This page has more information: http://laravel.com/docs/5.0/extending#container-based-extension
So what you need to do is:
Extend the built-in class from the vendor directory
Create a new service provider that add your translation class to the service container
Replace Laravel’s translation service provider in your config/app.php file with the namespace of your translation service provider
Now when you ask for the translation service provider out of the service container—either directly (app('translator')) or with the Lang façade, it will return your translation class rather than Laravel’s.

Subclassing Migrator not working for namespaced migration

I have some namespaced migrations, and I can't get past the Class Not Found errors due to namespacing. In an earlier question, Antonio Carlos Ribeiro stated:
Laravel migrator doesn't play nice with namespaced migrations. Your best bet in this case is to subclass and substitute the Migrator class, like Christopher Pitt explains in his blog post: https://medium.com/laravel-4/6e75f99cdb0.
I have tried doing so (followed by composer dump-autoload, of course), but am continuing to receive Class Not Found errors. I've got the project files set up as
inetpub
|--appTruancy
|--database
|--2015_04_24_153942_truancy_create_districts.php
|--MigrationsServiceProvider.php
|--Migrator.php
The migration file itself is as follows:
<?php
namespace Truancy;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class TruancyCreateDistricts extends Migration {
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('districts', function($table) {
$table->string('id')->unique()->primary()->nullable(false);
$table->string('district');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::drop('districts');
}
}
Migrator.php is as follows:
namespace Truancy;
use Illuminate\Database\Migrations\Migrator as Base;
class Migrator extends Base{
/**
* Resolve a migration instance from a file.
*
* #param string $file
* #return object
*/
public function resolve($file)
{
$file = implode("_", array_slice(explode("_", $file), 4));
$class = "Truancy\\" . studly_case($file);
return new $class;
}
}
MigrationServiceProvider.php is as follows:
<?php
namespace Truancy;
use Illuminate\Support\ServiceProvider;
class TruancyServiceProvider extends ServiceProvider{
public function register()
{
$this->app->bindShared(
"migrator",
function () {
return new Migrator(
$this->app->make("migration.repository"),
$this->app->make("db"),
$this->app->make("files")
);
}
);
}
}
The lines generated in autoload_classmap.php are as expected:
'Truancy\\Migrator' => $baseDir . '/appTruancy/database/migrations/Migrator.php',
'Truancy\\TruancyCreateDistricts' => $baseDir . '/appTruancy/database/migrations/2015_04_24_153942_truancy_create_districts.php',
'Truancy\\TruancyServiceProvider' => $baseDir . '/appTruancy/database/migrations/MigrationsServiceProvider.php'
I'm calling php artisan migrate --path="appTruancy/database/migrations" and I receive the error:
PHP Fatal error: Class 'TruancyCreateDistricts' not found in
C:\inetpub\laravel\vendor\laravel\framework\src\Illuminate\Database
\Migrations\Migrator.php on line 297
I know I must be doing something dumb (my instinct is $class = "Truancy\\" . studly_case($file); in Migrator.php is wrong), but I can't unscrew this lightbulb. The migrate command is obviously successfully finding my migrations file, and the correct classname is in the classmap, so it has to be somewhere in the process of resolving the classname itself from the file, which the subclass and substitution is supposed to address. Any suggestions as to where I've gone wrong?
Ok, I've gotten this working. It turns out that the Medium.com article assumes you'd just know where to put the files he talks about, which I didn't. I've made several changes, and now everything is working correctly:
I created a new appTruancy\providers subfolder, and add it to composer.json
I moved both Migrator.php and MigrationServiceProvider.php into the new folder
I changed the namespace in both of those files to Truancy\Providers to match the directory structure
I added 'Truancy\Providers\MigrationsServiceProvider' to the providers array in appTruancy\config\app.php
I added a \ in front of Schema in the migration file to reference the base namespace.
I ran dump-autoload to update the classmap
This is one of those cases where I'm not 100% certain that all of the changes were required, but the layout does make sense so I'm happy with it. So, in a nutshell, if you're trying to namespace your migrations, you need to subclass the Migrator class as described in the Medium.com article listed above, but you then need to register the service provider in config\app, making sure the class names in both files are consistent.

Doctrine + CodeIgniter: after generate entities with namespace, "cannot redeclare class" on schema create

I'm trying to generate both entities and the database schema with Doctrine under CodeIgniter 2.0, using annotations. I'm not sure if I'm doing this correctly.
I've setup base classes which have only the classname and properties defined, and then annotated. I'm trying to use the generate-entities command to have it create the get/set methods.
<?php
namespace Entities;
include('ContentItem.php');
/**
* #Entity
* #Table(name="blobs")
*/
class Blob extends ContentItem {
/**
* #var ContentItemId
*
* #ManyToOne(targetEntity="ContentItem")
* #JoinColumn(name="contentitem_id", referencedColumnName="id")
*/
protected $contentitem;
/**
* #Column(type="string", length=64, nullable=true)
*/
protected $content;
/**
* #Column(name="date_created", type="datetime", nullable=false)
*/
protected $date_created;
/**
* #Column(type="datetime", nullable=false)
*/
protected $date_updated;
}
This file is located in a folder named 'models'. If I run the command 'orm:generate-entities models', then it creates new classes inside of '/models/Entities' folder. This only happens because of the 'namespace Entities' declaration. If I run 'orm:schema-tool:create' to try and create my database schema, I get: "Fatal error: Cannot redeclare class Entities\Blob in /Users/rw3iss/Sites/ci/application/models/Entities/Blob.php on line 11".
This is happening because the generated 'models/Entities' classes inherit the namespace from the files they're generated from in the parent 'models' folder, hence the dual class conflict.
Now if I remove the namespace declaration from the parent files, and call generate entities, passing 'models/Entities' as the destination, I get the same file layout. Except then, when trying to use the models in my code:
$blob = new Entities\Blob;
this throws the same error, obviously because there are still two classes with the same name, without a namespace.
I have declared the Entities class loader like this:
$entityClassLoader = new \Doctrine\Common\ClassLoader('Entities', APPPATH.'models');
So my question is:
Is there anyway to generate these entity classes from a basic class (which has my annotations declared for the class and properties), preserving namespaces, so that I can still instantiate them using 'new Entities\Blob'? If there was even a way to tell the generated classes to use a different namespace from the file's they're generated from, that would be fine. I'd like to setup basic properties, and have the 'generate entities' command create my get/set methods for me. It seems that whenever I use namespaces, it will auto-create the classes inside of the namespace subfolders, and then I get the 'cannot redeclare class' error.
Maybe I'm doing something fundamentally wrong...
Thanks for any help!
UPDATE: Solution:
I may have gotten it working by putting the Entities folder side by side with my models folder. If I change the Entities ClassLoader to point to just 'APPPATH', and then instantiate my Entities using 'new Entities\Blob', then that works.
It seems like there is no way to put the Entities folder as a subfolder within the models folder without it complaining in some way. If anyone know of a way to do this, I'd be interested to hear.
i got the same problem. That's because you specify a subfolder in the command.
Just type : "orm:generate-entities ." (without quotes)
"." is meaning actual folder.
I have this working with entities and models in two different subfolders. Here is how i processed :
my files structure :
+ framework (root folder)
index.php
+ entities (model folder)
Formation.php
+ repositories (repositories folder)
FormationRepository.php
+ controllers ( controllers folder)
HomeController.php
in index.php :
require 'vendor/doctrine/common/lib/Doctrine/Common/ClassLoader.php';
$entitiesLoader = new ClassLoader('entities', __DIR__);
$entitiesLoader->setFileExtension('.php'); // not necessary, i think that .php is set by default
$entitiesLoader->register();
// registering entities repositories classloader
$repositoriesLoader = new ClassLoader('entities\repositories', __DIR__);
$repositoriesLoader->setFileExtension('.php');
$repositoriesLoader->register();
here is an entity : (Formation.php)
// Formation.php
<?php
namespace entities;
/**
* #Entity(repositoryClass="entities\repositories\FormationRepository")
* #Table(name="formations")
*/
class Formation
{
....
here is how i use it : (in HomeController.php)
// in HomeController.php
<?php
// if i need it directly :
use entities\Formation;
$formation = new Formation();
// if i want to use it with its repository (and Doctrine)
$formation = $this->getApp()->getDbConnection()->getRepository('entities\Formation')->findOneById(1);
pay attention to "getRepository('entities\Formation')". My mistake was to not specifying the namespace "entities\" before the name of the entity.

Resources