Jump to content

sforsman

Members
  • Posts

    131
  • Joined

  • Last visited

  • Days Won

    5

Everything posted by sforsman

  1. Hello Richard, Field Depedencies work with Inputfields - parent_id is not an Inputfield for the form. It is a property of the Page-object (which you cannot use). The selector string just looks like a normal selector, but it is not a normal selector. The same syntax is just used here because it feels familiar.
  2. Do you mean this was just a one time error? Then there is no problem at all! WireCache is initialized and used in Modules initialization before SystemUpdater, so on the first request after the upgrade you would get an error like that.
  3. Hey DaveP! Correct, it doesn't, but if you take a closer look, I was referring to a MySQL UDF. Stored procedures or post-processing with PHP would be awfully slow in comparison, which is the exact reason that forced me to write an UDF implementation back in the days. I can dig it up if you are interested in the subject. (Compiling and linking UDFs with MySQL isn't really as complex as they make it sound.) On a sidenote, Elasticsearch for an example - which is backed by Lucene - would obviously provide even greater speeds for fuzzy searching. However we were talking about something that can be combined with the native PW-selectors (i.e. something that can be sticked inside the resulting SQL query). The purpose of my example was to promote a generic way for hooking custom selector operators to existing matchers.
  4. Just create a custom Fieldtype (module) that stores the timestamps properly in a table designed for the purpose. Saving and querying them would then be blazing fast and no need for dirty tricks like comma delimited values on a blob field (which wouldn't obviously be very flexible to query on - especially if you need comparison operators - nor would it be very flexible to modify the values). If you need help implementing such Fieldtype, just let me know.
  5. No problem at all! I'm just glad if it was any help for you. PS. Just let us know if you need any help with the actual Process-module - I can also write an example of those if you like (since they work slightly different compared to the one I posted). However this is where you should probably start if you are going to experiment yourself: https://github.com/ryancramerdesign/ProcessHello.
  6. Could you then please elaborate on where the error is presenting itself? Have you done a hard refresh on your browser (e.g. CTRL-F5 or going Incognito)? This could also be something that's stuck on the new System Notifications and isn't actually a new exception at all. I'm able to give more accurate guesses with more information. If this happens on the admin-site, could you please turn debug-mode on from your site/config.php and give us the complete stack-trace? Of course, if this is not a real exception happening, then the debug-mode won't most likely make any difference. Could you also check if site/assets/logs/errors.txt has anything.
  7. Alright! Are you able to access the admin site at all? Can you for an example go and open the configuration of the SystemUpdater -module and tell me the version number you see there? Are you able to access the database directly? If yes, you could always create the table manually with CREATE TABLE caches ( name VARCHAR(128) NOT NULL PRIMARY KEY, data MEDIUMTEXT NOT NULL, expires DATETIME NOT NULL, INDEX expires (expires) ); However there might still be something wrong with your installation, so it's good to get to the bottom of this before putting anything to production that's fixed by manually modifying the database.
  8. Hello Gabe and welcome, Are we talking about a one single template called material here? Are all of the characteristics usually defined for all of the materials? And the problem is that you don't want to give your client access to the templates and fields of the system? If the answer to all questions is 'yes', then I think approaching the problem with autoloading modules, hooks, PageTables etc is a bit overkill. It is amazingly simple to create a Process-module that you can give the client access to, which simply allows the client to add/edit/remove such fields on the material-template. Here are all the relevant API-methods $template = wire('templates')->get('material'); // Adding a field $field = new Field(); $field->name = "c_durability"; $field->label = "Durability"; $field->type = "Integer"; $field->save(); $template->fields->add($field); $template->save('fields'); // Updating the label $field = wire('fields')->get('c_durability'); $field->label = "Characteristics: Durability"; $field->save(); // Removing the field $field = wire('fields')->get('c_durability'); $fieldGroups = $field->getFieldgroups(); if($fieldGroups->count() > 0) { foreach($fieldGroups as $fieldGroup) { $fieldGroup->remove($field); $fieldGroup->save(); } } wire('fields')->delete($field); Now of course you still need an UI with some confirmation dialogs and validation, but I'm sure you get the idea (if not, ask away). If you really, really want to create a module that does this automatically based on pages, then yes, that can be done with the same methods as well. Such module could be something like this class PageFieldCreator extends WireData implements Module { protected $material_template = "material"; protected $char_template = "characteristic"; protected $template; public static function getModuleInfo() { return Array( 'title' => __('Page Field Creator', __FILE__), 'summary' => __('Demo-module that creates fields from pages'), 'version' => 1, 'singular' => true, 'autoload' => true, ); } public function init() { $this->addHookAfter('Pages::saved', $this, 'saveHook'); } public function saveHook(HookEvent $e) { $page = $e->argument(0); if($page->template->name != $this->char_template) return; if($page->parent->isTrash()) $this->handleDelete($page); else $this->handleSave($page); } protected function handleDelete(Page $page) { $fieldname = $this->getFieldname($page); $field = $this->fields->get($fieldname); if(!$field) return; $fieldGroups = $field->getFieldgroups(); if($fieldGroups->count() > 0) { foreach($fieldGroups as $fieldGroup) { $fieldGroup->remove($field); $fieldGroup->save(); } } $this->fields->delete($field); $this->message(__("Characteristic {$fieldname} deleted")); } protected function handleSave(Page $page) { $fieldname = $this->getFieldname($page); $field = $this->fields->get($fieldname); if(!$field) $this->handleNew($page); else $this->handleUpdate($field,$page); } protected function handleUpdate(Field $field, Page $page) { if(strcmp($field->label, $page->title) == 0) return; $field->label = $page->title; $field->save(); $this->message(__("Characteristic {$field->name} updated")); } protected function handleNew(Page $page) { $field = new Field(); $field->name = $this->getFieldname($page); $field->label = $page->title; $field->type = "Integer"; $field->save(); $tpl = $this->getTemplate(); $tpl->fields->add($field); $tpl->save('fields'); $this->message(__("Characteristic {$field->name} created")); } protected function getFieldname(Page $page) { return "c_".$this->sanitizer->fieldName($page->name); } protected function getTemplate() { if(!isset($this->template)) $this->template = $this->templates->get($this->material_template); return $this->template; } } Such module would create/update/delete a field and update the template called material when a page that has the template characteristic is created/updated/trashed. The demo creates the field using the name of the page prefixed with "c_". While this would technically work, I'd still just create a Process-module for managing them to gain more fine-tuned control. Like I mentioned in the beginning, hooking is also a bit overkill since the fields are rarely modified.
  9. That's great to hear - no problem at all
  10. I'm afraid you haven't upgraded properly if the caches-table doesn't exist since it means that the SystemUpdater hasn't been executed, at least not with the latest SystemUpdates (SystemUpdate6.php in particular). The SystemUpdater is executed with every request, so you probably just haven't installed a fresh wire-folder. Upgrading means replacing the whole wire-folder, not just wire/core for an example. If in doubt, could you please list the contents of wire/modules/System/SystemUpdater so we can confirm this? PS. I'm not sure if I understood your OP correctly, but you should never edit or copy anything under the wire-folder. It is meant to be replaced entirely during the ugprade-process (just as Gabe there said).
  11. I think it would be great to have pluggable selector operators and/or matchers supported directly in the core. If it did, such behavior - and others - could then be easily extended with community modules. For an example, if I preferred an UDF Levenshtein distance calculator instead of SOUNDEX to implement fuzzy searching, I could then do that.
  12. I have some questions but first I'd like you to enable debug-mode in your site/config.php ($config->debug), then try again and post us the result. If you still get the same page (which I'm hoping you don't), could you answer these questions Are you able to access the web server's error log? If yes, please post the error here Do you have something in site/assets/logs/error.txt? If yes, please post the error here Do you get that on the frontend of your site, or when trying to access the admin-site? What modules do you have under site/modules? Could you post us the result of <?php print_r(get_loaded_extensions()); ?> (or `php -m` if you can access a shell)?
  13. Hey pwFoo! It's no trouble really. Check the code with examples from here https://github.com/sforsman/AutoloadContainer
  14. sforsman

    Lister

    What do you mean by "main menu"?
  15. That's the exact thing I try to avoid @Marvin: Here goes: https://github.com/sforsman/SessionLdapAuth I even added an example for the group mapper and did a modification to the code (well, I fixed a spelling error in the description of the module)! If you have any questions about some parts of it, just ask away. I've published it as a Proof of Concept. (see Nico, I'm learning!) No but really, the main point here is to give you something to think against regarding your own implementation. The group mapper configuration string for an example is parsed in a very quick and dirty (=error prone) way and shouldn't be given directly to clients.
  16. Great! I'll try to post it today in the evening
  17. Hey gyo! I'm a bit busy at the moment so I'll just quickly comment on this part only. You have absolutely nothing to worry about on the size of the $event-object - it is a tiny little object that will basically just hold references to other objects (that already exist in the memory anyway). This does not increase the size of the overall memory usage (in a way that really matters, at least). It sure is true that every single function call is theoretically "overhead", but we are talking about a very, very small overhead (in the context of hooks). The only thing you need to make sure of (to reduce the overhead), is that if you hook into something that's used a lot and your hook isn't always applicable, you need to return from the hook asap (i.e. check the conditions for execution in the first possible moment). If it makes you feel better, there's about a hundred hooks added by the PW "core" modules themselves On a side note, I think it's very cool that ProcessWire uses it's own core architecture to provide many of the "core" services we are used to (e.g. the admin-site). PS. I have put the word "core" inside quotes because the actual PW core is pretty lightweight. Much of the "core" that ships with the installation is actually just normal modules that hook in to the system.
  18. Wow ok, thanks for the encouraging comments guys I've worked with PW for quite a while, surfing the core silently in the background (I'm a little shy like that). But one day apeisa gave me a proper kick in the knee and told me to grow a pair - I did, ergo, here I am. I must say you have a really good thing going on here and I'm very happy to be part of it!
  19. The funny thing is, ProcessWire works like this for the exact same reason: to reduce loading of not needed modules If you really, really want to do this yourself, then you would have to create a container inside the main module (or create a new module), that holds the relationships (this can even be a module configuration field). Then each "sub" module registers themselves as a conditionally loadable module with the main module. This would be done inside their ___install() -method. Then in your main module's init(), you fetch all the registered "sub" modules and load them. This would work - I can even write you an example. But to be honest, I'd just autoload the damn the module Though just let me know if you still want an example of what I described.
  20. Those you can't see from the debug-mode admin site's timers, which I was primarily aiming at
  21. Edit: I'm maybe also confused by the word "filter" in context to PW, cause there's a $wirearray->filter(selector); but it's not about the same thing? I agree, but the term and the concept is originating from his WP -background - so each to their own, I guess
  22. Great, then I can try to help you. I'm certainly interested in the steps 4-7, that you described in your OP. It would help even more if you could add the timers around the different phases of your process, like this: $timer = "newsletter_debug"; Debug::timer($timer."1"); // Phase 1 code Debug::saveTimer($timer."1", "Phase 1"); Debug::timer($timer."2"); // Phase 2 code Debug::saveTimer($timer."2", "Phase 2"); Debug::timer($timer."3"); // Phase 3 code Debug::saveTimer($timer."3", "Phase 3"); Debug::timer($timer."4"); // Phase 4 code Debug::saveTimer($timer."4", "Phase 4"); If you can enable debug-mode, then you could copy the timers directly from your admin site. If not, then you could just save them to disk. You can do this with file_put_contents(wire('config')->paths->logs."/timers.txt", var_export(Debug::getSavedTimers(),true), FILE_APPEND); Then just surf to your logs -folder (site/assets/logs) and post us the contents of the timers.txt -file.
  23. That's great news - glad I could help PS. I did a few edits a few minutes before your reply (comments and stuff)
  24. Hello! There is a very simple answer for this: https://github.com/ryancramerdesign/ProcessWire/blob/dev/wire/core/WireInput.php#L60 This is ProcessWire's doing and it is meant to work like that. For now, I'd just suggest that you fetch them directly from the $_POST-variable ($_POST['players']). Obviously you need to validate/sanitize it yourself, but that's the way to go if you don't want to change your form. If you want to play by ProcessWire's "rules", then you will modify your checkboxes so that their name is "player_{{player.id}}[]" and parse them into a multi-dimensional array yourself. This could be done with a simple function like this: /** * Parses a multi-dimensional array * * This function will use $prefix to match the keys in the source $values. * For matching keys the suffix is then extracted and used as a key for the resulting array. * * @param array|Traversable $values The source values * @param string $prefix The prefix used for extraction * @return array The parsed multi-dimensional array */ function getMultiDimensional($values, $prefix) { // Validate the arguments if(!is_array($values) and !($values instanceof Traversable)) throw new Exception("Invalid values"); $len = strlen($prefix); if(!$len) throw new Exception("Invalid prefix"); $output = Array(); foreach($values as $key=>$value) { // The key needs to match our prefix if(strcmp(substr($key,0,$len), $prefix) != 0) continue; // We expect the other part of the key to hold numeric IDs $id = intval(substr($key,$len)); if(!$id) continue; $output[$id] = $value; } return $output; } // Demonstration $players = getMultiDimensional(wire('input')->post, "player_"); // print_r($players); // // [5157] => Array // ( // [0] => 1580 // [1] => 1578 // ) // ...and so on Edit: Added an example and some comments Needless to say, I suggest the latter solution
  25. Yes it will be - it's a method provided by the class all Fieldtypes are extending from. This method will be called when you echo the field inside a template, or to be more precise, when output formatting has been turned on. There is also a hook for FieldType::wakeupValue, which is called when the value for the field is retrieved from the database and attached to the Page object. In other words, if you want the filters to run regardless of the state of output formatting, that's where you want to hook. Or you could even hook both. Since your module is an autoloading singular module, there's a very easy way to provide a flexible way to disable/enable the filters temporarily - globally or per field. Here's an example // Filter.module protected static $disabled = false; protected static $disabled_fields; // Turn the whole filtering system off public static function setFiltersOff($disable = true) { self::disabled = $disable; } // Turn filters off for a specific field public static function setFieldFiltersOff($field, $disable = true) { // If you pass a string instead of a Field-object, it has to be the name of the field if(is_string($field)) $field = wire('fields')->get($field); if(!($field instanceof Field)) throw new Exception("Invalid field"); // Initialize if(!isset(self::disabled_fields)) self::disabled_fields = new SplObjectStorage(); if($disable) self::disabled_fields->attach($field); else self::disabled_fields->detach($field); } // Modify the init() to support these features public function init() { $class = __CLASS__; $this->addHookAfter("FieldType::formatValue", function(HookEvent $e) use ($class) { if($class::disabled) return; $page = $e->arguments(0); $field = $e->arguments(1); $value = $e->arguments(2); if(isset($class::disabled_fields) and $class::disabled_fields->contains($field)) return; // The rest is business as usual... }); // Just a bonus hook for another shortcut $this->addHook("Field::setFiltersOff", function(HookEvent $e) use ($class) { $field = $e->object; $disable = ($e->arguments(0) !== null) ? $e->arguments(0) : true; $class::setFieldFiltersOff($field, $disable); }); } // Now you can use these like this // Disable all filters wire('modules')->get('Filter')->setFiltersOff(); // Turn them back on wire('modules')->get('Filter')->setFiltersOff(false); // Disable a specific field wire('fields')->get('my_field')->setFiltersOff(); // Turn it back on wire('fields')->get('my_field')->setFiltersOff(false); Edit: Added examples You could obviously implement this in other ways too.
×
×
  • Create New...