jordanlev Posted October 6, 2014 Share Posted October 6, 2014 I am trying to build a module of the "process" variety (some custom admin dashboard pages). It looks like there is not much in the way of an MVC system or routing for these... from what I can tell my options for routing boil down to 2 options: execute(), executeSomething(), executeSomethingElse(), etc. The execute() method responds to the "top-level" url for my module (for example, http:// my-site.com/processwire/setup/my-module/). Any other methods whose names start with "execute" respond to a "2nd level" url (for example, executeSomething() responds to http:// my-site.com/processwire/setup/my-module/something/; and executeSomethingElse() responds to http:// my-site.com/processwire/setup/my-module/something-else/) Inside the execute() method, use $this->input->urlSegment1, $this->input->urlSegment2, etc. to retrieve the portions of the url under the "top-level" (for example, if the user visits http:// my-site.com/processwire/setup/my-module/something, then inside the execute() method $this->input->urlSegment1 would be "something" (and for http:// my-site.com/processwire/setup/my-module/another/thing , $this->input->urlSegment1 would be "another" and $this->input->urlSegment2 would be "thing"). Am I understanding the system correctly? If so, what is the purpose of having "executeSomething()" if you can just look to $this->input->urlSegment1 inside the "execute" method? It seems rather arbitrary, since there is no way to use "executeAnotherThing()" to respond to /my-module/another/thing (as far as I can tell?). Also, isn't it true that the url segments might be set to a different level on different sites? So if I'm building a module for others to install, how can I know that the site it is installed on even allows 2-, 3-, or more url segments under my top-level page? Are there any example modules out there that implement their own routing system that is more robust than the default way (or am I misunderstanding how the default way works and in actuality there is a way to handle more complex routes?) Thanks! Link to comment Share on other sites More sharing options...
Soma Posted October 6, 2014 Share Posted October 6, 2014 Process modules (admin pages) can't use urlSegments. It would be conflict with the execute routing methods, which is not a full MVC, and was never meant to be, but quite convenient and still enough flexible for what is needed. Whole PW is built on that, so it must be good enough. Link to comment Share on other sites More sharing options...
kongondo Posted October 6, 2014 Share Posted October 6, 2014 Here's some more explanation about Process Modules https://processwire.com/talk/topic/1313-modules-process-and-the-difference/ Link to comment Share on other sites More sharing options...
jordanlev Posted October 6, 2014 Author Share Posted October 6, 2014 @Soma, the urlSegments *do* work in process modules (I have it working right now, at least in ProcessWire 2.5 -- maybe this is a new feature?). In fact, if you follow the link that @kongodo posted, you will see that Ryan specifically says "PW doesn't pass any arguments to the execute() functions... rather you can retrieve them from $input->urlSegment($n) if you want them". @kongodo, thanks for the link, it is helpful. But it still does not answer my question about using $this->input->urlSegment1 == 'something' versus function executeSomething() ... why should I use one over the other? And if url segments are not the recommended thing to use for some reason, how exactly can I set up my modules that have a lot of different admin pages in them? How is this normally done in ProcessWire modules? I want to follow the best practices but I do not see anywhere that this is documented. Thanks! Link to comment Share on other sites More sharing options...
kongondo Posted October 6, 2014 Share Posted October 6, 2014 (edited) I think you understood Soma but he will speak for himself. As for my bit, have a look at my ProcessBlog module. I use both ___execute() and wire('input')->urlSegment1 (your $this....etc). ___execute(), in a sense, gives you 'virtual pages view'. They don't really exist but are created on the fly on view (if that makes sense). In my case (in Blog), in the method blogMenu(), I use urlSegment1 to set the css class for the active ___execute() page, i.e. what the user is currently viewing. It's basically grabbing a 'GET' query string (in a loose sense)...Otherwise, there was no other way to know what the active page was given that they don't actually exist. ... So, if you want a viewable 'page' in your ProcessModule, use ___executeSomething()...urlSegment1 just gives you the 'name' (something) of that virtual page... my 2p... Edited October 6, 2014 by kongondo 2 Link to comment Share on other sites More sharing options...
Soma Posted October 6, 2014 Share Posted October 6, 2014 Then why does admin template not have url segments enabled? And you get a unrecognized path when adding a segment to any admin url that is not defned route using executeNamex? I've built dozens of modules and admin pages over the years, and if this would be something completely new You can get the execute segment also using input url segment. But that's all... there's no more like 2 or 3 ( ahh bulls. .. read next post) Edited: Ah I know now what you mean. It's with after a executeSomething you can add segments to something/segment1/ etc. But not without. So you need at least one executeSomething defined. Sorry for my confusion and so... Edited: Yeah they're virtual and defined by the execute methods. I find them very easy to work with. Just look at some of the admin process modules as you surely did. There's no real best practice regarding those just use them as you need them. I would use those executes for different outputs of 1 admin page. They can also serve as ajax URLs in admin etc. Nothing really special and really simple system. There's no either that or those. Use executes and if really needed for sublogic use segments or simply url params. Link to comment Share on other sites More sharing options...
jordanlev Posted October 6, 2014 Author Share Posted October 6, 2014 Ah, very good to know that the urlSegments are only available if you have an `executeSomething()` method defined. So I guess I need to not use REST-like routing ("pretty urls") in the admin dashboard, and instead rely on a querystring "path" argument or something like that. Seems kind of "old-school" to me, but I guess it works, and the admin dashboard does not need to be SEO-friendly so it is not a major drawback (just requires some different thinking than what I'm used to from other more-modern frameworks). Thanks for the help! Link to comment Share on other sites More sharing options...
Soma Posted October 6, 2014 Share Posted October 6, 2014 So let's start again. I am trying to build a module of the "process" variety (some custom admin dashboard pages). It looks like there is not much in the way of an MVC system or routing for these... from what I can tell my options for routing boil down to 2 options: execute(), executeSomething(), executeSomethingElse(), etc. The execute() method responds to the "top-level" url for my module (for example, http:// my-site.com/processwire/setup/my-module/). Any other methods whose names start with "execute" respond to a "2nd level" url (for example, executeSomething() responds to http:// my-site.com/processwire/setup/my-module/something/; and executeSomethingElse() responds to http:// my-site.com/processwire/setup/my-module/something-else/) Inside the execute() method, use $this->input->urlSegment1, $this->input->urlSegment2, etc. to retrieve the portions of the url under the "top-level" (for example, if the user visits http:// my-site.com/processwire/setup/my-module/something, then inside the execute() method $this->input->urlSegment1 would be "something" (and for http:// my-site.com/processwire/setup/my-module/another/thing , $this->input->urlSegment1 would be "another" and $this->input->urlSegment2 would be "thing"). Am I understanding the system correctly? If so, what is the purpose of having "executeSomething()" if you can just look to $this->input->urlSegment1 inside the "execute" method? It seems rather arbitrary, since there is no way to use "executeAnotherThing()" to respond to /my-module/another/thing (as far as I can tell?). Also, isn't it true that the url segments might be set to a different level on different sites? So if I'm building a module for others to install, how can I know that the site it is installed on even allows 2-, 3-, or more url segments under my top-level page? Are there any example modules out there that implement their own routing system that is more robust than the default way (or am I misunderstanding how the default way works and in actuality there is a way to handle more complex routes?) Thanks! 2. is wrong and is what got me partly confused (apart from not knowing the multiple url segment after a executeSomething()) You can't add url segments to execute() base url of your module /admin/mymodule/ it would give you a unrecognized path. What also got me confused and can't agree, is I'm not sure I understand your statement that the current admin Process modules need a more roboust routing? Or maybe I don't understand. I find them very robust and flexible. I don't think it's ever meant to be used extensively with urlSegments rather than url params if many params are needed. I think you can assume that at least 1 urlSegment is given as you can't set it to 0, or processwire admin won't work cause the executeSomething() methods are internally using urlSegments (as I see now). I'm not sure what you mean with url segment level? I think you mean the maxUrlSegments in config? You could either check for the max setting in the init() and throw an exception or $this->error(message) to the admin that they need to up their setting. Default is 4 and if you really need more (unlikely) you could set that config value using an simple autoload module. I think Ryan isn't using urlSegments in admin extensively other than checking in the init(), if you're on executeSave() "save" and maybe load conditional modules that need to be loaded in the init() because of required load order and it would be too late in the executeSomething(). I'm not sure what Ryan thinks about using urlSegments in admin at all. He still thinks Process modules are a minority, yet I see dozens of them popping up all over the place and there's no real documentation. So basically, you use execute() for the default output of the admin page when you go to it, or maybe use it as ajax handler for something on JS side of your module. That part doesn't allow urlSegments. Segment one added your admin url, must be defined by a executeYoursegment() as we already know by now So those most likely build the "subpages" of your admin page, if really needed. And you could expand using urlSegments or url params. 1 Link to comment Share on other sites More sharing options...
Soma Posted October 6, 2014 Share Posted October 6, 2014 Ah, very good to know that the urlSegments are only available if you have an `executeSomething()` method defined. So I guess I need to not use REST-like routing ("pretty urls") in the admin dashboard, and instead rely on a querystring "path" argument or something like that. Seems kind of "old-school" to me, but I guess it works, and the admin dashboard does not need to be SEO-friendly so it is not a major drawback (just requires some different thinking than what I'm used to from other more-modern frameworks). Thanks for the help! I don't think it matters really in an admin context I don't think it's old school and that PW is a not-modern framework. It's a kind of its own. It may feel different when coming from other frameworks (I see that, as PW is not my first CMS or Framework), but then I embrace what PW is giving us. Never will everybody 100% agree with design decision made by Ryan, but then it's with everything and after all it's here to discuss and may be extend on a solid base. It's living software and forum. See it as Ryan is listening and giving his view on things, it's what he likes. And if there's something that makes a lot of sense he doesn't restrain from adding it. Need a method to be hookable that isn't? Don't be afraid to question it and ask to add it, after all it's just three underscores to add. 2 Link to comment Share on other sites More sharing options...
jordanlev Posted October 6, 2014 Author Share Posted October 6, 2014 Hi @Soma, You're "reboot" explanation is very clear and explains things quite well -- thank you for writing all that out, it is very much appreciated! I create a lot of "CRUD" applications in CMS dashboard, where you have lists of records, then you view sub-records of those, and you add/edit/delete... each of these operations requires its own form/page. And I am used to other systems where you try to map the URL's to the data entities (this is what I believe I meant by saying "REST-like routing", but I could be using the wrong term there... that's just how I think of it). Ruby on Rails is the big one, but since Rails was released it seems that almost all other PHP frameworks are using a similar style (CakePHP, CodeIgniter, Symfony, Kohana, Laravel, etc.). So that's what I meant by "more modern system"... not that PW isn't modern, but I do think that the lack of REST-like routing in the admin modules is definitely how things were commonly done before Rails, but it is not so common anymore. Not saying it is bad, just different I think I can easily recreate the routing style I am used to (along with sub-folders in my module for "controllers", "models", and "views"), and I just need to pass around the "path" as a querystring argument instead of looking at the actual URL segments. This way I can have as many url segments as I want, and I do not have to worry about the maxUrlSegments setting at all. Overall, I like that ProcessWire does not try to impose its own architecture on you too much (of course there is some but that is unavoidable in any system). Overall it seems to "get out of your way" which is very good for experienced developers like us who already have strong ideas about how we like things to work for us. Thanks again, I really do appreciate your help as I learn this new system! 1 Link to comment Share on other sites More sharing options...
Soma Posted October 6, 2014 Share Posted October 6, 2014 ... and instead rely on a querystring "path" argument or something like that I'm not sure you'll need to go as far as set a "path", as I see it you have multiple admin pages using the executeSomething, that's the path. Or not? Link to comment Share on other sites More sharing options...
jordanlev Posted October 6, 2014 Author Share Posted October 6, 2014 Oh, I did not explain that clearly. Yes, I will use "executeSomething()" for the "top-level" url of a certain controller (or data entity). For example, if I have something like "employees" and "joblistings", the I can have "executeEmployees()" and "executeJoblistings()". But within each of those sections, there are several different actions one might take... you might want to display the list of all employees or jobs, then be able to add a new employee or job, edit or delete an existings one. Ideally then my url structure would be /employees (to list all employees), /employees/add (for the form that lets you add a new employee record), /employees/edit/14 (to edit the existing employee record having id "14"), etc. So as you can see there is the need for several addition url segments. It gets even trickier if my data relationships are such that an employee can only exist under 1 job record... in this case I might have /jobs/27/employees/add (to show a form for adding a new employee to job #27). What I am hearing from your answers is that I should not rely on the url segments for this routing, but instead I must do something like /employees?path=edit/14 , or perhaps something like /employees?action=edit&id=14 (that is probably better now that I think about it). By the way, the "employees" and "jobs" is just for example -- I know that in ProcessWire I should actually instead create pages and templates to manage something like this. I guess this is why my issue does not come up often, because it can usually be bypassed by using PW's existing pages/templates/fields system. But since I am trying to create an editing interface that is for manipulating pages/templates/fields themselves, it is too confusing for me to wrap my head around how to use pages/templates/fields to manage themselves... so I am reverting to the method I am most familiar with. 1 Link to comment Share on other sites More sharing options...
kongondo Posted October 6, 2014 Share Posted October 6, 2014 ......What I am hearing from your answers is that I should not rely on the url segments for this routing, but instead I must do something like /employees?path=edit/14 , or perhaps something like /employees?action=edit&id=14 (that is probably better now that I think about it)....... Yes...IMO, seems like you are unnecessarily complicating matters with something like /employees/edit/14 Of course you know this is how PW does it.../mysite/myadmin/page/edit/?id=5094. How many people really care about pretty URLs in the backend? 3 Link to comment Share on other sites More sharing options...
Soma Posted October 6, 2014 Share Posted October 6, 2014 Remember that you can use more than just one Process module and admin pages hierarchically in the admin. Don't limit yourself to one module or admin page. Also each admin page (nested maybe) can have the same process module attached. Not sure if that would be helpful at all but it's very well possible. I see what you mean with the routes and how they can be used in a REST-like structure. I think if you try to rebuild those you're left with trying urlSegments, but maybe not. I would suggest to try and experiment some time before you deciding on something. Up to you. I mean adding or editing a page can be something like using the ProcessPageEdit and ProcessPageAdd in your module. As you said it's just pages and templates and fields, you already have the - and can extend the crud, and you can use what is there or build completely your own things. Everything fits nicely together with admin modules, Pages, Templates, Fieldtypes and Inputfields. It took some time to get into, but I'm maybe not the best person to advocate all this. Lister and Lister Pro is something that may be of interest for you also, cause it can build Admin pages simply by entering a Name in the module settings and click "add". It will generate a new Lister admin page, that can list pages/entries with the InputfieldSelector field type Ryan built, that let's you build filters/selectors for what to list, you then can edit or add pages etc, run actions (also add your own action modules you can build and extend on) on the results. It's what is new in PW 2.5 and the light version is now in Users and Admin page search. The pro version might also be available soon. It seems all to go very far and is complex, but also shows what's possible. I would try to study some process modules in core and what Ryan have built. But feel free to try implement your way of working, just keep in mind that maybe with a more PW way you also can ensure it will be more "compatible", if that's really an issue. Ryan said once Process modules are just mini apps inside PW, and they can be verstaile and modular. I'm not sure Ryan was ever into REST-like routing, as it's also not something that is an absolute best way. 3 Link to comment Share on other sites More sharing options...
Soma Posted October 6, 2014 Share Posted October 6, 2014 If you go the urlSegment REST like routing you could still ensure and set the maxUrlSegment for your module. This for example would work out: <?php class MyHelper extends WireData implements Module { public static function getModuleInfo() { return array( 'title' => 'MyHelper', 'version' => 1, 'summary' => '', 'singular' => true, 'autoload' => "Process=ProcessHello", // only load on your module ProcessHello ); } public function init() { $this->config->maxUrlSegments = 7; // more ? } } It's not possible from an non autoload Process module to overwrite it but a little helper module would do fine. 1 Link to comment Share on other sites More sharing options...
jordanlev Posted October 6, 2014 Author Share Posted October 6, 2014 This is fantastic information. The more I think about it, I think this is one of those cases where I just need to give up my pre-conceived notions of how to do it. @kongondo said it well: "How many people really care about pretty URLs in the backend?" ... this is very true But the technique @Soma shows is good to know in case I change my mind (or need it in the future for something else). Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now