Symfony2 Get just 1 row of oneToMany Entity - php

I have a user entity and a log entity. I have a OneToMany connection from User to Log.
In my Log Table are stored log entries according to users.
I output a User list:
Controller:
$user = $this->getDoctrine()
->getRepository('SeotoolMainBundle:User')
->findBy(array('isActive' => 1, 'isAdmin' => 0));
TWIG
{% for user in list_user %}
{{ user.username }}
{% endfor %}
Now I want to recieve ONE row of the log table, sorted by a field called "date" and return it in the for user loop like this:
{% for user in list_user %}
{{ user.username }}
{{ user.log.lastEntry
{% endfor %}
How do I do this?
Entity User.php:
/**
* #ORM\OneToMany(targetEntity="Log", mappedBy="user")
* #ORM\OneToMany(targetEntity="Log", mappedBy="editor")
*/
protected $log;
Entity Log.php
/**
* #ORM\ManyToOne(targetEntity="User", inversedBy="log")
* #ORM\JoinColumn(name="user", referencedColumnName="id")
*/
protected $User;

Assuming that your getter for accessing the Log Collection object is a getLogMessages method, and assuming you can access the log message with a getMessage method, the following should solve it:
{{ User.getLogMessages().last().getMessage() }}
The last method gives you access to the last element stored in the collection.
By the way, you should use the OrderBy annotation, otherwise the order must be considered undefined. (Although, in reality, you will usually get the elements in the order they were inserted).

I solved it now in TWIG. But this isn't nice at all... I would prefere a solution inside of the controller and not in the VIEW.
{% for log in last_userlog|reverse if(log.user.Id == user.Id) %}
{% if loop.index == 1 %}
{{ log.logTitle }}
{% endif %}
{% endfor %}

Related

Neither the property "id" nor one of the methods "id()", [...]"__call()" exist and have public access in class "Doctrine\ORM\PersistentCollection"

For the life of me I can't get this to work. I have a Many-To-One relationship between Round and Program Entity. Program is related to ProgramDetail by One-To-Many.
Basically Round < Many-To-One > Program < One-To-Many > ProgramDetail.
Round Entity
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Program", inversedBy="rounds")
* #ORM\JoinColumn(nullable=false)
*/
private $programs;
Program Entity
/**
* #ORM\OneToMany(targetEntity="App\Entity\Round", mappedBy="programs")
*/
private $rounds;
/**
* #ORM\OneToMany(targetEntity="App\Entity\ProgramDetail", mappedBy="program")
*/
private $details;
ProgramDetail Entity
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Program", inversedBy="details")
* #ORM\JoinColumn(nullable=false)
*/
private $program;
Here is how i query all existing Rounds with according to it ProgramDetail.
// RoundRepository.php
public function getRoundsWithProgramDetails()
{
return $this->createQueryBuilder('round')
->leftJoin('round.programs', 'rp')
->leftJoin('rp.details', 'pd')
->getQuery()->execute();
}
Here is how I try output it
{% for round in rounds %}
<tr>
<td>{{ round.year }}</td>
<td>{{ round.programs.details.id }}</td>
<td>{{ round.scoreSendDate|date('m-d-Y') }}</td>
<td>{{ round.sampleSendDate|date('m-d-Y') }}</td>
<td>{{ round.resultSendDate|date('m-d-Y') }}</td>
<td>{{ round.status }}</td>
</tr>
{% endfor %}
If I get this done I'll at once have like 40% progress on my project since I have mostly such problems. Any help appreciated
I think the error is triggered by this line {{ round.programs.details.id }}?
Now round.programs.details is a collection of ProgramDetail entities, since it is a OneToMany relation. That is why in the error message Doctrine\ORM\PersistentCollection is mentioned. You basically try to access the id attribute of a collection of ProgramDetail entities, which obviously doesn't exist.
I assume the relation should rather be OneToOne instead of ManyToOne/OneToMany, because in the current form every Program can have multiple ProgramDetails assigned and they are therefore represented as a list/collection of entities and not as a single entity.
If not, you either need to specify an index within that list to get the id from like that: {{ round.programs.details.first.id }} or in general find another way of working with a list of ProgramDetail entities there.

simple_array handling with SonataAdminBundle

My entity has a property from type simple_array, storing a list of strings which are generated by the user (so choice does not apply).
The relevant part from the entity:
/**
* #var array
*
* #ORM\Column(type="simple_array")
*/
private $tags;
I would like to use the SonataAdminBundle to show, create and edit the entity with the tags present:
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('tags', 'collection');
}
protected function configureListFields(ListMapper $listMapper)
{
$listMapper
->add('tags', 'array');
}
The list works, but shows [0 => Tag1, 1 => Tag2] where I'd rather show Tag1, Tag2. The create and edit does not work at all, showing nothing where the input field for the tags should be.
To be clear: Tags are not a related entity, they are simply an array of strings!
For add/edit your tags I recommend this general solution How to add an array (customisable) to a symfony2 form (with sonata Admin)?
For customization of array values (by defaults) in list mode as you need, just overwrites the list_array.html.twig template from SonataAdminBundle, to something like this:
{% extends admin.getTemplate('base_list_field') %}
{% block field %}
{{ value|join(', ') }}
{% endblock %}

Creating a front end relationship in octobercms

I have created the front end relationship between my models image and album by using hasMany and belongsTo however I am not getting any results displayed and
{{ dump(images) }} and {{ dump(albums) }} gives Object variables NULL 0 NULL
Any Ideas why the relationship is not being picked up?
Album
public $hasMany = [
'images' => [ 'Acme\Library\Models\Image' ,'key'=>'album_id'],
];
Image
public $belongsTo = [
'albums' => ['Acme\Library\Models\Album']
];
album-details.htm
{{ dump(images) }}
{% for image in images %}
{{image.id|raw }}
{% endfor %}
if I run a dump on {{ dump(record) }} I get
Object variables
Acme\Library\Models\Album
bootValidation() method Boot the validation trait for this model.
forceSave() method Force save the model even if validation fails.
validate() method Validate the model instance
isAttributeRequired() method Determines if an attribute is required based on the validation rules.
errors() method Get validation error message collection for the Model
validating() method Create a new native event for handling beforeValidate().
validated() method Create a new native event for handling afterValidate().
rules array(0)
timestamps boolean
table string
relationConfig string
hasMany array(1)
I can see using the builder plugin that record is defined {% set records = builderList.records %}
Does albums/images need to be defined in this manner also?
I you send record variable to the view and record is an instance of Album you can access your images this way.
{% for image in record.images %}
{{image.id|raw }}
{% endfor %}

Doctrine Mongodb Id is blank

I have the following code in PostController of my Symfony2 application
$dm = $this->get('doctrine_mongodb')->getManager();
$fields = array('id','title', 'content');
$qb = $dm->createQueryBuilder('AppBundle:BlogPost')
->select($fields);
$query = $qb->getQuery();
$blogPosts = $query->execute();
return $this->render('post/list.html.twig',array('posts' => $blogPosts));
And the following in it's view
<ol id="navigation">
{% for post in posts %}
<li> {{ post.id }} - {{ post.content }} delete </li>
{% endfor %}
</ol>
However, the id field returned to the view is always blank. I tried clearing the cache many times but still the id is blank. Am I doing anything wrong here?
Answering my own question.
It was pretty simple. I didn't have setter/getter for id field in AppBundle:BlogPost entity. Apparently, Doctrine Mongodb uses the getter/setter to populate values from the the db.
UPDATE: It's not Doctrine but Twig template engine which requires the getter/setter.
/** #ODM\Id */
protected $id;
public function setId($valId){
$this->id=$valId;
}
public function getId(){
return $this->id;
}

Laravel form binding with one to one relationships

I have an Account model that has a polymorphic relation to an Address model. This is set up as a one-to-one releationship set up like so:
Account:
public function address()
{
return $this->morphOne('Address', 'hasAddress', 'add_hasaddress_type', 'add_hasaddress_id', 'act_id');
}
Address:
public function hasAddress()
{
return $this->morphTo('hasAddress', 'add_hasaddress_type', 'add_hasaddress_id');
}
On my form to edit the account, I also have the address fields. I can bind my account object simply enough by doing:
{{ Form::model($account, array('route' => array('accounts/edit', $account->act_id), 'method' => 'put')) }}
{{ Form::label('act_name', 'Account Name:') }}
{{ Form::text('act_name', Input::old('act_name')) }}
and that fills in the fields properly. But, how do I populate the address fields? From what I researched, I need to do:
{{ Form::text('address.add_city', Input::old('address.add_city')) }}
To access the relation's values, but this doesn't work.
I also tried
{{ Form::text('address[add_city]', Input::old('address[add_city]')) }}
as suggested by a SO with a similar title. Both of these I tried with and without the old input. Does this just not work with poymorphic relations or am I doing something wrong?
Also, how do you handle these forms in the controller?
Nothing about relations is in the form model binding documentation, and doing a search mainly brings up people asking for one-to-many binding.
It works with any *-to-one relation (for many-to-many, ie. a collection of models it won't work):
// prepare model with related data - eager loading
$account = Account::with('address')->find($someId);
// or lazy loading
$account = Account::find($someId);
$account->load('address');
// view template
{{ Form::model($account, ...) }}
Account: {{ Form::text('acc_name') }}
City: {{ Form::text('address[add_city]') }}
{{ Form::close() }}
No need for Input::old or whatsoever, null is enough as default value. Laravel will fill the data in this order (Docs are wrong here!):
1. old input
2. bound data
3. value passed to the helper
Mind that you must load the relation (dynamic call won't work in this case).
Another thing is processing the input later - Laravel will not automatically hydrate the related model, so you need something like:
$accountData = Input::only(['acc_name', ... other account fields]);
// or
$accountData = Input::except(['address']);
// validate etc, then:
$account->fill($accountData);
$addressData = Input::get('address');
// validate ofc, then:
$account->address->fill($addressData);

Categories