This is my Controller Action:
public function jsonAction()
{
$this->view->setVariablesToRender(array('produkte'));
$this->view->setConfiguration(
array(
'produkte' => array(
'_descendAll' => array(
'only' => array('titel', 'beschreibung', 'bild', 'download', 'categories'),
'_descend' => array(
'bild' => array(),
'download' => array(),
'categories' => array(),
)
)
)
)
);
$this->view->assign('produkte', $this->produktRepository->findAll());
}
and I get a very nice JSON-String. Unfortunately I get only the PID und UID for contained files (FAL). How can I get the full object or at least the path to the contained files?
/**
* Returns the bild
*
* #return \TYPO3\CMS\Extbase\Domain\Model\FileReference $bild
*/
public function getBild()
{
return $this->bild;
}
/**
* Returns the download
*
* #return \TYPO3\CMS\Extbase\Domain\Model\FileReference $download
*/
public function getDownload()
{
return $this->download;
}
Try descending to the originalResource of the FileReference and expose publicUrl:
$this->view->setConfiguration(
array(
'produkte' => array(
'_descendAll' => array(
'only' => array('titel', 'beschreibung', 'bild', 'download', 'categories'),
'_descend' => array(
'download' => array(
'_descendAll' => array(
'_only' => array('originalResource');
'_descend' => array(
'originalResource' => array(
'_only' => array('publicUrl');
);
);
);
),
)
)
)
)
);
The originalResource is partly a computed property, on invoking the getter-method the entity will be retrieved automatically - that's how it's implemented in Extbase's FileReference model.
/**
* #return \TYPO3\CMS\Core\Resource\FileReference
*/
public function getOriginalResource()
{
if ($this->originalResource === null) {
$this->originalResource = \TYPO3\CMS\Core\Resource\ResourceFactory::getInstance()->getFileReferenceObject($this->getUid());
}
return $this->originalResource;
}
However, please make sure to write the JSON view configuration correct. All control-related properties are prefixes with an underscore _ - in the code examples above it should be _only instead of only. Valid control-names are _only, _exclude, _descend, _descendAll, _exposeObjectIdentifier, _exposedObjectIdentifierKey, _exposeClassName.
Find more details in the Flow documentation, which is still valid for the JsonView in TYPO3 CMS.
Try using \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference> instead of \TYPO3\CMS\Extbase\Domain\Model\FileReference for your FAL properties in your Model.
I dont need more than one File, but after i changed this i get the publicUrl.
Related
I am trying to build a dynamic page system with cakephp 3.
Using slugs I can show pages and content. But on the homepage, it is just using the default view template.
I have the routes as followed:
$routes->connect('/', ['controller' => 'pages', 'action' => 'display', 'home']);
$routes->connect('/:slug', ['controller' => 'pages', 'action' => 'view'], ['pass' => ['slug'], 'slug' => '[^\?/]+']);
Which works for the none homepage pages.
But I want to use the homepage as / (e.g. localhost:8000/)
And not /home (e.g. localhost:8000/home).
Currently the view function in the pages controller looks like this:
public function view($slug = null)
{
$pages = TableRegistry::getTableLocator()->get('webpages');
$page = $pages->findBySlug($slug)->firstOrFail();
$this->set(compact('page'));
}
Any idea?
Seems I already found the solution.
I changed the routing to just the following line:
$routes->connect('/*', ['controller' => 'pages', 'action' => 'view']);
Then I changed the view as followed:
public function view($slug = null)
{
$pages = TableRegistry::getTableLocator()->get('webpages');
if($slug == null){
$query = $pages->find('all', [
'conditions' => ['ishome' => 1]
]);
} else {
$query = $pages->find('all', [
'conditions' => ['slug' => $slug]
]);
}
$page = $query->first();
$this->set(compact('page'));
}
I use the answer from the following comment, but had to modify it a bit, since that code was used for an older version of cakephp (I am using cakekphp 3.8).
https://stackoverflow.com/a/3975923/6181243
I need to save html tags in features section of the create/edit product page.
I have changed TYPE_HTML and isCleanHTML in classes/FeatureValue.php, but the validation still ignores html tags.
Ex.
'value' => array('type' => self::TYPE_HTML, 'lang' => true, 'validate' => 'isCleanHtml', 'required' => true, 'size' => 255),
Thank you.
See example
You have to use definition of FeatureValue and change it so it can save HTML as well as need to change code in file where it is saving product custom feature value. Rather than changing in core files, I will make use of Overrides.
Follow below mentioned steps.
1) Create file Product.php file on path override\classes and put below code in it. This will save HTML in value field.
<?php
/**
* #override Product.php
*/
class Product extends ProductCore
{
/**
* Add new feature to product
*/
public function addFeaturesCustomToDB($id_value, $lang, $cust)
{
$row = array('id_feature_value' => (int)$id_value, 'id_lang' => (int)$lang, 'value' => pSQL($cust, true));
return Db::getInstance()->insert('feature_value_lang', $row);
}
}
2) Create FeatureValue.php file on path override\classes and put below code in it. Changing definition so that it can validate HTML.
<?php
/**
* #override FeatureValue.php
*/
class FeatureValue extends FeatureValueCore
{
/**
* #see ObjectModel::$definition
*/
public static $definition = array(
'table' => 'feature_value',
'primary' => 'id_feature_value',
'multilang' => true,
'fields' => array(
'id_feature' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true),
'custom' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
/* Lang fields */
'value' => array('type' => self::TYPE_HTML, 'lang' => true, 'validate' => 'isCleanHtml', 'required' => true, 'size' => 255),
),
);
}
3) To autoload newly created override class files; delete class_index.php file from var\cache\dev and var\cache\prod folder.
Hope it will help you!
I have this problem: I need to get data from database and filter them. but then I need to use custom php function to filter those filtered results using data from it.
Clasic search function in ActiveDataProvider
public function search($params) {
$query = Passenger::find();
// add conditions that should always apply here
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
// I guess my function would go like here
Passenger::filterResultsEvenMore($dataProvider);
$this->load($params);
if (!$this->validate()) {
// uncomment the following line if you do not want to return any records when validation fails
// $query->where('0=1');
return $dataProvider;
}
// grid filtering conditions
$query->andFilterWhere([
'passenger_id' => $this->passenger_id,
// ...
'version' => $this->version,
'status' => $this->status,
]);
return $dataProvider;
}
So my question is how to work with results of dataProvider because if I vardump the variable it looks like this and no actual data there.
yii\data\ActiveDataProvider Object
(
[query] => common\models\PassengerQuery Object
(
[sql] =>
[on] =>
[joinWith] =>
[select] =>
[selectOption] =>
[distinct] =>
[from] =>
[groupBy] =>
[join] =>
[having] =>
[union] =>
[params] => Array()
[_events:yii\base\Component:private] => Array()
[_behaviors:yii\base\Component:private] => Array()
[where] => Array
(
[status] => 1
)
[limit] =>
[offset] =>
[orderBy] =>
[indexBy] =>
[emulateExecution] =>
[modelClass] => common\models\Passenger
[with] =>
[asArray] =>
[multiple] =>
[primaryModel] =>
[link] =>
[via] =>
[inverseOf] =>
)
[key] =>
[db] =>
[id] =>
[_sort:yii\data\BaseDataProvider:private] =>
[_pagination:yii\data\BaseDataProvider:private] =>
[_keys:yii\data\BaseDataProvider:private] =>
[_models:yii\data\BaseDataProvider:private] =>
[_totalCount:yii\data\BaseDataProvider:private] =>
[_events:yii\base\Component:private] => Array()
[_behaviors:yii\base\Component:private] =>
)
UPDATE
I need to use function like this for each record:
if (myFunction(table_column_1, table_column_2)) {
result_is_ok_return_it
} else {
do_not_return_this_record
}
Why do you don't add your additional filters to query object used in DataProvider?
You can parse your conditions to $query->andFilterWhere(). If you need custom function for it just modify $dataProvider->query object inside function. After execute query in data provider you can only filter results by manually filter array of models stored in $dataProvider->models
To get result use models property or getModels()
For example,
$dataProvider->models;
OR
$dataProvider->getModels();
I think I came across a solution, (looks like it is working)
http://www.yiiframework.com/doc-2.0/yii-data-basedataprovider.html#setModels()-detail
After I do all my usual search stuff as described in question at beginning, I would do something like this using setModels() function
class PassengerSearch extends Passenger
public $status; // virtual attribute not present in database table
public function rules()
{
return [
// ... some other rules
[['status'], 'safe'],
];
}
// ...
$filtered_models = [];
$filter_models = false; // if you only want to filter if there is some value
foreach ($dataProvider->models as $model) {
// if ($model->status == 1) // example
if (!empty($this->status) && $model->status == $this->status) { // better approach, using virtual attribute $status
$filter_models = true;
$filtered_models[] = $model;
}
}
if ($filter_models)
$dataProvider->setModels($filtered_models);
return $dataProvider;
}
In a Yii application I display the data as a table. I use CGridView, that deals for me with (search based) data filter and sorting. It works.
Now I added an ENUM column status to the user database table. In the grid I can sort and filter this, but only by the value in the table. Well, it makes sense. But the user don't actually know, how it's saved n the database and works with (and wants to sort and filter by) labels.
Is there a way to provide sorting and filtering by custom labels for an ENUM database table column in Yii (using a CActiveRecord model and a CGridView generated data grid)?
database table
CREATE TABLE `users` (
`userid` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`email` varchar(45) NOT NULL,
...
`status` enum('processed', 'waiting') NOT NULL,
PRIMARY KEY (`userid`),
UNIQUE KEY `email_UNIQUE` (`email`)
);
User model
/**
* ...
* #property string $userid
* #property string $email
* ...
* #property string $status
*/
class User extends CActiveRecord
{
public function tableName()
{
return 'users';
}
public function getFirstAndLastName(){
return CHtml::encode($this->firstname." ".$this->lastname);
}
public function rules()
{
return array(
...
array('userid, email, status', 'safe', 'on'=>'search'),
);
}
public function attributeLabels()
{
return array(
'userid' => 'Userid',
'email' => 'Email',
...
'status' => Yii::t('app', 'status'),
);
}
public function relations()
{
return array(
...
);
}
public function search()
{
$criteria=new CDbCriteria;
$criteria->compare('userid',$this->userid,true);
$criteria->compare('email',$this->email,true);
...
$criteria->compare('status',$this->status,true);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
"pagination"=>array(
"pageSize"=>25
)
));
}
public static function model($className=__CLASS__)
{
return parent::model($className);
}
protected function beforeSave()
{
return parent::beforeSave(); // TODO: Change the autogenerated stub
}
public function getProcessingStatus()
{
return Yii::t('app', $this->processing_status);
}
}
UserController
class UserController extends Controller
{
...
/**
* Manages all models.
*/
public function actionAdmin()
{
// Yii::app()->cache->flush();
$model=new User('search');
$model->unsetAttributes(); // clear any default values
if(isset($_GET['User']))
$model->attributes=$_GET['User'];
$this->render('admin',array(
'model'=>$model,
));
}
...
}
view
...
<?php
$this->widget('zii.widgets.grid.CGridView', array(
'id' => 'user-grid',
'dataProvider' => $model->search(),
'filter' => $model,
'columns' => array(
'email',
'status',
array(
'class' => 'CButtonColumn',
'template' => '{view}{update}',
'buttons' => array(
'view' => array(
)
),
),
),
));
Model:
class User extends CActiveRecord {
const STATUS_PROCESSED = 'processed';
const STATUS_WAITING = 'waiting';
public static function getStatusList(){
return array(
self::STATUS_PROCESSED => 'Processed',
self::STATUS_WAITING => 'Waiting',
);
}
public function getStatusValue(){
$list = self::getStatusList();
return array_key_exists( $this->status, $list ) ? $list[ $this->status ] : 'Undefined';
}
}
View:
$this->widget('zii.widgets.grid.CGridView', array(
// other params
'columns' => array(
// other columns
array(
'name' => 'status',
'value' => '$data->getStatusValue()',
'filter' => User::getStatusList(),
),
)
));
That's all
You can specify a custom filter in your CDataColumn, by setting the filter property to be an array. It will result in a dropdown list filter instead of a text field filter.
Example:
<?php
$this->widget('zii.widgets.grid.CGridView', array(
'id' => 'user-grid',
'dataProvider' => $model->search(),
'filter' => $model,
'columns' => array(
'email',
array(
'name' => 'status',
'filter' => array(
'processed' => 'Processed',
'waiting' => 'Waiting',
),
),
array(
'class' => 'CButtonColumn',
'template' => '{view}{update}',
'buttons' => array(
'view' => array(
)
),
),
),
));
Also check out the docs
I'm having a weird problem with my relationships/aliases in CakePHP and now its preventing me from accessing my data correctly.
I have:
User hasMany CreatorModule (alias for Module)
User HABTM LearnerModule (alias for Module)
Module belongsTo Creator (alias for User)
Module HABTM Learner (alias for User)
And I'm trying to call:
$id = $this->Module->User->findByEmail($email);
$modules = $this->Module->findByUserId($id['User']['id']);
The queries that get generated aren't correct - the table-alias is wrong. I'm not sure which of the above is responsible but I get:
SELECT
`Creator`.`id`,
`Creator`.`email`,
`Creator`.`organization`,
`Creator`.`name`,
`Creator`.`password`,
`Creator`.`verified`,
`Creator`.`vcode`
FROM
`snurpdco_cake`.`users` AS `Creator`
WHERE
`User`.`email` = 'foo#example.com' # <--
LIMIT 1
I figured out that the error is that CakePHP should change 'User' in the WHERE clause to Creator, but doesn't, even if I use the alias. How do I complete this query correctly.
Further, as a related problem, I find that I can no longer use User in my model calls etc now that I have defined aliases. Is there a way around this?
EDIT: As requested, here is my model code defining the aliases:
class User extends AppModel {
public $name = 'User';
public $uses = 'users';
public $hasMany = array(
'OwnedModule' => array(
'className' => 'Module',
'foreignKey' => 'user_id',
'dependent' => true
));
public $hasAndBelongsToMany = array(
'LearnerModule' => array(
'className' => 'Module',
'joinTable' => 'modules_users',
'foreignKey' => 'user_id',
'associationForeignKey' => 'module_id',
'unique' => 'keepExisting',
));
//The rest of the Model
}
//Different file, condensed here for spacing
class Module extends AppModel {
public $name = 'Module';
public $belongsTo = array(
'Creator' => array(
'className' => 'User'));
public $hasAndBelongsToMany = array(
'Learner' => array(
'className' => 'User',
'joinTable' => 'modules_users',
'foreignKey' => 'module_id',
'associationForeignKey' => 'user_id',
'unique' => 'keepExisting',
));
//The rest of the Model
}
try
$id = $this->Module->Creator->find('first',
array('conditions' => array('Creator.email' => $email)
);
$modules = $this->Module->findByCreatorId($id['User']['id']);