Working with database parameters in session variables - laravel

I'm doing a project where I work with multiples databases.
The databases are dynamic, so in a general table (in my project database) I keep the names of the databases with which to work. On the initial screen (after login) I show the databases to choose which one to work with (multi-store site type, you choose the store and enter with its database). I do this by setting a session variable in the controller:
public function shopselect($id) {
if ($id != 0)
{
$shop = Shop::find($id);
Config::set('database.connections.tienda.database', $shop->database);
DB::reconnect('tienda');
Session::put('shop', $shop->id);
Session::put('shopname', $shop->name);
Session::put('shopdatabase', $shop->database);
}
else
{
Session::remove('shop');
Session::remove('shopname');
Session::remove('shopdatabase');
}
return redirect(route('dashboard'));
}
I call this function from two places.
First: in the view, in a dropdown where I show the user's data to choose another store, what I do is eliminate the variables.
Seleccionar otra tienda
Logically I declared this route in the routes file
Route::get('shopselect/{shop}', [App\Http\Controllers\ShopController::class, 'shopselect'])->name('shopselect');
Now, in the models, I have this constructor:
public function __construct()
{
Config::set('database.connections.tienda.database', Session::get('shopdatabase'));
DB::reconnect('tienda');
}
And in the Form Request I repeat those two lines of code, where I need to retrieve data from the database, for example for the records that must be 'unique'
public function rules()
{
Config::set('database.connections.tienda.database', Session::get('shopdatabase'));
DB::reconnect('tienda');
if ($this->method() == 'PUT')
{
return [
'name' => 'required',
'dni' => 'nullable|unique:tienda.customers,dni,'.$this->customer,
'address' => 'string|nullable',
...
I think I could simplify it by setting a Config::set to the database parameters, but would that work for multiple users? or the last one chosen by the database will save these parameters in the configuration file?

Related

Creating new 'belongs-to' relation in Laravel with form requests

I am new to Laravel and can't quite wrap my head around the Form Requests and how to use them. In simple cases, it's simple enough but what I need is a conditional creation of a related model before progressing with the rest of the request. Let me explain.
//Job model
job_id PK
client_id
some_field
//Client model
client_id
external_id
name
Now in my Create Job interface, I have a Select2 combo box that uses AJAX to search 2 different sources and can produce 3 different results.
So, say I am creating new Job and can have a POST looking like any of these:
Script found a Client with id 21, we just want to save, it all is simple
'client_id' => 21
'some_filed' => Whatever
OR
Script didn't find a Client but we did a search of external API and returned this Identifier, which I can then parse to create a new Client. This needs to be done before I save Job as I need to have a client_id ready for it
'client_id' => '196c3c7e34cde1d4593391ddf1901fd7'
'some_filed' => Whatever
OR
Script finds neither local Client nor a remote datapoint so we want to create a new Client using just the name provided. Of course this has to happen before saving the Job
'client_id' => 'My new client name'
'some_filed' => Whatever
Where do I perform all this functionality?
My first procedural guess would be to stick $data['client_id'] = Client::HandleClientAndReturnId($data['client_id']) in StoreJob's validationData() before returning the result.
But how would I handle/report possible validation issues with creating new Client and how to manage transaction - I don't want to create a Client if validation of Job fails.
I am using Form Requests and actually am parsing several models in the request already, but those are HAS_ONE type of relationships so I create them after the Job. Here I need to reverse the process. Here is what I have in my controller, if that is of any use:
class JobController extends Controller
{
public function store(StoreJob $request, StoreJobDataAdd $request_2, StoreJobDataSup $request_3)
{
$job = Job::create($request->validated());
if ($_POST['add_on']) {
$job->dataAdd()->create($request_2->validated());
}
if ($_POST['sup_on']) {
$job->dataSup()->create($request_3->validated());
}
return new JsonResponse([
'success' => true,
'message' => __('New Job has been created.')
]);
}
}
Here are my relations:
class Job extends Model
{
public function dataAdd()
{
return $this->hasOne(JobDataAdd::class, 'job_id', 'job_id');
}
public function dataSup()
{
return $this->hasOne(JobDataSup::class, 'job_id', 'job_id');
}
public function client()
{
return $this->belongsTo(Client::class, 'contact_id', 'contact_id_client');
}
}
I have a feeling I am missing the right way to do it but not quite sure where to look for the answers so please point me in the right direction.
Clarification:
The objective of the whole exercise is to allow users to create new Clients or select existing by using one combobox. It's a Select2 box. For unfamiliar - a dropdown replacement that has an ability to free-type a string that is used to search for existing records and if not found it sends to the server what user typed in. Something like a dynamic dropdown with ability to search and add options by the user.

Check if model belongs to other model

In my application, I have users that are connected to businesses. These businesses have job offers. When a user wants to edit a business' job offer, the url will be like /business/foo/job/bar. When I change the business variable to the name of a different one, like this: /business/other-business/job/bar I still get the job called bar even though it does not belong to the business. I tried to use gates to check if the job offers belong to the business but it didn't work. Below is the code for the edit function which shows the edit page.
public function edit(Business $business, Job $job)
{
return view('dashboard.business.jobs.edit', [
'business' => $business,
'job' => $job,
]);
}
I can add the following code to all the functions but it is not very pretty
if($business->id !== $job->business->id) { return abort(404); }
I was wondering if there is a better solution to this problem.
Well you can choose between
if($business->jobs->contains($job->id)) return redirect()->to("somewhere");
or
if($job->business->is($business)) return redirect()->to("somewhere");
The second one is more efficient because you have to retrive from the database just one record to check if they are correlated, the business record, where the first one instead you have to retrive all the jobs of that business.
Those solution in my opinion are actually very clear, you can literally read them and understand what you are doing.
Also if you want just one line of code, you can do this:
public function edit(Business $business, Job $job)
{
return
$job->business->is($business)
?
view('dashboard.business.jobs.edit', [
'business' => $business,
'job' => $job,
])
:
return redirect()->to("somewhere");
}

How to call several actions from within another action?

I'm migrating a non-MVC application to Laravel 4.2 and I'm unsure of the best way to accomplish this task. I have several reports created on routes like this:
/reports/this_report
/reports/that_report
/reports/another_report
These actions query the database, run a bunch of calculations, and generate some html tables and forms.
What I need to add now is a page like this:
/reports/dashboard
This dashboard page should display the output of all 3 reports in a condensed format, each with a "click to view details" link that takes the user to the main report page.
Is there a way for the dashboard action to call each of the report actions, and use their output as data in the dashboard view?
Here's a little code of how you would do this. I'm not exactly sure how you have everything structured, so you might have to adapt this a little.
Lets say you have a route for the dashboard like this.
Route::get('/reports/dashboard', DashboardController#showDashboard');
This route should call a controller method that will do your processing.
class DashboardController extends BaseController
{
public function showDashboard()
{
return View::make('dashboard')->with(array(
'report1_data' => $this->getReport1Data(),
'report2_data' => $this->getReport2Data(),
'report3_data' => $this->getreport3Data()
));
}
public function getReport1Data() { //calculations, return array of results }
public function getReport2Data() { //calculations, return array of results }
public function getReport3Data() { //calculations, return array of results }
public function showThisReport()
{
$data = $this->getReport1Data();
return View::make('report')->with(array('data' => $data));
}
public function showThatReport()
{
$data = $this->getReport2Data();
return View::make('report')->with(array('data' => $data));
}
public function showAnotherReport()
{
$data = $this->getReport3Data();
return View::make('report')->with(array('data' => $data));
}
}
So, this dashboard method will call the other methods (that you will also include in this controller) that will query the database and calculate the reports.
Then it returns a View with all of the data. The view will format the data and display it to the user.
Now, to make it so you can see the detailed view of each report, I suggest adding a couple more methods and routes to show detailed views.
Route::get('/reports/this_report', 'DashboardController#showThisReport');
Route::get('/reports/that_report', 'DashboardController#showThatReport');
Route::get('/reports/another_report', 'DashboardController#showAnotherReport');
I hope this helps! Good luck.

Custom Magento Module

So im creating a module in the backend, I have a shell module created (items in admin top menu and a page to visit.) basically I want to have an input field that the admin can type a number into then click a button "add", this will insert a row into an existing table in the database.
$connection = Mage::getSingleton('core/resource')->getConnection('core_write');
$connection->beginTransaction();
$fields = array();
$fields['name']= 'andy';
$connection->insert('test', $fields);
$connection->commit();
I have a table called "test" within my database. If I put the above code into my Controller file, it successfully adds a row to the database when i visit the admin page. But i need to allow the user to input the data that is inserted.
Would I have to move that code into the Model and somehow send the input data to the Model and let that do the work? or not. If this is correct could someone point me to a good place to research sending data to models? (if thats even possible)
iv tried lots of tutorials but they are all way to big for what I need, I dont need to display anything, I just need to have an input box and a save button.
EDIT
i have created a file block/Adminhtml/Form/Edit/Form.php which contains the following . . .
class AndyBram_Presbo_Block_Adminhtml_Form_Edit_Form extends Mage_Adminhtml_Block_Widget_Form
{
protected function _prepareForm()
{
$form = new Varien_Data_Form(
array(
'id' => 'edit_form',
'action' => $this->getUrl('*/*/test'),
'method' => 'post',
)
);
$form->setUseContainer(true);
$this->setForm($form);
$fieldset = $form->addFieldset('display', array(
'legend' => 'Display Settings',
'class' => 'fieldset-wide'
));
$fieldset->addField('label', 'text', array(
'name' => 'label',
'label' => 'Label',
));
if (Mage::registry('andybram_presbo')) {
$form->setValues(Mage::registry('andybram_presbo')->getData());
}
return parent::_prepareForm();
}
}
then in my controller i have 2 functions like below . . .
public function indexAction()
{
$this->loadLayout();
$this->_addContent($this->getLayout()->createBlock('presbo/adminhtml_form_edit_form'));
}
public function testAction()
{
echo 'form data here';
$this->loadLayout();
$this->renderLayout();
}
the form is displayed successfully but there is no button to send or say 'do an action'
Further Edit
i have successfully added a submit button to the form that successfully goes to the testAction and echo' "form data here".
how do i then access the data,
iv added the below line
$postData = $this->getRequest()->getPost();
now if i echo $postData, it just puts "array"
if i echo $postData[0] it doesnt put anything just a blank page
any ideas or pointers?
Magento is built as an MVC framework, thus you're right - you need to pass data from controller to the model, and do not do any DB updates directly in a controller's code. The best source for an example is the own Magento code - you can take any controller action, which saves data to DB to see, how it is done. E.g. check app/code/core/Mage/Adminhtml/controllers/NotificationController.php method markAsReadAction().
There you can see, that:
Data is retrieved from the request by calling
$this->getRequest()->getParam('id') - actually this is the answer
to the question, how to get the submitted data
Data is set to model, and then saved to the DB via call to the
$model->setIsRead(1)->save()
It is strongly encouraged to follow the same approach of working with models. This makes codes much better and easier to support.
Note, that "M" letter of "MVC" architecture in Magento is represented by two layers: Models and Resource Models.
Models:
Contain business logic of an entity. E.g. adding ten items to a
Shopping Cart model triggers a discount rule
Represented by classes with a general name of <Your_Module>_Model_<Model_Name>
If need to work with DB, then extend Mage_Core_Model_Abstract and have a Resource
Model, which is responsible for DB communication
Do not need to have basic save/load methods to be implemented, as the ancestor
Mage_Core_Model_Abstract already has all that routines ready to use
Created via call to Mage::getModel('<your_module>/<model_name>')
Resource Models:
Serve as DB abstraction layer, thus save/load data from DB, perform
other DB queries
Extend Mage_Core_Model_Resource_Db_Abstract in order to communicate with DB
Represented by classes with a general name of
<Your_Module>_Model_Resource_<Model_Name>
Automatically created by a corresponding model, when it needs to communicate with DB
So, in a controller you care about creating Models only. Resource Models are created by a Model automatically.
And, according to everything said above, your controller should look like:
public function testAction()
{
$model = Mage::getModel('your_module/your_model');
$model->setName('andy');
$model->save();
}
You can download a fully working example of the thing you need here.
There can be several variations to the code provided, depending on your specific case. But it represents a general approach to implementing the thing you want.

How to avoid errors in saving data - Cakephp

I'm using Cakephp and trying to put in a method to make sure our reservation system doesn't let two users book the same appointment. Ex. User 1 opens the appointment, and User 2 opens it simultaneously. User 1 books the appointment. User 2 tries to book it but the system checks and sees it is no longer available.
I imagine this would take place in validation, or in a beforeSave(), but can't figure out how to do it.
Right now I made a function in the model to call from the controller. In the controller I have:
if ($this->Timeslot->checkIfNotAvailable()) {
$this->Session->setFlash('This timeslot is no longer available');
$this->redirect(array('controller' => 'users', 'action' => 'partner_homepage'));
}
and in the model I have this function:
function checkIfNotAvailable($data) {
$this->recursive = -1;
$timeslot = $this->find('all', array(
'conditions' => array(
'Timeslot.id' => $this->data['Timeslot']['id'])
)
);
if ($timeslot['student_id'] == 0) {
//They can reserve it, do not spring a flag
return false;
} else {
//Throw a flag!
return true;
}
}
I think I'm mixed up using custom validation when it's not called for. And it's not working obviously. Any suggestions?
Thanks!
If what you have is working, you can stick with it, you could also try creating a beforeValidate() call back function in your Model.
class YourModel extends AppModel {
function beforeValidate(){
if( !$this->checkIfNotAvailable( $this->data ) ) {
unset($this->data['YourModel']['time_slot']);
}
return true; //this is required, otherwise validation will always fail
}
}
This way you remove the time_slot before it goes to validation and it will drop a validation error at that point, kicking the user back to the edit page and getting them to pick a different time slot, ideally the updated data entry page will no longer have the used time slot available.

Resources