Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
We need to show a message and disable all fields on the package type edit form, if there's a shipment entity that specifies the plugin derived from that package type config entity. We'll want a helper method inside the form class that will do an entity query.
Comments
Comment #2
jsacksick CreditAttribution: jsacksick at Centarro commentedI figured we probably need to implement an access control handler for the package type to prevent deleting already in use package types.
Should we extend the PackageTypeTest?
Let me know if the message needs to be polished as well.
Comment #3
jsacksick CreditAttribution: jsacksick at Centarro commentedForgot the Access control handler.
Comment #4
jsacksick CreditAttribution: jsacksick at Centarro commentedI now get the query from the storage.
Comment #5
bojanz CreditAttribution: bojanz at Centarro commentedWe want to generalize this concept to Commerce itself.
However, the current approach is potentially too expensive. An admin listing with 50 entities means 50 calls to access('delete'), which calls isUsed(), which means at least 50 entity queries (sometimes more).
We could call isUsed() from the delete form instead, then again from the controller as a protection against API deletes (REST or just code calling $entity->delete()), but the question then becomes whether we should skip deletion silently, set a message, or throw an exception.
Comment #6
skyredwang@bojanz sent me here from IRC, because I have a production DC site, currently with 469 colors, 18 sizes and 538 styles. They are all product attributes. I haven't tested the patch yet, because I am not using shipping. I just want to provide an example that expensive checking won't work well for me in general.
I will revisit this discussion once I got more time.
Comment #7
bojanz CreditAttribution: bojanz at Centarro commentedThis is what EntityResource (REST) does:
So, to be able to show why deletion is forbidden, we either need to use entity access, or to override this class and method to perform our separate isUsed check as well.
Comment #8
Wim LeersThe problem in this issue is: how to efficiently list N entities, and the access check for each entity needing an entity query over M entities.
This is a known problem. You could solve this with the Node Access API —
hook_node_grants()
'sgrant_delete
allows you to efficiently query. Unfortunately that only works for nodes, and we're obviously not dealing with nodes here. #777578: Add an entity query access API and deprecate hook_query_ENTITY_TYPE_access_alter() exists to generalize that API to all entity types. That issue would help you a lot.#5:
Note that Views have row-level caching, and access results have cacheability metadata. So, the access result would have the
commerce_shipment_list
cache tag. Which would mean that you'd only re-run that access check if any of the M entities had changed. Now, I can easily see shipment entities changing frequently, so that doesn't actually help you.You could create a custom cache tag, something like
commerce_shipment_using_package_type_{TYPE}_list
, add some logic toShipment::preSave()
that invalidates this cache tag when appropriate (i.e. when a shipment is created that uses this package type, or when the package type is changed and either the pre or post value matches this package type).#6: if you're not using shipments, then how is your site affected? Is it because colors/sizes/styles also affect whether package types can be deleted or not?
#7: I'm not sure what you're asking there. 3 possible interpretations, 3 answers:
return AccessResult::forbidden()->addCacheableDependency($entity);
, you can simply change that toreturn AccessResult::forbidden('This package type cannot be deleted because shipments are using it.')->addCacheableDependency($entity);
, and the reasonThe patch in #4 looks good to me. Thoughts:
\Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase
— I know @tstoeckler was very enthusiastic about how it helped him add REST test coverage for his custom entity types. See #2824572: Write EntityResourceTestBase subclasses for every other entity type. for lots and lots of examples.Comment #9
dawehnerThere is are quite some conditions here, I'm curious have you done some profiling whether this naive approach is too slow? I would guess the slowness is mostly focused around the entity query. Given that I'm curious whether you experienced with prefetching the entity query. Wouldn't that be possible using some of our thousand hooks and places to interact?