I'm trying to auto publish child pages if they are rearrange. Right now when we arrange those child pages it says modified.
We're trying to achieve an automation on how to auto publish it once we started drag and drop to their position.
The idea may be to check the change of the Sort field and execute the doPublish(). Please, note that you must check if the page wasn't in the Draft state.
class FooPage extends Page {
private $wasPublishedBeforeWrite = false;
protected function onBeforeWrite()
{
parent::onBeforeWrite();
// check if the page is published
$this->wasPublishedBeforeWrite = !$this->isArchived() && !$this->isOnDraftOnly() && !$this->isModifiedOnDraft();
}
protected function onAfterWrite()
{
parent::onAfterWrite();
if ($this->isChanged('Sort') && $this->wasPublishedBeforeWrite) {
$this->publishSingle();
}
}
}
Related
Could you please tell me how to publish pages after clicking edit button (left top menu) mode in cocrete5 cms version 5.8.1.0 not using compose button?
I can't publish any page clicking edit button in top left corner, editing it and clicking edit button again.
Publish Changes Button is disabled and there is message:
"The field Page Thumbnail is required."
But I can publish using compose menu (next to edit in left top corner).
What's the cause of this problem? Is it concrete5 bug?
It looks like it allows to publish if I comment out lines in check for publishinh method. But I can't still understand the cause of issue and how to fix it.
class CheckIn extends BackendInterfacePageController
{
protected $viewPath = '/panels/page/check_in';
// we need this extra because this controller gets called by another page
// and that page needs to know how to submit it.
protected $controllerActionPath = '/ccm/system/panels/page/check_in';
public function canAccess()
{
return $this->permissions->canApprovePageVersions() || $this->permissions->canEditPageContents();
}
public function on_start()
{
parent::on_start();
if ($this->page) {
$v = CollectionVersion::get($this->page, "RECENT");
$this->set('publishDate', $v->getPublishDate());
$this->set('publishErrors', $this->checkForPublishing());
}
}
protected function checkForPublishing()
{
$c = $this->page;
// verify this page type has all the items necessary to be approved.
$e = Loader::helper('validation/error');
if ($c->isPageDraft()) {
if (!$c->getPageDraftTargetParentPageID()) {
$e->add(t('You haven\'t chosen where to publish this page.'));
}
}
$pagetype = $c->getPageTypeObject();
// if (is_object($pagetype)) {
// $validator = $pagetype->getPageTypeValidatorObject();
// $e->add($validator->validatePublishDraftRequest($c));
// }
if ($c->isPageDraft() && !$e->has()) {
$targetParentID = $c->getPageDraftTargetParentPageID();
if ($targetParentID) {
$tp = Page::getByID($targetParentID, 'ACTIVE');
$pp = new Permissions($tp);
if (!is_object($tp) || $tp->isError()) {
$e->add(t('Invalid target page.'));
} else {
if (!$pp->canAddSubCollection($pagetype)) {
$e->add(
t(
'You do not have permissions to add a page of this type in the selected location.'
)
);
}
}
}
}
return $e;
}
The error says it all? 'The field Page Thumbnail is required.' Did you actually add a thumbnail?
Basically you can't submit a form without filling in all the required fields.
Or did you and still got the error?
I could solve the issue overriding file:
<?php
namespace Application\Attribute\ImageFile;
use Loader;
use Core;
class Controller extends \Concrete\Attribute\ImageFile\Controller
{
public function validateValue()
{
$f = $this->getAttributeValue()->getValue();
if (is_object($f)) {
return true;
}
$e = Core::make('helper/validation/error');
$e->add(t('You must specify a valid file for %s', $this->attributeKey->getAttributeKeyDisplayName()));
return $e;
}
}
I'm trying to develop a plugin in Moodle. One of the requirements is to add an element to the Settings Menu, in which I was able to achieve with the help of this guide
https://docs.moodle.org/dev/Local_plugins#Adding_an_element_to_the_settings_menu
And this is my code in local/myplugin/lib.php
<?php
function local_myplugin_extends_settings_navigation($settingsnav, $context) {
// question_extend_settings_navigation
global $CFG, $PAGE;
// Only add this settings item on non-site course pages.
if (!$PAGE->course or $PAGE->course->id == 1) {
return;
}
// Only let users with the appropriate capability see this settings item.
/*if (!has_capability('moodle/backup:backupcourse', context_course::instance($PAGE->course->id))) {
return;
}*/
if ($settingnode = $settingsnav->find('courseadmin', navigation_node::TYPE_COURSE)) {
$strfoo = get_string('classrecord', 'local_myplugin');
$url = new moodle_url('/course/classrecord.php', array('id' => $PAGE->course->id));
$foonode = navigation_node::create(
$strfoo,
$url,
navigation_node::NODETYPE_LEAF,
'myplugin',
'myplugin',
new pix_icon('i/grades', $strfoo)
);
if ($PAGE->url->compare($url, URL_MATCH_BASE)) {
$foonode->make_active();
}
$settingnode->add_node($foonode);
}
}
?>
I allowed the students to see the element "Class Record" in the settings menu
My concern is that how can I hide/show Class Record I added?
Any ideas would be great!
If you want only certain users to see the link, then create an appropriate capability in local/myplugin/db/access.php, e.g. 'local/myplugin:viewclassrecord', defaulting to being assigned to the 'student' role. Then check for it in the function you have defined.
e.g.
if (!has_capability('local/myplugin:viewclassrecord', $context)) {
return;
}
I am writing a module, let's call it base, which will show a button after vistor has clicked on buy+confirmed. That is the page where total price is displayed, a thank you message and an email will be send.
On that page, I would like to add my module with the button, which on-click sends product details to another web service. Now I have several questions:
Which hook can I use to place that button on the confirm (after checkout) page. As you can see I am using several hooks just to see if the button appears. It only appears in the leftCollumn
What do you think in general of the code. Would getProducts() be the right method, just copied from another standard module. Do you have an example for me?
please ignore global. I will refactor later.
base.php (only important part of it)
<?php
if ( !defined( '_PS_VERSION_' ) )
exit;
class Base extends Module
{
public function install() {
return parent::install() && $this->registerHook('payment') && $this->registerHook('invoice') && $this->registerHook('leftColumn');
}
public function uninstall() {
parent::uninstall();
}
public function getContent() {
return '<h2>'.$this->displayName.'</h2> <div>nothing to configure</div>';
}
public function hookPayment($params) {
if (!$this->active)
return;
global $smarty;
$smarty->assign('buttonText', $this->l('Send to my base'));
return $this->display(__FILE__, 'base.tpl');
}
public function ajaxCall($params) {
if (Configuration::get('PS_CATALOG_MODE'))
return "return;";
return $params['cart']->getProducts(true);
}
}
products.php
include(dirname(__FILE__).'/../../config/config.inc.php');
include(dirname(__FILE__).'/../../init.php');
include(dirname(__FILE__).'/base.php');
$cart = new Cart((int)($cookie->id_cart));
$cart->id_lang = (int)($cookie->id_lang);
$base = new Base();
var_dump( $base->hookAjaxCall(array('cookie' => $cookie, 'cart' => $cart)) );
You can use this hooks :
{$HOOK_ORDER_CONFIRMATION}
{$HOOK_PAYMENT_RETURN}
This hooks are displayed in order-confimation.tpl after payment validation.
I have users' table users, where I store information like post_count and so on. I want to have ~50 badges and it is going to be even more than that in future.
So, I want to have a page where member of website could go and take the badge, not automatically give him it like in SO. And after he clicks a button called smth like "Take 'Made 10 posts' badge" the system checks if he has posted 10 posts and doesn't have this badge already, and if it's ok, give him the badge and insert into the new table the badge's id and user_id that member couldn't take it twice.
But I have so many badges, so do I really need to put so many if's to check for all badges? What would be your suggestion on this? How can I make it more optimal if it's even possible?
Thank you.
optimal would be IMHO the the following:
have an object for the user with functions that return user specific attributes/metrics that you initialise with the proper user id (you probably wanna make this a singleton/static for some elements...):
<?
class User {
public function initUser($id) {
/* initialise the user. maby load all metrics now, or if they
are intensive on demand when the functions are called.
you can cache them in a class variable*/
}
public function getPostCount() {
// return number of posts
}
public function getRegisterDate() {
// return register date
}
public function getNumberOfLogins() {
// return the number of logins the user has made over time
}
}
?>
have a badge object that is initialised with an id/key and loads dependencies from your database:
<?
class Badge {
protected $dependencies = array();
public function initBadge($id) {
$this->loadDependencies($id);
}
protected function loadDependencies() {
// load data from mysql and store it into dependencies like so:
$dependencies = array(array(
'value' => 300,
'type' => 'PostCount',
'compare => 'greater',
),...);
$this->dependencies = $dependencies;
}
public function getDependencies() {
return $this->dependencies;
}
}
?>
then you could have a class that controls the awarding of batches (you can also do it inside user...)
and checks dependencies and prints failed dependencies etc...
<?
class BadgeAwarder {
protected $badge = null;
protected $user = null;
public function awardBadge($userid,$badge) {
if(is_null($this->badge)) {
$this->badge = new Badge; // or something else for strange freaky badges, passed by $badge
}
$this->badge->initBadge($badge);
if(is_null($this->user)) {
$this->user = new User;
$this->user->initUser($userid);
}
$allowed = $this->checkDependencies();
if($allowed === true) {
// grant badge, print congratulations
} else if(is_array($failed)) {
// sorry, you failed tu full fill thef ollowing dependencies: print_r($failed);
} else {
echo "error?";
}
}
protected function checkDependencies() {
$failed = array();
foreach($this->badge->getDependencies() as $depdency) {
$value = call_user_func(array($this->badge, 'get'.$depdency['type']));
if(!$this->compare($value,$depdency['value'],$dependency['compare'])) {
$failed[] = $dependency;
}
}
if(count($failed) > 0) {
return $failed;
} else {
return true;
}
}
protected function compare($val1,$val2,$operator) {
if($operator == 'greater') {
return ($val1 > $val2);
}
}
}
?>
you can extend to this class if you have very custom batches that require weird calculations.
hope i brought you on the right track.
untested andp robably full of syntax errors.
welcome to the world of object oriented programming. still wanna do this?
Maybe throw the information into a table and check against that? If it's based on the number of posts, have fields for badge_name and post_count and check that way?
Once you're OK with basic record form built after example from Tutorial, you realize you want more professionally designed Record Form. E.g. I don't want to duplicate record form for the same table in User and Admin areas.
1) Does anyone use some mechanism, possibly inheritance, to reduce duplication of almost similar admin and user forms? Is that burdensome or sometimes you better just do with copy-pasting?
2) Has anyone considered it to be a good idea to build some basic Record class
that can determine that among several record forms on this page, the current post is addressed specifically to this record form
that can distinguish between Edit or Delete buttons clicks in some organized fashion.
3) My current practice includes putting all form config code (decorators, validations, initial values) into constructor and form submit handling is put into a separate ProcessSubmit() method to free controller of needless code.
All the above addresses to some expected Record Form functionality and I wonder if there is any guideline, good sample app for such slightly more advanced record handling or people are still reinveting the wheel. Wondering how far you should go and where you should stop with such impovements...
Couple of suggestions:
First of all - Use the init() function instead of constructors to add your elements when you are subclassing the form. The init() function happens after the parameters you pass to the class are set.
Second - Instead of subclassing your form - you can just set an "option" to enable the admin stuff:
class My_Record_Form extends Zend_Form {
protected $_record = null;
public function setRecord($record) {
$this->_record = $record;
}
public function getRecord() {
if ($this->_record === null || (!$this->_record instanceOf My_Record)) {
throw new Exception("Record not set - or not the right type");
}
return $this->_record;
}
protected $_admin = false;
public function setAdmin($admin) {
$this->_admin = $admin;
}
public function getAdmin() { return $this->_admin; }
public function init() {
$record = $this->getRecord();
$this->addElement(......);
$this->addElement(......);
$this->addElement(......);
if ($this->getAdmin()) {
$this->addElement(.....);
}
$this->setDefaults($record->toArray());
}
public function process(array $data) {
if ($this->isValid($data)) {
$record = $this->getRecord();
if (isset($this->delete) && $this->delete->getValue()) {
// delete button was clicked
$record->delete();
return true;
}
$record->setFromArray($this->getValues());
$record->save();
return true;
}
}
}
Then in your controller you can do something like:
$form = new My_Record_Form(array(
'record'=>$record,
'admin'=>My_Auth::getInstance()->hasPermission($record, 'admin')
));
There is nothing "wrong" with making a My_Record_Admin_Form that handles the admin stuff as well - but I found this method keeps all the "record form" code in one single place, and a bit easier to maintain.
To answer section 2: The edit forms in my code are returned from a function of the model: $record->getEditForm() The controller code ends up looking a little like this:
protected $_domain = null;
protected function _getDomain($allowNew = false)
{
if ($this->_domain)
{
return $this->view->domain = $this->_domain;
} else {
$id = $this->_request->getParam('id');
if (($id == 'new' || $id=='') && $allowNew)
{
MW_Auth::getInstance()->requirePrivilege($this->_table, 'create');
$domain = $this->_table->createRow();
} else {
$domain = $this->_table->find($id)->current();
if (!$domain) throw new MW_Controller_404Exception('Domain not found');
}
return $this->view->domain = $this->_domain = $domain;
}
}
public function editAction()
{
$domain = $this->_getDomain(true);
MW_Auth::getInstance()->requirePrivilege($domain,'edit');
$form = $domain->getEditForm();
if ($this->_request->isPost() && $form->process($this->_request->getPost()))
{
if ($form->delete && $form->delete->getValue())
{
return $this->_redirect($this->view->url(array(
'controller'=>'domain',
'action'=>'index',
), null, true));
} else {
return $this->_redirect($this->view->url(array(
'controller'=>'domain',
'action'=>'view',
'id'=>$form->getDomain()->id,
), null, true));
}
}
$this->view->form = $form;
}
So - the actual id of the record is passed in the URI /domain/edit/id/10 for instance. If you were to put multiple of these forms on a page - you should make sure to set the "action" attribute of the form to point to an action specific to that form.
I created a SimpleTable extends Zend_Db_Table and SimpleForm extends Zend_Db_Form classes. Both of these assume that your table has an auto-incrementing ID column.
SimpleTable has a saveForm(SimpleForm $form) function which uses the dynamic binding to match form element names to the columns of the record. I also included an overridable saveFormCustom($form) for any special handling.
The SimpleForm has an abstract setup() which must be overridden to setup the form. I use the init() to do the initial setup (such as adding the hidden ID field).
However, to be honest, I really don't like using the Zend_Form object, I feel like that should be handled in the View, not the Model or Controller.