CakePHP 3 - Exclude fields by default in query unless specifically selected - select

Title pretty much says it all. I have some tables with fields that contain a lot of data. To save some performance I would like to not SELECT these by default.
The emphasis on the new default behaviour, differentiating the question from e.g. Select all except one field in cakephp 3 query
Example:
$cities = $this->Cities->find();
// A $city does not include the field `shape` (which is a huge polygon)
$cities = $this->Cities->find(['id', 'name', 'shape']);
// A $city now does include the `shape` property
I looked at the accessible and hidden properties of an entity, but these don't seem to affect the SELECT statement.
EDIT: The selectAllExcept query seems usefull. I combined this with the beforeFilter event like this:
public function beforeFind($event, $query, $options, $primary)
{
$query->selectAllExcept($this, ['shape']);
}
This works well for empty queries, shape is now excluded. But now I have no control over the other fields that might want to include or not:
$this->Cities->find()->select(['id', 'shape']) will then also select the other fields because the selectAllExcept().

You can simple overwrite find('all') method in your table.
For example in UsersTable:
public function findAll(Query $query, array $options)
{
$query->selectAllExcept($this, ['password']);
return $query;
}
then in your controller:
// select all except password
$users = $this->Users->find();
debug($users);
OR
// we try to select some fields, without success
$users = $this->Users->find()->select(['id', 'username', 'password']);
debug($users);
OR
// we try to select some fields incl. password, with success
$users = $this->Users->find()->select(['id', 'username', 'password'], true); // <-- this overwrite select / selectAllExcept in custom finder
debug($users);

Related

Add a Field to a CrudController that ONLY passes values to Store / Update Methods

I'm trying to handle how a field within a CrudController stores or updates the data on the particular model in a completely custom way. I would like the traitStore() and traitUpdate() methods to ignore this field entirely, but would like the data to still be passed in via the request. This is specifically in reference to a many-many relationship using a select2_multiple field.
I would like it so that the relationship ID's are passed via the request object to the Store or Update methods, but I DO NOT want the traitStore() or traitUpdate() methods to actually perform updates on that particular field reference.
For example...
I have this field within my crud controller
$this->crud->addField(
[
'label' => "Groups",
'type' => 'select2_multiple',
'name' => 'groups',
'entity' => 'groups',
'attribute' => 'title',
'model' => "App\Models\Group",
'pivot' => true
]
);
And I'm overriding the Store and Update Methods like so.
public function store()
{
$this->crud->setValidation(UserRequest::class);
// WOULD LIKE TO SAVE EVERYTHING BUT IGNORE THE GROUPS FIELD
$response = $this->traitStore();
// DO WHATEVER I WANT WITH GROUPS AT THIS POINT
$groups = $request->groups
return $response;
}
public function update()
{
$this->crud->setValidation(UserRequest::class);
// WOULD LIKE TO SAVE EVERYTHING BUT IGNORE THE GROUPS FIELD
$response = $this->traitUpdate();
// DO WHATEVER I WANT WITH GROUPS AT THIS POINT
$groups = $request->groups
return $response;
}
Looking at my comments I would like to get a reference to the groups and handle updating the model however I want.
I've tried to unset the groups value in the request, unset($this->request{'groups'}), but it still updates / removes the relationships when I do that.
Here is what you need to do to remove the references from being updated by the CrudController.
public function update()
{
$this->crud->setValidation(UserRequest::class);
$request = clone $this->request;
$this->crud->request->request->remove('groups');
$this->crud->removeField('groups');
$groups = $request->groups
$response = $this->traitUpdate();
return $response;
}
I found an easy way to ignore/pass form field.
Example:
In your form fields have first_name, last_name, gender and in your database is only have fullname, gender then you wanna create/update the form, it will show Column not found: 'first_name' not found...,
How to fix it:
Add $fillable in the model and fill the array data with name field that you want to store/update. In example case $fillable = ['fullname', 'gender'];
Then, just use mutators inside the model too.
public function setFullnameAttribute(){
return $this->attributes['fullname'] = \Request::input('first_name') . ' ' . \Request::input('last_name');
}
NB: You should have hidden field name 'fullname' in your CrudController.
$this->crud->addField(['name' => 'fullname', 'type' => 'hidden']);

Gravity Forms - Dynamically populate a drop down based on entries from another gravity form

So I am looking at dynamically populating a drop down field in a form with entries from another gravity form. Based on that choice, I will populate a second drop down dynamically based on entries from a gravity form.
More or less I am creating the ability to submit a work order. In that work order I want users to select a piece of equipment then based on that piece of equipment they can select a part.
I have looked at gform_get_entries_args_entry_list as a way of snagging entries, but I am not overly sure how to set it so it pulls from a particular form.
add_filter( 'gform_get_entries_args_entry_list', 'machine' );
function populate_posts( $form ) {
foreach ( $form['fields'] as &$field ) {
$items = gform_get_entries_args_entry_list( 'NOT SURE WHAT TO PUT HERE' );
$choices = array();
foreach ( $items as $GRAVITY FORM ENTRY VARIABLE) {
$choices[] = array( 'text' => $GFEV->THE MACHINE NAME, 'value' => $GFEV ->The Name Field of the machine );
}
$field->placeholder = 'Select a Post';
$field->choices = $choices;
}
return $form;
}
The Gravity Forms Dynamic Population Pro plugin uses the GFAPI:get_entries function, which you can just directly pass the form ID.
Here's the definition:
public static function get_entries( $form_ids, $search_criteria = array(), $sorting = null, $paging = null, &$total_count = null )

F3 ORM add new record omitting some fields

I have a postgres table in which I have some "defaulted" fields like date_created which automatically receives a current_timestamp as default.
or the ID field which gets it's value from a sequence defined in the database.
What would be (if possible) the syntax to tell the ORM module to not include these two fields when generating an INSERT statement ?
You can use a function as 2nd parameter to remove the fields:
$this->copyfrom('POST',function($val) {
unset($val['ID']);
unset($val['date_created']);
return $val
});
or to only copy allowed fields from the POST array:
$this->copyfrom('POST',function($val) {
return array_intersect_key($val, array_flip(array('name','age')));
});
Assuming you are using an HTML form to add new records into the tables, follow the steps below;
In the form, omit these 'defaulted' fields, i.e. add only the fields that you want to submit
Create a model with a function similar to below
public function add() {
$this->copyFrom ( 'POST' );
$this->save ();
}
Create a route that links the form to this function

How to sort elasticsearch results by distance?

I'm using elasticabundle for symfony2 and I want to sort results I'm seeking by distance
I'm new to elasticsearch and I don't know how I can start
the query I'm using :
$c = $this->container->get('fos_elastica.finder.cities_index.cities');
$nameQuery = new \Elastica\Query\Match();
$nameQuery->setFieldQuery('tokens', $city);
$nameQuery->setSort(array("distance" => "asc"));// I want to achieve this
Thanks for your time
here is what I did following the example as provided by Dimitris Tsarouhas
The following setup allows to filter by keyword, order by id, and add all sort of other filtering using the $boolQuery ->addMust($yourfilter) formula.
We fetch the keyword as posted by a form. This is $data['query'] and by default we use it to perform a _all search, thus searching throughout all the fields listed in our config.yml file. To perform this search, we use the QueryString object, as this allows us to use wildcards.
We then look if exists the variable $data['status'], which comes through a dropdown select box (please note the use of strtolower(), without which the query wouldn't work - either that or you set up your own case-insensitive analyzer). If so, we use it to filter our results.
By default, we also want to narrow down our search and pick up only active users.
$data = $form->getData();
$finder = $this->container->get('fos_elastica.finder.search.user');
$keyword = $data['query'];
$status= $data['status'];
$keywordQuery = new QueryString;
$keywordQuery->setQuery('*' . $keyword . '*');
$query = new Query();
$query->setQuery($keywordQuery);
$query->setSort(array('id' => array('order' => 'asc')));
$boolQuery = new Bool();
$active= new Term();
$active->setTerm('active', true);
$boolQuery ->addMust($active);
if (!empty($status)) {
$statusQuery = new Term();
$statusQuery->setTerm('status', strtolower($status->getName()));
$boolQuery ->addMust($typeQuery);
}
$query->setFilter($boolQuery);
$entities = $finder->find($query);
And of course do not forget to import the necessary libraries:
use
Elastica\Query\QueryString,
Elastica\Query,
Elastica\Filter\Bool,
Elastica\Filter\Term
;
Remember that to be able to perform actions on fields (searching, sorting, etc) these haveto be included in your config.yml. Of course, this would cause the field to be automatically picked up when searching generally onto a certain entity. So, if you need to avoid this, but you still need certain fields to be available to elastica. just define it as showed below:
user:
mappings:
name: ~
surname: ~
status: ~
active: { include_in_all: false }
id: { include_in_all: false }

Doctrine 2 + Zend Form - Populate Dynamic Select Menus

I'm building a Zend form that has a dropdown/select menu populated with data from a Doctrine 2 query.
In my repository class, I have the following query in a method named selectUser():
$query = $em->createQuery('SELECT u.id, u.name FROM XX\Entity\Users u ORDER BY u.name ASC');
$users = $query->getResult();
This returns a multidimensional array, which I'm trying to loop through like this (within the same method):
$options = array();
foreach ($users as $key => $value) {
$options[$value['id']] = $value['name'];
}
return $options;
Then in my Zend form class, I try to populate the Select element like this:
$id = new Zend_Form_Element_Select('id');
$options = $this->usersRepository->selectUser();
$id->AddMultiOptions($options);
The result is an error for each user row that states "Undefined index: [name] in ...UsersRepository.php..." where [name] is the value of the 'name' column in each row.
Does anyone see what I'm doing wrong or how to populate a dynamic select menu using Doctrine 2 and Zend Framework?
(By the way, in order to run the repository method, the form class has protected properties representing the Doctrine container, entity manager, and Users repository. If this isn't considered best practice, I'd welcome any suggestions on improving my technique.)
I think your problem is here
$options[$value['id'] = $value['name']];
this would be better
$options[$value['id']] = $value['name'];