Does anybody know a way of configuring DBAL/Doctrine2 in a Symfony2 (symfony-reloaded) yml config file to execute a "set names" query? This question has been asked in other places, but I could not find a correct answer.
http://fossplanet.com/f6/%5Bsymfony-users%5D-symfony2-sandbox-database-collation-49626/
If there is no such config option, how can I implement this using PHP? Or better: Where is the right place in a Symfony2 project to do this?
That is not possible yet. I am working on allowing this already, will be possible soonish.
Ok, just for anybody else who might run into this problem. This is what I did:
I ended up subclassing Symfony\Bundle\FrameworkBundle\Controller\Controller and introduced the method getEntityManager:
public function getEntityManager()
{
$em = $this->get('doctrine.orm.entity_manager');
static $utf8_set = false;
if (!$utf8_set) {
$em->getEventManager()->addEventSubscriber(new MysqlSessionInit('utf8','utf8_unicode_ci'));
$utf8_set = true;
}
return $em;
}
So everytime I am want to access the EntityManager or a repository in my controllers (which of course now subclass DoctrineController) I call
$this->getEntityManager()
resp.
$this->getEntityManager()->getRepository('What\Ever\Entity\I\Am\Looking\For')
Related
The Problem: I'm looking to implement the DateTime script found in the Doctrine 2.7 docs here. I'm having trouble figuring out where this script should naturally go in Symfony 5's file structure.
The Setup: Used Composer to create a Symfony 5 website skeleton using composer create-project symfony/website-skeleton.
The Context: I don't have any real code implemented yet as I'm still trying to learn how Symfony works with Doctrine. I'm trying to do everything right with Symfony, including figuring out where files should go. From what I understand, each php script found in src is either a Controller, an Entity, or a Repository. I don't see where to reasonably put the DateTime script without making another folder.
Any guidance is much appreciated! Thank you.
EDIT: The specific script I'm referring to is this class definition of UTCDateTimeType. I was under the impression that a skeleton was made to be THE file structure you worked with to allow for easy maintainability.
<?php
namespace DoctrineExtensions\DBAL\Types;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\ConversionException;
use Doctrine\DBAL\Types\DateTimeType;
class UTCDateTimeType extends DateTimeType
{
/**
* #var \DateTimeZone
*/
private static $utc;
public function convertToDatabaseValue($value, AbstractPlatform $platform)
{
if ($value instanceof \DateTime) {
$value->setTimezone(self::getUtc());
}
return parent::convertToDatabaseValue($value, $platform);
}
public function convertToPHPValue($value, AbstractPlatform $platform)
{
if (null === $value || $value instanceof \DateTime) {
return $value;
}
$converted = \DateTime::createFromFormat(
$platform->getDateTimeFormatString(),
$value,
self::getUtc()
);
if (! $converted) {
throw ConversionException::conversionFailedFormat(
$value,
$this->getName(),
$platform->getDateTimeFormatString()
);
}
return $converted;
}
private static function getUtc(): \DateTimeZone
{
return self::$utc ?: self::$utc = new \DateTimeZone('UTC');
}
}
I like to put doctrine types into src/Types (yeah, new folder*) and unless you're importing UTCDateTimeType from a library, I would change the namespace to be in line with convention (namespace would be App\Types and FQCN App\Types\UTCDateTimeType).
Adding the type to doctrine is somewhat easy, if you know where - config/packages/doctrine.yaml - this probably requires setting the typename via getName as seen in here https://www.doctrine-project.org/projects/doctrine-orm/en/2.7/cookbook/custom-mapping-types.html
doctrine:
dbal:
types:
#nameOfType: fullyQualifiedClassName
utcdatetime: App\Types\UTCDateTimeType
(this probably works if you set the name of your type to datetime and datetimetz, my short incomplete tests suggest so...)
however, the tutorial you linked said it wants to override the type. I don't know how to achieve this with config (if it's even possible - maybe you ), but you always have the chance to add the noted lines to your Kernel::configureContainer or even further up the line in your public/index.php.
*folders aren't magical. the existing ones are just the most common ones that are almost always used. adding new ones isn't unusual, so feel free to add them.
I'm developing php application with Doctrine (no symfony) and hence no DI container.
I'm using dependency Injection in one of my entities, which needs a service.
Class A implements Ia
{
public function __constructor( \requiredServiceClass $requiredService = NULL )
{
if ($requiredService === NULL) {
$this->requiredService = new \requiredServiceClass();
{
$this->requiredService = $requiredService;
}
}
}
Every thing works fine but while hydrating Doctrine doesn't call the __constructor as a result the dependency is not injected.
What's the best way to solve this?
Currently I use Doctrine lifecycle events to callback a method to set the dependency.
So first I add the lifecycle-callbacks in the mapping file of the entity
<lifecycle-callbacks>
<lifecycle-callback type="postLoad" method="setRequiredService"/>
</lifecycle-callbacks>
And then in the called method inject the dependency applying the setter dependency Injection.
public function setRequiredService()
{
$this->requiredService = new \requiredServiceClass();
}
My Questions:
Is this the best way to solve dependency Injection while hyderation in Doctrine?
And is it fine to pass DI param with default as NULL?
Thanks,
Abhinit Ravi
Does it store any information in the database for this "Service" I am not sure what that is.
If so you could define it as a custom data type.
Here is a link to the doctrine docs on that topic.
http://doctrine-orm.readthedocs.org/en/latest/cookbook/custom-mapping-types.html
http://docs.doctrine-project.org/en/2.0.x/cookbook/mysql-enums.html
I don't see any issues if it is just some class you need, not sure without know what service is and it could be better to restructure the code so it doesn't need this, but I cant tell without know what that does.
Id say the way you are doing it is fine, not sure if onLoad is fired only when pulling from the database or not but you might want to check if is null there instead.
I would possible write the class in this way
Class A implements Ia
{
protected $requiredService; //null by default
public function __constructor( \requiredServiceClass $requiredService = NULL )
{
$this->setRequiredService($requiredService);
}
public function postLoad(){
$this->setRequiredService();
}
public function setRequiredService(\requiredServiceClass $requiredService = NULL)
{
if(NULL === $this->requiredService){
//check if class has service - assuming you never want to set it again once it is set.
if(NULL === $requiredService){
$this->requiredService = new \requiredServiceClass();
}else{
$this->requiredService = $requiredService;
}
}
}
}
<lifecycle-callbacks>
<lifecycle-callback type="postLoad" method="postLoad"/>
</lifecycle-callbacks>
My reasons are.
This way all your check are right before injecting the service into
the class.
Its clear looking at the code that a lifecycle callback is used.
Follows better with separation of concerns, ie. the constructor
shouldn't be concerned with checking the status of requiredService,
it just passes it on. Same with the callback.
Should you need to reset the service ( remove the outer if in
setRequiredService ) you wont need to change the logic in the constructor etc..
I'm creating symfony2 application with doctrine2 and I would like to ask for advice regarding common/good practice for DTO-Entity, Entity-DTO conversion. I've found some information for all languages and frameworks, but none for SF2.
I would like to isolate Entities, so they are used only in Services and DAO's (Managers, Repositories in SF2 terminology). Controllers won't ever see DAO's or Entities and will interact with business logic only via Services. All communication between Services and Controllers should be done via primitive types, scalars, DTO's.
Example :
Controller
class RegistrationController extends Controller
{
public function registerAction($name)
{
$userDTO = new UserDTO();
$form = $this->createForm(new UserType(), $userDTO);
$form->handleRequest($request);
if ($form->isValid()) {
$userService = $this->get('userService');
$userService->createUser($userDTO);
return $this->redirect($this->generateUrl('success'));
}
--//--
}
}
Service
class UserServiceImpl implements UserService
{
private $userDao;
public function __construct(UserDao $userDao)
{
$this->userDao = $userDao;
}
public function createUser(UserDTO $user)
{
$user = new User(); #doctrine entity
$user->setFirstName($userDTO->getFirstName());
$user->setLastName($userDTO->getLastName());
$this->userDao->persist($user);
$this->userDao->flush();
--//--
}
}
Problem quickly appears with rising amount of properties in User object. In my application User has 13 fields. Are there any SF2 tools (classes) to simplify this process ? Do you write your own convertors / transformers ? Could you please show example of how it should look like ? Maby PHP magic methods could help ? What about reflection ?
Thanks for advices and opinions.
Start by using public properties on your dto's. That eliminates a bunch of getter/setter methods which really should not do anything for dto's. You can always add some majic methods for special cases.
Next, rethink the design of your DoctrineUserEntity aka Domain object. Do you really need getter/setter for each attribute? If so then what's the point?
Instead try to group properties into value objects:
$userNameValueObject = new UserNameValueObject($userDto->firstName, $userDto->lastName);
$userEntity = new UserEntity($userDTO->username,$userDTO->password, $userNameValueObject);
// And maybe this for updates
$userEntity->updateName($userNameValueObject);
But again, make sure you are actually getting some value for your work. A bunch of one to one mappings might make sense on other platforms where domain objects can stay alive between request. In php, everything starts from ground zero.
One option I've recently found is https://github.com/jasonrobertfox/DTOx which is a generator for DTO's and tests. It does the annoying boiler plate generation work for you.
I was trying to find a way to execute some code to alter the results of an objects methods without actually touching the object's code. One way I came up is using a decorator:
class Decorator {
private $object;
public function __construct($object) {
if (!is_object($object)) {
throw new Exception("Not an object");
}
$this->object = $object;
}
protected function doSomething(&$val) {
$val .= "!!";
}
public function __call($name, $arguments) {
$retVal = call_user_func_array(array($this->object, $name), $arguments);
$this->doSomething($retVal);
return $retVal;
}
}
class Test extends BaseTest {
public function run() {
return "Test->run()";
}
}
$o = new Decorator(new Test());
$o->run();
That way it will work properly but it has one disadvantage which makes it unusable for me right now - it would require replacing all lines with new Test() with new Decorator(new Test()) and this is exactly what I would like to avoid - lots of meddling with the existing code. Maybe something I could do in the base class?
One does not simply overload stuff in PHP. So what you want cannot be done. But the fact that you are in trouble now is a big tell your design is flawed. Or if it is not your code design the code you have to work with (I feel your pain).
If you cannot do what you want to do it is because you have tightly coupled your code. I.e. you make use of the new keyword in classes instead of injecting them (dependency injection) into the classes / methods that need it.
Besides not being able to easily swap classes you would also have a gard time easily testing your units because of the tight coupling.
UPDATE
For completeness (for possible future readers): if the specific class would have been namespaced and you were allowed to change the namespace you could have thought about changing the namespace. However this is not really good practice, because it may screw with for example autoloaders. An example of this would be PSR-0. But considering you cannot do this either way I don't see it is possible what you want. P.S. you should not really use this "solution".
UPDATE2
It looks like there has been some overload extension at some time (way way way back), but the only thing I have found about it is some bug report. And don't count on it still working now either way. ;-) There simply is no real overloading in PHP.
Found something (a dead project which doesn't work anymore that enables class overloading): http://pecl.php.net/package/runkit
Possibly another project (also dead of course): http://pecl.php.net/package/apd
I am not a PHP programmer, but I think that AOP is what you are looking for. You can try some frameworks, for example listed in this answer.
From the Wikipedia article on the decorator pattern:
Subclass the original "Decorator" class into a "Component" class
So I think you're supposed to keep the class to be decorated private and expose only the already-decorated class.
I'm just a newbe in Kohana ORM, so my question may be a bit silly for pro's, but.. :)
I have some ORM models, and all of them have a few the same methods like:
public function items_order_by_id($reverse = false)
{
if($reverse) return $this->order_by($this->_primary_key, 'desc')->find_all();
else return $this->order_by($this->_primary_key, 'asc')->find_all();
}
OR
public function get_form()
{
$result = array();
foreach($this->_table_columns as $key => $value)
{
if($value['form']) $result[$key] = $this->_prefix.'_'.$key;
}
return $result;
}
If I'm adding a new model I must copy all similar methods, and If I want to modify any method I must modify all files. I know object programming has inheritance, but when I'm trying to extend Kohana_ORM I get exception for example:
The comment_id property does not exist in the Model_Comment class
And all another properities also do not exist.
Is it possible, to have a parent model which contain these methods?
Yes it is possible. You just have to make sure you write your functions so that they can be used by all Other models that will be extending it.
Most likely you are setting variables that don't exist for the Model you are running. That is why it's throwing errors.
Also this is a bit offtopic but you should take a look at AutoModeler. If you want a flexible Model system. https://github.com/zombor/Auto-Modeler
It has about the same functions as ORM but makes extending a lot easier.
Oh, It was definitely silly.
I have just override _construct function and forgot parent::_construct().
So the problem is solved and now everything is ok.
Sorry for that :)