Sonata + Fos_user - How to display only entities related to the user? - symfony

I have users who are venue managers. I want them to be able to manage their places and events that are happening in these places.
I created fos_user_user and there I built relations to places:
<entity name="Application\Sonata\UserBundle\Entity\User" table="fos_user_user">
<id name="id" column="id" type="integer">
<generator strategy="AUTO" />
</id>
<many-to-many field="places" target-entity="EchoBundle\Entity\Place">
<join-table name="users_places">
<join-columns>
<join-column name="user_id" referenced-column-name="id" />
</join-columns>
<inverse-join-columns>
<join-column name="place_id" referenced-column-name="id" />
</inverse-join-columns>
</join-table>
</many-to-many>
</entity>
So now, I can manage users and add places that they manage. It works fine.
Questions:
How can I filter so once they log in they only see their own places?
How can I allow them to only add events to their own places? Currently when you add an event you have a full list of places to select from.
How can I filter all events so that they only see events related to places they manage?
I looked at "CUSTOMIZING THE QUERY USED TO GENERATE THE LIST" in the Sonata documentation but don't know how to use it. I tried to add security queries found in answers on StackOverflow from 4 years ago but it didn't work.

In your Admin class you can override createQuery (you should check and fix example below to meet your app model) ;)
This solution will cover question 1 and 3.
public function createQuery($context = 'list')
{
$query = parent::createQuery($context);
$aliases = $query->getRootAliases();
$query
->leftJoin($aliases[0] . '.users_places', 'users_places')
->andWhere($query->expr()->eq('users_places.user_id', ':user') )
->setParameter('user', $this->getConfigurationPool()->getContainer()->get('security.token_storage')->getToken()->getUser());
return $query;
}
Question 2:
If you are using sonata formMapper and configureFormFields method, you can pass Custom Query Builder in field definition.
$formMapper
->add('events', 'sonata_type_model', [
'label' => 'Events',
'placeholder' => 'Select ...',
'required' => true,
'query' => $blQueryBuilder,
]);

Related

Symfony - Sonata admin - override validation

i'm using sonata admin, i tried to override max length allowed for name of categorie
I have an entity MyEntity who extend Application\Sonata\ClassificationBundle\Entity\Category
// MyEntity admin class
I put this following function, regarding https://sonata-project.org/bundles/core/master/doc/reference/conditional_validation.html#inline-validation
public function validate(\Sonata\Form\Validator\ErrorElement $errorElement, $object)
{
parent::validate($errorElement, $object);
$errorElement->with('name')
->assertLength(['max' => 100])
;
}
Current display
Expected to get ride of this 32 max length on name's field
Thx for helping
It looks like what you need to do instead, is override this validation config: https://github.com/sonata-project/SonataClassificationBundle/blob/3.x/src/Resources/config/validation.xml
<class name="Sonata\ClassificationBundle\Model\Category">
<property name="name">
<constraint name="NotBlank"/>
<constraint name="Length">
<option name="min">2</option>
<option name="max">32</option>
</constraint>
</property>
</class>

Unable to delete Entity with Many to Many related objects using SF2 Form

I have a activity planning system and i'm facing an issue. My main item is called AircrewAvailability and is linked to a Period item through a Many To Many relation (the Period must stay agnostic so it can be used by other entities without storing their ids).
This availability is displayed on a FullCalendar system : Each period of each availability is an event on the FullCalendar. When clicking on the FullCalendar, we access to the CRUD form.
Create and Edit work both fine, but Delete is troublesome. When i try to remove an Availability, the ORM tries to delete the Period but does not touch to the relation table (aircrew_availability_period), so I get an Integrity constraint violation (which makes perfect sense).
Here are my mappings :
Availability entity :
<entity name="Mouke\Component\Availability\Model\AircrewAvailability" table="TBL_aircrew_availability">
<id name="id" length="40">
<generator strategy="CUSTOM"/>
<custom-id-generator class="Mouke\Component\Resource\Doctrine\ORM\Id\Sha1IdGenerator"/>
</id>
<many-to-many target-entity="Mouke\Component\Application\Model\PeriodInterface" field="periods" orphan-removal="true" fetch="EAGER">
<cascade>
<cascade-all/>
</cascade>
<join-table name="aircrew_availability_period">
<join-columns>
<join-column name="aircrew_availability_id"/>
</join-columns>
<inverse-join-columns>
<join-column name="period_id"/>
</inverse-join-columns>
</join-table>
<gedmo:versioned/>
</many-to-many>
</entity>
</doctrine-mapping>
Period entity :
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping">
<entity name="Mouke\Component\Application\Model\Period" table="TBL_period">
<id name="id" column="id" type="string" length="40">
<generator strategy="CUSTOM"/>
<custom-id-generator class="Mouke\Component\Resource\Doctrine\ORM\Id\Sha1IdGenerator"/>
</id>
<field name="startedAt" column="started_at" type="datetime"/>
<field name="endedAt" column="ended_at" type="datetime"/>
</entity>
</doctrine-mapping>
About my Forms, here the concerned part :
Availability form :
$builder->add('periods', CollectionType::class, [
'entry_type' => PeriodType::class,
'label' => 'Periods',
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
'attr' => [
'class' => 'ajax-collection section-no-padding',
],
]);
Period form :
$builder
->add('startedAt', DateTimePickerType::class, [
'label' => 'model.started_at',
'model_timezone' => $options['model_timezone'],
])
->add('endedAt', DateTimePickerType::class, [
'label' => 'model.ended_at',
'model_timezone' => $options['model_timezone'],
]);
The tricky part : I can delete a period from an availability, no problem. But if an availability has no period, it is not displayed in my calendar so you can't edit it anymore. Not only "ghost entity" may have side effects that I don't want to deal with, but also it isn't user friendly to "delete periods" to delete the whole availability, especially when you have a huge "Delete" button in the bottom of the form.
Any idea on the issue ?
Missed the on-delete="CASCADE" notation :
<join-table name="aircrew_availability_period">
<join-columns>
<join-column name="aircrew_availability_id" on-delete="CASCADE"/>
</join-columns>
<inverse-join-columns>
<join-column name="period_id" on-delete="CASCADE"/>
</inverse-join-columns>
</join-table>

Sylius - Entity variable value doesn't load in a form

I decided to write a new feature to Sylius. Now, products has availableOn parameter, but in some situations (like selling tickets for concert,which takes place on particual day) also availableTo would be very usefull.
So I added variable to database
<field name="availableTo" column="available_to" type="datetime" nullable="true">
<gedmo:versioned />
</field>
Added parameter to Product and Variant model as well,added to constructor
$this->availableTo = new \DateTime();
added method definitions to ProductInterace and VariantInterface.
Add label and widget to layout
{{ form_label(form.masterVariant.availableTo) }}
{{ form_widget(form.masterVariant.availableTo, {'label': false})}}
Add it to VariantType builder also:
->add('availableTo', 'datetime', array(
'date_format' => 'y-M-d',
'date_widget' => 'choice',
'time_widget' => 'text',
'label' => 'sylius.form.product_variant.available_to'
))
And everything works fine except when I'm in editing mode the loaded value isn't from database (saving works ok, so I can type date, save and this is stored in database and displaying correctly in other views). There is a value 2010-01-01 without hours. What can I do to fix it?
The solution of this problem was I didn't add this field in mapped-superclass in Variant.orm.xml file
<mapped-superclass name="Sylius\Component\Product\Model\Variant" table="sylius_product_variant">
<field name="availableOn" column="available_on" type="datetime" nullable="true" />
<field name="availableTo" column="available_to" type="datetime" nullable="true" />
</mapped-superclass>

symfony2 comparing hidden field with its hash with form validation

I would like to know how to compare fields in symfony2 form with custom validation.
In particular I want to compare a simple hidden field with its hash.
<input type="hidden" name="smoke" value="1" />
<input type="hidden" name="smoke_hash" value="kahsjkdasjkdh3iuy84932798" />
Something like "repeated Field" but validated with my own logic.
But more something like this:
use Symfony\Component\Validator\Constraints\HashMatchString;
$builder
->add('smoke', 'hidden', array(
'data' => 1,
)
)
->add('smoke_hash', 'hidden', array(
'constraints' => array(
new HashMatchString('smoke')
),
)
)
;
Form Goodness in Symfony 2.1
I’ve already see the solution of Steven Brown (http://www.yewchube.com/2011/08/symfony-2-field-comparison-validator/) but is one year ago with multiple touches on core files...
SOLVED
I’ve created a gist: Gist
Just add validation method to your entity http://symfony.com/doc/current/book/validation.html#getters

NHibernate One-To-Many Delete Not Cascading

I have a 'Photo' class and a 'Comment' class. An Photo can have multiple comments assigned to it.
I have this configured as a one-to-many relationship within my HBM mapping file, and have set cascade="all-delete-orphan" against the 'Comments' bag within the Photo.hbm.xml mapping file.
However, if I try to delete a Photo which has 1 or more Comments associated with it, I am getting 'The DELETE statement conflicted with the REFERENCE constraint "FK_Comments_Photos"'
I tried a couple of other cascade options against the Comments bag in my Photo.hbm.xml but regardless of what I set it to, I'm getting the same outcome each time. I just want to be able to delete a Photo and have any associated comments automatically delete too.
Here is my Photo mapping (edited for brevity):
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" .... default-access="property" default-cascade="none" default-lazy="true">
<class xmlns="urn:nhibernate-mapping-2.2" name="Photo" table="Photos">
<id name="PhotoId" unsaved-value="0">
<column name="PhotoId" />
<generator class="native" />
</id>
...
<bag name="Comments" table="Comments" cascade="all-delete-orphan" order-by="DateTimePosted desc" where="Approved=1">
<key column="PhotoId" />
<one-to-many class="Comment" />
</bag>
</class>
Here is my Comment mapping (edited for brevity):
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" ... default-access="property" default-cascade="none" default-lazy="true">
<class xmlns="urn:nhibernate-mapping-2.2" name="Comment" table="Comments">
<id name="CommentId" unsaved-value="0">
<column name="CommentId"></column>
<generator class="native" />
</id>
...
<property name="Author" not-null="true" />
<property name="Body" not-null="true" />
<property name="Approved" not-null="true" />
<many-to-one name="Photo" not-null="true">
<column name="PhotoId" />
</many-to-one>
</class>
Does anyone have any suggestions as to why the cascade is not happening when I try to delete a Photo with comments associated with it?
UPDATE: The only way I can get the cascade to happen is to configure the 'Delete Rule' within SQL Server against this relationship to 'Cascade', and in doing so means that I don't need to specify any cascade action within my NHibernate Mapping. However, this isn't ideal for me - I'd like to be able to configure the cascade behaviour within the NHibernate Mapping ideally, so I'm still confused as to why it doesn't appear to be taking any notice of my NHibernate cascade setting?
My guess would be that the problem comes from the fact that the many-to-one in the Comment mapping is set to not-null="true".
Because of that, NHibernate is not allowed to set this property to null temporarily before it deletes the Photo object and therefore when is goes about deleting the Photo object SQL Server throws an foreign key exception.
If I remember correctly for the order of actions when deleting is:
Set foreign key value to null in all child objects
Delete parent object
Delete all child references
Try to remove the not-null="true" from the many-to-one and see what will happen.
Try with inverse="true" on the bag collection of your mapping.
I had similar problem for 1 day .. and got frustrated over it.
Finally the solution boiled down to the DB.
I had to change the FK key constraints in "INSERT UPDATE SPECIFICATION"
'Delete Rule' : from 'No Action' to 'Cascade'
additionally you can also set
'Update Rule' : from 'No Action' to 'Cascade'
You can specify the delete-cascade option in NH:
<bag name="Comments" cascade="all-delete-orphan" order-by="DateTimePosted desc" where="Approved=1">
<key column="PhotoId" on-delete="cascade"/>
<one-to-many class="Comment" />
</bag>
You probably should make it inverse. Then I wonder where your FK_Comments_Photos column is specified.

Resources