I have a Static Page in OctoberCMS named General that has a bunch of site-wide settings including phone number and address. Is it possible to access this page in code to read these settings from its ViewBag?
UPDATE: a plugin was created with the following, where properties like twitter_username for example can now be accessed in templates with {{ general('twitter_username') }}:
use System\Classes\PluginBase;
use RainLab\Pages\Classes\Page;
use Cms\Classes\Theme;
class Plugin extends PluginBase
{
private static $generalViewBag = null;
public function registerMarkupTags()
{
return [
'functions' => [
'general' => function($var) {
if (self::$generalViewBag === null) {
self::$generalViewBag = Page::load(Theme::getActiveTheme(), 'general')
->getViewBag();
}
return self::$generalViewBag->$var;
},
],
];
}
}
The twitter_username form field was added to the General page in the backend using a separate plugin:
use System\Classes\PluginBase;
use Event;
class Plugin extends PluginBase
{
public function boot()
{
Event::listen('backend.form.extendFields', function($widget) {
if (! $widget->getController() instanceof \RainLab\Pages\Controllers\Index) {
return;
}
if (! $widget->model instanceof \RainLab\Pages\Classes\Page) {
return;
}
switch ($widget->model->fileName) {
case 'general.htm':
$widget->addFields([
'viewBag[twitter_username]' => [
'label' => 'Twitter username',
'type' => 'text',
'tab' => 'Social Media',
],
], 'primary');
break;
}
});
}
}
yes you can do it actually you need to use this code in page life-cycle method
In page code block you can use something like this OR anywhere else
use RainLab\Pages\Classes\Page as StaticPage;
function onStart() {
$pageName = 'static-test';
$staticPage = StaticPage::load($this->controller->getTheme(), $pageName);
dd($staticPage->viewBag);
}
let me know if it you find any issues
Related
I'm using Laratrust and try implements:
I created these files
App\MyMenuFilter.php
<?php
namespace App;
use JeroenNoten\LaravelAdminLte\Menu\Builder;
use JeroenNoten\LaravelAdminLte\Menu\Filters\FilterInterface;
class MyMenuFilter implements FilterInterface
{
public function transform($item, Builder $builder)
{
if (isset($item['permission']) && Laratrust::can($item['permission'])) {
return false;
}
return $item;
}
}
I changed this
config\adminlte.php
'menu' => [
'MAIN NAVIGATION',
[
'text' => 'Blog',
'url' => 'admin/blog',
'permission' => 'create-post', // Here
],
#code
]
'filters' => [
#code
//JeroenNoten\LaravelAdminLte\Menu\Filters\GateFilter::class,
App\MyMenuFilter::class,
],
But show this error:
Class 'App\Laratrust' not found (View: /var/www/html/multi-auth/vendor/jeroennoten/laravel-adminlte/resources/views/page.blade.php)
Simplest way
if (isset($item['permission']) && \Laratrust::can($item['permission'])) {
return false;
}
or you can
use Laratrust;
if (isset($item['permission']) && Laratrust::can($item['permission'])) {
return false;
}
the use statement should be right at the top before class definition and the condition will obviously be in your method
It appears that Laratrust is a package residing in vendor directory thats why trying to get it under the \App location will throw an error.
You dont import the App\Laratrust in your namespace. Add use App\Laratrust; to the top of your class and it should work.
In Symfony 2.8 I've got Movie entity with actors field, which is ArrayCollection of entity Actor (ManyToMany) and I wanted the field to be ajax-loaded Select2.
When I don't use Ajax, the form is:
->add('actors', EntityType::class, array(
'class' => Actor::class,
'label' => "Actors of the work",
'multiple' => true,
'attr' => array(
'class' => "select2-select",
),
))
It works, and this is what profiler displays after form submit: http://i.imgur.com/54iXbZy.png
Actors' amount grown up and I wanted to load them with Ajax autocompleter on Select2. I changed form to ChoiceType:
->add('actors', ChoiceType::class, array(
'multiple' => true,
'attr' => array(
'class' => "select2-ajax",
'data-entity' => "actor",
),
))
//...
$builder->get('actors')
->addModelTransformer(new ActorToNumberModelTransformer($this->manager));
I made DataTransformer:
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Persistence\ObjectManager;
use CompanyName\Common\CommonBundle\Entity\Actor;
use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Exception\TransformationFailedException;
class ActorToNumberModelTransformer implements DataTransformerInterface
{
private $manager;
public function __construct(ObjectManager $objectManager)
{
$this->manager = $objectManager;
}
public function transform($actors)
{
if(null === $actors)
return array();
$actorIds = array();
$actorsArray = $actors->toArray();
foreach($actorsArray as $actor)
$actorIds[] = $actor->getId();
return $actorIds;
}
public function reverseTransform($actorIds)
{
if($actorIds === null)
return new ArrayCollection();
$actors = new ArrayCollection();
$actorIdArray = $actorIds->toArray();
foreach($actorIdArray as $actorId)
{
$actor = $this->manager->getRepository('CommonBundle:Actor')->find($actorId);
if(null === $actor)
throw new TransformationFailedException(sprintf('An actor with id "%s" does not exist!', $actorId));
$actors->add($actor);
}
return $actors;
}
}
And registered form:
common.form.type.movie:
class: CompanyName\Common\CommonBundle\Form\Type\MovieType
arguments: ["#doctrine.orm.entity_manager"]
tags:
- { name: form.type }
But seems like the reverseTransform() is never called. I even put die() at the beginning of it - nothing happened. This is, what profiler displays after form submit: http://i.imgur.com/qkjLLot.png
I tried to add also ViewTransformer (code here: pastebin -> 52LizvhF - I don't want to paste more and I can't post more than 2 links), with the same result, except that reverseTransform() is being called and returns what it should return.
I know that this is an old question, but I was having a very similar problem. It turned out that I had to explicitly set the compound option to false.
That is to say, for the third parameter to the add() method, you need to add 'compound => false'.
I created a form with validation rules. Everything is fine, form is visible and works.
Problem is with validators. Only first validator works in addValidators([ ....])
My form class source code:
public function initialize()
{
$title = new Text('title');
$title->setLabel('Title of article');
$title->setFilters([
'striptags', 'trim'
]);
$title->addValidators([
new PresenceOf([
'message' => 'Title can not be empty'
]),
new StringLength([
'min' => 5,
'messageMinimum' => 'Title is too short. Should has more than 5 letters'
]),
new MYArticleAddCheckTitleValidator([
'message' => 'aaaaaaaaaaaaaaa'
])
]);
$this->add($title);
..........
Validator PresenceOf works fine. validation flash message is visible.
Validator StringLength does not work. It looks like form doesn't know about it
Validator MYArticleAddCheckTitleValidator (my own validator class) - the same as StringLength.
Phalcon version 2.0.4 on windows.
Any proposition, or suggestions ?
Thanks a lot.
Using Phalcon\Flash\Direct
The best way to get around this problem is to use flash messages, with the class Phalcon\Flash\Direct. You can find the documentation here.
This strategy is used by the phalcon vokuro project which I suggest you to look at.
The key of this solution is the message() function inside your form class.
Form class
<?php
namespace Your\App\Forms;
use Phalcon\Forms\Form;
use Phalcon\Forms\Element\Text;
use Phalcon\Validation\Message;
use Phalcon\Validation\Validator\PresenceOf;
use Phalcon\Validation\Validator\StringLength;
use Your\App\Validation\MYArticleAddCheckTitleValidator;
class YourForm extends Form {
public function initialize()
{
$title = new Text('title');
$title->setLabel('Title of article');
$title->setFilters([
'striptags', 'trim'
]);
$title->addValidators([
new PresenceOf([
'message' => 'Title can not be empty'
]),
new StringLength([
'min' => 5,
'messageMinimum' => 'Title is too short. Should has more than 5 letters'
]),
new MYArticleAddCheckTitleValidator([
'message' => 'aaaaaaaaaaaaaaa'
])
]);
$this->add($title);
}
/**
* Prints messages for a specific element. Call it in the view
*/
public function messages($name)
{
if ($this->hasMessagesFor($name)) {
foreach ($this->getMessagesFor($name) as $message) {
$this->flash->error($message);
}
}
}
}
Controller
<?php
namespace Your\App;
use Your\App\YourForm;
class YourController extends ControllerBase
{
public function indexAction()
{
$form = new YourForm();
$this->view->form = $form;
if($this->request->hasQuery('title')){
if ($form->isValid($this->request->getQuery()) != false) {
// Code when form is valid
}
}
}
}
View
If you follow the suggested schema should be located in /app/views/your/index.html
<form method="GET" action="">
<?= $form->label('title') ?>
<?= $form->render('title')?>
<?= $form->messages('title') //show messages here ?>
</form>
If you have more than one form, it is useful to register the flash service with the DI.
When you define your services (could be in the index.php in the root folder or services.php in the /app/config/ folder) you define your flash service:
<?php
use Phalcon\DI\FactoryDefault;
$di = new FactoryDefault();
// Register the flash service with custom CSS classes
$di->set('flash', function () {
$flash = new Phalcon\Flash\Direct(
array(
'error' => 'your-error-class',
'success' => 'your-success-class',
'notice' => 'your-notice-class',
'warning' => 'your-warning-class'
)
);
return $flash;
});
This is a wierd situation because magento is loading my backend model, its just not calling it when I load and save it. I know this because 1. I see it in my database, 2. when I rename my backend model, my test case fails. Here is my code
It saves my values just fine and completely ignores my afterload and beforesave methods.
TEST CASE
<?php
class Super_Base_Test_Controller_Test extends EcomDev_PHPUnit_Test_Case_Controller {
const DEFAULTSTORE = 1;
public function setUpMocks() {
$this->setCurrentStore(1);
$customer = Mage::getSingleton('customer/customer')
->load(1);
$customer->setCoinBalance(20)
->save();
}
public function setUp() {
$this->setUpMocks();
$data = array(
'customer_id'=>1,
'message'=>'this is a test message',
'income'=>20,
'created_at'=>'9/11/84',
'updated_at'=>'9/11/84',
'current'=>1
);
$this->getRequest()->setParams($data);
}
protected function getTearDownOperation() {
return PHPUnit_Extensions_Database_Operation_Factory::TRUNCATE();
}
}
backend model
<?php
/**
* Created by PhpStorm.
* User: numerical25
* Date: 3/8/14
* Time: 6:22 PM
*/
class Super_Coin_Model_Customer_Attribute_Coinbalance extends Mage_Eav_Model_Entity_Attribute_Backend_Abstract {
protected function _afterLoad()
{
if (!is_array($this->getValue())) {
$value = $this->getValue();
$this->setValue(empty($value) ? false : unserialize($value));
}
}
protected function _beforeSave() {
if (is_array($this->getValue())) {
$this->setValue(serialize($this->getValue()));
}
}
public function setCoinAmount($amount) {
$this->setValue($amount);
}
}
installation file
$eavsetup->addAttribute('customer', 'coin_balance', array(
'input' => 'text',
'type' => 'decimal',
'label' => 'Customer Coin Balance',
'backend' => 'coin/customer_attribute_coinbalance',
'global' => 1,
'visible' => 1,
'required' => 0,
'user_defined' => 1, ));
When I set break points, the system completly ignores my methods.
Look at abstract class Mage_Eav_Model_Entity_Attribute_Backend_Abstract. It contains the following public methods: beforeSave() and afterLoad().
There are no _afterLoad() and _beforeSave() methods in that class
How can I change the url of an dataobject?
I can get the dataobject under the following url with this function.
www.domain.tld/articles/art?=1234
public function ArticleByID() {
$articleID = isset($_GET['art']) ? $_GET['art'] : false;
return $articleID ? Articles::get()->filter(array('ShortNumber' => $articleID))->First() : false;
}
But what I want is for example this
www.domain.tld/articles/1234 or www.domain.tld/members/member-name
You can create a show() function that you would call on your ArticleHolder to get and return the Articles page you want with a URL like www.domain.tld/articles/show/1234
ArticleHolder.php
...
class ArticleHolder_Controller extends Page_Controller {
...
public function show(SS_HTTPRequest $request) {
if ($request->param('ID') && $article = Articles::get()->filter(array('ShortNumber' => $page->param('ID')))->First()) {
return $this->customise(array(
'Title' => $article->Title,
'Content' => $article->Content,
'MetaTitle' => $article->MetaTitle,
'MetaDescription' => $article->MetaDescription,
'MetaKeywords' => $article->MetaKeywords
))->renderWith(
array('ArticlesPage', 'Page')
);
}
return $this->httpError(404);
}
...
}
Or, better yet, use URLSegment to get your articles. For this you need to the URLSegment in your Article class.
There is an excellent tutorial for this at ssbits.com:
http://www.ssbits.com/tutorials/2010/dataobjects-as-pages-part-2-using-model-admin-and-url-segments-to-create-a-product-catalogue/
The tutorial is for Silverstripe 2.4, but the code should work with minor tweaks in Silverstripe 3.1.
There is also a module based off this tutorial called DataObjectAsPage: https://github.com/arambalakjian/DataObjects-as-Pages
You could use this a base for your code.