Create Virtual Fields on the Fly in CakePHP3 - cakephp-3.x

I'm trying to duplicate the answer to this question but in CakePHP 3: Search distance between 2 points CakePHP
How do I create virtual fields on the fly for CakePHP 3?
And here's my custom finder, which of course doesn't work because of the bad virtual field creation:
protected function findByDistance($lat, $long, $distance)
{
$distanceValue = $this->calcDistance($lat, $long, $this->_properties['latitude'], $this->_properties['longitude']);
$this->virtualFields['distance'] = $distanceValue;
return $query->where(['distance <=' => $distance]);
}

Related

How do i get data once in model and use the same data in multiple views passing through controller in laravel 8.x

For example, I want data from 3 models to MyModel4.
$model1data = MyModel1::getList();
$model2data = MyModel2::getList();
$model3data = MyModel3::getList();
Purpose of getting these data is to prepare my create view, edit view and show view based on above models data.
Now the issue I am facing is I can get the data using MyModel1::getList(); and pass it to my controller's create method. The same data I want for my controller's show and edit method. And for that again I have to get data using MyModel1::getList();. I want to optimize my code for less interaction with database/reduce redundant processing.
So is there any shorter method by which I can write it in my controller or in my model to get these data once and use it multiple times without getting data repeatedly from another model?
I have tried defining the separate method in the model but unable to access using a variable.
public static function getRequiredData()
{
$model1data = MyModel1::getList();
$model2data = MyModel2::getList();
$model3data = MyModel3::getList();
}
public static function prepareCreate()
{
return (object)array("model1" => PublishPlan::getRequiredData().$model1data, "viewModes" => ViewMode::getList(), "planSchemes" => PlanSchemes::getList());
}
I am getting an error while accessing $model1data in the above method(prepareCreate).
I think you should use a constructor for your issue.
public function __construct()
{
$model1data = MyModel1::getList();
$model2data = MyModel2::getList();
$model3data = MyModel3::getList();
}
with the constructor, you can access the lists in all methods of the same controller.
but if you want to access the same list in all controllers, you should define a static variable in Model1, Model2, and Model3.

Drupal 8 - Accessing a referenced entity through $fields (implementing validation on node creation)

Within a custom module, I'm working on validating a field based on an entry from another field. The validation works when the hash is hard coded (i.e. // $bookhash = 1;). However, I cannot seem to figure out how to access hash of the referenced book.
What's the proper way of accessing that data from book referenced within book_signatures?
use \Drupal\Core\Entity\EntityTypeInterface;
/**
* Implements hook_entity_bundle_field_info_alter().
*/
function custom_validation_entity_bundle_field_info_alter(&$fields, \Drupal\Core\Entity\EntityTypeInterface $entity_type, $bundle) {
if ($bundle === 'book_signatures') {
if (isset($fields['field_confirm_book_hash'])) {
$book = $fields['field_book']; // book is a referenced entity within book_signatures.
$bookhash = $book->field_hash_check; // need to set this equal to the hash in the book entity.
// $bookhash = 1; works with static hash. need specific books hash
$fields['field_confirm_book_hash']->addConstraint('BookHash', ['hash' => $bookhash]);
}
}
}
Edit: output from devel on the field $fields['field_book']. It's id outputs "node.book_signatures.field_book"
Taking a slightly different approach exposed both fields more elegantly.
/**
* Implements hook_entity_type_build().
*/
function custom_validation_entity_type_build(array &$entity_types) {
// Add our custom validation to the order number.
$entity_types['node']->addConstraint('BookHash');
}

Best method to check for duplicates in store function prior to saving

I have a team-based app where one database services multiple teams. We have a custom fields table which allows for each team to create their own custom fields they want to create in addition to the global fields universally available to every team. Each custom field record has a name, type, and church_id field in the create.blade input form. Now with the nature of having separate teams, we need a system where they could create their own custom field that might share the same name of a custom field created and connected to another church team. This has been done and works just fine.
The problem is that we need to also make it so that only one custom field by a specific name can be created within the same church team. We do not want duplicate fields within the same church team. And herein lies my question, what is the best way in the store function to keep duplicates from occurring within the same team-based records. I have looked at firstOrNew, firstOrCreate, and updateOrCreate but which one is best suited to my need.
As I said, the fields we have in the form are 'name', 'type', and 'church_id' and these correspond to the custom field DB fields as 'name', 'type', and 'created_by_team_id'. What I need to have happen is for the system to check to see if there is a record matching the input 'name' that shares the same 'created_by_team_id' as the input 'church_id. If there is a record by that 'name' which also shares a marching 'id' then the system recognizes that as a duplicate and does NOT create a new record in the DB. But, if there is a record that shares the same 'name' but does not share the same 'created_by_team_id/church_id' then the system goes ahead and creates that new record because it is not a duplicate.
This is my create function:
{
if (! Gate::allows('custom_field_create')) {
return abort(401);
}
if (auth()->user()->role->contains(1)) {
$churches = Team::all();
$churchArr = array('empty' => 'Please select a church...');
foreach ($churches as $church) {
$churchArr[$church->id] = $church->name;
}
$churches->created_by_id = auth()->user()->id;
$church_id = null;
} else {
$churches = false;
$church_id = auth()->user()->team_id;
$churchArr = [];
}
return view('admin.custom_fields.create', compact('churches', 'churchArr', 'church_id'));
And this is my store function:
{
if (! Gate::allows('custom_field_create')) {
return abort(401);
}
$custom_field = CustomField::create($request->all());
$custom_field->created_by_team_id = $request->input('church_id');
$custom_field->save();
return redirect()->route('admin.custom_fields.index');
As I stated, I have been looking at and trying the firstOrNew, firstOrCreate, and updateOrCreate methods but all my attempts have been a failure. What would be the proper way to implement one of these methods to achieve my goals using my fields and DB criteria to avoid creating duplicate fields by the same name within the same team-based id?
I found the workable solution to be updateOrCreate. This allows the use of both 'name' and 'type' to be needing to be found to match. If either one is found but not the other it will create a new record. If both are found it just updates the record, which by nature avoids the duplicate creation. This allows the 'church_id' field to just added on as a filler rather than using it as one of the fields keyed on to.
$custom_field = CustomField::updateOrCreate(['name' => $request->input('name'), 'type' => $request->input('type')]);
$custom_field->created_by_team_id = $request->input('church_id');
$custom_field->save();

Algolia Restrict Index's data

I am trying to create a new index in Algolia which is identical with my first index but will have a different data from my first index. I want to have a contacts index for NZ and another for AU.
I used indexOnly($index_name) with a condition inside this function. But it is not working properly and I don't know if this function is what I need.
This is how I am creating it
class Contact extends Model {
use AlgoliaEloquentTrait;
protected $table = 'contacts';
public $indices = ['contacts_local'];
/** ALGOLIA SETTINGS */
public function getAlgoliaRecord()
{
return fractal()->item($this)->transformWith(new ContactTransformer)->toArray();
}
private $index_name = 'contacts_local';
public function indexOnly($index_name) {
return $this->contact_country == 'New Zealand';
}
}
I then run the reindex function.
The above method returns nothing in my contacts_local index.
Anything i'm doing wrong here?
I am using the same table in my database but the two indices will have different data depending on the country of the contact. Would this be possible in Algolia?
I'm not sure this is doable with the Algolia Laravel/Eloquent integration. What I would do instead is:
push all the records/contacts to the same (unique) index
tag the records with their associated countries (in the _tags attribute)
use Algolia's Secured API Keys to hash-generate some keys that are restricted to a specific countries using the tagFilters (https://www.algolia.com/doc/guides/search/filtering-faceting#filter-by-tag)
This will be easier and as fast as having 1 index per country.

Eloquent Ordering Related Data

I am using Eloquent Repository to get a 'menu' by ID, and return all the associated 'menuitems' along with it. This is working fine, but I am having an issue reordering the 'menuitems' by one of their fields. So I am currently doing:
$menu = $this->menuRepo->getById($id, 'menuitems');
which calls this function within the Eloquent Repo:
public function getById($id, $with = false)
{
if ($with)
{
return $this->model->withTrashed()->with($with)->findOrFail($id);
}
return $this->model->withTrashed()->findOrFail($id);
}
That function is being used throughout the system, so ideally I want to leave that as it is - or would need to change it so that it would not break in all the current usages. But even so, when I tried to add a
->orderBy('name')
within there it applies to 'menu' and not 'menuitems'.
Your with($with) needs to be rewritten, so that it uses relationship constraints:
...->with($with => function($query){
$query->orderBy('name','asc');
})->...

Resources