Jump to content

bernhard

Members
  • Posts

    6,671
  • Joined

  • Last visited

  • Days Won

    366

Everything posted by bernhard

  1. TracyDebugger shows all the available options, so you don't have to remember them already. But you have to write them down manually at the moment. I guess it would be possible to create that yaml file on the fly. If tracy knows all the settings and can write them to the panel I'm quite sure it is possible to write them to a yaml file as well. Maybe @adrian can tell us something about that?
  2. This would be some kind of a dream for me to have in ProcessWire. ?‍♂️
  3. /site/modules/MyModule /site/modules/MyModule/classes /site/modules/MyModule/classes/MyPageClassOne.php /site/modules/MyModule/classes/MyPageClassTwo.php /site/modules/MyModule/MyModule.module.php The module: <?php namespace ProcessWire; class MyModule extends WireData implements Module { public static function getModuleInfo() { return [ 'title' => 'MyModule', 'version' => '0.0.1', 'summary' => 'Your module description', 'autoload' => true, 'singular' => true, 'icon' => 'smile-o', 'requires' => [], 'installs' => [], ]; } public function init() { $this->rm()->initClasses(__DIR__."/classes"); } /** * @return RockMigrations */ public function rm() { return $this->wire->modules->get('RockMigrations'); } } The class: <?php namespace ProcessWire; class MyPageClassOne extends Page { public function init() { $this->wire->addHookAfter("Pages::saveReady", $this, "onCreate"); } public function onCreate(HookEvent $event) { $page = $event->arguments(0); if(!$page instanceof self) return; if($page->id) return; $page->status = 1; // auto-publish this page $this->message('Auto-published page '.$page->path); } } initClasses() will not only load your custom page classes but also trigger the init() method once. That makes it possible to attach all kinds of hooks that belong to the custom page class where they belong: Into the page classe's php file. You avoid hook-hell in ready.php like this. It will load one instance of your page class on every request though. You can also use custom namespaces easily: // in the module: $this->rm()->initClasses(__DIR__."/classes", "MyNameSpace"); // your page class: <?php namespace MyNameSpace; use ProcessWire\Page; class MyPageClassOne extends Page { ... } You don't need to use RockMigrations for that. You can have a look what initClasses() does. You could also just set the page class on the template. I don't know if that can be done manually but using RockMigrations it is just setting one property of the template: 'my_template' => [ 'fields' => [...], 'pageClass' => ..., ]
  4. Hi @Krlos that's not an easy question and depends a lot on the use case. What are the circumstances that make the decision hard? I can't give any advice without any knowledge about the situation... Tricky? For whom? For the developer? For the person managing content? Counter question: Wouldn't it be tricky to reorganize hundreds of pages once a single thing in your project setup changes? See https://github.com/processwire/processwire-issues/issues/1459 for a recent issue... Unlimited possibilities using a hook ? I'm often using http://tabulator.info/ for displaying data and I have a module for that, so for me this is no issue. But you can also use ListerPro or the regular page finder I guess. If you don't have those tools it might be easier to stick with the page tree... But having business logic in the page tree is - in my experience - not a good idea for projects that need to scale in some extent, might change in the future or have have custom logic and calculations (for example I've built a survey tool where answers have been pages and the parent defined where the answers belonged to. That sounded great and easy on first glance, but the longer the project went and the more feature/change requests the client came up with, the more i regretted the decision and I think it would have been a lot easier to save all those answers under one parent and add a page field to save a reference to the related survey). But your setup looks like you want to show the items to website visitors under an existing urls, so probably having them where users can visit them makes sense (site.com/lodging/hotels/hotel-a)
  5. Sorry I missed your second post... Actually something similar would already be possible using RockMigrations. At least for basic setups. I'm not sure how that can work for more complex setups though. I'll try to explain that by an example: Let's say we created a new blog module. We need a blog page (parent) and several blog-items (children): - home '- blog |- blog entry 1 |- blog entry 2 ... This setup could easily be built into a module using rockmigrations: <?php namespace ProcessWire; class MyBlog extends WireData implements Module { public static function getModuleInfo() { return [ 'title' => 'MyBlog', 'version' => '0.0.1', 'summary' => 'blog module using rockmgirations', 'autoload' => true, 'singular' => true, 'icon' => 'smile-o', 'requires' => [], 'installs' => [], ]; } public function init() { $this->rm()->fireOnRefresh($this, "migrate"); } public function migrate() { $this->rm()->migrate([ 'fiels' => [...], 'templates' => [ 'blog_parent' => [...], 'blog_item' => [...], ], ]); $this->rm()->setParentChild('blog_parent', 'blog_item'); // --> this sets the family settings for both the parent and the child template - how long does that take by hand? ;) It means that all pages having the "blog_parent" template will create a "blog_item" page automatically when you click on "add new page". Basically the stuff that you set on the family tab of the template. } /** * @return RockMigrations */ public function rm() { return $this->wire->modules->get('RockMigrations'); } } That means I'm literally defining my config in the module code. We could also have the config read from a config.yaml - that would really be the same (just less powerful IMHO)! The problem arises when you want to make that config customizable. For example you want a page reference field to select the author for every blog post. Building that into the blog module would probably not be a good idea because not every site might need such a field. What I do in such situations is this: I make the migrate() method hookable and create one module that handles all the project-specific stuff: <?php namespace ProcessWire; class MyProject extends WireData implements Module { public static function getModuleInfo() { return [ 'title' => 'MyProject', 'version' => '0.0.1', 'summary' => 'module that handles site specific stuff', 'autoload' => true, 'singular' => true, 'icon' => 'smile-o', 'requires' => [], 'installs' => [], ]; } public function init() { $this->addHookAfter("MyBlog::migrate", $this, "migrate"); } public function migrate(HookEvent $event) { $this->rm()->createField("author", "page", [ 'label' => 'Select the author', ... ]); $this->rm()->addFieldToTemplate("author", "blog_item", "title"); } /** * @return RockMigrations */ public function rm() { return $this->wire->modules->get('RockMigrations'); } } That means you can have your blog module that you can reuse from project to project (and improve it and just pull changes if you need to) and you can still customize it the ProcessWire way (which we all love I guess). BUT Now we got a new field on the "blog_item", the "author" field. So the config.yaml of the blog module would change, wouldn't it? I'm not sure how CraftCMS handles such situations? And that's one of the reasons why I think that efforts like this are going in a wrong direction. It sounds intriguing for sure to have something like a "migrations recorder". I'm working or at least thinking about that since 2016. But I simply can't imagine a way that could reliably work in all situations. RockMigrations does. And it does it really well. And it does it for almost 3 years now and has evolved a lot. It's still not perfect for sure. But I don't think that This feels wrong. I'dont know how to explain. I think you have a good understanding of composer and such things. Likely a much better understanding than I have. So if it is true what you are saying, I must be doing a lot wrong in my daily work or at least I must be understanding a lot wrong... Because a lot of my workflows do feel very version control friendly. And I've lately started working in a company in vienna where we work on ProcessWire projects with fully automated workflows. We work in a team. We work on different local machines. We deploy to staging and if everything works (which has been the case 100% so far), we deploy to production with a single click. But maybe I'll change my opinion some day and look back and laugh. Maybe I should just try CraftCMS. Maybe many other fancy new tools. At my company they also work (or worked) with another CMS. They said they liked to be able to define fields and templates in code. They said that was one of the (few) things they didn't like about ProcessWire, because they love professional workflows and automated deployments... But they also admitted, that it was somewhat painful to define fields and templates in the other CMS. They said you have to add pieces of config in that file, then change another piece in another file. And end up changing many files for simple changes. Now they like RockMigrations ? And such comments make me think I am on a right track and we as ProcessWire enthusiasts are not that far away from what you seem to be missing. @MoritzLost have you ever heard someone saying "ProcessWire is great for small websites, but not for larger, more complex ones"? We all know how wrong that is, don't we? That's the way I feel when people here on the forum are talking about missing migration / version control features... PS: I tried to keep this post short and not so emotional. I think I failed, sorry ?
  6. Yes <?php $rm->migrate([ 'templates' => [ 'car' => [ 'fields' => [ 'title' => [ 'label' => 'Name of the Car', 'columnWidth'=>50, ], 'km' => ['columnWidth'=>50], ], ], ], ]); voila. fields "title" and "km" will be 50% width in the car template context. the title field will have a custom label on the car template. It's really that simple most of the time! Change some properties, commit, push, done! What are you missing? Depends. Both are possible. RockMigrations is really also great if you add it later on a project that did not handle migrations before. It really does not care. For example you could add this in your ready.php: <?php $rm = $modules->get('RockMigrations'); $rm->createField('test', [ 'type' => 'text', 'label' => 'Testing RockMigrations', ]); // add field test to home template after the title field $rm->addFieldToTemplate("test", "home", "title"); You'll have your test field right after the title field of the home template. You can do the same for everything you add to your site. Doing it like this, of course, the migration will run on every page request. The great thing about the migrations is that this will just work! It's not ideal of course, but I just want to show how it works. Add another field? Here we go: <?php $rm = $modules->get('RockMigrations'); $rm->createField('test', [ 'type' => 'text', 'label' => 'Testing RockMigrations', ]); $rm->createField('test2', [ 'type' => 'text', 'label' => 'Testing RockMigrations again', ]); $rm->addFieldToTemplate("test", "home", "title"); $rm->addFieldToTemplate("test2", "home", "test"); Now we got two fields. Ok, we want those fields in a row? Lets refactor this (it would be possible using the syntax from above as well, but I just prefer the array syntax as it has everything in place): <?php $rm = $modules->get('RockMigrations'); $rm->migrate([ 'fields' => [ 'test' => [ 'type' => 'text', 'label' => 'Testing RockMigrations', ], 'test2' => [ 'type' => 'text', 'label' => 'Testing RockMigrations again', ], ], 'templates' => [ 'home' => [ 'fields' => [ 'title' => ['columnWidth'=>33], 'test' => ['columnWidth'=>33], 'test2' => ['columnWidth'=>33], ], ], ], ]); Commit, Push, Done. So do you really think manually creating those fields was quicker? Even if you create those fields remotely first and then pull a DB dump and you have at least semi-automated the process and a dump takes "only 15 seconds or so"... I bet migrations are quicker, more versatile, more powerful. Let's say you want to tidy up your project a little bit. Let's add tags for those two test fields: <?php $rm = $modules->get('RockMigrations'); $rm->migrate([ 'fields' => [ 'test' => [ 'type' => 'text', 'label' => 'Testing RockMigrations', 'tags' => 'RockMigrationsTests', // <----- add this ], 'test2' => [ 'type' => 'text', 'label' => 'Testing RockMigrations again', 'tags' => 'RockMigrationsTests', // <----- add this ], ], 'templates' => [ 'home' => [ 'fields' => [ 'title' => ['columnWidth'=>33], 'test' => ['columnWidth'=>33], 'test2' => ['columnWidth'=>33], ], ], ], ]); Thats it! Both fields live under that new tag: Nice and clean! Ok, now let's remove those changes: The IDE will help you find the right method... So we can do: /** @var RockMigrations $rm */ $rm = $modules->get('RockMigrations'); $rm->deleteFields("tags=RockMigrationsTests"); $rm->setFieldData("title", ["columnWidth"=>100], "home"); How long would it take you to delete those two fields manually? Making sure that all checks are met ("you can't delete this field... it is used by XX templates..." *#*&!), going back to the templates editor, removing the field first, then deleting the field, then going back to the home template and setting the title field back to 100%... I don't know the exact workflow - I haven't done that for a long time now ? Yeah and we are not even talking about doing those changes in a team... Have fun ? Yeah, @adrian, I know Tracy can help. Just trying to show how quick you can get when doing things using RockMigrations. Of course there are some situations where you might not know the properties you need to set. But Tracy can help you. Or you inspect the inputfield and lookup the name in your devtools. The nice side effect: You learn a lot about PW and you will understand it a lot better and improve even more. Well... I don't know what more to say. I feel your pain, but I don't really understand why there are many here "complaining" about those missing features of ProcessWire but nobody seems to be using RockMigrations or seems to have given it an hour or two to simply try it out... ?‍♂️ PS: I know the example runs migrations on every page request, which is not ideal. You can come up with your own strategy to prevent that or you can simply use $rm->fireOnRefresh() so migrations will only fire on modules::refresh I'm maybe similar. There's not a single new project not using RockMigrations and custom PageClasses now. It might be overkill for some, but I think for people that are asking questions that you are asking RockMigrations is just the right tool and you are missing something. That would be a pity. We need more people like you here ? Sometimes life as a developer is hard. But we get paid for that ?? I agree on that. I'm working on it and I wished more were doing so ? Why not? I agree it's not perfect, but I've put hard work into making this possible over the last years. And I think I've come very far. I don't know much other systems though, so I might be on the wrong track. If you know any better systems I'm just as happy to hear about them as @adrian
  7. Nope, that was my first idea ? Yeah, it should, but it detects PRODUCTION on my dev setup! Great! That works and solves my problem ? I'm using different configs for dev/production so that's a perfect solution ?
  8. Several updates have been pushed to the module. The latest one concerns the fireOnRefresh method / strategy. If you are using this technique together with bootstrapping ProcessWire be sure to test everything as this change might introduce different behaviour than before! From the readme: Note about fireOnRefresh() Prior to v0.0.82 the fireOnRefresh did NOT fire in bootstrapped environments. This is because ProcessWire by default runs as guest user when bootstrapped and the fireOnRefresh method did not attach any hooks if the user was no superuser. That was a problem for me because a $modules->refresh() did not trigger any migrations when invoked from the commandline. To solve that issue v0.0.82 introduces another concept: fireOnRefresh fires always after Modules::refresh even for guest users. If you need to prevent RockMigrations from firing actions that where attached via fireOnRefresh you have two options: Setting a constant: define("DontFireOnRefresh", true) Setting a config property: $config->DontFireOnRefresh = true; Note that the setting must be available to RockMigrations BEFORE the action gets attached via fireOnRefresh. This is best explained by examples: define('DontFireOnRefresh', true); include("index.php"); // fireOnRefresh is triggered here $modules->refresh(); // this will not trigger any migrations We define the constant before ProcessWire gets loaded and therefore any module attaching migrations via fireOnRefresh will actually NOT attach any migrations because the flag to prevent that is present when the triggered from init() or ready(). include("index.php"); // fireOnRefresh is triggered here $config->DontFireOnRefresh = true; $modules->refresh(); // this WILL trigger all migrations! In this example the migrations will be triggered because the migrations have been attached BEFORE the config setting was set. In other words the flag was set too late for RockMigrations to realize it.
  9. Hey @adrian I've recently switched to DDEV for my local development. Everything works great so far ? Today I found one issue with tracy and the "force guest users into DEV mode on LOCALHOST" This feature does not work when using ddev. I'm also not sure about the "DETECT" setting of output mode... Would it be possible to make the output mode configurable from the host name? myproject.ddev.site --> DEVELOPMENT myproject.com --> PRODUCTION It would then be great to have an option "force guest users into DEV mode on DEV environment" How can I check wich output mode my tracy detects when using "DETECT" setting? Thx for your help!
  10. Once my PRs are approved the latest version of this module will make it possible to set the main color via an inputfield:
  11. Don't think so, I was just curious ? This is what I'm using nowadays: <?php namespace ProcessWire; if(!defined("PROCESSWIRE")) die(); /** @var Config $config */ $config->debug = false; $config->useFunctionsAPI = false; $config->useMarkupRegions = false; $config->usePageClasses = true; $config->prependTemplateFile = '_init.php'; $config->appendTemplateFile = '_main.php'; $config->defaultAdminTheme = 'AdminThemeUikit'; $config->dbHost = 'localhost'; $config->dbPort = '3306'; $config->chmodDir = '0755'; $config->chmodFile = '0644'; $config->timezone = 'Europe/Vienna'; $config->dbEngine = 'InnoDB'; $config->installed = 123456789; setlocale(LC_ALL, 'de_AT.utf8', 'de_DE.utf8', 'de_AT', 'de_DE'); // try to load config foreach([ "/path/to/your/live/config.php", __DIR__."/config-local.php", ] as $c) { if(!is_file($c)) continue; return include($c); } die("no config found"); This file is under git, so everything that is the same for all environments comes into config.php; Everything else comes into the live or dev config: <?php namespace ProcessWire; /** @var Config $config */ $config->debug = true; $config->dbName = 'db'; $config->dbUser = 'db'; $config->dbPass = 'db'; $config->dbHost = 'db'; $config->userAuthSalt = 'abcdefg'; $config->httpHosts = ['my.ddev.site']; $config->filesOnDemand = 'https://staging.mysite.com'; ?
  12. @thetuningspoon doesn't that mean that you put all your database secrets into git?
  13. Yes, RockMigrations Yes Yes It depends. Imagine you already have a setup using RockMigrations and your class uses code like this: <?php $rm->migrate([ 'fields' => [ 'field1' => [ 'type' => 'text', 'label' => 'Field ONE', ], ], 'templates' => [ 'my_template' => [ 'fields' => [ 'title', 'field1', ], ], ], ]); And you wanted to add 2 new fields and show those fields in a 3-column layout in your page editor. Using RockMigrations: open the file that holds your migrate code in your IDE (eg /site/classes/MyTemplate.php) add some lines of code (it's copy&paste most of the time and really easy once you are used to doing so): <?php $rm->migrate([ 'fields' => [ 'field1' => [ 'type' => 'text', 'label' => 'Field ONE', 'columnWidth' => 33, ], 'field2' => [ 'type' => 'text', 'label' => 'Field TWO', 'columnWidth' => 33, ], 'field3' => [ 'type' => 'text', 'label' => 'Field THREE', 'columnWidth' => 33, ], ], 'templates' => [ 'my_template' => [ 'fields' => [ 'title', 'field1', 'field2', 'field3', ], ], ], ]); run the migration add code that uses the new fields test your results, commit and push to staging/production Not using migrations, option 1: login on the live system add new field2 set column width, save add new field3 set column width, save go to setup > fields > edit > field1 set column width, save add code that uses the fields on live system hope that everything works and none of your site visitors sees anything from what you are doing... if anything goes wrong: restore the backup you took before creating your fields what? you forgot to create a backup? ok... you took care of that and lazycron is doing backups every day! write an email to your client that explains that you had to restore a database backup from last night, which means that his website lost XX comments, or YY orders, or ZZ new entries ... That means that option 1 CAN be quicker, but can quickly get a lot more time-consuming than properly migrating your fields. Not using migrations, option 2: take your site offline to make sure that you don't lose any live data (you already mentioned that) make a db dump on the live system import data from the live system to your dev setup go to setup > fields > edit > field1 set column width, save go to setup > fields > edit > field2 set column width, save go to setup > fields > edit > field3 set column width, save create a db dump of your local system upload your local db dump to your live system take your site online again Option 2 is a little more secure, but imagine you are working on that project as a team... You'll quickly get a huge overhead in not using migrations! You need to tell all your colleagues what you did somewhere. Imagine one of your colleagues works on a different feature at the same time and pushes changes to live overwriting your changes... You'll be in trouble! RockMigrations was built for all those things you mentioned. And we have not even been talking about reusing things you do... Using RockMigrations you can literally copy&paste setups from one project to another. That can save you a huge amount of time. All of what I mentioned depends a lot on how you work, what projects you work on, what clients you have etc... The fact that you are using automated deployments already and asking those questions sounds like you should definitely give RockMigrations a try though ?
  14. Sorry, I still don't get what you guys are trying to do here. What problem are you solving? Don't get me wrong - I don't want to discredit your work just trying to understand, maybe learn or maybe help ? I've had this problem some years ago (hook hell in site/ready.php etc). But I don't have it any more. Are you writing custom modules? Are you using custom page classes? Are you using RockMigrations? Maybe all you need is just other workflows? But maybe I'm missing something, that's why I'm asking which problems you are solving. Maybe you can tell me some examples and maybe we can compare different strategies to solve them (with or without PW)... The thing is... when I found PW several years ago I quickly found several things that I thought weren't possible. @gebeer was kind and patient enough to show me how all these concerns could easily be overcome in PW and I'm still having this experience from time to time... On the other hand I agree that some parts are still missing for a more professional setup. RockMigrations for example are great, but would likely be even greater if something like that was in the core with proper docs and without some deprecated methods ? Personally my only real issue at the moment is with how PW handles multiple languages. The recent updates that allow us to ship translations with modules were a first step in the right direction but it still sucks IMHO as there are still so many manual steps (sometimes even clicks and copy&paste actions) involved that are hard to automate... But i haven't had the problem of a poorly organized project in a long time. ?
  15. Reminds me of this: nette.org ? Back to topic: My most important tools: VSCode + Intelephense + PWSnippets TracyDebugger (!!) RockMigrations Formerly Laragon now DDEV
  16. It is just a problem with these two modules. You can have multiple formatters on one field.
  17. I'm developing locally on my laptop using VSCode and Intelephense and I'm using RockMigrations to replicate everything that I did locally to the remote server. That's all it is about afterall, so I'm not sure why one would use RockMigrations if he/she did all the changes remotely anyhow?! No need for migrations then...
  18. If your code completion does not work properly you are making your life unnecessarily hard and you should definitely find a way to make that work. It's like moving around in a dark room and then finding the switch to turn on the light. If you like darkness better docs for RockMigrations won't help ? Array syntax just uses all the properties that PW uses and you can see those properties using TracyDebugger... Another switch to turn on the light ? I don't understand what you are saying and neither does deepl, sorry. Note that not everybody here is a native speaker..
  19. Hi @benbyf please use your IDE for that: I don't know. I guess updateModuleConfig is deprecated ?
  20. I'm using the on-demand feature a lot. That's why it is part of RockMigrations using one single config setting: $config->filesOnDemand = 'https://example.com'; See https://github.com/BernhardBaumrock/RockMigrations/blob/b09bf8236d376913a63b6fce63f91e05a0da1f2a/RockMigrations.module.php#L413-L453 That works great with one exception: When I delete an image the hooks still try to download the image from remote and this makes two problems: If the file exists on remote, the file will be downloaded to the local filesystem and will never be deleted because the image does not exist in the DB any more so PW will not know about it If the file does not exist on remote I will always get an error that it tried to download an image which does not exist: Any ideas how I can fix this?
  21. you can get some inspiration here: https://processwire.com/talk/topic/22632-rockawesome-fontawesome-icon-picker/
  22. Or without any dependencies: <?php $wire->addHookAfter("ProcessPageEdit::buildFormContent", function($event) { $form = $event->return; $page = $event->object->getPage(); if($page->template != 'my-template') return; $form->add([ 'type' => 'markup', 'label' => 'foo', 'value' => 'bar@'.date('Y-m-d H:i:s'), ]); });
  23. Sure, you can access it via WireHttp, but then your 120s limit will apply because it will be seen as a regular web request... $http = new WireHttp(); $http->get("https://your.site/your/url");
  24. You can bootstrap PW and create your own command line scripts that have full access to the PW API: https://processwire.com/docs/front-end/include/
  25. Where exactly do you need help? What did you already achieve on your own? What works? What does not?
×
×
  • Create New...