Work with different schemas in Doctrine - oracle

I am using doctrine2 with oracle. There are several schemas schema1 and schema2. When I create a form with the following content
// ....
public function buildForm(FormBuilderInterface $builder, array $options)
{
// ....
$builder
->add('userPartner', 'entity', array(
'class' => 'SoftclubTopbyBundle:Party',
'property' => 'legalName',
'placeholder' => '',
'multiple' => true,
))
;
// ....
}
//...
the symfony throws me an exception:
MappingException in MappingException.php line 37:
The class 'Softclub\TopbyBundle\Entity\Nsi\NsiChainStore' was not found in
the chain configured namespaces Softclub\TopbyBundle\Entity\Topby
I have the following setting in the config.yml
entity_managers:
default:
connection: default
mappings:
SoftclubTopbyBundle: { type: yml, dir: Resources/config/doctrine/topby, prefix: Softclub\TopbyBundle\Entity\Topby }
nsi:
connection: nsi
mappings:
SoftclubTopbyBundle: { type: yml, dir: Resources/config/doctrine/nsi, prefix: Softclub\TopbyBundle\Entity\Nsi }
and also the following relationship between the two entities
Softclub\TopbyBundle\Entity\Topby\Party:
manyToOne:
chainStore:
targetEntity: Softclub\TopbyBundle\Entity\Nsi\NsiChainStore
cascade: { }
mappedBy: null
inversedBy: null
joinColumns:
CHAIN_STORE_ID:
referencedColumnName: ID
orphanRemoval: false
what can I do wrong?

Thank you all for the answers. As Matteo said, the entities were placed in a separate bundle. The problem was solved as follows
default:
connection: default
mappings:
SoftclubTopbyBundle: ~
SoftclubNsiBundle: ~
# for generate entities
topby:
connection: default
mappings:
SoftclubTopbyBundle: ~
nsi:
connection: nsi
mappings:
SoftclubNsiBundle: ~

You can not make doctrine relations over different connections. You can use event listener for that purpose.
For instance, one entity (say Note) has some property which is reference to another entity (say User) belonging to another entity manager (connection). The Note entity persists User's ID as foreign key.
Event listener is used to instantiate User object by using it's ID whenever the Note object is loaded (postLoad event).
http://symfony.com/doc/current/cookbook/doctrine/event_listeners_subscribers.html
Doctrine events:
http://doctrine-orm.readthedocs.org/en/latest/reference/events.html#lifecycle-events
Regarding the form, put option entity manager with 'nsi' if 'userPartner' is mapped to that connection.
'em'=>'nsi'
Have not worked with Oracle, hope this helps.

Related

Setting the Symfony session storage factory

I'm using Symfony 6 to refactor a CodeIgniter 3 framework. User logging in is done via CodeIgniter so I'd like to read the CI session data (stored in a DB) in Symfony.
I'm trying to use my own session storage factory because the CI session name is dynamically constructed using the hostname and also because of the way CI stores the session in the db is different to Symfony.
I've set the session storage factory in framework.yaml
# config/packages/framework.yaml
session:
storage_factory_id: App\Service\CINativeSessionStorageFactory
And I've configured my services (including my own PDO session handler):
# config/services.yaml
services:
# default configuration for services in *this* file
_defaults:
autowire: true # Automatically injects dependencies in your services.
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
bind: # defines the scalar arguments once and apply them to any service defined/created in this file
string $locales: '%app_locales%'
string $defaultLocale: '%locale%'
string $emailSender: '%app.notifications.email_sender%'
# makes classes in src/ available to be used as services
# this creates a service per class whose id is the fully-qualified class name
App\:
resource: '../src/'
exclude:
- '../src/DependencyInjection/'
- '../src/Entity/'
- '../src/Kernel.php'
- '../src/Tests/'
# CodeIgniter Session handler
App\Service\CIPdoSessionHandler:
arguments:
- '%env(DATABASE_URL)%'
- {
db_table: 'ci_sessions',
db_id_col: 'id',
db_data_col: 'data',
db_time_col: 'timestamp',
db_lifetime_col: 'sess_lifetime'
}
properties:
logger: '#logger'
tags:
- { name: monolog.logger, channel: session }
App\Service\CINativeSessionStorageFactory:
arguments:
$handler : '#App\Service\CIPdoSessionHandler'
$options : {
cookie_secure: auto,
cookie_samesite: lax,
gc_maxlifetime: 7200
}
tags:
- { name: monolog.logger, channel: session }
However I am getting these errors in the logs:
[2022-11-30T17:32:16.738059+00:00] php.CRITICAL: Fatal Compile Error: Cannot declare class App\Service\CINativeSessionStorageFactory, because the name is already in use {"exception":"[object] (Symfony\\Component\\ErrorHandler\\Error\\FatalError(code: 0): Compile Error: Cannot declare class App\\Service\\CINativeSessionStorageFactory, because the name is already in use at /workspace/symfony/src/Service/CINativeSessionStorageFactory.php:16)"} []
[2022-11-30T17:32:16.739841+00:00] request.CRITICAL: Uncaught PHP Exception Symfony\Component\ErrorHandler\Error\FatalError: "Compile Error: Cannot declare class App\Service\CINativeSessionStorageFactory, because the name is already in use" at /workspace/symfony/src/Service/CINativeSessionStorageFactory.php line 16 {"exception":"[object] (Symfony\\Component\\ErrorHandler\\Error\\FatalError(code: 0): Compile Error: Cannot declare class App\\Service\\CINativeSessionStorageFactory, because the name is already in use at /workspace/symfony/src/Service/CINativeSessionStorageFactory.php:16)"} []
[2022-11-30T17:32:16.741681+00:00] session.DEBUG: Using App\Service\CIPdoSessionHandler [] []
[2022-11-30T17:32:16.741839+00:00] session.DEBUG: Setting session name to ci_session_XXXXXXX [] []
The last two lines indicate that my storage factory is working (at least partially) so I'm unsure as why I'm getting these errors.
The first part of my question is: Where am I going wrong?
As an aside, I noticed that if I set up my framework.yaml like this:
# config/packages/framework.yaml
session:
handler_id: App\Service\CIPdoSessionHandler
storage_factory_id: App\Service\CINativeSessionStorageFactory
Then the handler passed to my constructor was always null
public function __construct(array $options = [], AbstractProxy|\SessionHandlerInterface $handler = null, MetadataBag $metaBag = null, bool $secure = false)
{
// $handler is null!
So the second part of my question is: Do handler_id and storage_factory_id not work together?
Some additional information from trying to debug this issue:
If I save config/services.yaml and then refresh the page - I don't get this message.
If I then refresh the page again - I get the error message.
If I then save config/services.yaml again and refresh the page - I don't get this message
... etc
Is my installation broken? I followed the steps here : https://symfony.com/doc/current/setup.html

How to connect to remote oracle database using typeorm in nestjs?

I was wondering how to connect to remote oracle database from nestjs using typeorm.
I installed typeorm and oracle package using following command.
npm i --save #nestjs/typeorm typeorm oracle
npm install oracledb --save
and then tried configuring in app.module.ts using TypeOrmModule.forRoot but it was not succesfull.
Here are my configuration settings.
TypeOrmModule.forRoot({
type: 'oracle',
host: 'ip of hostname',
port: port number,
username: 'username',
password: 'password',
serviceName: 'servicename',
synchronize: false,
entities: []
})
Can anybody help me out what am I missing? Also would like to know how can I execute the query once this connection is succesfully? If any example that would be helpfull.
Got it.
one missing thing was database name.
Added
database: 'databasename' in above configuration and it worked.
But, still my question is how to use this connection in service to fetch/push the data from/to oracle databse?
If you provide a name in your connection details you should be able to refer to the database connection using that. Otherwise, if no name is provided I believe it assigns it the name 'default'.
Basically these are the steps you should perform to use the database connection: (examples below each)
Create a model - this is how TypeORM knows to create a table.
export class Photo {
id: number
name: string
description: string
filename: string
views: number
isPublished: boolean
}
Create an Entity. - this should match your model, with the appropriate decorators. At minimum you should have the #Entity() decorator before your class definition and #Column() before each field.
import { Entity, Column } from "typeorm"
#Entity()
export class Photo {
#Column()
id: number
#Column()
name: string
#Column()
description: string
#Column()
filename: string
#Column()
views: number
#Column()
isPublished: boolean
}
Create your data source - looks like you have already done this. But I would give it a name field and you will need to pass your entities into the entity array you have.
const AppDataSource = new DataSource({
type: "postgres",
name: "photos",
host: "localhost",
port: 5432,
username: "root",
password: "admin",
database: "test",
entities: [Photo],
synchronize: true,
logging: false,
})
Then you can use repositories to manage data in the database:
const photo = new Photo()
photo.name = "Me and Bears"
photo.description = "I am near polar bears"
photo.filename = "photo-with-bears.jpg"
photo.views = 1
photo.isPublished = true
const photoRepository = AppDataSource.getRepository(Photo)
await photoRepository.save(photo)
console.log("Photo has been saved")
const savedPhotos = await photoRepository.find()
console.log("All photos from the db: ", savedPhotos)
For more details I would spend some time reading through the typeORM website, all the examples I pulled were from there:
https://typeorm.io/

Symfony4: How to toggle entities using dotenv and multiple Entity Manager?

How it is possible through dotenv select different entity path with same name of entities.
Originally, We had application in Symfony 3 for people meetings on events of our organization. Then we decided to offer this application to our partners.
One of the partners asked us to customize the application for them with their data and specifications. We basically created a new instance of Symfony application with copy of database tables (with different prefix), changes in Entities to reflect new db table names, and some translation text changes.
It seems that other partners will follow this trend of customized instances.
Therefore, I am trying to update core application to Symfony 4 and I am trying to use multiple Entity Managers and dotenv to differentiate between partners database tables, as described bellow.
In a nutshell, I am trying to use multiple Entity Manager to switch db table names by prefix.
.env
###> doctrine/doctrine-bundle ###
# Format described at http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url
# For an SQLite database, use: "sqlite:///%kernel.project_dir%/var/data.db"
# Configure your db driver and server_version in config/packages/doctrine.yaml
DATABASE_URL=oci8://user:pass#127.0.0.1:1521/XE
EM_TYPE=OpenAccess
###< doctrine/doctrine-bundle ###
Only in security.yaml working env good
security:
encoders:
App\Entity\%env(EM_TYPE)%\Osoba:
providers:
our_db_provider:
entity:
class: App\Entity\%env(EM_TYPE)%\Osoba
property: username
When i tried get %env(EM_TYPE)% in default_entity_manager, then give error You have requested a non-existent service "doctrine.orm.%env(EM_TYPE)%_entity_manager". doctrine.yaml
parameters:
env(DATABASE_URL): ''
doctrine:
dbal:
default_connection: '%env(EM_TYPE)%'
connections:
MeetingTool:
driver: 'oci8'
charset: UTF8
schema_filter: /^MT_/
url: '%env(resolve:DATABASE_URL)%'
OpenAccess:
driver: 'oci8'
charset: UTF8
schema_filter: /^OA6_/
url: '%env(resolve:DATABASE_URL)%'
orm:
auto_generate_proxy_classes: true
default_entity_manager: '%env(EM_TYPE)%'
entity_managers:
MeetingTool:
connection: MeetingTool
mappings:
Main:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity/MeetingTool'
prefix: 'App\Entity\MeetingTool'
alias: App2
OpenAccess:
connection: OpenAccess
mappings:
App:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity/OpenAccess'
prefix: 'App\Entity\OpenAccess'
alias: OpenAccess
and biggest problem is use, how i targeting right entity here? for example loginController.php
<?php
namespace App\Controller;
use Doctrine\ORM\EntityManagerInterface;
use App\Entity\OpenAccess\LogPrihlaseni;
//use App\Entity\MeetingTool\LogPrihlaseni;
class LoginController extends AbstractController {
private $entityManager;
public function __construct(EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
}
public function logPrihlaseni() {
$log = new LogPrihlaseni();

Doctrine with two Entitymanagers looks at wrong database

I did follow these rules of setting up a second connection and a second entity manager in doctrine. The "default" database is called revee and the "source" database reveesrc.
What works
When I dry-run a migration with this code in the postUp() method:
/** #var EntityManager $em */
$em = $this->container->get('doctrine.orm.entity_manager');
/** #var EntityManager $emSrc */
$emSrc = $this->container->get('doctrine.orm.source_entity_manager');
var_dump($emSrc->getConnection()->getDatabase());
$dates = $emSrc->getRepository('App:Dates')->findAll();
Weirdly, I get the database reveesrc written our correctly! Meaning that the mapping from the connection to the entity manager works just fine.
What doesn't work
However, the next line produces the error.
Base table or view not found: 1146 Table 'revee.dates' doesn't exist"
As dates was defined in the Entity folder attached to the second source entity manager I thought doctrine would know where to look for the table. What do I have to do to map the Entity to the other source database?
doctrine.yaml
parameters:
# Adds a fallback DATABASE_URL if the env var is not set.
# This allows you to run cache:warmup even if your
# environment variables are not available yet.
# You should not need to change this value.
env(DATABASE_URL): ''
doctrine:
dbal:
# configure these for your database server
default_connection: default
connections:
default:
url: '%env(resolve:DATABASE_URL)%'
driver: 'pdo_mysql'
server_version: '5.7'
charset: utf8mb4
default_table_options:
charset: utf8mb4
collate: utf8mb4_unicode_ci
source:
url: '%env(resolve:DATABASE_URL_SOURCE)%'
driver: 'pdo_mysql'
server_version: '5.7'
charset: utf8mb4
default_table_options:
charset: utf8mb4
collate: utf8mb4_unicode_ci
orm:
default_entity_manager: default
auto_generate_proxy_classes: true
entity_managers:
default:
naming_strategy: doctrine.orm.naming_strategy.underscore
auto_mapping: true
connection: default
mappings:
App:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity'
alias: App
source:
naming_strategy: doctrine.orm.naming_strategy.underscore
connection: source
mappings:
App:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/EntitySrc'
prefix: 'App\EntitySrc'
alias: App
src\Entity\Dates.php (first lines)
<?php
namespace App\EntitySrc;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="App\Repository\DateSrcRepository")
*/
class Dates
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
src\Repository\DateSrcRepository.php
<?php
namespace App\Repository;
use App\EntitySrc\Dates;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Symfony\Bridge\Doctrine\RegistryInterface;
class DateSrcRepository extends ServiceEntityRepository
{
public function __construct(RegistryInterface $registry)
{
parent::__construct($registry, Dates::class);
}
If anybody experiences the same problem, I fixed it by specifying the table explicetly in the entity, prefixing it with the database. If anyone knows if that is not the correct way of solving it I would be interested.
<?php
namespace App\Entity\Src;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="App\Repository\DateSrcRepository")
* #ORM\Table(name="reveesrc.dates")
*/
class Dates
{

Creating a custom validator as a service in Symfony2

I'm trying to send an EntityManager object to my custom validator. For that, I created a service and defined the entity manager as an argument.
The problem is that the argument isn't sent to the validator, it fires an error in the __construct() function indicating that no arguments have been passed.
This is the definition of my service:
dinamic.shop.validator.deliverydate:
class: Dinamic\ShopBundle\Validator\Constraints\DeliveryDateValidator
arguments:
- #doctrine.orm.entity_manager
tags:
- { name: validator.constraint_validator, alias: deliverydate }
Here is the validateBy() method of my Constraint:
class DeliveryDate extends Constraints
{
...
public function validateBy()
{
return 'deliverydate';
}
}
Here is my ConstraintValidator:
Finally, this is how I set the constraint on the field. The field is not mapped to any entity:
->add('deliveryday', 'date', array(
'label' => 'Día de entrega',
'widget' => 'single_text',
'format' => 'dd/MM/yyyy',
'constraints' => array(
new NotBlank(),
new DeliveryDate($deliveryDateOptions),
),
)
)
I think that my error is in the FormType class, where I set the constraint on the field, but I can't find any examples of non-mapped fields.
I'm using Symfony2.3, any help will be appreciated, thanks a lot.
[EDIT]
I've used the command "sudo php app/console container:debug | grep validator" and the service I've created appears on the results
dinamic.shop.validator.deliverydate container Dinamic\ShopBundle\Validator\Constraints\DeliveryDateValidator
It's very likely one of those syntax issues!
The syntax can be this:
dinamic.shop.validator.deliverydate:
class: Dinamic\ShopBundle\Validator\Constraints\DeliveryDateValidator
arguments: [#doctrine.orm.entity_manager]
tags:
- { name: validator.constraint_validator, alias: deliverydate }
or this:
dinamic.shop.validator.deliverydate:
class: Dinamic\ShopBundle\Validator\Constraints\DeliveryDateValidator
arguments:
entityManager: "#doctrine.orm.entity_manager"
tags:
- { name: validator.constraint_validator, alias: deliverydate }
Note: To check if the service you're passing exists:
php app/console container:debug | grep doctrine
Will give you:
....
doctrine.orm.entity_manager n/a alias for doctrine.orm.default_entity_manager
....
I found the error. The problem was the function 'validateBy', it should have been validatedBy()
So the only change I needed to do was to change said function.
Thank you for the help #Patt

Resources