How to use adapters to implement a feature

believe it or not, I'm trying to use the adapters concept for the first time in my Plone life.

can someone please tell me if what I'm doing is right?

3 Likes

Although talking about grok, https://docs.plone.org/4/en/appendices/five-grok/core-components/adapters.html is useful as well giving more info about how adapters work.

I think @hvelarde got the concept right.

I added some feedback as comments on GitHub.

2 Likes

thank you for your comments; I was discussing yesterday with @rodfersou about using a helper browser view and other possible options.

IMO, calling a browser view inside another browser view will have worst performance than using the adapter and that's why I skipped that.

for me the best solution in this case must be easy to implement and fast: that's why I think the adapter is fine here.

A browser view is an adapter (adapting the tuple "viewed object, request"); thus, the performance penalty should not be that large (if browser view and adapter do comparable things internally)

1 Like

we need to test that and I have no time right now, but I doubt an adapter on a content type instance will have the same performance penalties associated with security that a browser view.

maybe I'll come back later with some hard data.

I was right: the adapter is 3 times faster than the helper browser view:


class AMPView(BrowserView):
    """Accelerated Mobile Pages default view."""
    ...
    @property
    def pixel(self):
        adapter = queryAdapter(self.context, IAMPPixelProvider)
        if adapter is not None:
            return adapter.pixel()

    @property
    def amp_tracking_pixel(self):
        return api.content.get_view('amp-tracking-pixel', self.context, self.request)()

class AMPTrackingPixel(BrowserView):
    def __call__(self):
        return u'<amp-pixel src="https://example.com/tracker/foo" layout="nodisplay"></amp-pixel>'
  <browser:page
      class=".AMPTrackingPixel"
      for="plone.dexterity.interfaces.IDexterityContent"
      layer="collective.behavior.amp.interfaces.IAddOnLayer"
      name="amp-tracking-pixel"
      permission="zope2.View"
      />
from profilehooks import timecall
...
class AMPViewTestCase(unittest.TestCase):
    ...
    def test_adapter(self):
        @timecall(immediate=True)
        def render(times):
            for i in xrange(0, times):
                self.view.pixel
        render(times=1000)

    def test_helper_view(self):
        @timecall(immediate=True)
        def render(times):
            for i in xrange(0, times):
                self.view.amp_tracking_pixel
        render(times=1000)
$ bin/test -m performance
Running collective.behavior.amp.testing.collective.behavior.amp:Integration tests:
...
collective.behavior.amp.testing.collective.behavior.amp:Integration in 0.000 seconds.
  Running:
    1/2 (50.0%)
  render (/home/hvelarde/collective/behavior.amp/src/collective/behavior/amp/tests/test_performance.py:23):
    0.022 seconds

    2/2 (100.0%)
  render (/home/hvelarde/collective/behavior.amp/src/collective/behavior/amp/tests/test_performance.py:30):
    0.073 seconds

                
  Ran 2 tests with 0 failures and 0 errors in 0.382 seconds.
...
3 Likes

#hedidthemath

I respect that, and I'm in the same place.

Found some code, just today, while explaining adapters to a co-worker.

I did everything right registering an adapter, defining the interface, implementing the class, etc.... beautiful.

Then found the faux coup de grâce where I just imported the factory and instantiated it with the context. (oops)