Unable to determine entity identifier for object of type "Namespace\Class"; no fields matching "id" - orm

I am trying to use ORM in my laminas api tools. Everything is working, however, looks like the api-tools-hal is not able to recognise the fields.
This is part of my module.config.php
'router' => [
'routes' => [
'customer.rest.customer' => [
'type' => 'Segment',
'options' => [
'route' => '/customer[/:customer_id]',
'defaults' => [
'controller' => 'Customer\\V1\\Rest\\Customer\\Controller',
],
],
],
],
'api-tools-hal' => [
'metadata_map' => [
\Customer\V1\Rest\Customer\CustomerEntity::class => [
'entity_identifier_name' => 'id',
'route_name' => 'customer.rest.customer',
'route_identifier_name' => 'customer_id',
'hydrator' => \Laminas\Hydrator\ObjectPropertyHydrator::class,
],
],
]
My Customer\V1\Rest\Customer\CustomerEntity::class
use Doctrine\ORM\Mapping as ORM;
/**
* CustomerEntity
* #ORM\Entity
* #ORM\Table(uniqueConstraints={
* #ORM\UniqueConstraint(name="email", columns={"email"}),
* })
* #ORM\Entity(repositoryClass="Customer\V1\Rest\Customer\CustomerRepository")
* #ORM\Table(name = "customers")
*/
class CustomerEntity
{
/**
* The unique auto incremented primary key.
*
* #var int|null
*
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
ORM cli command orm:schema-tool:create does works.
But upon going to domain.com/customer it throws this error:
Unable to determine entity identifier for object of type
"Customer\V1\Rest\CustomerType\CustomerEntity"; no fields
matching "id"
When I remove the ORM annotation in the entity then it works.
What do I need to do in this case?

Actually, no, that is not stupid ;). And please, don't make your id public since your have no reason to do it.
Another way to fix this is to create a couple of getter/setter. In this case, I would guess that a getter is enought. So simply make a public function getId(): ?int to fix the error, no need for a setter as you only need it to resolve the argument of a route.
public function getId(): ?int
{
return $this->id;
}
Small tips: if you use PHPStorm, simply press Alt + Inser and then Getter to generate quickly this ;)

Ok, so I need to make my fields public.
protected $id; becomes public $id then it works.
This is just me being stupid. Learning is good.

Related

Declaration of ... must be compatible with

I'm using this Yii2 plugin for my user model
https://yii2-usuario.readthedocs.io/en/latest/
In my main.php i have this.
'user' => [
'class' => Da\User\Module::class,
'enableEmailConfirmation' => true,
'classMap' => [
'User' => 'app\models\user\Model\User',
'SocialNetworkAccount' => 'app\models\user\Model\SocialNetworkAccount',
],
then in the directory models/user/Model i have this
namespace app\models\user\Model;
use Yii;
use app\models\user\Model\User;
use Da\User\Model\SocialNetworkAccount as BaseClass;
class SocialNetworkAccount extends BaseClass
{
public function connect(User $user)
{
return $this->updateAttributes(
[
'username' => null,
'firstname' => $user->firstname,
'lastname' => $user->lastname,
'email' => null,
'code' => null,
'user_id' => $user->id,
]
);
}
}
but when i go to my login page i get this error
Declaration of app\models\user\Model\SocialNetworkAccount::connect(app\models\user\Model\User $user) must be compatible with Da\User\Model\SocialNetworkAccount::connect(Da\User\Model\User $user)
i tried following the tutorial here to override classes, but no luck
https://yii2-usuario.readthedocs.io/en/latest/enhancing-and-overriding/overriding-classes/
what am i doing wrong here? thanks
UPDATE:
i tried this
public function connect(\Da\User\Model\User $user)
don't get the error anymore, but now i noticed it doesn't add firstname and lastname
in my user model rules i have this
public function rules()
{
return [
...
[['email', 'firstname', 'lastname'], 'safe'],
]
}
From what you've described it looks like usuario is using DI container to create the User class instance when calling the connect() method.
When overriding it you have to follow the rule that preconditions cannot be strengthened in a subtype. That means that you can't typehint the parametr with the subclass of what the original method uses as its parametr. Your connect method definition must look like what you've posted in your question:
public function connect(\Da\User\Model\User $user)
But because of that, the dependency injector is creating an instance of Da\User\Model\User when calling connect() method. So, what you've missed is setting the DI container to create instance of app\models\user\Model\User whenever it's supposed to create instance of Da\User\Model\User like this:
'container' => [
'definitions' => [
Da\User\Model\User::class => app\models\user\Model\User::class,
],
],
Of course, for this to work your app\models\user\Model\User class must extend the Da\User\Model\User class.
There is a complete example how to override usuario's User model in usuario's documentation

EasyAdmin 3 Symfony 5 CrudController AssociationField

I'm using EasyAmdin 3 with Symfony 5 and I have a OneToMany relation between Challenge and Encadrement. Defined In Challenge.php:
/**
* #ORM\OneToMany(targetEntity=Encadrement::class, mappedBy="challengePartner")
*/
private $bornes;
I made a CRUDController for Challenge, and I want to be able to add Encadrement directly when creating/editing a Challenge. I did this :
AssociationField::new('bornes'),
I can choose between all the Encadrement already created. But what I want is to be able to multiple add Encadrement and I can't find how to do this. I tried making my own EncadrementType :
class EncadrementType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', TextType::class, array(
"label" => "Nom"
))
->add('low', IntegerType::class, array(
"label" => "Borne basse"
))
->add('high', IntegerType::class, array(
"label" => "Borne haute"
))
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Encadrement::class,
]);
}
}
And something like this in the ChallengeCRUD:
AssociationField::new('bornes')->setFormType(EncadrementType::class),
But I get this error when I don't even use those options:
An error has occurred resolving the options of the form "App\Form\EncadrementType": The options "class", "multiple", "query_builder" do not exist. Defined options are: "action", "allow_extra_fields", "allow_file_upload", "attr", "attr_translation_parameters", "auto_initialize", "block_name", "block_prefix", "by_reference", "compound", "constraints", "csrf_field_name", "csrf_message", "csrf_protection", "csrf_token_id", "csrf_token_manager", "data", "data_class", "disabled", "ea_crud_form", "empty_data", "error_bubbling", "error_mapping", "extra_fields_message", "getter", "help", "help_attr", "help_html", "help_translation_parameters", "inherit_data", "invalid_message", "invalid_message_parameters", "is_empty_callback", "label", "label_attr", "label_format", "label_html", "label_translation_parameters", "legacy_error_messages", "mapped", "method", "post_max_size_message", "property_path", "required", "row_attr", "setter", "translation_domain", "trim", "upload_max_size_message", "validation_groups".
I tried adding the multiple option to the AssociationField but it does nothing:
AssociationField::new('bornes')->setFormTypeOption("multiple","true"),
I'm stuck there, thanks for any help !
Try CollectionField like this:
<?php
yield CollectionField::new('bornes')
->setFormTypeOptions([
'delete_empty' => true,
'by_reference' => false,
])
->setEntryIsComplex(false)
->setCustomOptions([
'allowAdd' => true,
'allowDelete' => true,
'entryType' => EncadrementType::class,
'showEntryLabel' => false,
])
;

error in Laravel8: SQLSTATE[42S02]: Base table or view not found: 1146 Table

I have started a new project with Laravel 8.
I use the starter kit Laravel Breeze.
But I can't customize fields.
I have changed fields in the migration and Register Controller and User model.
here is my code:
migration file.
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class TblUsers extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('tbl_users', function (Blueprint $table) {
$table->id();
$table->string('fullname');
$table->string('username');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('phone');
$table->string('organization_type');
$table->string('community_dev_auth_id');
$table->string('file_names');
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('tbl_users');
}
}
register controller file.
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Models\User;
use App\Providers\RouteServiceProvider;
use Illuminate\Auth\Events\Registered;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
class RegisteredUserController extends Controller
{
/**
* Display the registration view.
*
* #return \Illuminate\View\View
*/
public function create()
{
return view('auth.register');
}
/**
* Handle an incoming registration request.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\RedirectResponse
*
* #throws \Illuminate\Validation\ValidationException
*/
public function store(Request $request)
{
$request->validate([
'fullname' => 'required|string|max:255',
'username' => 'required|string|max:255',
'email' => 'required|senter code heretring|email|max:255|unique:users',
'phone' => 'required|string|max:255',
'organization' => 'required|string|max:255',
'community' => 'required|string|max:255',
// 'phone' => 'required|string|max:255',
'password' => 'required|string|min:8',
]);
Auth::login($user = User::create([
'fullname' => $request->fullname,
'username' => $request->username,
'email' => $request->email,
'phone' => $request->phone,
'organization_type' => $request->organization,
'community_dev_auth_id' => $request->community,
'password' => Hash::make($request->password),
]));
event(new Registered($user));
return redirect(RouteServiceProvider::HOME);
}
}
user model file.
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'fullname',
'username',
'email',
'phone',
'organization',
'community',
'password',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
}
I have run this project, but it returns this error:
SQLSTATE[42S02]: Base table or view not found: 1146 Table
'ambulance_dubai.users' doesn't exist (SQL: select count(*) as
aggregate from users where email = asdf#sdf.df)
Since you are using a different table name for the user model you have to define it in your model. By default, Laravel will look for the plural name
of a model(users) if your model doesn't have a table property.
Add this to the user model:
protected $table='tbl_user';
first, you will check user table was migrate, the user table not to be migrated
use this command
php artisan migrate
Open your User Model
and add $table
class User extends Authenticatable {
protected $table = 'users';
}
Another cause could be that the validation has a different name for the table. For example, having the table tbl_users in the validation could exist an error and have:
'required|unique:tbl_user,email'.
The letter "s" is missing and the error would be thrown.
`
return [
//
'name' => 'required',
'image' => 'required',
'email' => 'required|unique:users,email',
'username' => 'required|unique:users,username',
'password' => 'required|min:8',
];
`
Where you see users should correspond to your table name in the database.
This is under validation.

Codeception add new JsonTypes

I wonder if it's possible to define some custom JsonType for validation API responses through seeResponseMatchesJsonType method. I mean, let's suppose I have response with a structure:
[
'id' => 'integer',
'name' => 'string',
'address' => [
'street' => 'string',
'city' => 'string'
]
]
Obviously this structure has complex type address embedded and in the whole app such type might be used several times so I would like to write simply:
$I->seeResponseMatchesJsonType([
'id' => 'integer',
'name' => 'string',
'address' => 'addressType'
]);
Without rewriting this embedded structure all the time. How can I achieve it in Codeception?
Yes you can do this by using method addCustomFilter from \Codeception\Util\JsonType class.
/**
* Adds custom filter to JsonType list.
* You should specify a name and parameters of a filter.
*
* Example:
*
* ```php
* <?php
* JsonType::addCustomFilter('email', function($value) {
* return strpos('#', $value) !== false;
* });
* // => use it as 'string:email'
*
* // add custom function to matcher with `len($val)` syntax
* // parameter matching patterns should be valid regex and start with `/` char
* JsonType::addCustomFilter('/len\((.*?)\)/', function($value, $len) {
* return strlen($value) == $len;
* });
* // use it as 'string:len(5)'
* ?>
* ```
*
* #param $name
* #param callable $callable
*/
public static function addCustomFilter($name, callable $callable)
{
static::$customFilters[$name] = $callable;
}

How to use yii2-user as sub-module inside another module

I want to implement one module in an existing application.In that module I am trying to use yii2-user module.The yii2 docs say we can do that.
namespace app\modules\forum;
class Module extends \yii\base\Module
{
public function init()
{
parent::init();
$this->modules = [
'admin' => [
// you should consider using a shorter namespace here!
'class' => 'app\modules\forum\modules\admin\Module',
],
];
}
}
I have module code as
namespace app\modules\cdas;
class cdas extends \yii\base\Module
{
public $controllerNamespace = 'app\modules\cdas\controllers';
public function init()
{
parent::init();
// custom initialization code goes here
$this->modules = [
'user' => [
'class' => 'dektrium\user\Module',
'modelMap' => [
'Profile' => 'app\modules\cdas\models\users\Profile',
'User'=>'aapp\modules\cdas\models\users\User',
],
'controllerMap' => [
'settings' => 'app\modules\cdas\controllers\user\SettingsController',
'admin' => 'app\modules\cdas\controllers\user\AdminController',
'role' => 'app\modules\cdas\controllers\user\RoleController',
'security' => 'app\modules\cdas\controllers\user\SecurityController',
],
];
}
}
But when I use the above methodology and try to access
http://localhost/<app_name>/web/cdas/user/security/login
I get the following error
PHP Notice – yii\base\ErrorException
Trying to get property of non-object
in ....vendor\dektrium\yii2-user\views\_alert.php
/**
* #var $module dektrium\user\Module
*/
<?php if ($module->enableFlashMessages): ?>
Please suggest proper way to implement the sub-module.