Jump to content

ryan

Administrators
  • Posts

    17,151
  • Joined

  • Days Won

    1,668

Everything posted by ryan

  1. Here's how to implement the page picker in your Redirects module. First, give your redirect_to field an id attribute in addition to the name attribute it already has. So replace this: $field->name = "redirect_to"; with this: $field->name = "redirect_to"; $field->id = "redirect_to"; Now add a new field to your form, right after the redirect_to field: <?php $field = $this->modules->get("InputfieldPageListSelect"); $field->label = 'Select Page to Redirect to'; $field->attr('id+name', 'select_page'); $field->startLabel = "Select Page"; $field->parent_id = 0; // tell it to start from homepage if(strpos($to, '/') === 0) { // if a value is already set, determine if it's a page // if it's a page, then populate the input with the page_id $page = $this->pages->get($to); if($page->id) $field->value = $page->id; } $form->add($field); // now add a script that makes it automatically populate the redirect_to field // with the URL of the selected page. $script = <<< _END <script type="text/javascript"> $("#select_page").bind('pageSelected', function(event, data) { if(data.url.length) $("#redirect_to").val(data.url); }); </script> _END; Lastly, at the bottom of your function, we want to include the $script in the output, so replace this: return $form->render(); with this: return $form->render() . $script; Let me know how that works? Thanks, Ryan
  2. Thanks Marcin! That's great -- I'll be glad to take you up on that. In about a month or so I hope to have a separate dev branch that includes the multi language support (at least the basics).
  3. Just tried it out and it works great! I will definitely use this, thanks for putting it together. Nice work! Two minor CSS suggestions (see attached screenshots showing before and after): /* adds padding at bottom so floated buttons don't touch footer */ #redirects_form { margin-bottom: 3em; } /* the margin-right addition ensures the button floats all the way right */ #submit_delete { float: right; margin-right: 0; } This is such a useful module, it makes me start thinking of what more could be added... any thoughts on future additions? A couple ideas are: ability to upload (or paste into a textarea) a CSV file with the "from, to" urls. A counter for each redirect that keeps track of how many times it's been used. Thanks, Ryan
  4. To uninstall something you want to do it through admin>modules. If the dir/files were removed without uninstalling, it's best to put them back where they were. It sounds like you may have already tried this? If so double check that the dirname and filenames are the same as before. If that still doesn't work, you can always remove the entry from the modules table manually, if you are sure it's not actively being used on any fields. Better yet, try deleting the modules cache file in site/assets/. I dont recall what the filename is (I'm not at computer) but I think the name is recognizable as being for modules. Please let me know how this works out.
  5. I'm not sure how I missed this before, but turns out we already have a hook that looks like it'll work. It's ProcessPageView::pageNotFound Here's one approach that could be used to handle the hook and redirect. This is coded in the browser/forum, so not tested and probably has parse errors, etc., but hopefully the general idea works. <?php public function init() { $this->addHook('ProcessPageView::pageNotFound', $this, 'checkRedirects'); } public function checkRedirects($event) { // determine the URL that wasn't found $url = $_SERVER['REQUEST_URI']; // if installed in a subdirectory, make $url relative to the directory ProcessWire is installed in if($this->config->urls->root != '/') { // you might need to double check that below results in a path with a slash still at beginning $url = substr($url, strlen($this->config->urls->root)-1); } // we'll check the DB against trailing slash version and non-trailing slash version // and escape them for the DB select while we are at it $url = $this->db->escape_string(rtrim($url, '/')); $url2 = $this->db->escape_string($url . '/'); // now see if it's in the DB $sql = "SELECT redirect_to FROM {$this->className} WHERE redirect_from='$url' OR redirect_from='$url2'"; $result = $this->db->query($sql); // if there is a match, then redirect to it if($result->num_rows) { list($redirect_to) = $result->fetch_array(); $this->session->redirect($redirect_to); } }
  6. Sorry I forgot something. Add this right after you get the $table from $modules: $table->setEncodeEntities(false); I recommend having ProcessRedirects live in it's own directory, like: /site/modules/ProcessRedirects/ProcessRedirects.module Then create another file in there called ProcessRedirects.css Use that CSS file to place the button element where you want. In your module file, you can give the button an id attribute so that it's easier to target in the css file: $button = $this->modules->get("InputfieldButton"); $button->id = 'submit_delete'; // assign an ID attribute $button->type = 'submit'; $button->value = 'Remove selected redirects'; Note that id attribute may actually be assigned to a containing element of the button (not positive). If it is, then you'd want to target in your CSS as "#submit_delete button" rather than just "#submit_delete". In your executeSave function, I recommend escaping the $from and $to vars before insertion into the DB. The reason is that there are some chars allowed in URLs that would need to be escaped for the database (at last I think there are). To do that, you'd just use PHP's mysqli escape_string function: $from = $this->db->escape_string($from); $to = $this->db->escape_string($to); I'm working on adding the hook and should have that this morning! Edit: One last thing is to add is "$count = 0;" at the top of your executeDelete function. Otherwise PHP will throw notice errors about an uninitialized variable when ProcessWire is in debug mode. Thanks, Ryan
  7. ProcessWire wasn't built to be a full-on MVC framework like CodeIgniter, and so most of what is used in developing the admin modules is fairly basic. Though I've never actually built anything in CodeIgniter, so I don't know all that it does specifically. I know CI maps URL segments to functions (like a Process module), but it also maps URL segments to function arguments (unlike a Process module). I didn't do that because I preferred to keep dynamic arguments as GET or POST vars. PW1 enforced MVC for processes, and enforced keeping everything in separate files. It had it's benefits, but in my case it was a net loss to time and maintenance compared to PW2's system. PW2 leaves it more up to you how much you want to enforce a pattern. I usually keep my views in the class, but under a function called "render()" ... that's stylistic only. You'll find that most Process modules call upon other modules to provide views, like the Markup and Inputfield modules. (i.e. MarkupAdminDataTable, InputfieldForm, InputfieldText, etc.). If you want to maintain a view in a separate file, use the TemplateFile class. It works much the same way that a view in CodeIgniter would work, and it's the same class that ProcessWire uses to render template files throughout the site. Though I don't actually do this in any of the Process modules, but here's how you would: public function ___execute() { $view = new TemplateFile($this->config->paths->MyModuleName . "view.php"); $view->set('videos', $this->getVideos()); return $view->render(); } ProcessWire assumes that all "execute" functions return the output that will ultimately be populated in the main part of the template. It includes a couple of helpers in the "fuel" for populating the headline (processHeadline) or breadcrumbs. These are optional -- if you omit these, the breadcrumb trail will be to the current page, and the headline will be the title field from the current page. Very often, this is what you want, so I don't bother with the headline or breadcrumbs until my Process module is up and running and I find it makes sense to add them. Any function that begins with 3 underscores, like "___execute()" is hookable. If you don't want it to be hookable, then just use the same function name, but without the 3 underscores, i.e. "execute()". ProcessWire doesn't care which version you use. When in doubt, make them hookable. For functions that you make hookable (by preceding with 3 underscores), any other module can add a hook either before or after it. Hooks that run 'before' can modify the function arguments sent to the hooked function. Hooks that run 'after' can modify the return values of the function. Beyond that, hooks can do whatever they want. See the /wire/modules/Helloworld.module for an example of a couple hooks. For more insight on Process modules, I would first look at the Module interface, defined in the /wire/core/Module.php file. This basically just lists the functions that all modules are required to have. Most are optional, so you'll see them documented, but commented out. As a result, this Module.php file is more for documentation purposes than anything else. Next look at the definition of a Process module in /wire/core/Process.php. You'll see it's pretty simple and short. It enforces an execute() function, which gets called on a request of /path/to/page/. Any others you create, i.e. executeEdit(), executeSave(), etc., it only calls if it finds "edit" or "save" in the URL. There are no predefined names after the "execute" part, so it could just as easily be "executeHello()" and that function would get called when the URL was "/path/to/page/hello/". The only other significant thing that Process module does for you is that it looks for a css and js file that follow the same name format (and are in the same dir) as your .module file: /site/modules/Process/ProcessVideos/ProcessVideos.module /site/modules/Process/ProcessVideos/ProcessVideos.css /site/modules/Process/ProcessVideos/ProcessVideos.js If it finds them, they get automatically included in the admin template's <head> section.
  8. I'd like to build a ready-to-go blog site profile in PW at some point. I think PW would lend itself very well to building a blog. But the need comes up so rarely in my own work, that I haven't done much other than experiment ... my site (ryancramer.com, in PW1) is loosely in a blog format, though I built that several years go and it's long past time for a redesign and redevelopment. On sites where the client has asked for a blog, I've used WordPress. ProcessWire and WordPress run alongside each other quite well. Then I'll use WordPress RSS feeds to pull blog entry headlines into ProcessWire so that they can be output anywhere on the site, so make it seem like it's all running together...
  9. Since it looks like you have some cached pages, another thing you might want to do when moving a site is to clear the cache. You can do it before or after, but probably do it before just so you are transferring fewer files. Go to Admin > Modules > Page Render > and click on the "clear cache" checkbox, and submit. This can be especially useful when moving a site from one path to another (like subdirectory to root), because cached pages might temporarily be looking for external assets like CSS and JS files in the wrong directory. So if you ever transfer a site and see your homepage show up with no stylesheets or images, go in and clear that cache and you'll be set. Another way to clear the cache is: rm -rf ./site/assets/cache/Page/* But I always get a little nervous with anything involving an "rm -rf" (one stray character could wipe out everything) so I usually do it from the admin.
  10. Technically modules are just a class that implements an interface. It doesn't have to extend any other class in order to implement that interface, but it does make life a little easier ... especially in the case of Process modules, because they have some flow control built in and know to look for specific CSS/JS files, etc. There isn't any requirement that you have to use Process modules in the admin. You can just as easily use any template of your own if you prefer. But if Process modules save work for what you need to do, then I think they are a good way to go. The ProcessPage modules are probably the broadest in scope of all of them. For most other instances, I'll usually integrate the List, Edit, Add, Delete all into a single Process module. In the case of ProcessPageEdit/Add/List, it was a lot of code so I split them up. But for your own needs, you may find you prefer keeping it to a single module, or splitting them up.. it doesn't matter. The main advantage of keeping them in a single module is that they are attached to a single page, so you don't have to worry about a multi-page dependency (not that it matters that much though). Now that I know people are going in and using these as examples to create others, it makes me think I need to go in there and make sure all my code is clean. That was fast! Glad that it worked out well. Though I think your previous approach was a good one too. But I also think that using pages will hopefully save you time and be more fun to work with. I'm in the process of doing the same thing that you did, but with the user system rather than videos. I'm converting the user/role/permissions system to use pages rather than WireSaveableItems, along with multi language support. From the user side, I'm doing it so that the system can accommodate any number of users (more scalable), and let you add custom fields to users, roles and permissions just like any other page template (more flexible), as well as reduce some redundancies on the multi language system. Sounds good, I look forward to seeing what you are doing. And of course, please let me know anytime I can be of any help with questions. You and a couple of other people are getting deeper into the code than what is currently in the documentation, and I'm here to help with any questions you have. Thanks, Ryan
  11. That's great to hear! Thanks for your message, this makes my day. That's impressive! Sounds like a great site, and that you've done a lot of great things with it. I'm always wanting to add new sites to this page, if you ever have any you want me to post there just let me know: http://processwire.com/about/sites/ There really isn't much in the way of a form builder right now, but it's something we've been talking about. I expect we'll be making progress on this in the summer (soon!), assuming someone else doesn't do it first. But multi-language support and a redesign of the user/role/permissions system are in progress now, and a form builder comes after that. This is relatively straightforward because pages in the Admin are just like any other pages on your site. You can add a page to the admin, and make it use any one of your templates. Internally, ProcessWire uses what are called "Process" modules to serve as a very basic framework for managing flow control on a given page (very loosely like CodeIgniter in terms of calling a function based on a URL segment). But it's not a requirement to use them. I've found that my clients relate well to the tree structure too. Or when they don't, I tell them to think of a family tree, and then they get it. Thanks for using ProcessWire and being part of the community here! I look forward to talking more. Ryan
  12. Looks like you've got a good start here! To create the table, I would do it in your install function. The only part of PW that creates tables are the fieldtypes, and those aren't useful here, so you'll want to issue the create table yourself. Something like this: <?php public function ___install() { parent::___install(); $p = new Page(); $p->template = $this->templates->get("admin"); $p->parent = $this->pages->get($this->config->adminRootPageID); $p->title = 'Redirects'; $p->name = 'redirects'; $p->process = $this; $p->save(); // hold off on the permissions if you can because this system is being redesigned. // $this->installPermission('Edit'); $sql = <<< _END CREATE TABLE {$this->className} ( id int unsigned NOT NULL auto_increment, redirect_from varchar(512) NOT NULL DEFAULT '', redirect_to varchar(512) NOT NULL DEFAULT '', UNIQUE KEY(redirect_from) ); _END; $this->db->query($sql); } public function ___uninstall() { $p = $this->pages->get('template=admin, name=redirects'); $p->delete(); $this->db->query("DROP TABLE {$this->className}"); } For your CRUD, I would make your default function (execute) the one that lists the redirects, and then create functions to edit, save and delete. Here's an example of how you might do some of it as a starting point (written in the browser, so not tested!): <?php /** * List Redirects - Called when the URL is: ./ * */ public function ___execute() { $this->setFuel('processHeadline', 'List Redirects'); // example here uses a PW module to output this table, but that's not required. $table = $this->modules->get("MarkupAdminDataTable"); $table->headerRow(array('Redirect From', 'Redirect To', 'Delete')); $result = $this->db->query("SELECT * FROM {$this->className} ORDER BY created"); while($row = $result->fetch_assoc()) { // output in table rows with edit link and delete checkbox? $table->row(array( $row['redirect_from'] => "edit/?id=$row[id]", $row['redirect_to'] => "edit/?id=$row[id]", "<input type='checkbox' name='delete[]' value='$row[id]' />" )); } $table->action(array('Add Redirect' => 'edit/?id=0')); return "<form action='./delete/' method='post'>" . $table->render() . "</form>"; } /** * Edit/Add Redirect - Called when the URL is: ./edit/ * */ public function ___executeEdit() { $this->fuel->breadcrumbs->add(new Breadcrumb('./', 'Redirects')); $id = (int) $this->input->get->id; if($id > 0) { // edit existing record $result = $this->db->query("SELECT id, redirect_from, redirect_to FROM {$this->className} WHERE id=$id"); list($id, $from, $to) = $result->fetch_array(); $this->setFuel('processHeadline', "Edit Redirect"); } else { // add new record $id = 0; $from = ''; $to = ''; $this->setFuel('processHeadline', "Add Redirect"); } $form = $this->modules->get("InputfieldForm"); $form->method = 'post'; $form->action = './save/'; $field = $this->modules->get("InputfieldHidden"); $field->name = 'id'; $field->value = $id; $form->add($field); // maybe use InputfieldURL for the 'redirect_from' and 'redirect_to' inputs return $form->render(); } /** * Save Redirect - Called when the URL is ./save/ * */ public function ___executeSave() { // perform save of existing record if id>0, or add new if id=0 $this->message("Saved Redirect"); $this->session->redirect("./"); // back to list } /** * Delete Redirect - Called when URL is ./delete/ * */ public function ___executeDelete() { if(!is_array($input->post->delete) || empty($input->post->delete)) { $this->message("Nothing to delete"); $this->session->redirect("./"); // back to list } foreach($input->post->delete as $id) { $id = (int) $id; $this->db->query("DELETE FROM {$this->className} WHERE id=$id"); } $this->message("Deleted " . count($input->post->delete) . " redirect(s)"); $this->session->redirect("./"); // back to list } I will work on setting up an appropriate hook in the ProcessPageView module. thanks, Ryan
  13. When replacing a site, I usually handle some of the 301 redirects in the .htaccess file: RewriteRule ^about.html$ /about/ [R=permanent,L] But a lot of these sites have thousands of URLs to replace. Very often, they are URLs with variables in them, like: www.site.com/products.cfm?product_id=8573 To handle that, I'll add a field in ProcessWire called old_product_id, and add it to the new "product" template. When importing the products into the new site, I make sure that old_product_id field gets populated with it's ID from the old site. If you are dealing with thousands of URLs, you want to make sure to automate this. Next, I'd either create a page in ProcessWire named "product.cfm" (along with a template), or create an actual file on the server called product.cfm. I'm more likely to create the file, since I don't really like pages from the old site in the new site tree. So I'd name that file /product.cfm and update the .htaccess file to run cfm files as php: AddType application/x-httpd-php .cfm Here's what the contents of product.cfm might look like: <?php // load ProcessWire's API require("./index.php"); // if no 'id' var present, send them to the new products page if(!isset($_GET['id'])) $wire->session->redirect("/products/"); // get the requested product id $id = abs((int) $_GET['id']); // find the new page with that product id $page = $wire->pages->get("old_product_id=$id"); // if it was found, redirect them to it. if($page->id) $wire->session->redirect($page->url); // otherwise send them to the new products index else $wire->session->redirect("/products/"); This is just one approach... but one I had to implement recently, so figured I'd paste it in as an example. The template-level redirects are great for future redirects that the client might setup. And it's easy to add a field called redirect_href and then setup a template that deals with it, i.e. /site/templates/redirect.php: <?php if($page->redirect_href) $session->redirect($page->redirect_href); Then your clients can select "redirect" as the template when they want to create a redirect. Though, they still might pollute the site tree over time with lots of extra and unnecessary redirect pages... I've seen it happen, and it's a problem. If you want a 302 redirect, specify 'false' as the second argument to the redirect function, i.e. $session->redirect($url, false). So you might add a checkbox field to the page's template called 'permanent', and handle it like this: $session->redirect($page->redirect_href, $page->permanent == 1); There was in PW1 but not yet in PW2. I think it would be a worthwhile module to have, especially for the post-launch redirects. If you are interested in building a module, I think it would be a great. I'll be happy to add any of the necessary hooks into the core or assist with anything you'd like me to. As for best route, I'm thinking I would add a hook before 'ProcessPageView::execute' that checks the value of $_GET['it']. That value is what PW's htaccess file uses to send PW the requested page URL. You could also look at any of the $_SERVER[] variables, to see if any of them suit your needs better, but I'm guessing $_GET['it'] is what you need. If your module finds a matching URL, it would redirect to it. Otherwise, it would just return, letting ProcessPageView continue on about it's way. A better solution might be to have your module hook into some function that only gets called when a page is not found. That way it wouldn't have to compare redirects for every request. I don't think I have a good function for you to hook into for that yet, but I will be happy to add one. One thing I should mention is that ProcessWire only sees URLs with the path/file containing ASCII these characters: -_.a-zA-Z0-9/ That's applicable to the path/file only, not the query string. Those characters accounts for most URLs you are likely to run across, but ProcessWire won't ever see URLs with commas or other more rare characters that are technically allowed in URLs. This is because the htaccess file filters out any requests for those requests and never sends them to ProcessWire (since they don't follow PW's name format). I mention this just because any redirect module built into PW also wouldn't see URLs that don't follow that format. Thanks, Ryan
  14. Hey Jim, The session start can't easily be hooked into the traditional way just because the session is initiated before the plugin modules are. So you have to take a little bit different approach to override the session: Place your Zend_Session::start() at the bottom of your /site/config.php file. That will override ProcessWire's session_start() because in PHP subsequent calls to session_start() are ignored. Also /site/config.php is a site-specific file, so you don't have to worry about it being overwritten during upgrades. Here is what I suggest placing at the bottom of your /site/config.php file, though of course tweak it to suit your needs: session_name($config->sessionName); ini_set('session.use_cookies', true); ini_set('session.use_only_cookies', 1); ini_set('session.gc_maxlifetime', $config->sessionExpireSeconds); ini_set('session.save_path', rtrim($config->paths->sessions, '/')); Zend_Session::start(); Let me know if that works? Thanks, Ryan
  15. Thanks that's very generous of you. If you ever find parts that aren't smart (there always are some) please let me know too. I sometimes come across my code (whether on this project or others) where I look at it and think to myself "what the hell was I thinking?". ;D I avoid coding at night for this reason.
  16. Thank you, that's kind of you to say. But I think you are giving me too much credit. You deserve the credit here for discovering this issue here that I missed, so thanks for that.
  17. This is one of the potential problems with using the WireSaveableItems, because the default behavior is that they load an entire table and all it's rows in memory at runtime. This is desirable for things like templates and fields because we need all this stuff in memory to build pages, and don't necessarily know what we'll need ahead of time. But for large inventories of information, there might be memory or speed issues as the number of items increases. To account for this, you can specify a selector to the load() function to tell it what you want with a selector string: $this->load($this->videosArray, "limit=10, sort=id"); That selector string can have both "start" and "limit" and "sort" options for pagination. You can also have it match any given field name in your table. For operators, you are limited to: =, <, >, !=. With those limitations in mind, they work like selectors on pages in all other respects. I also want to mention that ProcessWire does not currently use this feature of the WireSaveableItems class, so if you use it, you are the first to test it. Let me know if you run into any issues and we'll get them fixed. That's correct, but that pagination is only specific to pages. You can certainly use pagination with your module, but you'll need to specify the "start" and "limit" options to your load function manually. (When it comes to paginating actual pages, ProcessWire takes care of the "start" part for you.) When working in a database client (like PHPMyAdmin) it's true that your view of the data will be in a traditional single-table format, unlike pages where fields occupy their own table. But within ProcessWire, the view is just a manner of how you use the API code. The way you work with items coming from a WireSaveableItems class and items coming from pages is going to be the same. For example, in this part of your code: <?php $table = $this->modules->get("MarkupVideoDataTable"); $table->headerRow(array( 'Volume', 'Name', 'Description', 'Event Date', 'Price', )); foreach($videos as $video) { $volume = 'Vol. '.$video->volume; $table->row(array( $volume => "edit?id={$video->id}", $video->name, $video->description, $video->eventDate, $video->price, )); } ...$videos could just as easily be a PageArray (like from $pages->find(...) or $page->children(...), etc.), and it could be substituted without any changes. So while there is a difference in the view at the database table level, there isn't any difference at the ProcessWire API level. I don't want to talk you out of the approach you are taking, because I like what you are doing and am thrilled to see some of these classes get used outside the core -- so stick with it, and I'll be here to help. But I also want to make sure I communicate that the data you are working with is exactly what pages were designed for. Pages are data containers of a defined type (template) with defined fields... they may or may not represent an actual page on your web site, that's up to you. But pages are really useful for building huge inventories of data and making it easy to view, search and manipulate, and even change it's structure without changing your code. Think of pages like you would a node in Drupal... they may represent a page on your site, but their intended use is much more abstract than that. You can! Lets say that Users were pages. Here is how you would load an filter them by role at the same time: <?php $users = $this->pages->find("template=user, role=superuser"); foreach($users as $user) { ... } // output them in the same manner as ProcessUser.module This approach has an advantage over what's being done in ProcessUser.module right now, because it only loads the users that match the filter. The way ProcessUser works right now is that it iterates through all the users and skips the iteration if the filter doesn't match. Here's another example more specific to your case, filtering by volume number: <?php $videos = $this->pages->find("template=video, volume=123"); forech($videos as $video { ... } ...or... <?php $videos = $this->pages->get("/path/to/videos/")->children("volume=123"); foreach($video as $video) { ... } Of course, ProcessWire does this filtering at the database level (not in memory). That makes sense, and there are very good reasons for having something completely separate from a storage standpoint. From an organization standpoint, the main difference would be that the videos don't appear anywhere in the page structure. But I think your ProcessVideo.module would be equally useful whether videos are pages or WireSaveableItems (and the code behind it would likely be very much the same). Each page is assigned a template that defines it's data structure, and optionally provides a file where you can produce output for the page's URL. But that part is totally optional. If you choose to display them in some other way, the manner in which you do it should be the same. I built pages for this purpose, so that's the approach I would take myself. But I also think you have good reasons for the approach you've taken and there's nothing wrong with it. There are both tradeoffs and benefits which only you can evaluate what is best for your needs. If I'm understanding it all correctly, here are a few of the pros for your approach: 1) it can be more efficient if you are careful about how much data you load at once; 2) the data relates directly to a table, making it a simpler matter if you like to work directly in SQL; 3) it's compartmentalized, not relying upon prerequisite fieldtypes or templates (which may make for simpler portability if you distribute the module). I think in your case it is a good approach because you have PHP knowledge and know your way around code, and I am glad to see you doing it ... it also helps me to make a better product when people push the utility of these core classes. Thanks, Ryan
  18. Hani, welcome to the forums and thanks for your interest in ProcessWire! I'm glad to see you getting down into the code. Before we take a closer look at it, I just wanted to get a better idea of the approach you've taken with extending WireSaveableItems. It's admittedly something that hadn't occurred to me to do outside of the core, as pages are the primary data type for API usage. Have you looked at using pages, templates and fields as a way to structure this data? In your case, what are the benefits to the approach you've taken? I'm actually pretty impressed with your approach, because it means you've really gotten down into the code, and you are using it like a framework. But I also worry we might be creating more work for you than is necessary by doing it that way, so I just wanted to get a better idea. ProcessWire uses WireSaveableItems for some of it's core pre-defined data types like Templates and Fields. But Users, Roles and Permissions are in the process of being converted to Page-based data types -- I want them to be things that people can easily add additional fields and data to according to the needs of their site. Page-based data types also benefit from all the page selecting, finding, pagination and manipulation functions that are built in. I haven't taken a really close look at your code yet, but looking at it so far I am wondering if you might be better of using pages, since they would translate well to your videos datatype. But I could be wrong about that, as I'm not yet an expert on what you've put together in this module, so am just posing it as a question. With regard to the error you are experiencing, I'm thinking you might need to move line 189: Wire::setFuel('videos', new Videos()); ...into your init() function. The reason is that $this->videos won't exist in your executeEdit() function. executeEdit() is only called when the URL matches "/edit/" and executeList() is only called when the URL matches "/list/" (or "/" as you've coded it.) Since you are creating the $videos object in the executeList() function, that part never gets executed in the executeEdit() function. Also, you don't even need to do Wire::setFuel('videos', new Videos()). That setFuel() method is only for things that need to be system-wide. Things like $pages, $templates, $fields, etc. It's kind of like an alternative to a global variable, but used as a way to provide the basic API objects. In your case, it looks like $videos is only used in your ProcessVideo class. So you probably only need to make $videos local to that class, rather than creating a new system-wide API variable. So I'm thinking you could put this at the top of your class: protected $videos; And then update your $videos creation line (moved to the init() function) to be this: $this->videos = new Videos(); Let me know if this makes sense, or if I'm misunderstanding? As a side note, I don't think this is what you want... but if for some reason you did want $videos to be an always-accessible system wide variable, you'd have to create it somewhere that it was automatically loaded every time ProcessWire boots... The way you'd do that is by creating a new module: createVideos.module: <?php // move your Video, VideosArray and Videos classes into this module's file. // they will be available to your Process module since this one is always loaded. class createVideos extends WireData implements Module { public static function getModuleInfo() { return array( 'title' => '...', 'version' => 100, 'summary' => '...', 'autoload' => true // tells PW to automatically instantiate this module at boot ); } public function init() { Wire::setFuel('videos', new Videos()); } } Thanks, Ryan
  19. I was thinking about this option too, as it sounds like a good one. But then another thing occurred: what if they first uploaded hello.0x100.jpg and then later uploaded hello.jpg? Then we'd indirectly run into the same problem. I figured the safest bet is probably just to disallow uploading/adding images to PW that are in the same format that it's image cache generates, and removing any dots from the filename (other than the extension) seems to solve it. In that case, the uploaded hello.0x100.jpg becomes hello_0x100.jpg, which ProcessWire wouldn't recognize as one of it's cached images. I figured removing dots from the filename has other security benefits too, and your suggestion motivated the change. Thanks, Ryan
  20. I installed locally too and it looks great and is very nice to use. I've setup a new admin themes page here: http://processwire.com/download/admin-themes/ I'll expand this in the future to include screenshots once we've got a couple more in there. Thanks, Ryan
  21. The idea was that the cached filenames would be system-specific enough that it would be unlikely you'd choose the same filename as one already in the system using the same dimension format. But not so system specific that you could immediately identify what CMS it is based on the filenames. Given that, ProcessWire will assume these images are related and when the first is deleted, the other should be too: hello.jpg hello.[width]x[height].jpg While it seems like an unlikely scenario, it's not impossible that someone would upload another image to the same page called hello.123x456.jpg ... especially if they had perhaps downloaded it from another site running ProcessWire. If they did, and it matched the filename already on the given page (but with .[width]x[height].jpg appended to it) then it would get deleted when they deleted hello.jpg. That would be an error. In the latest commit, I fixed this by having ProcessWire filter out any extra dots in filenames during the upload or the $page->files->add("new file name") process. Without the extra dot there, ProcessWire isn't going to recognize it as being an image cache file, so this error should no longer be possible. Thanks for the finding this. Ryan
  22. Thanks for finding that. I've just pushed an update to the GitHub source that fixes it.
  23. Nice work! The screenshots look great. I can't wait to try this Monday (stuck on cell phone for the weekend). Thanks for your work with this.
  24. It's basically a full-blown RBAC system: http://en.wikipedia.org/wiki/Role-based_access_control Despite writing the system, I still find it confusing to use in my own projects. Roles with different combinations of permissions inheriting through hierarchies are difficult to keep track of. I just want something simpler. The new system will still be role based, but you'll assign roles at the template level, and the "who can do what here" will be unambiguous. Granted the current system may be more powerful in some respects, but simplicity and ease-of-use are more important to this project. This will be for the admin. Although the result will also provide tools that can be useful on the front-end too, but there won't be any translation necessary there (since ProcessWire doesn't output anything at the front end). We definitely appreciate your help! I hope to be in touch about this within the next month or so. Thanks, Ryan
  25. Actually this is already started. But multi language support is next on the roadmap followed by the user system. Because they depend on each other some ways, it's likely they will be built together, or close to it.
×
×
  • Create New...