CakePHP 3: Migration doesn't save update data - postgresql

Environment:
CakePHP 3
Postgres
I'm trying to do a migration to add a new field, then update some data for that field in our Postgres database. The entity seems to indicate that it's updated, but when I view the database, it is not saved.
Code
<?php
use Cake\Cache\Cache;
use Cake\ORM\TableRegistry;
use Migrations\AbstractMigration;
class AddDisplayRouteNumberToAgencies extends AbstractMigration
{
/**
* Up Method.
*/
public function up()
{
$table = $this->table('agencies');
$table->addColumn('display_route_number', 'boolean', [
'default' => true,
'null' => false,
]);
$table->update();
// Try to clear the Model cache
Cache::clear(null, '_cake_model_');
$patchData = [
'display_route_number' => false
];
$agencies = TableRegistry::get('Agencies');
$agency = $agencies->get(25);
// And save it back to the DB
$agencies->patchEntity($agency, $patchData);
debug($agency);
// Added after comment from ndm
$agencies->save($agency);
}
/**
* Down method
*/
public function down()
{
$table = $this->table('agencies');
$table->removeColumn('display_route_number');
$table->update();
// Clear the CakePHP Model cache
Cache::clear(null, '_cake_model_');
}
}
Results from debug()
object(App\Model\Entity\Agency) {
'id' => (int) 25,
'full_name' => 'Agency',
'legacy_agency_slug' => null,
'created' => object(Cake\I18n\Time) {
'time' => '2015-11-19T10:58:51+0000',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'modified' => object(Cake\I18n\Time) {
'time' => '2015-11-19T10:58:51+0000',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'display_route_number' => false,
'[new]' => false,
'[accessible]' => [
'*' => true
],
'[dirty]' => [
'display_route_number' => true
],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[repository]' => 'Agencies'
}
Postgres query and results
SELECT id, display_route_number
FROM agencies
WHERE id = 25;
id | display_route_number
----+----------------------
25 | t
(1 row)
Other attempts
I also tried just using save() rather than patchEntities(), which returned the same results, except [dirty] is empty.
$agencies = TableRegistry::get('Agencies');
$agency = $agencies->get(25);
// Items to update
$agency->display_route_number = false;
// And save it back to the DB
$agencies->save($agency);

Thanks to #ndm for figuring this out for me. I ended up having to update the table schema. I believe this is because the Migration table part updates the SQL, but doesn't update the Schema.
Here's the final code:
// Clear the CakePHP Model cache
Cache::clear(null, '_cake_model_');
$table = $this->table('agencies');
$table->addColumn('display_route_number', 'boolean', [
'default' => true,
'null' => false,
]);
$table->update();
$agencies = TableRegistry::get('Agencies');
// REQUIRED!! Add the field to the Table schema
$agencies->schema()->addColumn('display_route_number', [
'type' => 'boolean',
'default' => true,
'null' => false
]);
$agency = $agencies->find()
->where(['short_name' => 'bart'])
->first();
// Items to update
$agency->display_route_number = false;
// And save it back to the DB
$agencies->save($agency);

Related

Laravel backpack InlineCreate Operation Method not allowed error

Trying to use inline_create i can create in modal but i can't select i get error
Method not allowed The POST method is not supported for this route.
Supported methods: GET, HEAD.
URL is : http://127.0.0.1:8000/admin/question/fetch/tags
Field
$this->crud->addField(
[
'label' => "Les mote clé",
'minimum_input_length' => 0,
'type' => 'relationship',
'name' => 'tags', // the method that defines the relationship in your Model
'ajax' => true,
// 'method' => 'GET',
'minimum_input_length' => 0,
'attribute' => 'name', // foreign key attribute that is shown to user
'inline_create' => [ // specify the entity in singular
'entity' => 'tag', // the entity in singular
'force_select' => true, // should the inline-created entry be immediately selected?
'modal_class' => 'modal-dialog modal-md', // use modal-sm, modal-lg to change width
'modal_route' => route('tag-inline-create'), // InlineCreate::getInlineCreateModal()
'create_route' => route('tag-inline-create-save'), // InlineCreate::storeInlineCreate()
]
]
);
Question modal
// tags
public function tags()
{
return $this->belongsToMany(Tag::class, 'question_tags', 'question_id', 'tag_id');
}
I finally found the problem.
I needed to define the ajax route to work with the field, either creating my own endpoin, or using FetchOperation https://backpackforlaravel.com/docs/5.x/crud-operation-fetch#about-1.
In QuestionCrudController:
use \Backpack\CRUD\app\Http\Controllers\Operations\FetchOperation;
...
public function fetchTags()
{
return $this->fetch(Tag::class);
}

Laravel Backpack attribute accessor causing bug on update command

I am working on Laravel Backpack. I have two fields like this:
$this->crud->addField([ // SELECT2
'label' => 'Type',
'type' => 'select_from_array',
'name' => 'type',
'options' => [
'' => 'select type',
'Movie' => 'Movies',
'Series' => 'Series'
],
]);
$this->crud->addField([ // select2_from_ajax: 1-n relationship
'label' => "Entity", // Table column heading
'type' => 'select2_from_ajax',
'name' => 'entity_id', // the column that contains the ID of that connected entity;
'entity' => 'entity', // the method that defines the relationship in your Model
'attribute' => 'name', // foreign key attribute that is shown to user
'data_source' => url('api/entity'), // url to controller search function (with /{id} should return model)
'placeholder' => 'Select', // placeholder for the select
'include_all_form_fields' => true, //sends the other form fields along with the request so it can be filtered.
'minimum_input_length' => 0, // minimum characters to type before querying results
'dependencies' => ['type'], // when a dependency changes, this select2 is reset to null
// 'method' => 'GET', // optional - HTTP method to use for the AJAX call (GET, POST)
]);
The second field options are dependent on the first one.
In my model, I have:
public function getEntityIdAttribute()
{
$id = $this->attributes['entity_id'];
$type = $this->attributes['type'];
if ($type == "Movie") {
$attribute = Movie::find($id);
} else {
$attribute = Series::find($id);
}
return $attribute->name;
}
Create and List operations work perfectly. But on update, it throws this error:
Undefined array key "entity_id"
Why is this accessor not working on the update? or can we somehow skip the accessor on the update command?

Disable field in TCA when editing a record

Is it possible to disable a field in the TCA config, only when editing a record?
TCA config for new record:
'title' => [
'exclude' => true,
'label' => 'Title',
'config' => [
'type' => 'input',
'size' => 30,
'eval' => 'trim,required'
],
],
TCA config for existing records:
'title' => [
'exclude' => true,
'label' => 'Title',
'config' => [
'type' => 'input',
'size' => 30,
'eval' => 'trim,required'
'readOnly' => true,
],
],
I'm not aware of a built in solution for different TCA settings for new and existing records.
Since the final TCA is cached there is also no way to manipulate it with some PHP on runtime.
It is possible to add Javascript in the backend. With this Javascript your are able, to disable fields on the fly. But be aware, that this is just a hacky workaround which can easily be overcome!
Add Javascript in ext_localconf.php:
if (TYPO3_MODE === 'BE') {
$renderer = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Page\PageRenderer::class);
$renderer->addJsFile(
'EXT:myext/Resources/Public/JavaScript/Backend.js'
);
}
In Backend.js you can do something like this:
require(["jquery"], function ($) {
const queryString = decodeURI(window.location.search),
urlParams = new URLSearchParams(queryString);
if (urlParams.has('route') && urlParams.get('route') == '/record/edit') {
// check, that you just do changes, if you edit records of the desired model
if (queryString.indexOf('edit[tx_myextension_domain_model_model][')) {
let idPosStart = queryString.indexOf('edit[tx_myextension_domain_model_model][') + 40,
idPosEnd = queryString.indexOf(']=', idPosStart),
idLength = idPosEnd - idPosStart,
idEl = queryString.substr(idPosStart, idLength),
elVal = urlParams.get('edit[tx_myextension_domain_model_model][' + idEl + ']');
if (elVal == 'edit') {
// Delay everything a little bit, otherwise html is not fully loaded and can't be addressed
setTimeout(function () {
// disable desired fields, eg field "title"
let titleField = $('[data-field="title"]').parents('.form-section');
titleField.find('input').prop('disabled', true);
titleField.find('button.close').remove();
}, 800);
}
}
}
}

How to sort by related table field when sending Yii2 REST GET request

I want to expand this question.
Basically I have users endpoint. But I am also returning data from the related profiles table. I am not expanding with profiles, I always want to return it. So I have fields method like this:
public function fields()
{
$fields = parent::fields();
$fields[] = 'profile';
return $fields;
}
When I do GET request and demand sorting by profile.created_at field and user.status, it does not sort by profile.created_at.
GET v1/users?sort=-profile.created_at,status
Can this be achieved somehow ?
This is my current code:
/** #var $query ActiveQuery */
$query = User::find();
// get data from profile table
$query->innerJoinWith('profile');
// add conditions that should always apply here
$dataProvider = new ActiveDataProvider([
'query' => $query,
'sort' => ['defaultOrder' => ['id' => SORT_DESC]],
'pagination' => [
'pageSize' => 10,
],
]);
return $dataProvider;
You have overridden 'sort' parameter of ActiveDataProvider. To keep default behaviour of Sort object and change defaultOrder property, create an instance, such as:
$sort = new \yii\data\Sort([
'attributes' => [
'profile.created_at',
],
'defaultOrder' => ['id' => SORT_DESC],
]);
// add conditions that should always apply here
$dataProvider = new ActiveDataProvider([
'query' => $query,
'sort' => $sort,
'pagination' => [
'pageSize' => 10,
],
]);

How to edit cell Zfdatagrid

how I can make editing row using ajax with zfdatagrid, thanks
ZF 1.11 -
My Bootstrap
protected function _initZfdatagrid()
{
$this->_config = new Zend_Config_Ini(APPLICATION_PATH .'/configs/grid.ini', 'production');
Zend_Registry::set('config', $this->_config);
if ( #isset(Zend_Registry::get('config')->site->jqGridUrl) ) {
Bvb_Grid_Deploy_JqGrid::$defaultJqGridLibPath = Zend_Registry::get('config')->site->jqGridUrl;
}
}
My Controller
public function indexAction()
{
$grid1 = new Bvb_Grid_Deploy_JqGrid(Zend_Registry::get('config'));
$this->configG1($grid1);
$grid1->setDeployOptions(array
('title'=>'Grado 10A',
'subtitle'=>'School2.0 : Matematicas:'.date('Y-m-d'),
'logo'=>$this->view->baseUrl.'/zfdatagrid/public/images/logotipo.jpg',
));
$this->view->grid = $grid1->deploy();
$this->render('index');
}
public function configG1 ($grid)
{
$select = $this->_db->select()->from('Articulos', array('id', 'titulo', 'fecha','nota', 'publicar', 'dependencia'));
$grid->setSource(new Bvb_Grid_Source_Zend_Select($select));
$grid->updateColumn('id',
array('title' => '#ID', 'hide' => true));
$grid->updateColumn('_action',
array('search' => false, // this will disable search on this field
'order' => 1, 'title' => 'Action', 'width' => 100, 'class' => 'bvb_action bvb_first', 'callback' =>
array('function' => array($this, 'g1ActionBar'), 'params' =>
array('{{ID}}')), 'jqg' =>
array('fixed' => true, 'search' => false)));
$grid->updateColumn('titulo', array('title' => 'Titulo Articulo', 'width' => 260));
$grid->updateColumn('fecha', array('title' => 'Fecha', 'searchType' => "="));
$grid->updateColumn('Nota', array('title' => 'Calificacion (ucase)', 'callback' => array('function' => create_function('$text', 'return strtoupper($text);'), 'params' => array('{{District}}'))));
$grid->setDefaultFilters(array('titulo' => '1'));
$grid->setExport(array(// define parameters for csv export, see Bvb_Grid::getExports
'csv' => array('caption' => 'Csv'),
'pdf' => array('caption' => 'Pdf')));
$grid->setJqgParams(array('caption' => 'jqGrid Example', 'forceFit' => true, 'viewrecords' => false, // show/hide record count right bottom in navigation bar
'rowList' => array(10, 20, 30, 40, 50), // show row number per page control in navigation bar
'altRows' => true)// rows will alternate color
);
$grid->setJqgParam('viewrecords', true);
$grid->jqgViewrecords = true;
$grid->setBvbParams(array('id' => 'ID'));
$grid->setBvbParam('id', 'ID');
$grid->bvbId = 'ID';
$grid->bvbOnInit = 'console.log("this message will not be logged because of call to bvbClearOnInit().");';
$grid->bvbClearOnInit();
$grid->bvbSetOnInit('console.log("jqGrid initiated ! If data are remote they are not loaded at this point.");');
$grid->setAjax(get_class($grid));
}
If you haven't gotten anywhere on this, you might want to look at the jqgrid wiki. They provide information on adding inline cell editing:
http://www.trirand.com/jqgridwiki/doku.php?id=wiki:cell_editing
as well as popup form editing:
http://www.trirand.com/jqgridwiki/doku.php?id=wiki:form_editing
According to the inline cell editing page, adding the cellEdit parameter should enable cell editing. You can provide the url the data is submit to with the cellurl parameter.