contao / core

Contao 3 → see contao/contao for Contao 4
GNU Lesser General Public License v3.0
490 stars 213 forks source link

Provide a class for handling AJAX #4415

Open qzminski opened 12 years ago

qzminski commented 12 years ago

How about providing a new class for AJAX things, so we don't have to download Andreas' extension (http://www.contao.org/en/extension-list/view/ajax.10010039.en.html) every time? Perhaps you can bundle this extension into core?

leo-unglaub commented 12 years ago

Where is the problem by using aschempp's extension or my SimpleAjax extension?

qzminski commented 12 years ago

There is no problem at all @LeoUnglaub! However, I think it would be nice to have it included by default :)

leo-unglaub commented 12 years ago

I don't know. Not everything sould be included in the core it it is solvable with an extension. Specially in this case, because Ajax handler have almost everytime complete different usecases. In my case, i very often can't use the extension from aschempp. Because he is forcing the return format to be a json string with the request token in it. In so many cases this is simple not usefull. So i thing the 5 lines für building the ajax handler sould stay externaly, so everyone can build there own.

Just my two cents ;)

qzminski commented 12 years ago

Well, you're right, but I'm pretty sure that @leofeyer could provide something universal and really awesome, which would fit every single developer. Also, relying on the 3rd party extensions might be a little risky, as their updates come usually some days/weeks after the new Contao version. Despite the fact that none of the current front end elements doesn't use AJAX, I still think a system that wants to expanse over the world should provide basic (nowadays) functionality. It's a shame when client wants some AJAX magic and you have to download extra files just to do that. It's really not a big deal to have one extra file in the core! :)

leofeyer commented 12 years ago

Why do you have to download extra files? There is an Ajax hook in the core.

qzminski commented 12 years ago

As far as I remember, that hook applies only to the back end?

leofeyer commented 12 years ago

Not sure, but I'll check. If it was the case, of course we would have to enhance it.

Serhii-DV commented 12 years ago

I agree with @qzminski and I also think that AJAX class should be in Contao core. @aschempp ajax extension is good but the problem with it that it doesn't updated quick after new Contao release.

Yes, we can use in frontend modules code like this:

<?php

if ($this->Environment->isAjaxRequest)
{
   // do something...
}

But this code is not always convenient.

qzminski commented 12 years ago

Also, putting the AJAX code in the front end module will affect the performance, as using @aschempp ajax.php seems to execute whole process faster.

aschempp commented 12 years ago

Be also aware that ajax is difficult to protect. My extension currently allows to retrieve every unprotected frontend module and content element, event if the parent page is protected (or the module is on no page).

leo-unglaub commented 12 years ago

@aschempp thats one of the main reasions i really DON'T like your extension. I am really against an ajax class in the core witch provides methods like the Ajax Class from @aschempp. This is just to difficult to protect.

An ajax class can only be a "meta" class. Every ajax request must be handled by the developers manualy. So if i have to catch some ajax requests i must have full control over the response like in my simple_ajax extension. Every thing else is useless and a security risk.

aschempp commented 12 years ago

You are somewhat correct. However, how does any developer protect against this? They would have to find the same routine over and over again, which could be included in the core script.

Btw, the possibility to retrieve every module has also raised from people's need who can't do much extensions (because of their lack of PHP knowledge), but they can do javascript stuff to retrieve data.

leo-unglaub commented 12 years ago

The protection is simple. If you have the ajax request: http://foo.bar/simple_ajax.php?requestedModule=foobar the developer knows that it's a request for him and he only returns data witch is needed.

The argument, that people can JavaSCript but no PHP is not valid. If you want to work withc Ajax, you need to know a server side language to, otherwize you can't prepare the data you need. The developer how writes the server side extension MUST know PHP. There is no way around that.

aschempp commented 12 years ago

that protection is not sufficient. If the frontend module you're handling is on a protected page, your routine should not return data if the member is not logged in...

leo-unglaub commented 12 years ago

LOL, @aschempp you are so cute if you are confused. The page has NOTHING todo with an ajax request. That is the main problem that you still think this. An ajax class normaly extends System or Controller, but NOT Frontend oder something else. You have there NO pregenerated page object. Nothing. You have just an hook witch calls your custom metods witch prepare whatever response you need.

aschempp commented 12 years ago

In most cases, a new frontend module or content element will provide ajax functionality (like ajax pagination). So it is always related to a page. No matter how your function works, if you tell it to "get the next 10 results" it still needs to know if the user is even allowed to do that.

leo-unglaub commented 12 years ago

No, thats NOT an Ajax class witch all developers can use. Thats an ajax handler for one case, but not useable for everything else.

aschempp commented 11 years ago

I'd like to have this in 3.1... Let's discuss that @contao/workgroup-core

leo-unglaub commented 11 years ago

Why now? This was discussed because there was NO alternative for it. But now we have 2 extensions for that. Why putting it now in the core?

aschempp commented 11 years ago

Cause in my opinion, only the core can handle this correctly. I'll explain it to the team, then we'll see...

leo-unglaub commented 11 years ago

One of those extensions is from me, please can you tell me in what point a core implementation would be better than mine? Also, if you explain it to the team how can i know that you are talking about?

In case you have forgotten that Contao is an open source CMS, you can't just bring all important discussions to your internal team calls and leave the rest of the developers out of the decision process. Thats now how open source works. I know you all love your fancy teams, but with what reason do you discuss this in an closed internal team call?

If you want to discuss this matter, please do it here so everybody can read it.

backbone87 commented 11 years ago

The protection system of contao is calculated on the fly while page rendering. So to keep modularity, you can only assume that all access checks of Contao are done, when the generate method of your page/module/CE/whatelse is invoked. Therefore the earlier mentioned $this->Environment->isAjaxRequest is the right way. I use this technique in various of my custom extensions (though I may use another trigger) and it works out quite well. Of course everything else generate before your module is wasted, but that is a limitation of Contaos poor (or "very simple" if it does offend you less) rendering process.

aschempp commented 11 years ago

That is exactly my point. The core would be able to skip the generate method of all modules except the one you're interested in.

leofeyer commented 11 years ago

Ok, so the basic point is that there should be an option to request an article, a module or content element via Ajax through a page without the core loading all the other page elements?

aschempp commented 11 years ago

Correct

leo-unglaub commented 11 years ago

But thats only one part of an ajax extension. Because not every ajax request simply wants a pre-parsed html string for the response. If the core ships an ajax endpoint ther should be also a way to request content generated by a special module. (via hook, ... )

aschempp commented 11 years ago

Correct. A hook should be included, or they can use one of our extension for that.

Also, don't get confused, the module does not need to return HTML, it could be JSON or anything...

backbone87 commented 11 years ago

Please stop that hooking... Events or something like this please with API to interact, not hook with two parameters...

Although how do you want to achieve system security? Articles... ok CEs... ok Modules... ok News???? Events???? Custom extensions????

aschempp commented 11 years ago

News = Frontend Module Events = Frontend Module Extension = CE or FMD

backbone87 commented 11 years ago

Consider a ajax request for news entry X. How do you want to ensure security, if there are two different listers with different security settings?

Consider you have created an article X in a not published page (working container), and referenced it within page protected article Y.

You dont know which security checks are done while nested rendering (for example the article reference), so you cannot recheck everything centerlized. The only way to know is to do the rendering tree again (at least up to the point of interest)

leofeyer commented 11 years ago

As far as I've understood, you never directly request a news item, but the news reader module on the news reader page. For instance, to request the news article "James Wilson returns", the URL would be:

http://domain.tld/en/news/james-wilson-returns.html?m=12

Contao would then compile the news page with the news reader module and the item "james-wilson-returns" and – since you only requested to return the module ID 12 – only render the news reader module instead of the whole page.

You can never do something like this:

http://domain.tld/en/academy.html?news=james-wilson-returns

aschempp commented 11 years ago

Leo is correct, but Oli rised a problem I did not think about. Our idea would not work if a module has been included through inserttags?

leofeyer commented 11 years ago

That's true, but isn't it a minor limitation we can live with?

leo-unglaub commented 11 years ago

I have to ask on this issue again, because i am not understanding what you are planning. If i get you right you want to let the modules decide what type of content to be generated?

Example: http://www.foo.bar/my-hobbies is generating the normal HTML site and if it's an ajax call it just returns the article my-hobbies? Are you sure that's even possible? Because what if you have multiple articles on one page? Do i get both articles? If yes, i have a question. In what case can you use such an ajax module? I basically can't think of even one use case of this. I mean where do i use ajax content with does not follow hard rules?

Another example with the news: http://www.foo.bar/news-lister it contains 3 news lister for three different news archives. How should Contao decide on what archive to return?

Besides the fact that i can't think of any usecase where that kind of content would be usefull, i don't see a reasion for it. Because the permission from a page tree can't be applied to an ajax request. Those are always some different kind of data sets. You can't map the permissions from the reader and lister module to a single ajax endpoint because in the page you have a tree but in ajax you simply have one endpoint.

Greetings Leo

xat commented 11 years ago

Sorry for that posts before.. somehow GH acted weired ;)

We solved some similar problems discussed here within the contao-rpc extension which can also be used as an Ajax Endpoint (actually I do it that way in my projects).

Within contao-rpc there is an Configuration Array where Developers are able to register Methods in. It looks like this:

$GLOBALS['RPC']['methods'] => array
(
  'pong'    => array
  (
    'call'    => array('MyPing', 'ping')
  )
);

Now you have the ability to define rights in the contao backend who should be able to use the exported 'pong' method.

Maybe the core Ajax extension could be built in a similar way?

And I have to agree with LU that it is not common to retrieve entire HTML blobs through Ajax Requests. Mostly you will want to receive data structures which you can then process in the frontend and for example output the data using frontend template engines like Handlebars.JS.

xat commented 11 years ago

Btw, you will also run into trouble if the HTML-Blob you receive through the Ajax Requests has dynamic stuff like lightboxes, videoplayers, sliders and so on since you will need to reinject the JS functionality after the HTML-Blob was inserted into the DOM. What if the HTML-Blob received contains some inline JS (script-tags) Funcationality? You would need to eval that... and so on.

aschempp commented 11 years ago

apparently, both of you (@leounglaub + @xat) have never used my ajax extension.

1: building an RCP endpoint, where the user needs to set permission is something totally different. If I place a module with ajax functionality on a specific page, I can't think of a reason to set additional permissions.

2: @leounglaub, you still misunderstood it. Imagine you create your own news module, that will load the next 5 items when the user scrolls to the bottom. I want the module that is already on the page to receive my call, and know how to handle it. It will know (e.g., by an url parameter) which next items to show. It will know what items it is allowed to show, because that configuration is already in the module.

The big benefit of including this in the core is simply that Contao will make sure you can't call the module without having access to the specific page. Imagine the ajax extension from @leounglaub. The scroll-load-news extension would register for the hook to return news items. How is it supposed to know if the requesting browser has access to this news content? If the module is anywhere placed on a page the user can see? If not, he should not be able to get to the information.

leo-unglaub commented 11 years ago

@aschempp You still don't understand the problem. Whats going to happen if you have 2 news modules on a site? What happens if you don't want an ajax call that returns the prepared html string? Whats going to happen if i want the news as json? Whats going to happen if news/events are not the only data source? Whats about custom data sources?

All those points are currently not solved! Greetings Leo

xat commented 11 years ago

I have to apologize again for the spam.. Somehow my Chrome/Ubuntu combination automaticly sends the answer 4 time after hitting 'enter' in the textfield. Maybe I should boot my macbook and do the commenting from there :)

@aschempp

Your assumation is wrong, I used your ajax extension but had to comment out some code in it because I didnt want every FE Module/CE etc. to be accessable public.

I basicly agree that it may not be practical that the user has to set permissions vor each ajax functionality.

However, I still disagree with the general idea of sending whole HTML-Blobs. As I said, most times you need the data in a way your still able to process it on the clientside. I think more and more stuff is handled on the Clientside (Browser) these days. And the Client loads the data which it needs on demand from the server through Ajax Requests or Websockets. And most time it's simply not just done by sending an HTML-Blob.

tristanlins commented 11 years ago

I read a lot of comments now and I think @aschempp is on the wrong way. As far as I understand, you try to make an "all-in-one" solution (like your ajax extension), that check the user permissions to a specific element.

that protection is not sufficient. If the frontend module you're handling is on a protected page, your routine should not return data if the member is not logged in...

And you think the core can handle this? I don't think so, lets have a look on the permission system:

- themes (unprotected)
  - modules (can be protected)

- page (can be protected)
  - layout (unprotected)
    - modules (can be protected, see above)

- merger module (can be protected, see my merger2 extension)
  - module (can be protected)

- page (can be protected)
  - article (unprotected, btw. why not???)
    - content element (can be protected)
      - module (can be protected, see above)

- {{insert_module::*}} (the containing element may be protected)
  - module (can be protected)

Now there are two situations: (1) I want a module, independent of the layout/content/article/page the module is included. In this case the only protection is the protection settings of the module itself. Simple Example: /ajax.php?mod=123

(2) I want a on a specific page This is difficult, because a module can be included in so many ways! Simple Example: /some-page.html?mod=123

If you provide both methods (thats the only useful way for developers), the big question is how you decide which of the two situations is given? In second case, you know the page and all elements that are including the module. In this case you can decide if the module is accessible, because you have to build the complete page before.

But how you protect that a user rewrite the request from /some-page.html?mod=123 to /ajax.php?mod=123? In first case the complete permission management, expect the protection of the module itself is omitted!

When I look on the situation, there is only one protection setup that works: Protect the module itself and don't trust the protection mechanisms from page, content or other modules.

BTW: @aschempp you are wrong with this:

1: building an RCP endpoint, where the user needs to set permission is something totally different. If I place a module with ajax functionality on a specific page, I can't think of a reason to set additional permissions.

An ajax endpoint is absolutely the same as an RPC endpoint! I can think of a reason to set additional permissions, for example If you wan't to connect with an API-Key (in a mobile app or something similar).

Summary: you have to set the permission set on the module itself, that is the only useful and "not insecure" method contao can provide!!! All other is a fake.

aschempp commented 11 years ago

@tristanlins Situation (2) is the only one that should be provided.

tristanlins commented 11 years ago

Do you really one wan't to provide this expensive method for ajax calls? If you wan't so, do it, I will probably never use it :-D

leo-unglaub commented 11 years ago

I will probably never use it :-D

Thats exactly my point. It's not useable. Maybe on the paper, but not in an real world example. (real world = internet g )

leofeyer commented 11 years ago

Let us do a workshop on this at the Contao conference in May.

leo-unglaub commented 11 years ago

@leofeyer are you on the "Contao Nordtag"? If yes, all @tristanlins and me will be there. So we can talk there. :)

leofeyer commented 11 years ago

I will not be there unfortunately :(

leo-unglaub commented 11 years ago

Thats sad. You are missing me ranting about SEO people. :)

tristanlins commented 11 years ago

@leofeyer a workshop sound good, why not make a little Devcon before or after the conference? g

Toflar commented 11 years ago

I think the conference is not the right place for the developers to hide and do their thing. There are many people coming to the conference to see and talk to us about their daily issues when handling Contao. If you want to do a workshop for one specific issue, there's nothing to be said against that. But if you want to do hackdays, then do that on another occasion, please :)

tristanlins commented 11 years ago

@Toflar you'r right, thats why I say before or after, not the same time ;-)