Jump to content

da²

Members
  • Posts

    396
  • Joined

  • Last visited

  • Days Won

    5

Everything posted by da²

  1. Ho yes it is in ProFields sub-forum, he said:
  2. Hi, I'm using the same as you, and already reported it to @ryan, you can see his answer here, it looks like he can do something:
  3. An issue fixed, just need to accept this small pull request. ? https://github.com/processwire/processwire/pull/274
  4. That looks good if online documentation has a note on it. ? Thanks for your commitment. ?
  5. OK, thanks for the explanations, I understand better your point of view. Yes this project is 3.0.200 using processInput(), here is the class I used, it's basically just a wrapper over InputfieldForm. Since then, I updated this class, because I saw you updated it in the same way (to make InputfieldForm API easier). abstract class TemplateFormManager { /** @var Inputfield $form */ private $form; private string $submitFieldName; function __construct( array $defaultValues = null, string $formAction = "./", string $method = FormMethod::POST, bool $showSubmit = true, string $submitFieldName = "submit_form" ) { $this->submitFieldName = $submitFieldName; $this->form = modules('InputfieldForm'); $this->buildForm($this->form); $this->applyDefaultValues($defaultValues); if ($showSubmit) $this->addSubmit(); $this->form->action = $formAction; $this->form->method = $method; } function render(): string { return $this->form->render(); } function isSubmitted(): bool { $submitName = $this->form->method == FormMethod::POST ? wire()->input->post($this->submitFieldName) : wire()->input->get($this->submitFieldName); return $submitName != null; } function processInput() { $this->form->processInput( $this->form->method == FormMethod::POST ? wire()->input->post : wire()->input->get ); } function getErrorCount(): int { return count($this->form->getErrors()); } function setError(string $fieldName, string $error) { $field = $this->form->get($fieldName); if (!$field) { throw new InvalidArgumentException("Field '$fieldName' doesn't exist!"); } $field->error($error); } /** * Get value of a Inputfield. */ function __get($fieldName) { $field = $this->form->get($fieldName); if (!$field) { throw new InvalidArgumentException("Field '$fieldName' doesn't exist!"); } return $field->attr('value'); } function getField(string $fieldName): Inputfield { $field = $this->form->get($fieldName); if (!$field) { throw new InvalidArgumentException("Field '$fieldName' doesn't exist!"); } return $field; } protected abstract function buildForm(Inputfield $form); private function applyDefaultValues(?array $values) { if ($values) { foreach ($values as $fieldName => $value) { $field = $this->form->get($fieldName); if (is_a($field, "ProcessWire\InputfieldCheckbox", true)) $field->checked($value); else $field->attr('value', $value); } } } private function addSubmit() { $submit = modules('InputfieldSubmit'); $submit->attr('name', $this->submitFieldName); $submit->value = "Valider"; $this->form->add($submit); } } Next one is my current version (PW 3.0.210), you can look at the execute() method, this is where I use the callback method onValidate() to do extra validation in template file. In the previous version above it was coded in a function executeForm() outside of abstract form class. On getErrorCount() method, I'm smiling at my comment "Strange method that gave me strange bugs, I just understand nothing..." ? abstract class AbstractForm { protected readonly InputfieldForm $form; protected readonly string $submitFieldName; public function __construct( array $defaultValues = null, string $formAction = "./", string $method = FormMethod::POST, bool $showSubmit = true, string $submitFieldName = "submit_form" ) { $this->submitFieldName = $submitFieldName; /** @var InputfieldForm $form */ $form = modules('InputfieldForm'); $this->form = $form; $this->buildForm($this->form); if ($showSubmit) $this->addSubmit(); $this->form->populateValues($defaultValues); $this->form->action = $formAction; $this->form->method = $method; } public function render(): string { return $this->form->render(); } public function execute( callable $successCallback = null, callable $validateCallback = null, ): int { if ($this->isSubmitted()) { $this->form->process(); // Check errors managed by form. $errorCount = $this->getErrorCount(); if ($errorCount > 0) return $errorCount; // Do extra validation. if ($validateCallback) $validateCallback($this); // Check errors after our extra validation. $errorCount = $this->getErrorCount(); if ($errorCount > 0) return $errorCount; if ($successCallback) $successCallback($this); } return 0; } /** * Strange method that gave me strange bugs, I just understand nothing... */ public function getErrorCount(): int { return count($this->form->getErrorInputfields()); } public function setError(string $fieldName, string $error): void { $field = $this->form->getChildByName($fieldName); if (!$field) { throw new InvalidArgumentException("Field '$fieldName' doesn't exist!"); } $field->error($error); } /** * Get value of an Inputfield. */ public function __get(string $fieldName): mixed { $value = $this->form->getValueByName($fieldName); if ($value === null) throw new InvalidArgumentException("Field '$fieldName' doesn't exist!"); return $value; } public function setValue(string $fieldName, string $value): void { /** @noinspection PhpUnhandledExceptionInspection */ $field = $this->form->get($fieldName); if (!$field) throw new Error("Field $fieldName it not in form."); $field->attr('value', $value); } protected abstract function buildForm(InputfieldForm $form): void; protected function isSubmitted(): bool { /** @noinspection PhpUnhandledExceptionInspection */ return $this->form->isSubmitted($this->submitFieldName); } private function addSubmit(): void { try { /** @var InputfieldSubmit $submit */ $submit = wire()->modules->get('InputfieldSubmit'); $submit->attr('name', $this->submitFieldName); $submit->value = __("Valider", COMMON_TRANSLATION_DOMAIN); // Traduire dans _commonTranslations.php $this->form->add($submit); } catch (WirePermissionException $e) { throw new Error($e->getMessage()); } } } I use it like that in a template: $onValidate = function (AbstractForm $form): void { // Calling a remote API to valid some data // We got an error $form->setError('fieldName', "Don't do that please"); }; $onSuccess = function (AbstractForm $form): void { // Saving user and redirecting to another page }; // Form default values $currentValues = [ 'foo' => $bar ]; $form = new AccountEditionForm($currentValues); $formErrorCount = $form->execute($onSuccess, $onValidate); Twig::render('account-edition', [ 'form' => $form, 'formErrorCount' => $formErrorCount ]); Thank you. Yes this is often necessary. I'm checking errors that are outside of pure form context. Another user had this same issue since 3.0.210, I'm not alone doing this. ? Sometimes I add the namespace, but just to get cleaner imports. I didn't know there is a relation with template compilation, could you explain what's the problem of having my template compiled by PW? I'm gonna add it in PHPStorm template file, so I don't forget it. EDIT: in fact $config->templateCompile was already false by default.
  6. OK, I don't know if this is possible in PW. I searched in source code for "ORDER BY FIELD" but found nothing. Maybe that could be a PW feature request to add selector for ORDER BY FIELD. You can also do the MySQL request using $database API variable, but then you must do yourself values sanitization, and resolving pages references if any. SELECT * FROM table ORDER BY FIELD(id, 5,3,6,1,4,2);
  7. Could you explain the conditions that justify this sorting? Is it static or dynamic? If static maybe you can solve this by manual sorting in PW admin. Then you use "sort=sort" in your selector. If dynamic the only solution I see actually would be like: $sortedIds = [5872, 5869, 5870, 5871]; // List created dynamically $results = $pages->find('id=' . implode('|', $sortedIds)); $sortedResults = []; foreach ($results as $result) { // echo $result->id . "\n"; $nextId = array_shift($sortedIds); if(!$nextId) break; $sortedResults[] = $results->getPageByID($nextId); } var_dump($sortedResults);
  8. So, except if there's a magic trick I'm not aware of, you have to get the pages in correct order from the resulting PageArray, with your own code.
  9. Sorting is managed with "sort" selector. If you want to sort by reverse id: $pages->find('id=4|2|1', sort='-id');
  10. Yes I'll open it if no answer from Ryan. ?
  11. Hello, Probably a mistake when configuring host. Edit C:\Windows\System32\drivers\etc\hosts and add line: 127.0.0.1 my-project.local.fr Edit xampp\apache\conf\extra\httpd-vhosts.conf and add: <VirtualHost *:80> # Directory that contains index.php DocumentRoot "E:\src-processwire" ServerName my-project.local.fr <Directory "E:\src-processwire"> Options FollowSymLinks Indexes Order allow,deny Allow from all AllowOverride All Require all granted </Directory> </VirtualHost> Restart XAMPP Apache server and go to http://my-project.local.fr/
  12. Up. @ryan Did you read this?
  13. Is it possible that your provider changed the network configuration? It happened to me few months ago, provider migrated my server to another server rack and then I wasn't able to reach external URLs, a single file_get_contents() to a remote URL wasn't working anymore. Reason was: new network config used IPv6 but it wasn't available. Dunno if your symptoms are compatible with this scenario, but something must have been modified. ?
  14. I don't know if that can help you, but on my project, backend side, I hide all pages that a user can't edit, with this hook: /** * In PW admin, hide pages that user can't edit. */ $wire->addHookAfter('Page::listable', function (HookEvent $event) { /* @var Page $page */ $page = $event->object; if ($page->path == "/") $event->return = true; else $event->return = wire()->user->hasPermission("page-edit", $page); }); There is no impact on the frontend side.
  15. Hello, Documentation of this module is here: https://processwire.com/api/ref/textformatter-markdown-extra/ You can do something like: modules('TextformatterMarkdownExtra')->format($text);
  16. Hi, There's not enough information to talk about the issue. It seems the provider changed its API, asking for a cookie that you don't provide. You should check if the API works outside of the form and ProcessWire.
  17. I also can't login in Developer Directory too. Red popup too.
  18. Hi, I'm using PHP 8.2 and 8.1. No issue with Processwire 3.0.210 but you may find issues with third-party modules. For example I recently installed Twig module and it has this minor issue easy to fix.
  19. Hello, I suppose this is due to text domain. You are asking for a translation that has been defined in another file, so to get it you need to specify the text domain of this file. echo __($string, '/site/templates/file_containing_translation.php'); If you want to automatically export translations, I think you should put all translations in a single file, let say it's named _commonTranslations.php: __('translation 1'); __('translation 2'); // And so on... Then when you insert this translations in the template that needs it, you need to specify text domain (you can put it in a constant or create a global function that inserts it automatically): __('translation 1', '/site/templates/_commonTranslations.php'); Note that in PW, you translate this sentences ONLY in _commonTranslations.php. Finally your function looks like that: function echoSnippet($string, $lang) { // Echo the string in english wire('user')->setLanguage(wire('languages')->get('name=en')); echo __($string, '/site/templates/_commonTranslations.php'); // Echo the string in german wire('user')->setLanguage($lang); echo __($string, '/site/templates/_commonTranslations.php'); }
  20. Hello @Craig I don't know if you get notifications from Github issues, so I notice you here that your module has a huge bug, it just doesn't manage cookie expiration date. Greetings, and thanks for your work.
  21. Hello, @ryan I tried to use in PW 3.0.210 and 3.0.218 a class I wrote in PW 3.0.200 for managing forms, and it's not working anymore. When I manually set an error on a field, $form->getErrors() returns no error cause it's returning an empty cached array generated with $form->process(). A simple example: <?php use ProcessWire\InputfieldForm; use function ProcessWire\modules; /** @var InputfieldForm $form */ $form = modules('InputfieldForm'); $form->add($form->InputfieldText->attr('id+name', 'foobar')); $form->add($form->InputfieldSubmit->attr('name', 'submit_subscribe')->val('Subscribe')); if ($form->isSubmitted('submit_subscribe')) { if ($form->process()) { // Simulating a callback method doing extra form validation (for example requesting a URL to verify data). $fieldInError = $form->getChildByName('foobar'); $fieldInError->error("test error"); echo "<u>form->getErrors():</u> " . count($form->getErrors()) . "<br>"; // BUG: getErrors() == 0 echo "fieldInError->getErrors(): " . count($fieldInError->getErrors()) . "<br>"; // this is correct, == 1 echo "form->getErrorInputfields(): " . count($form->getErrorInputfields()) . "<br>"; // this is correct, == 1 echo $form->render(); } else { echo "<h3>There were errors, please fix</h3>"; echo $form->render(); } } else { echo $form->render(); } ?> $form->getErrors() returns 0 cause it's returning the cache. But even if you call $form->getErrors(clear: true) you are stuck with cache forever, look at InputfieldForm.getErrors(): public function getErrors($clear = false) { if($this->errorCache !== null) return $this->errorCache; $errors = parent::getErrors($clear); $this->errorCache = $clear ? null : $errors; return $errors; } Cache cleaning is at line 3, but if we have cache we always stop at line 1. Maybe we could fix it like this, but I don't get the purpose of this error cache so this code may be problematic in some cases: public function getErrors($clear = false) { if($this->errorCache !== null && !$clear) return $this->errorCache; $errors = parent::getErrors($clear); $this->errorCache = $clear ? null : $errors; return $errors; } Actually the easiest fix is to use getErrorInputfields() from InputfieldWrapper, because it doesn't implement error cache. ------------------------------------------- I also randomly found 2 things about errors being stored somewhere in PW. This cases should not happen but maybe it's worth reporting them. If we don't call $form->render(); after setting the field in error, the error is stored and will be displayed on next page load. Demonstration: $form = modules('InputfieldForm'); $form->add($form->InputfieldText->attr('id+name', 'foobar')); $form->add($form->InputfieldSubmit->attr('name', 'submit_subscribe')->val('Subscribe')); if ($form->isSubmitted('submit_subscribe')) { $form->getChildByName('foobar')->error("test error"); } else echo $form->render(); Click Subscribe, select url bar and hit enter, or open same url in another tab => you see the field in error. If we do a redirection after setting the field in error, the error will also appear in PW admin: $form = modules('InputfieldForm'); $form->add($form->InputfieldText->attr('id+name', 'foobar')); $form->add($form->InputfieldSubmit->attr('name', 'submit_subscribe')->val('Subscribe')); if ($form->isSubmitted('submit_subscribe')) { $form->getChildByName('foobar')->error("test error"); $session->redirect($page->url); } else echo $form->render(); Click Subscribe, navigate to admin => you see the red error notice: ------------------------------------------- And the last thing, getErrors() have different behavior depending if we use $form->process(); or $form->processInput($input->post);. Here with process(), getErrors() returns 0. This is caused by process() calling getErrors(clear:false), and getErrors() creating this forever cache. $form = modules('InputfieldForm'); $form->add($form->InputfieldText->attr('id+name', 'foobar')); $form->add($form->InputfieldSubmit->attr('name', 'submit_subscribe')->val('Subscribe')); if ($form->isSubmitted('submit_subscribe')) { $form->process(); $form->getChildByName('foobar')->error("test error"); echo "<u>form->getErrors():</u> " . count($form->getErrors()) . "<br>"; // ZERO echo $form->render(); } else { echo $form->render(); } And with processInput() it returns 1. $form = modules('InputfieldForm'); $form->add($form->InputfieldText->attr('id+name', 'foobar')); $form->add($form->InputfieldSubmit->attr('name', 'submit_subscribe')->val('Subscribe')); if ($form->isSubmitted('submit_subscribe')) { $form->processInput($input->post); $form->getChildByName('foobar')->error("test error"); // ONE echo "<u>form->getErrors():</u> " . count($form->getErrors()) . "<br>"; echo $form->render(); } else { echo $form->render(); } Thanks for reading, I hope it will be useful, I've lost my night on that trying to figure why my code wasn't working even if I used it tens of times on a PW 3.0.200 project. ?
  22. Where is the "mark as solution" button that the email I just received is talking about? ?
  23. Check in your template > Advanced tab > List of fields to display in the admin Page List
  24. Hello, I'm using the W3C validator to check my pages and find that Textarea CKEditor outputs line breaks as <br /> instead of <br>. Is there a way to make it HTML5 compliant? I used no text formatter and checked Markup/HTML content type. EDIT : Same issue with InputfieldForm, <input /> should be <input> Thanks.
  25. Thank you for your answers @bernhard and @Jan Romero . The ProFields Table looks like a good solution. ? So I can use PageReference fields for users, cars and tracks, and display the standings in each hotlap page (same for races and other events). Also I prefer to use PW solutions instead of developing my own modules. I already used PW for some projects, but never at this scale, I'm quite excited to start development but I'm also a bit blind about how to do this or that. ?
×
×
  • Create New...