My situation is this, firstly there is a entity Person which have a OneToMany relationship with the entity Face (and of course the other way around with ManyToOne), and each time I update the Person entity I might add some extra Face entities to the Person. Basically it looks like this:
/**
* #ORM\OneToMany(targetEntity="Face", mappedBy="person", cascade={"persist"})
*/
private $faces;
...
/**
* #ORM\PrePersist()
* #ORM\PreUpdate()
*/
public function preUpload()
{
foreach ($this->images as $image) {
if (null === $image) {
break;
}
$face = new Face();
$face->setPerson($this);
$face->setImagePath(sha1(uniqid(mt_rand(), true)));
$this->addFace($face);
}
}
This works as expected when I do persist the Person with some Face entities for the first time, but when I try to update a existing Person and add more Face entities I cannot make them persist, everything that should happen does, except that no new Face entities is persisted.
Hope somebody has been in the same situation and can give me some advice, peace out!
I have a comparable project, where a survey has questions and each Question has an Image.
I followed the docs here and for updating the related entity I moved all the logic to that Entity, which wuold be "Face" in your case. Everything works fine and my controller looks like this:
...
$survey->preUpload();
$questions = $survey->getQuestions();
foreach ($questions as $question)
{
$question->preUpload();
}
$em->persist($survey);
$em->flush();
...
Hope that helps.
You need to specify a cascade persist policy even on the other side of the relation. It's not automatically bidirectional.
/**
* #ORM\ManyToOne(targetEntity="Person", inversedBy="faces", cascade={"persist"})
*/
Related
I have the following problem: when i try to change the town of a user by passing the modified user entry to my ModifyUser method in my UserService class everything seems ok but the changes are not applied in the database.
I tried the solutions from similar problems i found on stackoverflow but none of them seem to work.
As they say "a picture is worth a thousand words" take a look at this, since its easier to understand compared to my short explanation.
http://prntscr.com/el51z0
else if (property == "BornTown")
{
if (this.townService.TownExists(value))
{
User user = this.userService.GetUserByName(username);
Town town = this.townService.GetTownByName(value);
user.BornTown = town;
this.userService.ModifyUser(user);
}
else
{
Console.WriteLine($"Value {value} is not valid.");
throw new ArgumentException($"Town {value} not found!");
}
}
When i pass the user to the ModifyUser the database does not update, and BornTown stays NULL.
public void ModifyUser(User user)
{
using (PhotoShareContext context = new PhotoShareContext())
{
context.Users.Attach(user);
context.Entry(user).State = EntityState.Modified;
context.SaveChanges();
}
}
Or else try below code:
User user = context.users.where(x=>x.username == username).FirstOrDefault();
user.BornTown = town; //string
context.savechanges();
Can you try
context.Users.where(x=>x.username == username).FirstOrDefault();
and don't use any()
Can you check if you are getting the proper username, by again checking the username once you are getting back the value in the function.
Instead of manipulating the navigation properties directly try to manage the entity relation using it's foreign keys:
Town town = this.townService.GetTownByName(value);
user.BornTownId = town.Id;
Keep in mind that if you have not created explicit foreign keys in your model entity you should map the existing one: take a look at "Users" table - see how the foreign key column is named- it should look something like UserTown_Id. Then put it in your model class (you may add foreign key attribute or map it in model builder).
Be careful when adding the new property to your model (it can make your optional relation with "Towns" required).
I probably missed something really obvious, but have had no luck thus far. I have two related models, Messages and Users. I'm trying to append only the 'username' of the user who created the message when retrieving all messages. I am getting a fully serialized related user model however. I understand I could $hidden in my User model, but would like to avoid that.
In my Messages model, I've created a relationship
public function createdBy()
{
return $this->belongsTo('App\User', 'created_by');
}
Then I've added
protected $appends = ['username'];
Along with a custom attribute
public function getUsernameAttribute($value)
{
$username = null;
if ($this->createdBy){
$username = $this->createdBy->username;
}
return $username;
}
When I'm getting messages through another relationship such as
return $channel->messages()->orderBy('id','desc')->get();
I end up with the following response:
[{"id":97,"to_id":"12345","message":"This is the message content","created_at":"2017-02-25 08:58:22","created_by":{"id":1,"email":"REDACTED","name":"REDACTED","username":"myusername","created_at":"2016-09-26 16:00:00","created_by":null,"updated_at":"2017-02-20 00:33:06","updated_by":null},"updated_at":"2017-02-25 08:58:22","updated_by":null,"deleted_at":null,"username":"myusername"}, ...
What am I doing wrong, or is there a better way to accomplish what I'm trying to do?
I didn't realize I was able to hide the relationship in the original model. I ended up hiding the createdBy relationship in the Messages model.
protected $hidden = [
'createdBy'
];
This is what my table relationship is like:
One user may have multiple groups. One group may have multiple users.
One message maybe be only by one user and group.
I have three models in laravel.
User,Message, and Group. And my pivot table is mssg_group which stores which user sent which message to which group.
(if this design is incorrect, do tell me the better way).
How do I write relationships to access all messages before a certain time by supplying a groupID?
I think your searching for the hasManyThrough relationship.
You need a Group model with a relationship to messages. See the Laravel Docs for more info.
/**
* app/Group.php
*/
public function messages(){
return $this->hasManyThrough('App\Message','App\MessageGroup');
}
In your Message Group Model you need to create the messages relation.
/*
* app/MessageGroup.php
*/
protected $table = "mssg_grp";
public function messages(){
return $this->hasMany('App\Message','id','mssg_id');
}
In your Message model be sure to define your custom table name.
/*
* app/Message.php
*/
class Message extends Model {
protected $table = 'mssg';
}
In your controller you can eager load the date requirement.
$group_messages = Group::where('id', $group_id)->with(function($query)
{
return $query->where('created_at','>',$date);
})->get()
I haven't tested it, so this may need to be tweaked a little bit, but it should get you close to where you want to be. I haven't address retrieving users, but it should be nearly the same as getting the messages synced up. Let me know if this helps.
I presently have a model called UserLevels which defines some user levels (user, premium user, admin, etc) and some properties of them (number, description, color, etc).
I've decided I would rather hard code this, and be able to use the __() method on the names and descriptions.
How do I go about providing data to a model so that it doesn't use a database? Is there a better way to approach this?
Thank you.
Update: Full multi-field records in a model without a database
After the author made his goal more clear, this should be the solution:
How to use models without database on CakePHP and have associations?
Don't get the title wrong, read it first, the answer describes exactly what would be the solution here as well.
Solution for single field, enum like data:
If you don't use a DB table and entries are limited it is always good to use constants because you can't do a typo without causing an error somewhere and UserLevel::USER is much more clear than a random 'user' string somewhere that could mean anything.
class UserLevel extends AppModel {
public $useTable = false;
const ADMIN = 'admin';
const USER = 'user';
/* ... */
public function getUserLevels() {
return [
UserLevel::ADMIN => __('Admin'),
/* ... */
];
}
}
Today I've got a problem when I tried using following code to alter the model attribute in the controller
function userlist($trigger = 1)
{
if($trigger == 1)
{
$this->User->useTable = 'betausers'; //'betausers' is completely the same structure as table 'users'
}
$users = $this->User->find('all');
debug($users);
}
And the model file is
class User extends AppModel
{
var $name = "User";
//var $useTable = 'betausers';
function beforeFind() //only for debug
{
debug($this->useTable);
}
}
The debug message in the model showed the userTable attribute had been changed to betausers.And It was supposed to show all records in table betausers.However,I still got the data in the users,which quite confused me.And I hope someone can show me some directions to solve this problem.
Regards
Model::useTable is only consulted during model instantiation (see the API documentation for Model::__construct). If you want to change the model's table on the fly, you should use Model::setSource:
if ( $trigger == 1 ) {
$this->User->setSource('betausers');
}
The table to use is "fixed" when the model is loaded/instantiated. At that time a DB connection object is created, the table schema is being checked and a lot of other things happen. You can change that variable later all you want, Cake is not looking at it anymore after that point.
One model should be associated with one table, and that association shouldn't change during runtime. You'll need to make another model BetaUser and dynamically change the model you're using. Or rethink your database schema, a simple flag to distinguish beta users from regular users within the users table may be better than a whole new table.