Adding dynamic form field options to FuelPHP model properties - php

I'm creating a select form element within FuelPHP's model _properties variable:
protected static $_properties = array(
'category_id' => array(
'data_type' => 'int',
'label' => 'Category',
'form' => array(
'type' => 'select',
'options' => array()
)
)
);
I want to set [category_id][form][options] to the result of an SQL query, however this obviously cannot be done within the class declaration and I've tried modifying the variable from with __construct(), this code is below but yielded errors.
function _construct() {
parent::__construct();
self::$_properties['category_id']['form']['options'] = array('a');
}
My question is, how do I set the field options to something dynamic using FuelPHP?

You are almost there. Fuel provides a static constructor called init that will allow you to assign static properties.
function _init() {
parent::_init();
self::$_properties['category_id']['form']['options'] = array('a');
}

Related

how to check if value contain white space - Prestashop

I'm developing simple module for prestashop.in my admin controller i have input text called username.i want user to enter his user name without space.
what i tried
i have added below code in to Validate.php and tried to access it from Module class.but its not working.
Validate.php
public static function checkWhiteSpace($var){
return preg_match('/\s/',$var);
}
Model class
class User extends ObjectModel
{
public $id_user;
public $username;
public static $definition = array(
'table' => 'Users',
'primary' => 'id_user',
'multilang' => false,
'fields' => array(
'username' => array(
'type' => self::TYPE_STRING,
'required' => true,
'validate' => 'checkWhiteSpace',
),
),
);
}
Try to invert your result from Validate. Because when your field is invalid it shows true and opposite when valid. So try this
public static function checkWhiteSpace($var){
return !preg_match('/\s/',$var);
}
It should work within your Model class, you don't need to change Validate.php.

Silverstripe: $has_many summary fields issue

I am trying to use a Has_many relation as the summary fields for a DataObject and can't seem to get it working.
Basically:
I have a Form
each form has many submissions/entries
each form has many fields
Each field has many answers.
I'm trying to create a gridfield in the back end admin area of each form which displays the entries for each form.
In the summary fields for the entry, i'd like to display the Date created, and the first 3 fields for that form.
So, for example if we had a form with a name, email, and phone field the summary fields would be as follows:
Date Created
Name
Email
Phone
with the relevent entry data/responses as summary information for the entry.
Here is what I have so far. This is the form:
<?php
class ContactBlock extends Block {
private static $db = array(
// Fields for the form/block go here
);
private static $has_many = array(
'ContactBlockFields' => 'ContactBlockField',
'ContactBlockEntries' => 'ContactBlockEntry'
);
public function getCMSFields() {
// Irrelevant code goes here!
// CONTACT BLOCK ENTRIES
$entriesInfo = new GridFieldDataColumns();
$entriesInfo->setDisplayFields(singleton('ContactBlockEntry')->summaryFields());
$entriesConfig = GridFieldConfig::create();
$entriesConfig->addComponents(
new GridFieldToolbarHeader(),
new GridFieldAddNewButton('toolbar-header-right'),
$entriesInfo,
new GridFieldSortableHeader(),
new GridFieldPaginator(50),
new GridFieldEditButton(),
new GridFieldDeleteAction(),
new GridFieldDetailForm()
);
$entriesGrid = GridField::create('ContactBlockEntries', 'Form Entries', $this->ContactBlockEntries(), $entriesConfig);
$fields->addFieldToTab('Root.FormEntries', $entriesGrid);
return $fields;
}
}
This is the Entry DataObject:
<?php
class ContactBlockEntry extends DataObject {
private static $has_one = array(
'ContactBlock' => 'ContactBlock'
);
private static $has_many = array(
'ContactBlockFieldAnswers' => 'ContactBlockFieldAnswer',
);
private static $many_many = array(
'FormFields' => 'ContactBlockField'
);
static $summary_fields = array(
'Date'
);
public function getCMSFields() {
$fields = parent::getCMSFields();
//=== REMOVE FIELDS ====
$fields->removeFieldFromTab('Root','FormFields');
$fields->removeFieldFromTab('Root','ContactBlockFieldAnswers');
$fields->removeFieldFromTab('Root.Main','ContactBlockID');
//=== REMOVE FIELDS ====
return $fields;
}
public function onBeforeDelete() {
parent::onBeforeDelete();
// Delete answers that are associated with this block.
$data = ContactBlockFieldAnswer::get()
->filter('ContactBlockEntry', $this->ID);
foreach( $data as $d) {
$d->delete();
}
}
public function getDate() {
$date = date('d/m/Y',strtotime($this->Created));
return $date;
}
}
This is the field code:
<?php
class ContactBlockField extends DataObject {
private static $db = array(
'SortOrder' => 'Int',
'FieldName' => 'Varchar',
'FieldType' => 'Varchar',
'DropdownValues' => 'Varchar(255)',
'Label' => 'Varchar',
'Placeholder' => 'Varchar',
'Required' => 'Boolean'
);
private static $has_one = array(
'ContactBlock' => 'ContactBlock',
);
private static $has_many = array(
'ContactBlockFieldAnswer' => 'ContactBlockFieldAnswer',
);
private static $belongs_many_many = array(
'Entries' => 'ContactBlockEntry'
);
static $searchable_fields = array(
'FieldType',
'FieldLabel',
'Required'
);
static $summary_fields = array(
'FieldType' => 'Field Type',
'Label' => 'Field Label',
'Required' => 'Required Field?'
);
public function getCMSFields() {
$fields = parent::getCMSFields();
// Unrelated stuff here
return $fields;
}
}
I can't seem to figure out how to get the column labels, and their relevant data showing on the gridfield. Any help or advice would be much appreciated.
UPDATE 24/3/17:
OK I've got a little further with this. On the ContactBlockEntry DataObject, after implementing the changes suggested by UncleCheese, I have discovered the following:
public function getFirstField() {
return $this->FormFields()->first();
}
public function getSecondField() {
return $this->FormFields()->offsetGet(1);
}
public function getThirdField() {
return $this->FormFields()->offsetGet(2);
}
public function summaryFields() {
return [
'Date' => 'Submitted',
'Answers.First.Value' => $this->getFirstField()->Label,
'Answers.Second.Value' => $this->getSecondField()->Label,
'Answers.Third.Value' => $this->getThirdField()->Label,
];
}
$this->getFirstField()->Label is returning [Notice] Trying to get property of non-object however, when I echo/print this function in getCMSFields() I can see the label value.
Answers.First.Value works. It returns the value/answer submitted in the first field. The problem is, I can't seem to get the second and third values, as I can't figure out the method to retrieve them. I tried offsetGet() and it said the method isn't available.
In this case, you can define a summaryFields() method in lieu of the static array. This will allow you to return a computed value for the headings.
What complicates things is getting the values. The first three fields are not properties of the Entry object, so you'll need to provide getters for the Entry dataobject to compute them on the fly as "virtual" properties. It's a bit clunky, but something like this should work.
public function getFirstField()
{
return $this->FormFields()->first();
}
public function getSecondField()
{
return $this->FormFields()->offsetGet(1);
}
public function getThirdField()
{
return $this->FormFields()->offsetGet(2);
}
public function summaryFields()
{
return [
'Created' => 'Created',
'FirstField.Answer' => $this->getFirstField()->FieldName,
'SecondField.Answer' => $this->getSecondField()->FieldName,
'ThirdField.Answer' => $this->getThirdField()->FieldName,
];
}
I'm not too sure about your data model, though. You have the answers has a has_many on your field object. You would in that case have to create another getter on your Field object for AnswerLabel that somehow concatenated all the answers into a string, or maybe just got the first one. Whatever business logic you choose. Just use FirstField.AnswerLabel etc. in your array, or whatever you choose to call that method. The point being, you need to resolve a plural relationship into a single readable value. How you do that is up to you.

ZF2: Validate collection field based on parent fieldset element

I'm trying to validate a field inside a Collection.
The Collection refers to Company Areas and is tied to a Company Fieldset
The validation needs to check that the Area Name doesn't exists for that Company in the Database yet.
I'm trying to do this using a Callback validator within my collection element 'area_name', my problem is that the collection is aware only of its own context, that means all fields associated to the Area but not aware of the Company context, so i can't filter my validator by its Company parent.
Is there a way to access the parent context of a collection? or should i need to initialize my form passing the Company object to the Collection prior validating?
EDIT: I forgot to mention that i'm using Doctrine2 so i'm not sure if it is possible to use the Db_NoRecordExists Validator bundled with ZF2
This is an old question and you might have fixed this already, but I had a similar problem recently.
You can create a function in your area model/service: validateAreaCompanyRelation(area, company)and in your fieldset use the callback to use it:
AreaService class:
add a method to return true or false based on query limited by 1 row.
in my case it was somthing like this:
public function validateAreaCompanyRelation($company, $area)
{
$result = false;
$count = $this->getRepository()
->createQueryBuilder('q')
->select('q')
->innerJoin('q.company', 'c')
->innerJoin('q.area','b')
->where('b.id = :area and c.company = :company')
->setParameter('area',$area)
->setParameter('company',$area)
->setMaxResults( 1 )
->getQuery()
->getArrayResult();
if(count($count) <>1){
$result=true;
}
return $result;
}
Area Field set:
inject AreaService to the field set (pass it to construct in factory)
class AreaFieldset extends Fieldset implements InputFilterProviderInterface
{
private $areaService;
public function __construct(areaServiceEntityService $areaService)
{
$this->areaService = $areaService;
}
public function init()
{
$this->add(
array(
'name' => 'area',
'filters' => array(),
'validators' => array (
array(
'name' => 'Zend\Validator\Callback',
'options' => array(
'messages' => array(
\Zend\Validator\Callback::INVALID_VALUE => 'Your custom error message',
),
'callback' => array($this,'vlidateUniqueRelation'),
),
),
)
)
);
array(
'name' => 'company',
'filters' => array(),
'validators' => array (
array(
'name' => 'Zend\Validator\Callback',
'options' => array(
'messages' => array(
\Zend\Validator\Callback::INVALID_VALUE => 'Your custom error message',,
),
'callback' => array($this,'vlidateUniqueRelation'),
),
),
)
)
);
}
public function vlidateUniqueRelation($value, $context)
{
// $value = value
// $context['xxxx'] = xxxxx value
// Logic to validate goes here
$context["company"]
$context["area"]
return $this->AreaService->validateAreaCompanyRelation($context["company"], $context["Area"]);
}

Upsert embedded document in yiimongodbsuite

I need to perform an upsert command in yiimongodbsuite.
I tried
$model = new Murls();
$model->userid=$userid;
$model->title=$title;
$model->edits[0] = new Medithtml();
$model->edits[0]->path= $htm;
$model->edits[0]->html=$path;
$model->edits[0]->ci=$ci;
$model->update(array('_id'=>$rec->_id ),array('userid', 'title','edits' ), true );
But this shows an error.
Murls model is defined as follows
class Murls extends EMongoDocument
{
public $userid;
public $title;
public $edits;
public static function model($className=__CLASS__)
{
return parent::model($className);
}
// This method is required!
public function getCollectionName()
{
return 'murls';
}
public function attributeLabels()
{
return array(
'html'=>'Html',
);
}
public function embeddedDocuments()
{
return array(
// property name => embedded document class name
'edits'=>'Medithtml',
);
}
public function behaviors(){
return array(
'embeddedArrays' => array(
'class' => 'ext.YiiMongoDbSuite.extra.EEmbeddedArraysBehavior',
'arrayPropertyName' => 'edits', // name of property, that will be used as an array
'arrayDocClassName' => 'Medithtml' // class name of embedded documents in array
),
);
}
}
and model Medithtml as
class Medithtml extends EMongoEmbeddedDocument{
public $html;
public $path;
public $ci;
public static function model($className=__CLASS__)
{
return parent::model($className);
}
}
What I need to achieve is that a record with $title can have n number of $html , $path and $ci.
Any help will be appreciated.
What I am looking is to store data like this
array (
'_id' =>
MongoId::__set_state(array(
'$id' => '51ee1956d39c2c7e078d80da',
)),
'userid' => '12',
'title' => 'Mongo',
'edits' =>
array (
0 =>
array (
'html' => 'html>body>div:nth-child(2)>a>div>a>div',
'path' => 'ssssss',
'ci' => '1',
),
1 =>
array (
'html' => 'html>body>div:nth-child(2)>a>div:nth-child(3)>a>h2',
'path' => '/assets/img/demo/demo-avatar9604.jpg',
'ci' => '2',
),
2 =>
array (
'html' => ' html>body>div:nth-child(2)>a>div:nth-child(3)>a>center:nth-child(16)>a>h1',
'path' => '333',
'ci' => '3',
),
),
)
Only the comments array will be updated if record with a particular combination of 'title' and 'userid' exists.If it doesn not exists a new record will be inserted
You are inheriting from wrong class. To save document you must inherit from EMongoDocument not EMongoEmbeddedDocument. These classes are similar but have different purpose.
EMongoEmbeddedDocument Is for embedded documents only, it should be used only for embedded documents
EMongoDocument extends from EMongoEmbeddedDocument with methods to actually save data to db.
For array of comments, you have two options:
Use plain php array - simple less maintanable, less power, erron prone..
Use array of embedded documents - each comment is document, so can be validated, has rigid structure etc.
By default save/insert/update stores all attributes. For partial updates use combination of $attributes and set $modify to true. Warning: Passing array of attributes without $modify will store only passed attributes, discarding rest of document.
public function save($runValidation = true, $attributes = null)
...
public function insert(array $attributes = null)
...
public function update(array $attributes = null, $modify = false)
...
So in your case you can update like that:
$model->update(array('comments'), true);
Or if it's ok for you to ovverride whole document just save:
$model->save();
Note: for composite pk ovverride primaryKey():
public function primaryKey()
{
return array('title', 'userid');
}
Uh, good that stackoverflow have drafts autosave feature:)
Finally I got solution in this way:
$rec = $model->find($criteria) ;
if($rec){
foreach($rec->edits as $editarray){
$var[]=$editarray;
}
$edits_new= new Medithtml();
$edits_new['html']=$htm;
$edits_new['ci']=$ci;
$edits_new['path']=$path;
$var[]=$edits_new;
$rec->edits=$var;
$rec->userid=$userid;
$rec->title=$title;
$rec->update(array('edits' ), true);
}

php merge class variables instead of replacing them

i have multiple php classes
// a Base class
abstract class Base_Page {
protected static $config = array(
'status' => 'int',
);
}
// an inheriting class
class Page extends Base_Page{
protected static $config = array(
'title' => 'varchar',
'description' => 'text',
);
// and one more level of inheritance
class Page_Redirect extends Base_Page {
protected static $config = array(
'href' => 'http://domain.com',
);
}
now id'd like to do this:
$page_redirect = new Page_Redirect();
$page_redirect->getConfig(); // which i assume to be implemented (this is my problem)
// should return:
// array(
// 'status' => 'int',
// 'title' => 'varchar',
// 'description' => 'text',
// 'href' => 'http://domain.com',
// )
Due to the fact that the variable gets overwrote by the extending class a dont't get how to accomplish this. Thanks for your look at it.
You cannot do this with a bare property. It would be much better to use methods instead:
abstract class Base_Page {
protected function getConfig() {
return array('status' => 'int');
}
}
// an inheriting class
class Page extends Base_Page{
protected function getConfig() {
return array(
'title' => 'varchar',
'description' => 'text',
) + parent::getConfig();
}
}
// and one more level of inheritance
class Page_Redirect extends Base_Page {
protected function getConfig() {
return array(
'href' => 'http://domain.com',
) + parent::getConfig();
}
}
Of course now you have lost the ability to get the configuration statically, but it's highly likely that this does not matter. If it does (i.e. you need to know the configuration without having an instance at hand, and it is meaningless to create one on a whim) then the code needs further refactoring.
<?php
// a Base class
abstract class Base_Page {
protected static $config = array(
'status' => 'int',
);
}
// an inheriting class
class Page extends Base_Page {
protected static $config = array_merge(
parent::$config,
array(
'title' => 'varchar',
'description' => 'text',
)
);
}
Try something like this.

Categories