I'm making a command in Laravel 7 that creates some migrations in a folder inside database/migrations and a seeder. Then, it runs dumpAutoloads() to make sure that the created migrations and seeder are registered in the autoload classmap. Then, my command calls the php artisan migrate command and consecutively the php artisan db:seed command with the --class flag to only seed the created seeder.
Everything runs fine until the db:seed command is called. The seeder is indeed created, but it keeps throwing me the next exception:
Illuminate\Contracts\Container\BindingResolutionException
Target class [StudentOperationTypesSeeder] does not exist
This is obviously just an example, but I have checked that the name of the created Seeder is exactly the same as the one the exception shows and it matches. Also, just after this exception is thrown to me, I run by myself the db:seed --class=StudentOperationTypesSeeder command and it works!
This makes me think that maybe the autoload classmap isn't updated until the process of the command is finished or something... I really have no idea.
My code is the following:
TimeMachineGeneratorCommand.php
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB;
class TimeMachineGeneratorCommand extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'time-machine:generate {table_name}';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Generates the tables and structure of a time machine for the given table.';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
// Convierte a snake case singular el nombre de la entidad.
$entity = Str::singular(
Str::snake(class_basename($this->argument('table_name')))
);
// Revisa que el nombre del modelo esté en el formato adecuado.
$modelName = Str::singular(
Str::studly($this->argument('table_name'))
);
$seederClassName = "{$modelName}OperationTypesSeeder";
// Crea las migraciones para la estructura de la máquina del tiempo.
$this->createMigrations($entity);
// Genera el Seeder del los operation types básicos.
$this->createSeeder($seederClassName);
// Para asegurarse que las migrations y el seeder está registrada en
// los class loaders se ejecuta el dump-autoload.
$this->line("<fg=yellow>Dumping Autoloads...</>");
$this->laravel->composer->dumpAutoloads();
$this->info("Autoloads dumped.");
// Ejecuta las migraciones.
$this->call('migrate', [
'--path' => '/database/migrations/'.Str::plural(Str::snake($modelName)).'/'
]);
// Ejecuta el seeder recién creado.
$this->call('db:seed', [
'--class' => $seederClassName
]);
(...) // <-- Some other code that isn't executed because of the exception
}
/**
* Genera los archivos de código de las migraciones necesarias
* para la estructura de la máquina del tiempo.
*/
private function createMigrations($entity)
{
// Genera la migración para los tipos de operación de la entidad.
$this->call('time-machine:operation-type-migration', [
'entity' => $entity
]);
// Genera la migración para los logs de la entidad.
$this->call('time-machine:log-migration', [
'entity' => $entity
]);
// Genera la migración para los logs de la entidad.
$this->call('time-machine:required-fields-migration', [
'entity' => $entity
]);
}
/**
* Crea el seeder de operationt types basado en el
* template diseñado para la máquina del tiempo.
*
* #param string | $seederClassName | El nombre de la clase para el seeder.
* #return void.
*/
private function createSeeder($seederClassName)
{
$this->call('time-machine:seeder', [
'name' => $seederClassName
]);
// Agrega el seeder recién creado al DatabaseSeeder.php.
$this->updateDatabaseSeeder($seederClassName);
}
/**
* Agrega el seeder recién creado al DatabaseSeeder.php.
*
* #var $seederClassName.
* #return void.
*/
private function updateDatabaseSeeder($seederClassName)
{
$filePath = base_path().'\\database\\seeds\\DatabaseSeeder.php';
// Lee el archivo del DataBaseSeeder.
$seeder = file_get_contents($filePath);
// Si el seeder no ha sido agregado ya al DatabaseSeeder.php...
if(preg_match('/\$this\-\>call\('.$seederClassName.'\:\:class\)\;/', $seeder) == 0) {
// Agrega el seeder recién creado.
$newContent = preg_replace(
'/public function run\(\)\s*\{/',
"public function run()
{
\$this->call({$seederClassName}::class);",
$seeder, 1
);
// Guarda el contenido del archivo.
file_put_contents($filePath, $newContent);
$this->info('Seeder added to DatabaseSeeder.php.');
} else {
$this->error('Seeder is already in DataBaseSeeder.php.');
}
}
}
Also, this is the autoload section of my composer.json (I read there may be something with that or something, I couldn't find a solution for my issue anyway).
"autoload": {
"psr-4": {
"App\\": "app/"
},
"classmap": [
"database/seeds",
"database/factories"
]
},
StudentOperationTypesSeeder.php
<?php
use Illuminate\Database\Seeder;
class StudentOperationTypesSeeder extends Seeder
{
/**
* Run the database seeds.
*
* #return void
*/
public function run()
{
$studentOperationType = new \App\StudentOperationType();
$studentOperationType->description = "Created";
$studentOperationType->save();
$studentOperationType = new \App\StudentOperationType();
$studentOperationType->description = "Updated";
$studentOperationType->save();
$studentOperationType = new \App\StudentOperationType();
$studentOperationType->description = "Deleted";
$studentOperationType->save();
}
}
Please help. The command generates succesfully the migrations and the seeder, then runs the migrations and everything works exactly as intended, except for the seeder and I haven't find why.
Note: The other "time-machine" commands that I call in the functions of the TimeMachineGeneratorCommand.php are other custom commands that I created that literally only extend the existing migration commands of the vendor and change the stub to a custom one.
I followed the approach that lagbox suggested and found something that works.
I included the generated file adding the next line of code before calling the bd:seed command, obviously after the line that generates the seeder.
include base_path()."\\database\\seeds\\".$seederClassName.".php";
After doing this the seeder is executed correctly and the whole command works just as expected.
The final handle method looks as follows.
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
// Convierte a snake case singular el nombre de la entidad.
$entity = Str::singular(
Str::snake(class_basename($this->argument('table_name')))
);
// Revisa que el nombre del modelo esté en el formato adecuado.
$modelName = Str::singular(
Str::studly($this->argument('table_name'))
);
$seederClassName = "{$modelName}OperationTypesSeeder";
// Crea las migraciones para la estructura de la máquina del tiempo.
$this->createMigrations($entity);
// Genera el Seeder del los operation types básicos.
$this->createSeeder($seederClassName);
// Para asegurarse que las migrations y el seeder está registrada en
// los class loaders se ejecuta el dump-autoload.
$this->line("<fg=yellow>Dumping Autoloads...</>");
$this->laravel->composer->dumpAutoloads();
$this->info("Autoloads dumped.");
// Ejecuta las migraciones.
$this->call('migrate', [
'--path' => '/database/migrations/'.Str::plural(Str::snake($modelName)).'/'
]);
include base_path()."\\database\\seeds\\".$seederClassName.".php";
// Ejecuta el seeder recién creado.
$this->call('db:seed', [
'--class' => $seederClassName
]);
(...) // <-- Some other code that isn't executed because of the exception
}
Related
I have a problem with Oauth2. It returns me as error "Invalid state parameter passed in callback URL."
I'm on symfony 6
I don't know where this can come from, in localhost everything works but in production I have this error.
I looked everywhere for a solution without finding anything.
knpu_oauth2_client.yaml
knpu_oauth2_client:
clients:
azure:
type: azure
client_id: '%env(OAUTH_AZURE_CLIENT_ID)%'
client_secret: '%env(OAUTH_AZURE_CLIENT_SECRET)%'
redirect_route: connect_azure_check
redirect_params: {}
# scope: {}
tenant: '%env(AZURE_TENANT_ID)%'
security.yaml
security:
enable_authenticator_manager: true
# https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords
# https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
providers:
# used to reload user from session & other features (e.g. switch_user)
users_in_memory: { memory: null }
my_provider:
entity: {class: App\Entity\User, property: uuid}
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
lazy: true
provider: my_provider
custom_authenticators:
- App\Security\AzureAuthenticator
logout: true
# activate different ways to authenticate
# https://symfony.com/doc/current/security.html#firewalls-authentication
# https://symfony.com/doc/current/security/impersonating_user.html
# switch_user: true
# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
access_control:
- { path: ^/connect/azure, role: PUBLIC_ACCESS }
- { path: ^/, roles: ROLE_USER}
AzureController.php
<?php
namespace App\Controller;
use KnpU\OAuth2ClientBundle\Client\ClientRegistry;
use League\OAuth2\Client\Provider\Exception\IdentityProviderException;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
class AzureController extends AbstractController
{
/**
* Cette fonction effectue la connexion avec Azure
* Ex: Si vous allez sur cette route, un formulaire microsoft vous demandera de vous connecter
*/
#[Route('/connect/azure', name: 'connect_azure', )]
public function connectAction(ClientRegistry $clientRegistry)
{
return $clientRegistry
->getClient('azure')
->redirect([
'openid', 'profile', 'email'
], []);
}
/**
* Cette fonction permet de savoir si l'authentification à réussi
* Ex: Après vous être connecté ci-dessus, vous serez rediriger sur cette route qui vous redirigera à son tour vers la route home
*/
#[Route('/connect/azure/check', name: 'connect_azure_check', schemes:['http'])]
public function connectCheckAction(Request $request, ClientRegistry $clientRegistry)
{
try {
return $this->redirectToRoute('home');
} catch (IdentityProviderException $e) {
return new JsonResponse(array('status' => false, 'message' => "User not found!", 'error' => $e->getMessage()));
}
}
}
AzureAuthenticator.php
<?php
namespace App\Security;
use App\Entity\User;
use League\OAuth2\Client\Provider\azureUser;
use Doctrine\ORM\EntityManagerInterface;
use KnpU\OAuth2ClientBundle\Client\ClientRegistry;
use KnpU\OAuth2ClientBundle\Security\Authenticator\OAuth2Authenticator;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
class AzureAuthenticator extends OAuth2Authenticator implements AuthenticationEntryPointInterface
{
private ClientRegistry $clientRegistry;
private EntityManagerInterface $entityManager;
private RouterInterface $router;
public function __construct(ClientRegistry $clientRegistry, EntityManagerInterface $entityManager, RouterInterface $router)
{
$this->clientRegistry = $clientRegistry;
$this->entityManager = $entityManager;
$this->router = $router;
}
/**
* Cette fonction renvoie true alors la fonction authenticate sera appelée
* #param Request $request
* #return bool|null
*/
public function supports(Request $request): ?bool
{
return $request->attributes->get('_route') === 'connect_azure_check';
}
/**
* Cette fonction permet de traiter les données et de les utiliser. Elle vérifie également si l'utilisateur est déjà existant en base de donnée, si se n'est pas le cas elle l'ajoute.
* #param Request $request
* #return Passport
*/
public function authenticate(Request $request): Passport
{
$client = $this->clientRegistry->getClient('azure');
$accessToken = $this->fetchAccessToken($client);
return new SelfValidatingPassport(
new UserBadge($accessToken->getToken(), function() use ($accessToken, $client) {
/** #var AzureUser $AzureUser */
$AzureUser = $client->fetchUserFromToken($accessToken);
// 1) have they logged in with Azure before? Easy!
$existingUser = $this->entityManager->getRepository(User::class)->findOneBy(['uuid' => $AzureUser->getId()]);
if ($existingUser) {
return $existingUser;
}
$user = new User();
$user->setUuid($AzureUser->getId());
$user->setNom($AzureUser->claim('family_name'));
$user->setPrenom($AzureUser->claim('given_name'));
$user->setEmail($AzureUser->claim('upn'));
$this->entityManager->persist($user);
$this->entityManager->flush();
return $user;
})
);
}
/**
* Si l'authentification réussi, l'utilisateur sera renvoyé sur la route home
* #param Request $request
* #param TokenInterface $token
* #param string $firewallName
* #return Response|null
*/
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
{
$targetUrl = $this->router->generate('home');
return new RedirectResponse($targetUrl);
}
/**
* Si l'authentification échoue, l'utilisateur sera informé avec un message d'erreur
* #param Request $request
* #param AuthenticationException $exception
* #return Response|null
*/
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
{
$message = strtr($exception->getMessageKey(), $exception->getMessageData());
return new Response($message, Response::HTTP_FORBIDDEN);
}
/**
* Cette fonction permet de rediriger l'utilisateur sur la route de connexion
* Dès que l'utilisateur sera sur une route qu'il n'a pas le droit d'avoir accès il sera rediriger à cet endroit (Dans le cas de notre application toutes les routes sont par défaut interdite)
* #param Request $request
* #param AuthenticationException|null $authException
* #return Response
*/
public function start(Request $request, AuthenticationException $authException = null): Response
{
return new RedirectResponse(
'/connect/azure',
Response::HTTP_TEMPORARY_REDIRECT
);
}
}
When I add use_state: true in parameter another error is returned: "Authentication failed! Did you authorize our app?"
I have this two model with relationship manytomany
`<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Plate extends Model
{
/**
* La tabella associata al modello.
*
* #var string
*/
protected $table = "plates";
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $guarded = [];
// funzione che collega la tabella plate con la tabella user (one to many)
public function user()
{
return $this->belongsTo("App\User");
}
// funzione che collega la tabella order con la tabella plate (many to many)
public function order()
{
return $this->belongsToMany("App\Order");
}
}
`<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Order extends Model
{
/**
* La tabella associata al modello.
*
* #var string
*/
protected $table = "orders";
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $guarded = [""];
// funzione che collega la tabella order con la tabella user (one to many)
public function user()
{
return $this->belongsTo("App\User");
}
// funzione che collega la tabella plate con la tabella order (many to many)
public function plate()
{
return $this->belongsToMany("App\Plate");
}
}`
then when i sent email to customer with ordercontroller, i receive the neworder data on the mail controller
`<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class NewOrderCustomer extends Mailable
{
use Queueable, SerializesModels;
protected $newOrder;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct($_order)
{
$this->newOrder = $_order;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->subject('Riepilogo ordine')->view('mail.new-order-customer')->with(['order' => $this->newOrder ]);
}
}
`
then i show on email the info of order, but quantity dont show.. i have tried with
`<div style="padding: 20px 10px">
<h1>Grazie per aver ordinato da noi {{ $order->customer_name }}.</h1>
<h4>Di seguito il riepilogo del tuo ordine:</h4>
<p>Nome e cognome: {{ $order->customer_name }} {{ $order->customer_surname }} </p>
<p>Indirizzo: {{ $order->customer_address }}</p>
<p>Telefono: {{ $order->customer_phone }}</p>
#if ($order->customer_note)
Note: {{ $order->customer_note }}
#endif
<h3>Piatti ordinati:</h3>
#foreach ($order->plate as $plate)
<p>{{ $plate->order->quantity }} {{ $plate->quantity }} {{ $plate->name }} - €{{ $plate->price }}</p>
#endforeach
<p>Importo totale ordine: €{{ $order->total_price }}</p>
</div>`
this code... dont work $plate->order->quantity or $plate->quantity..
this is my order controller
`<?php
namespace App\Http\Controllers\Api\Orders;
use App\User;
use App\Order;
use App\Plate;
use Braintree\Gateway;
use App\Mail\NewOrderUser;
use Illuminate\Http\Request;
use App\Mail\NewOrderCustomer;
use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Validator;
use App\Http\Requests\Orders\OrderRequest;
use App\Http\Requests\Orders\OrderTableRequest;
class OrderController extends Controller
{
public function payment(Request $request)
{
$data = $request->all();
$validator = Validator::make(
$data,
[
'customer_name' => 'required|string|max:50',
'customer_surname' => 'required|string|max:50',
'customer_address' => 'required|string|max:255',
'customer_phone' => 'required|numeric',
'customer_email' => 'required|string|max:255',
],
[
'customer_name.required' => 'Il nome è obbligatorio',
'customer_name.max' => 'Il nome non può essere più lungo di 50 caratteri',
'customer_surname.required' => 'Il cognome è obbligatorio',
'customer_surname.max' => 'Il cognome non può essere più lungo di 50 caratteri',
'customer_address.required' => 'L\'indirizzo è obbligatorio',
'customer_address.max' => 'L\'indirizzo non può essere più lungo di 255 caratteri',
'customer_phone.required' => 'Il numero di telefono è obbligatorio',
'customer_phone.numeric' => 'Il numero di telefono deve essere numerico',
'customer_email.required' => 'L\'email è obbligatoria',
'customer_email.max' => 'L\'email non può essere più lunga di 255 caratteri',
]
);
$newOrder = new Order();
$newOrder->fill($data);
$newOrder->save();
$plates_id = [];
$plates_quantity = [];
foreach ($data['plates'] as $plate) {
$plates_id[] = $plate['id'];
$plates_quantity[] = $plate['quantity'];
}
$sync_data = [];
for ($i = 0; $i < count($plates_id); $i++)
$sync_data[$plates_id[$i]] = ['quantity' => $plates_quantity[$i]];
$newOrder->plate()->sync($sync_data);
$userMail = User::where('id', $data['user_id'])->get();
if(isset($data['customer_email']) && isset($userMail)){
$newOrder->plates;
Mail::to($data['customer_email'])->send(new NewOrderCustomer($newOrder));
Mail::to($userMail)->send(new NewOrderUser($newOrder));
}
if ($newOrder) {
return 'data saved succesfully';
} else {
return 'data not sent';
}
return response()->json([
"mess" => 'creato',
"status" => true,
]);
return response()->json($data);
}
public function generate(Request $request, Gateway $gateway)
{
$token = $gateway->clientToken()->generate();
$data = [
"success" => true,
"token" => $token
];
return response()->json($data, 200);
}
public function makePayment(OrderRequest $request, Gateway $gateway)
{
$result = $gateway->transaction()->sale([
'amount' => $request->amount,
'paymentMethodNonce' => $request->token,
'options' => [
'submitForSettlement' => true
]
]);
if ($result->success) {
$data = [
'success' => true,
'message' => ' Transazione eseguita'
];
return response()->json($data, 200);
} else {
$data = [
'success' => false,
'message' => 'Transazione fallita'
];
return response()->json($data, 401);
}
}
}`
How can I access {{ app.session.get('user') }}
I don't understand much about controllers I only have this is the one I use to control that template
//accedemos a las dependencias de Twig
require_once './vendor/autoload.php';
use Symfony\Component\HttpFoundation\Session\Session;
//accedemos a la clase LoginModel para realizar operaciones a la base de datos
require_once './model/LoginModel.php';
require_once './core/ControladorBase.php';
class LoginController
{
private $loader;
private $twig;
private $controladorBase;
public function __construct(){
$this->controladorBase = new ControladorBase();
$this->loader = new \Twig\Loader\FilesystemLoader('./view');
$this->twig = new \Twig\Environment($this->loader);
}
/**
* Muestra la página principal y el listado de empleados dados de alta
* #throws \Twig\Error\LoaderError
* #throws \Twig\Error\RuntimeError
* #throws \Twig\Error\SyntaxError
*/
public function index(){
$session = new Session();
$session->set('user', 'juan' );
echo $this->twig->render('/login/index.html.twig');
}
}
I'm running two test XAMPP servers, both with similar PDO Connection classes
First:
<?php
/**
* Clase que envuelve una instancia de la clase PDO
* para el manejo de la base de controladores
*/
require_once 'login_mysql.php';
class ConexionBD
{
/**
* Única instancia de la clase
*/
private static $db = null;
/**
* Instancia de PDO
*/
private static $pdo;
final private function __construct()
{
try {
// Crear nueva conexión PDO
self::obtenerBD();
} catch (PDOException $e) {
// Manejo de excepciones
}
}
/**
* Retorna en la única instancia de la clase
* #return ConexionBD|null
*/
public static function obtenerInstancia()
{
if (self::$db === null) {
self::$db = new self();
}
return self::$db;
}
/**
* Crear una nueva conexión PDO basada
* en las constantes de conexión
* #return PDO Objeto PDO
*/
public function obtenerBD()
{
if (self::$pdo == null) {
self::$pdo = new PDO(
'mysql:dbname=' . BASE_DE_DATOS .
';host=' . NOMBRE_HOST . ";",
USUARIO,
CONTRASENA,
array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8")
);
// Habilitar excepciones
self::$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
return self::$pdo;
}
/**
* Evita la clonación del objeto
*/
final protected function __clone()
{
}
function _destructor()
{
self::$pdo = null;
}
}
Second (this one doesn't work):
<?php
/**
* Clase que envuelve una instancia de la clase PDO
* para el manejo de la base de datos
*/
require_once 'mysql_login.php';
class Database
{
/**
* Única instancia de la clase
*/
private static $db = null;
/**
* Instancia de PDO
*/
private static $pdo;
final private function __construct()
{
try {
// Crear nueva conexión PDO
self::getDb();
} catch (PDOException $e) {
// Manejo de excepciones
}
}
/**
* Retorna en la única instancia de la clase
* #return Database|null
*/
public static function getInstance()
{
if (self::$db === null) {
self::$db = new self();
}
return self::$db;
}
/**
* Crear una nueva conexión PDO basada
* en los datos de conexión
* #return PDO Objeto PDO
*/
public function getDb()
{
if (self::$pdo == null) {
self::$pdo = new PDO(
'mysql:dbname=' . DATABASE .
';host=' . HOSTNAME .
';port:63343;',
USERNAME,
PASSWORD,
array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8")
);
// Habilitar excepciones
self::$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
return self::$pdo;
}
/**
* Evita la clonación del objeto
*/
final protected function __clone()
{
}
function _destructor()
{
self::$pdo = null;
}
}
?>
And for some reason the second connection is not resolved. Any ideas why this might be?
Both files are on different directories and are referenced by different, isolated files.
EDIT: Error returned
exception 'PDOException' with message 'SQLSTATE[HY000] [2002] Connection refused' in /opt/lampp/htdocs/estudiantesServer/Database.php:60 Stack trace:
#0 /opt/lampp/htdocs/estudiantesServer/Database.php(60): PDO->__construct('mysql:host=loca...', 'root', 'root', Array)
#1 /opt/lampp/htdocs/estudiantesServer/Database.php(27): Database->getDb()
#2 /opt/lampp/htdocs/estudiantesServer/Database.php(42): Database->__construct()
#3 /opt/lampp/htdocs/estudiantesServer/estudiantes.php(26): Database::getInstance()
#4 /opt/lampp/htdocs/estudiantesServer/getEstudiantes.php(10): Estudiantes::getAll()
#5 {main}
What do I want
I have saved in session an object of type App\Model\Company and at the time of inserting a new customer I need to proper reference is made to this company already registered.
Currently this happens
When saving a new record of App\Model\People, a new record of App\Model\ Company is created (with the same data record that is in session) and the new record of Crm\Model\People who I want to create is being related to the new App\Model\Company registration and not to the previous record.
Here's my People entity:
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="tbl_crm_people")
*/
class People extends Entity
{
/**
* #ORM\Id
* #ORM\Column(type="integer");
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $people_id;
/**
* #ORM\ManyToOne(targetEntity="App\Model\Company", cascade={"all"})
* #ORM\JoinColumn(name="people_company_id", referencedColumnName="company_id")
*/
protected $people_company;
/**
* #ORM\Column(type="string", length=60)
*/
protected $people_name;
}
and my Company entity
<?php
namespace App\Model;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="tbl_app_company")
*/
class Company extends Entity
{
/**
* #ORM\Id
* #ORM\Column(type="integer");
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $company_id;
/**
* #ORM\Column(type="string", length=250)
*/
protected $company_name;
public function getId()
{
return $this->company_id;
}
}
and the action:
public function saveAction()
{
//INSTANCIA UM FORMULARIO
$form = new PeopleForm();
//INFORMAÇÕES SOBRE A REQUISIÇÃO
$request = $this->getRequest();
//SE TIVER SIDO UMA REQUIZIÇÃO POST
if ($request->isPost()) {
$people = new People;
$form->setInputFilter($people->getInputFilter());
$form->setData($request->getPost());
// CASO O FORMULÁRIO SEJA VÁLIDO
if ($form->isValid()) {
// RECEBE DA SESSÃO UM OBETO REFERENTE AO USUÁRIO LOGADO
$CurrentUser = $this->CurrentUserInfo();
// ORGANIZA A ESTRUTURA DAS INFORMAÇÕES A SEREM SALVAS
$data = $form->getData();
unset($data['submit']);
// DEFINE O ITEM COM UM OBJETO DO TIPO APP\MODEL\COMPANY
$data['people_company'] = $CurrentUser->getCompany();
//CASO SEJA ATUALIZAÇÃO EU SELECIONO O REGISTRO
if (isset($data['people_id']) && $data['people_id'] > 0) {
$people = $this->getEntityManager()->find('Crm\Model\People', $data['people_id']);
}
// PREENCHO O REGISTRO COM O RESTANTE DOS DADOS
$people->setData($data);
// SALVO O REGISTRO
$this->getEntityManager()->persist($people);
$this->getEntityManager()->flush();
return $this->redirect()->toUrl('/crm/people/index');
}
}
//SE FOR VISUALIZAÇÃO DO FORM
$this->getServiceLocator()->get('ViewHelperManager')->get('HeadTitle')->set('Novo');
$people_id = (int) $this->params()->fromRoute('id', 0);
if ($people_id > 0) {
$this->getServiceLocator()->get('ViewHelperManager')->get('HeadTitle')->set('Edição');
$people = $this->getEntityManager()->find('Crm\Model\People', $people_id);
$form->bind($people);
$form->get('submit')->setAttribute('value', 'Salvar alteração');
}
//GERA A VISUALIZAÇÃO
return new ViewModel(
array('form' => $form)
);
}
I would say you should try removing the cascade={"all"} from your People entity. You should only add this if you want to create/delete/update a company while you create/delete/update a user. I guess this is not the behavior you want.
The cascade operation is why a new company is created when you post a new user.
In principle it should not create a new company if the record already exists. So I guess there is also something inconsistent happening in your saveAction.
Are you sure that $CurrentUser->getCompany() is returning a proper entity of type App\Model\Company
Would it not better to create a method to set the company in your People entity and use that to set the company instead of setting the $data['people_company']. Advantage is also that the PHP will trow an exception if $company is not of type Company.
public function setCompany(Company $company)
{
$this->people_company = $company
return $this;
}