Jump to content

ryan

Administrators
  • Posts

    17,306
  • Joined

  • Days Won

    1,724

Everything posted by ryan

  1. You might find the attached LazyCronTest.module helpful. This basically just demonstrates LazyCron in action. Install this module after LazyCron is installed, and it'll record a log entry every 5 minutes (or so) to /site/assets/logs/lazytest.txt. That's assuming the site is getting non-cached pageviews so that LazyCron gets a chance to run. LazyCronTest.module <?php class LazyCronTest extends WireData implements Module { public static function getModuleInfo() { return array( 'title' => 'Lazy Cron Test', 'version' => 100, 'summary' => 'Tests lazy cron by writing to a log file in /site/assets/logs/lazytest.txt', 'singular' => true, 'autoload' => true, ); } public function init() { $this->addHookAfter('LazyCron::every5Minutes', $this, 'lazyTest'); } public function lazyTest($event) { $seconds = $event->arguments[0]; $log = new FileLog($this->config->paths->logs . 'lazytest.txt'); $log->save('LazyCron 5 minute test - ' . date('Y-m-d H:i:s') . " - $seconds seconds"); } } Here's an example of the log file it generates: 2013-02-02 11:19:02:LazyCron 5 minute test - 2013-02-02 11:19:02 - 356 seconds 2013-02-02 11:24:04:LazyCron 5 minute test - 2013-02-02 11:24:04 - 302 seconds 2013-02-02 11:31:52:LazyCron 5 minute test - 2013-02-02 11:31:52 - 468 seconds 2013-02-02 11:37:22:LazyCron 5 minute test - 2013-02-02 11:37:22 - 330 seconds 2013-02-02 11:43:14:LazyCron 5 minute test - 2013-02-02 11:43:14 - 352 seconds 2013-02-02 11:49:13:LazyCron 5 minute test - 2013-02-02 11:49:13 - 359 seconds 2013-02-02 11:54:37:LazyCron 5 minute test - 2013-02-02 11:54:37 - 324 seconds 2013-02-02 12:00:07:LazyCron 5 minute test - 2013-02-02 12:00:07 - 330 seconds 2013-02-02 12:05:07:LazyCron 5 minute test - 2013-02-02 12:05:07 - 300 seconds 2013-02-02 12:12:42:LazyCron 5 minute test - 2013-02-02 12:12:42 - 455 seconds 2013-02-02 12:18:35:LazyCron 5 minute test - 2013-02-02 12:18:35 - 353 seconds 2013-02-02 12:23:37:LazyCron 5 minute test - 2013-02-02 12:23:37 - 302 seconds 2013-02-02 12:30:54:LazyCron 5 minute test - 2013-02-02 12:30:54 - 437 seconds 2013-02-02 12:36:22:LazyCron 5 minute test - 2013-02-02 12:36:22 - 328 seconds 2013-02-02 12:41:57:LazyCron 5 minute test - 2013-02-02 12:41:57 - 335 seconds 2013-02-02 12:50:48:LazyCron 5 minute test - 2013-02-02 12:50:48 - 531 seconds 2013-02-02 12:56:58:LazyCron 5 minute test - 2013-02-02 12:56:58 - 370 seconds 2013-02-02 13:03:03:LazyCron 5 minute test - 2013-02-02 13:03:03 - 365 seconds 2013-02-02 13:15:03:LazyCron 5 minute test - 2013-02-02 13:15:03 - 720 seconds 2013-02-02 13:26:03:LazyCron 5 minute test - 2013-02-02 13:26:03 - 660 seconds 2013-02-02 13:31:46:LazyCron 5 minute test - 2013-02-02 13:31:46 - 343 seconds 2013-02-02 13:37:37:LazyCron 5 minute test - 2013-02-02 13:37:37 - 351 seconds Notice how the number of elapsed seconds is always more than 5 minutes (and sometimes a lot more). That's just because it has to be triggered by a PageView. In most cases, this is okay because a lack of pageviews usually means there's nobody there to see what was updated anyway.
  2. Twig is a nice template engine. I'd like to explore the possibilities of expanding upon what porl started with that module sometime. Though ProcessWire will always be based on a PHP API, but I'd like us to have a simple integration method for supporting other template engines for the people that want them.
  3. Awesome work Wanze! Thanks for posting it. I'm also thrilled to see the awesome things people are doing with the blog profile as a base.
  4. Soma, I'm not totally sure I understand just because I've not seen buttons look like that before. I could probably figure it out by digging a little deeper in the code, but I'm trying to get through a large queue of messages in a short amount of time (they dont' give me much on the weekend!). If there's a code change you think would be worthwhile in the core CSS, let me know what to change (post code here or pull request, etc), and I'll make it.
  5. It wouldn't be from PW's cache unless you aren't logged in, and you are using cache features. But it's not much of a mystery when you encounter that. I'm guessing it's not the case in your instance. Lots of the *AMP installs (like MAMP) come with a PHP cache built-in. It's certainly possible that could cause something like you've mentioned. But personally, I've not experienced any unexpected behavior like you are describing, and I'm literally using PW all day every day. Check and see what PHP cache you might be using, just in case.
  6. Nik's AfterSaveActions module is also a great time saving optimization for when you are creating pages, templates, fields. I was using it just yesterday on a site where I needed to add a hundred or so pages via copy/paste (the content was too inconsistent in order to automate it with something API-driven). I set my 'after save action' to 'create another sibling page', and it probably cut the time it would have taken in half.
  7. That's a good idea. Though I'd still be nervous about it. Something to think about adding though... One way you can override things on your own is to edit the Fieldtype module file that you want to convert from. So if you've got a float that you want to convert to a string, edit /wire/modules/Fieldtype/FieldtypeFloat.module and add the following function to it (temporarily): /** * Return Fieldtypes that are compatible with this one (i.e. ones the user may change the type to) * * @param Field $field Just in case it's needed * @return Fieldtypes|null * */ public function ___getCompatibleFieldtypes(Field $field) { $fieldtypes = new Fieldtypes(); $fieldtypes->add($this->fieldtypes->get('FieldtypeText')); return $fieldtypes; } If the Fieldtype you are editing already has that function, that you could just modify it according to what you need.
  8. For the most part, you only want to hook into Process modules if you are manipulating something on the admin interface side. Process modules don't get used for anything else. So if a page is added from some other method in the API, your ProcessPageAdd hook would never get called. Instead, you'd want to hook Pages::added to get a $page that was just added. Or you'd want to hook into Pages::saveReady if you wanted to get it before it was added. If using saveReady, you'd just confirm that it's a new page being added by it not having a $page->id (already existing pages will have a $page->id). If you find you still need to hook ProcessPageAdd, tell me more about what you are trying to do and I can add an appropriate hook. public function init() { $this->pages->addHook('added', $this, 'hookPageAdded'); $this->pages->addHook('saveReady', $this, 'hookSaveReady'); } public function hookPageAdded(HookEvent $event) { $page = $event->arguments[0]; $template = $page->template; // here's your template } public function hookSaveReady(HookEvent $event) { $page = $event->arguments[0]; if(!$page->id) { // new page about to be added $template = $page->template; // here's your template } }
  9. Nearly all built-in Fieldtype functions are passed a copy of the $page and $field being edited. So you pretty much always have a copy in your Fieldtype. For example, every Fieldtype has this function: /** * Return a new Inputfield, ready to be used * * @param Page $page Page being edited * @param Field $field Field that needs an Inputfield * */ public function getInputfield(Page $page, Field $field) { // $page is the Page you want } Since there is only 1 copy of any given Fieldtype in memory at once, you don't want to keep any copies of $page outside of the individual functions because the same Fieldtype instance might get called several times for different pages within the same request. Inputfields are different: They aren't supposed to know anything about the page being edited, because Inputfields are used for far more than just pages. There will be multiple instances of the same Inputfield in memory at once. Basically, there is a new instance of it for every single input that's needed. Unlike Fieldtypes, Inputfields don't get reused for multiple fields of the same type. Since Inputfields aren't supposed to have a $page context, they don't already have a copy of it anywhere. However, if you need one, you can pass it a copy from your Fieldtype's getInputfield method, shown above: /** * Return a new Inputfield, ready to be used * * @param Page $page Page being edited * @param Field $field Field that needs an Inputfield * */ public function getInputfield(Page $page, Field $field) { $inputfield = wire('modules')->get('InputfieldSomething'); $inputfield->set('editPage', $page); // give it a copy of $page being edited return $inputfield; } Now InputfieldSomething can access the $page from $this->editPage. This is what FieldtypeRepeater does for InputfieldRepeater, btw.
  10. When you change a field's type, it doesn't keep the configuration settings for the old one around. That's because the new one may have very different settings or may conflict with the new one. So it's safest to start fresh on this. Tags is one that could feasibly stick around, so maybe we'll find a way to do that in the future, but for now we reset the field's settings when you change it's type.
  11. I've updated it so that it can now support using formatted values before concatenation--like you would want with dates. Grab the new version (1.0.1). Then, in your format string, just specify an exclamation point after any field names you want to use the formatted version for. For example, "title, date!" rather than "title, date".
  12. What I've extracted is that you don't like statics. You've set a goal of avoiding statics at all costs. And that's fine--I understand your reasons. I'm middle of the road on statics--I avoid them, but not at all costs. There is a reason they don't appear in PW's public API. But if they are the best fit for a given situation, given all factors, then I'd consider it a bad choice to use something else. We've got very good reasons for using them where we do. I hope you can understand why we wouldn't abandon an interface that works very well for us just because one person doesn't like statics. What I wrote in my previous message was that I support your ideas, but as an alternative method of configuration, not as a replacement. Step out of the ivory tower and propose something tangible and realistic. Use some code. For instance, I understand you'd like to have a separate class to handle configuration. I like this idea for many situations. So how would you formalize that in code? What specific methods would be in the ModuleConfig interface or abstract base class? How would you propose relating the configuration class to the module class? I'd suggest that it could be done by an agreed-upon class name, like "Config[ModuleName] implements ModuleConfig", or a module's getModuleInfo() could specify it's configuration class in it's info array. But maybe there's more ideas too. Get some momentum going here and maybe we'll have something we can commit to the code base now rather than later. I understand why it matters in many situations. But this distinction does not matter in ProcessWire modules. Can you think of any instance where it does? We go out of our way to keep these considerations away from those actually using the module. I don't yet know much about Laravel, so can't knock it or praise it. But I was turned off by the syntax I was seeing in the examples. Though I can find plenty to like after a quick look too. But it does seem like a lot of people are treating Laravel as God's greatest gift to PHP. So far I don't understand. Maybe there's something to learn here, even if there is some to dislike as well. While I don't hate statics like you do, I do agree in general -- I don't much like seeing them in APIs. That's why you don't seem them in ProcessWire's API.
  13. In real usage, ^= and $= just aren't that useful when paired with a fulltext index, because fulltext indexes store words, not partials. I actually cant think of any situation where the old fulltext implementation for those is worthwhile. I dont think anyone was using them, as a result. The %^= syntax is far more useful. But I don't want to have something as cryptic as %^= and %$= being part of our official set of operators... Would rather leave it as undocumented and eventually deprecate it, and let ^= and $= take the behavior. That's really how they were supposed to behave in the first place. So that change you linked was my attempt to correct the behavior of those.
  14. You should also be able to retrieve them via just $field->tags or $template->tags
  15. There isn't a page like this that exists in the system unless you are an admin and can view user accounts in Access > Users. However, you certainly could create a template on your front-end that does something similar. You can iterate all users by: foreach($users as $user) { // ... } You can retrieve any user by: $u = $users->get(123); // user ID; or... $u = $users->get('ryan'); // user name Here is the $user API which shows you what you can do once you've located the user you want to display.
  16. I think it just depends on what you are trying to do. But as a guideline, only consider using your own custom tables if the data you are pulling doesn't need to be represented by unique URLs. Pages are designed to be represented by URLs, though they don't always have to be. But if you've got complex data that is large in quantity or fields, and individual records don't benefit by each having their own URL, then you may find it more efficient to use alternate data storage like SQL (if you are comfortable doing so). If you want the data to be managed in ProcessWire admin and queried from PW's API, you can create custom Fieldtypes by extending Fieldtype or FieldtypeMulti. An individual Fieldtype can represent as complex of a table structure as you want it to.
  17. A page does not need to have two parents of the same generation like we do. In the case of ProcessWire, all pages are female.
  18. Biorn, here's some more info about LazyCron: http://processwire.com/api/modules/lazy-cron/ Ultimately, it's lazy, which you will notice if you don't have consistent traffic to your site. So if you need something to run every 5 mins consistently, then you should either use regular cron (from your server) or use regular cron to ping a non-cached page on your website (thus triggering Lazycron).
  19. I don't think there's a way to reliably change system paths after bootstrap has occurred. I also don't recommend trying it, just because it seems like there's potential to break things by doing that, and it may work in some cases and not others. Ultimately it wasn't designed for runtime changes to system paths. It probably works from $config.php just because all that happens before bootstrap. It is however designed for runtime changes to template paths via the $template->filename = '...'; syntax.
  20. I'm guessing you don't like Laravel much? There is a reason why statics exist as a language construct, and there is a reason why we use them where we do. Though our usage is admittedly rare, there has never been a goal to "avoid statics as much as possible". The goal has been to use the tools available to us to make ProcessWire as simple, flexible and extendable, to the intended audience, as possible. It's not often that we have use for a static method in ProcessWire, but when we use them it's because they are the most appropriate solution. Keep in mind, we don't actually "need" static methods. We could certainly do without them. They just make a whole lot more sense in our context than the alternative. It's important to realize that Module is just an interface for communication between ProcessWire and the functionality you want to provide. It is not a class or even an abstract class. It provides no implementation for you (other than what you might optionally choose to extend from some other class). The only requirement for a module is that ProcessWire can ask it what it is. That comes from the Module interface's 1 static method: getModuleInfo(). Without that, it is not a Module. The ConfigurableModule interface has 1 static method: getModuleConfigInputfields(), which you can choose to delegate elsewhere if you choose. Beyond the obvious benefits, these methods are static for correctness: they are about all instances, not a specific one. The existence of the interface is not a suggestion that you implement everything in the class itself. That's entirely up to you. If the scope or philosophy of your need is such that you want to split every part of it into separate classes and files, then you should (this is what I do in FormBuilder). The Module interface facilities this. But the reality is that most modules are not of that scope, and there's rarely a tangible benefit in our context to being more verbose. But we ultimately leave that choice to the developer. A module is a singleton only if the developer specifies "singular" in his/her module definition. Otherwise you will get a new instance every time you ask for a module. I understand what you are trying to get at here. There may be someday when the configuration needs of modules increases in scope to the point where we might benefit from such an approach, but we're not near that yet. In the present, I think the majority of module cases benefit more from less verbosity and the current approach. We already have the door open to this approach, even if it's not implicit--FormBuilder uses something very similar, for example. But I would be happy to support this more implicitly as a second option for module configuration in the future. Instance types are not loaded before they are needed. They are loaded on-demand, unless the module's definition specifies "autoload". ProcessWire caches its module information so that it doesn't need to even include a module's file until ready to instantiate. It's the module developer that should make the call about whether their module is designed to be singular or multi-instance. A singular module might very well be coded differently than a multi-instance one. I don't want the consumer to have to think about this variable. I'm not opposed to making architectural changes in major releases so long as they are geared at make things simpler or easier for the users of the software. While I don't share all your opinions on how some things should work, I appreciate and respect them, and am especially glad for your interest in them. If we were to implement an architectural change to make module configuration more implicit to a separate class, I'd support it (after all, it's an approach I already take in some modules). But it would be added as an option, rather than a replacement. In terms of future major releases, I don't like breaking backwards compatibility unless absolutely necessary. But if there's a net benefit to the wider audience, then I have no problem with it. The only thing in my mind that carries that status right now is the switch to namespaces in 2.4 (and the changes that would go along with it), which I'm looking forward to collaborating on.
  21. How about: $level = count($page->parents);
  22. $_SERVER['DOCUMENT_ROOT'] would have to be the same as $config->paths->root in order for that to work. Usually they would be, but sometimes they aren't, whether due to a subdirectory install or aliases/symbolic links. You'd probably want to set it like this instead, which should work (unless I'm forgetting something): $home->template->filename = wire('config')->paths->root . 'basic-page.php'; Also, since your basic-page.php is not protected by PW's .htaccess, put this at the top: if(!defined("PROCESSWIRE")) die('No access');
  23. You can configure the behavior of when the cache is cleared. But when you save a page, the cache is always cleared for that page, regardless of any other behaviors you've set. The other built-in options are to clear all children (and everything below), clear all parents (except homepage), clear homepage, or clear site. Another thing is that even a short 5-10 minute cache is hugely beneficial. That means that your page will only be rendered a max of once per 5-10 minutes, even if it gets hit thousands of times in that period. And the shorter the cache time, the less chance someone will ever see stale data. While I think we all have a tendency to make the cache time as high as possible (like an hour, a day, or a week), the right balance is often a much shorter time period. This would especially be the case if your site involved lots of page-to-page relations that fall outside of the tree relationship. Can you explain this a little more in detail. I'm on a shared Plesk Hosting Enviroment. This is not related to the hosting environment. Instead, it means that if you have code in your template files that is performing actions based on the hostname, then ProCache doesn't yet recognize that. For instance, if you are doing anything that checks $config->httpHost in your template file, you wouldn't want to cache that page with ProCache (or the built-in page cache, for that matter). This is an example of a template file you wouldn't want to cache: if($config->httpHost == 'de.domain.com') { $user->language = $languages->get('de'); } else { // www.domain.com // keep default language } However, I will be upgrading ProCache so that it saves the hostname with its cache files so that such a template file could still be cached.
  24. What is your /path/to/file.php? Here's the actual code from Template::setFilename that gets executed when you do $somepage->template->filename = '/path/to/file.php'; protected function setFilename($value) { if(empty($value)) return; if(strpos($value, '/') === false) { $value = $this->config->paths->templates . $value; } else if(strpos($value, $this->config->paths->root) !== 0) { $value = $this->config->paths->templates . basename($value); } if(is_file($value)) { $this->filename = $value; $this->filenameExists = true; } } Look at the "else" condition above, which is what's enforcing your template file to be somewhere below PW's root installation dir.
  25. Very interesting and unique--I like it! I look forward to trying this one out.
×
×
  • Create New...