netcarver

Database Counters Module

Recommended Posts

This module provides a very simple interface to a set of named counters. You simply call a single function, next('name'), to pull the next value out of a counter - or to set it up if it does not yet exist. Next() takes a few extra parameters to allow you to increment by values other than 1 or to start at a certain number.

This provides some similar functionality to the built-in page naming feature of PW, and to this module recently posted by Stikki but I think it offers a little more flexibility than either. Having said that, I do like the simplicity of Stikki's new auto-increment module.

Module Availability

Here is my module on Github.

Here it is in the module repository.

Example Usage

Here's how this module can be used to title and name a new page by adding a couple of simple hooks to site/ready.php. This example applies to new pages using a template called 'invoice' that can be quick-added to the page tree. In order to get the following to work, you must edit the template that will be the parent of the 'invoice' template and setup the template for children to "invoice" and set the "Name Format for Children" field to something other than the default blank value (I use  title  as my value.)

<?php

/**
 * Function to recognise our special template.
 */
function isInvoiceTemplate($template) {
    return ($template == 'invoice');
}

/**
 * Pre-load the page title for invoice pages with a unique value
 * which includes a counter component.
 */
$pages->addHookBefore("Pages::setupNew", function($event) {
    $page = $event->arguments(0);

    $is_invoice = isInvoiceTemplate($page->template);
    $no_inv_num = $page->title == '';

    if ($is_invoice && $no_inv_num) {
        $counter_name = 'WR-' . date('Y');
        $number = $this->modules->get('DatabaseCounters')->next($counter_name, 10, 5000);
        $page->title = $counter_name . '-' . sprintf("%06u", $number);
    }
});

/**
 * Prevent ProcessPageEdit from forcing an edit of the name if we got here
 * through a quickAdd from ProcessPageAdd. We can do this because we
 * preset the title field in the Pages::setupNew hook.
 */
$pages->addHookAfter("ProcessPageEdit::loadPage", function($event) {
    $page = $event->return;

    $is_invoice = isInvoiceTemplate($page->template);
    $is_temp    = $page->hasStatus(Page::statusTemp);

    if ($is_invoice && $is_temp) {
        $page->removeStatus(Page::statusTemp);
        $event->return = $page;
    }
});

Note, the above code + module is one direct solution to the problem posted here by RyanJ.

post-465-0-56264100-1459552276_thumb.png

post-465-0-67628000-1459552450_thumb.png

Version History

1.0.0 The initial release.

  • Like 12

Share this post


Link to post
Share on other sites

To extend the above example to hide the name, template and parent fields on the settings page of invoices, you can add the following to the ready.php snippet in the above post.

/**
 * Work out if the template's settings should be tweaked to hide things that should be fixed...
 */
function shouldHideTemplateSettings() {

    // Super users retain super-setting-edit powers
    if (wire('user')->isSuperUser()) {
        return false;
    }

    // Are we even editing a page?
    if (wire('page')->process != 'ProcessPageEdit') {
        return false;
    }

    $id = (int) wire('input')->get('id');
    if (!$id) {
        return false;
    }

    $editedPage = wire('pages')->get($id);
    if ($editedPage->template->flags & Template::flagSystem) {
        return false;
    }

    if (!isInvoiceTemplate($editedPage->template->name)) {
        return false;
    }

    return true;
}

/**
 * Hide some fields from the invoice settings page from non-super-users.
 *
 * There's not much point allowing edits to the name field, so we want it immutable (at least) and probably totally
 * hidden (better.)
 *
 * We don't want invoices being moved from their parent, so we hide the parent field.
 * We don't allow them to use a different template, so we hide the template field.
 *
 */
if (shouldHideTemplateSettings()) {
    $pages->addHookAfter("ProcessPageEdit::buildFormSettings", function($event) {
        $wrapper = $event->return;

        // To show the name field but make it immutable
        $wrapper->_pw_page_name->collapsed = Inputfield::collapsedNoLocked;
        $wrapper->_pw_page_name->description = '';

        // Alternatively, to hide the name field do uncomment the following and comment out the 2 lines above
        //$wrapper->_pw_page_name->collapsed = Inputfield::collapsedHidden;

        // Hide the template changer, invoices can only use the invoice template
        $wrapper->template->collapsed = Inputfield::collapsedHidden;

        // Hide the parent page, as it is fixed in our page structure
        $wrapper->parent_id->collapsed = Inputfield::collapsedHidden;
    });
}
  • Like 6

Share this post


Link to post
Share on other sites

Question of  setupNew page hook  

$pages->addHookBefore("Pages::setupNew"

Instead of creating page at the pw's back-end admin ui, will this page hook be executed if I create a page thru api manually ?

Share this post


Link to post
Share on other sites

Besides of my last question,

I followed the op's setup, but it didn't work at atll

post-2272-0-32536000-1460864209_thumb.pn

post-2272-0-39834500-1460864219_thumb.pn

This is my  /site/ready.php

instead of invoice, i changed it to order

<?php

function isOrderTemplate($template) {
    return ($template == 'order');
}

$pages->addHookBefore("Pages::setupNew", function($event) {
    $page = $event->arguments(0);
 
    $is_order = isOrderTemplate($page->template);
    $no_inv_num = $page->title == '';
 
    if ($is_order && $no_inv_num) {
        $counter_name = 'ORDER-' . date('Y');
        $number = $this->modules->get('DatabaseCounters')->next($counter_name, 10, 5000);
        $page->title = $counter_name . '-' . sprintf("%06u", $number);
    }
});

$pages->addHookAfter("ProcessPageEdit::loadPage", function($event) {
    $page = $event->return;
 
    $is_order = isOrderTemplate($page->template);
    $is_temp    = $page->hasStatus(Page::statusTemp);
 
    if ($is_order && $is_temp) {
        $page->removeStatus(Page::statusTemp);
        $event->return = $page;
    }
});

When I checked back the DatabaseCounter module config,

there is no such a counter named ORDER-   was created

Share this post


Link to post
Share on other sites

I'm curious, the

/site/ready.php

is not executed.

is there any other settings to activated it ?

None that I know of. Are you sure you have that file in the right place?

From second screen cap, how to make the invoice number (i.e.title field) not editable ?

Edit the template for your order pages in PW. Click on the title (invoice number) field and, on the input tab, set the visibility to whatever you need.

  • Like 2

Share this post


Link to post
Share on other sites

Hi, I was trying this module becuase I this is the solution for my needs, I cant not make it work.

When I click new page I get the same as adrianmak , Title and name are not autopopulated.

 

I know my ready.php is working fine because I was trying this code from another post and the field was being autopopulated with the generated title:

$this->pages->addHookAfter('added', function($event) {
    $page = $event->arguments[0];
    if($page->template != 'your-template-name') return;
    $page->setAndSave('title', 'my page - ' . date("YmdHis"));
});

I'am missing something?


 

Share this post


Link to post
Share on other sites

@Krlos, just writing to acknowledge your post. Please could you send me your site/ready.php file via the forum message system so I could have a look at it tonight? (Please don't post it here.)

Share this post


Link to post
Share on other sites

Hi, I was testing your module and decided to leave it for later. As recheck this part I will send a report.

Thank you.

5 hours ago, netcarver said:

Bump. @Krlos, did you get this working?

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By BitPoet
      Since I was stuck to my flat today I took up a wish and rolled a Process module / CKEditor plugin combo that adds @-autocomplete like the mentions here in the forum to CKEditor fields. It's configurable, but only in module settings for now, the positioning of the select list is quite off and there's still some visual work to be done, so it is in early alpha state.
      Nonetheless, if you want to take a look, here it is:
      https://github.com/BitPoet/ProcessMention

       
      After installation, you may want to look into the "Additional selector" entry in the module's settings. You will most likely want to limit results to certain templates there.
       
      Edit: Updated to version 0.0.30 with fixed positioning of the dropdown.
      Edit2: Settings are configurable in field context now. If pwmentions is enabled, the according settings are shown on the "Input" tab.
       
    • By thuijzer
      https://github.com/thuijzer/processwire-FieldtypeBusinessHours
      Fieldtype Business Hours
      ProcessWire Fieldtype for entering business hours (opening hours)
       
      Input format
      Leave a day empty when closed on that day
      Times are in 24 hour format.
      9:00-12:00 9:00-12:00, 13:00-17:30 16:00-2:00  
      Usage in templates
      Days are from 1 to 7 where 1 is Monday and 7 is Sunday (ISO-8601)
      echo $page->field_name->isNowOpen() ? 'Now open' : 'Now closed'; if($page->field_name[1] == null) { echo 'Closed on Monday'; } if($page->field_name[2]->inRange('11:00')) { echo 'Tuesday at 11:00 open'; } echo $page->field_name[1]; echo $page->field_name[1]->getEntries()->getFrom()->format('H:i');  
    • By hellomoto
      I was working on this:
      class PWCRM extends WireData implements Module { public static function getModuleInfo() { return array( 'title' => 'Client Relationship Management', 'version' => .001, 'singular' => true, 'autoload' => true ); } public function init() {} public function ready() { $this->pages->addHookBefore('render', $this, 'accessHook'); $this->pages->addHookAfter('render', $this, 'hookAfterPageRender'); } public function accessHook(HookEvent $event) { $page = $this->wire('page'); if (!strpos($page->template->tags, 'crm')) return; if (!$this->wire('user')->hasRole('crm')) $this->wire('session')->redirect($this->wire('config')->urls->login);//throw new Wire404Exception(); } public function hookAfterPageRender(HookEvent $event) { $page = $event->object; echo $page->template->tags; if (!strpos($page->template->tags, 'crm')) return; echo $this->wire('config')->urls->templates; include_once($this->wire('config')->urls->templates.'functions.inc'); $pagehtml = $event->return; $pagehtml = str_replace( '</head>', '<link id="css_crm" rel="stylesheet" href="'.$this->wire('config')->urls->templates.'css/crm.css"> </head>', $pagehtml ); $event->return = $pagehtml; //$event->replace = true; } } I have tried placing the hooks into the init() function, and more... Neither method is effective. The echoes now output, but no redirection (although I have the access settings for the top-level template for this set to render a 404 for underprivileged users, which it does, overriding this, but nonetheless this should work aside from that.
      Then I wrote this up quick:
      <?php namespace ProcessWire; class MaintenanceMode extends WireData implements Module { public static function getModuleInfo() { return array( 'title' => 'Maintenance Mode', 'version' => 1, 'summary' => 'Disables the website frontend for non-superusers.', 'singular' => true, 'autoload' => true, 'permanent' => false ); } public function init() { $this->addHookBefore('Page::render', $this, 'displayDecide'); } public function displayDecide($event) { $page = $event->object; if ($page->template == 'admin' || $this->wire('user')->hasRole('superuser')) return; // replace the method hooked $event->replace = true; $event->return = "Patience please while we undergo some brief maintenance work."; } } which likewise avails nothing. What the hell is my problem here? 
    • By adrian
           Tracy Debugger for ProcessWire
      The ultimate “swiss army knife” debugging and development tool for the ProcessWire CMF/CMS
       

       
      Integrates and extends Nette's Tracy debugging tool and adds 30+ custom tools designed for effective ProcessWire debugging and lightning fast development
      The most comprehensive set of instructions and examples is available at: https://adrianbj.github.io/TracyDebugger
      Modules Directory: http://modules.processwire.com/modules/tracy-debugger/
      Github: https://github.com/adrianbj/TracyDebugger
      A big thanks to @tpr for introducing me to Tracy and for the idea for this module and for significant feedback, testing, and feature suggestions.