Check each param Symfony - symfony

I have a Route to create User, and I need some parameters to get this.
For example my controller is like this:
$dataJson = json_decode($request->getContent(),true);
$data = new \stdClass();
$data->email = $dataJson['email'];
$data->pwd = $dataJson['pwd'];
$data->role = $dataJson['role'];
I need of all of the (email, pwd, role) to create my User.
Do I have to check each param to invalidate my request?
e.g.
$dataJson['email'] == null ? 'error' : $dataJson['email']
$dataJson['pwd'] == null ? 'error' : $dataJson['pwd']
$dataJson['role'] == null ? 'error' : $dataJson['role']
Of course this isn't the right way, but How can I sure that my request is valid?

The approach I would take would be to have a value object and define validation rules for it.
You can load the object manually, for example:
$data = new VO\UserChangeRequest($dataJson['email'], $dataJson['pwd'], $dataJson['role']);
I would then check whether the object is valid:
$violations = $this->get('validator')->validate($data);
$isValid = 0 === count($violations);
The validations rules would be obtained by the validator component from your bundle configuration.
Here's an article explaining validation in Symfony2:
http://symfony.com/doc/current/book/validation.html
P.S For your specific case I would rather use JMSSerializerBundle. It integrates nicely and upon using param converter you will end up with the object automatically instantiated and hydrated for you. It may be a bit challenging to setup at first.

Related

Get WorkflowDesigner from a ModelItem

I am trying to create a custom IExpressionEditor. In order to new one up I need a WorkflowDesigner, All I have is the ModelItem representing my custom activity. Is it possible to access the WorkflowDesigner from a given ModelItem?
List<ModelItem> variables = new List<ModelItem>();
List<ModelItem> nameSpaces = new List<ModelItem>();
// get the activity from the datacontext
CustomActivityDesigner cad = this.DataContext as CustomActivityDesigner;
// try to get the variables
// look for variables collection cant seem to find them
ModelProperty mp = cad.ModelItem.Properties["Variables"];
if(mp != null && mp.PropertyType == typeof(Collection<Variable>))
{
mp.Collection.ToList().ForEach(i => variables.Add(i));
}
// get name spaces
ModelProperty mp2 = cad.ModelItem.Properties["NameSpaces"];
if(mp2 != null && mp2.PropertyType == typeof(Collection<NameSpace>))
{
mp2.Collection.ToList().ForEach(i => nameSpaces.Add(i));
}
// finally need the WorkflowDesigner object
WorkflowDesigner designer = Modelitem.Root....??? as WorkflowDesigner
// now we have what we need we can create the IExpressionEditor
CustomExpressionEditior ce = new CustomExpressionEditior(designer, variables, nameSpaces)
Following the Using a Custom Expression Editor as reference, it seems you should be able to create a Custom Expression Service (which will be creating the Expression Editor instances) and register it to the Services collection on the WorkflowDesigner.
Once it's registered in the WorkflowDesigner's Services collection, you'll be able to:
Get the editing context for the ModelItem by using ModelItemExtensions.GetEditingContext
Access the Services property of the returned EditingContext
Retrieve the Custom Expression Service you registered on the WorkflowDesginer
Hope it helps!

Adding users and attributes programatically in Concrete5 version 8

Hi I have recently followed some documentation to create new users from a csv file programatically. According to the Concrete5 docs/api there was method called getByID( $uID ) but this has since be deprecated!
I am creating a new user like so:
$userRegistration = Core::make('user/registration');
$file = fopen("test-users.csv","r");
while (($data = fgetcsv($file)) !== FALSE) {
echo "email address " . $data[0];
$userRegistration->create([
'uName' => $data[0],
'uPassword' => $data[1],
'uEmail' => $data[2],
'uIsValidated' => true,
]);
}
However if I want to add a value to an existing non-core attribute for instance lets call it user_county then how would I change this after programatically adding the user? I may need to do this for several user attributes as well so the values would need to come from the CSV and automatically be looped through to apply the correct value to the corresponding attribute whether it is blank or filled.
The create() method will return a UserInfo object (Concrete\Core\User\UserInfo) after successfully adding a new user. With the returned UserInfo object, you can use the setAttribute() method to set your custom user attribute.
Make sure that you have created the customer user attribute first and check that it is available before setting it, otherwise setting it will throw an error. I believe you can do this using Concrete\Core\Attribute\Key\UserKey::getByHandle('my_user_attribute') and seeing if it returns an object.
The create() method is in the RegistrationService class:
https://github.com/concrete5/concrete5/blob/develop/concrete/src/User/RegistrationService.php#L51-L140

Doctrine saves changed but not persisted entities

I have a REST Api that accepts a bulk collection of entities and then validates them one by one in order to save only valid ones and ignore invalid ones. I tried to achieve this by
foreach($bets['bets'] as $bet){
$bet['betRound'] = $betRound->getId();
$bet['user'] = $this->getUser()->getId();
$betObj = $this->getBetForGame($bet['game']);
$singleForm = $this->formFactory->create('bet', $betObj);
$singleForm->submit($bet);
if($singleForm->isValid()){
$em->persist($betObj)
}
}
$em->flush();
This checks every single entity and only persists it if it was valid. Somehow when I submit 12 valid entities an 4 invalid ones, the flush is still committing all 16 and changing the database values even for the invalid ones.
Does anybody know why?
Use $em->refresh to restore any invalid bets to their original condition.
Update: if the bet objects are already being managed then there is no need to call persist on them.
foreach($bets['bets'] as $bet){
$bet['betRound'] = $betRound->getId();
...
// Basically reloads invalid objects
if(!$singleForm->isValid()) $em->refresh($betObj);
}
$em->flush();
flush() method synchronize every change in the unit of work with the database. Try to flush only the valid valid ones separately:
foreach($bets['bets'] as $bet){
$bet['betRound'] = $betRound->getId();
$bet['user'] = $this->getUser()->getId();
$betObj = $this->getBetForGame($bet['game']);
$singleForm = $this->formFactory->create('bet', $betObj);
$singleForm->submit($bet);
if($singleForm->isValid()){
$em->persist($betObj);
$em->flush($betObj);
}
}
I do not know if it is typo, but you forgot a ; here:
$em->persist($betObj)

How does Entity Framework decide whether to reference an existing object or create a new one?

Just for my curiosity (and future knowledge), how does Entity Framework 5 decide when to create a new object vs. referencing an existing one? I might have just been doing something wrong, but it seems that every now and then if I do something along the lines of:
using (TestDB db = new TestDB())
{
var currParent = db.Parents.Where(p => p.Prop == passedProp).FirstOrDefault();
if(currParent == null) {
Parent newParent = new Parent();
newParent.Prop = passedProp;
currParent = newParent;
}
//maybe do something to currParent here
var currThing = db.Things.Where(t => t.Prop == passedPropTwo).FirstOrDefault();
currThing.Parent = currParent;
db.SaveChanges();
}
EF will create a new Parent in the database, basically a copy of the currParent, and then set the Parent_ID value of currThing to that copy. Then, if I do it again (as in, if there's already two of those parents), it won't make a new Parent and instead link to the first one. I don't really understand this behavior, but after playing around with it for a while something like:
using (TestDB db = new TestDB())
{
var currParent = db.Parents.Where(p => p.Prop == passedProp).FirstOrDefault();
if(currParent == null) {
Parent newParent = new Parent();
newParent.Prop = passedProp;
currParent = newParent;
}
//maybe do something to currParent here
var currThing = db.Things.Where(t => t.Prop == passedPropTwo).FirstOrDefault();
currThing.Parent = db.Parents.Where(p => p.ID == currParent.ID).First();
db.SaveChanges();
}
seemed to fix the problem. Is there any reason this might happen that I should be aware of, or was there just something weird about the way I was doing it at the time? Sorry I can't be more specific about what the exact code was, I encountered this a while ago and fixed it with the above code so I didn't see any reason to ask about it. More generally, how does EF decide whether to reference an existing item instead of creating a new one? Just based on whether the ID is set or not? Thanks!
If your specific instance of your DBContext provided that specific instance of that entity to you, then it will know what record(s) in the database it represents and any changes you make to it will be proper to that(those) record(s) in the database. If you instantiate a new entity yourself, then you need to tell the DBContext what exactly that record is if it's anything but a new record that should be inserted into your database.
In the special scenario where you have multiple DBContext instances and one instance provides you this entity but you want to use another instance to work with and save the entity, then you have to use ((IObjectContextAdapter)firstDbContext).ObjectContext.Detach() to orphan this entity and then use ((IObjectContextAdapter)secondDbContext).ObjectContext.Parents.Attach() to attach it (or ApplyChanges() if you're also editing it - this will call Attach for you).
In some other special scenarios (your object has been serialized and/or you have self-tracking entities), some additional steps may be required, depending on what exactly you are trying to do.
To summarize, if your specific instance of your DBContext is "aware" of your specific instance of an entity, then it will work with it as if it is directly tied to that specific row in the database.

Symfony2: How to change Entity Manager just before doing login_check

I've two dbal connections. One static, defined in config.yml, and one defined dynamically. When I need it in a controller I set the connection parameters, such as host, database name, password, etc...
I need to set the dynamic connection just before doing the login check action (or in this action).
This is because my "User" entity is on different databases according to the URL. So I can't put the dynamic connection definition in config.yml file.
I use that method to set the entity manager I need:
public function switchConnection($connectionParam=array())
{
$conn = array_merge(
array('host'=>'127.0.0.1', 'port'=>'3306', 'dbName'=>'myDatabaseName', 'user'=>'myUser', 'pass'=>'myPass', 'driver'=>'pdo_mysql', 'connection'=>'default', 'em'=>'default')
, $connectionParam);
$dbalConnectionTo=sprintf('doctrine.dbal.%s_connection', $conn['connection']);
$connection = $this->container->get($dbalConnectionTo);
$connection->close();
$refConn = new \ReflectionObject($connection);
$refParams = $refConn->getProperty('_params');
$refParams->setAccessible('public');
$params = $refParams->getValue($connection);
$params['dbname'] = $conn['dbName'];
$params['user'] = $conn['user'];
$params['host'] = $conn['host'];
$params['port'] = $conn['port'];
$params['password'] = $conn['pass'];
$params['driver'] = $conn['driver'];
$params['charset']='UTF8';
$refParams->setAccessible('private');
$refParams->setValue($connection,$params);
$this->container->get('doctrine')->resetEntityManager($conn['em']);
return;
}
Could I change the "login_check" action code to set the Entity Manager my way?
In general it's bad practice to change the default database connection under a certain condition. Also the user needs to be loaded on any (logged in) request, not just in the login request.
But there is of course a symfony way to achieve to load the user froma different database.
You would need to implement your own UserProvider that loads the user from a different database connection. Here is an example of a userprovider.

Resources