I'm having a problem using methods in my module's model class.
I have a public function which triggers 2 protected methods. The problem is that only the first 1 returns a value.
Here is my class:
<?php
class Osdave_Points_Model_Mysql4_Points_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract
{
const POINTS_CONFIRMED = 2;
const POINTS_REDEEMED = 4;
protected $_customer;
public function _construct()
{
parent::_construct();
$this->_init('points/points');
$this->_customer = Mage::getSingleton('customer/session')->getCustomer();
}
public function getCustomerAvailablePoints()
{
$confirmed = $this->_getCustomerConfirmedPoints();
$redeemed = $this->_getCustomerRedeeemedPoints();
$balance = ($confirmed - $redeemed);
return $balance;
}
protected function _getCustomerConfirmedPoints()
{
$availablePoints = $this->addFieldToFilter('customer_id', $this->_customer->getId())
->addFieldToFilter('points_status', self::POINTS_CONFIRMED)
->addFieldToSelect('points_pending')
->addExpressionFieldToSelect('available_points', 'SUM({{points_pending}})', 'points_pending');
return $availablePoints->getFirstItem()->getAvailablePoints();
}
protected function _getCustomerRedeeemedPoints()
{
$redeemedPoints = $this->addFieldToFilter('customer_id', $this->_customer->getId())
->addFieldToFilter('points_status', self::POINTS_REDEEMED)
->addFieldToSelect('points_pending')
->addExpressionFieldToSelect('redeemed_points', 'SUM({{points_pending}})', 'points_pending');
return $redeemedPoints->getFirstItem()->getRedeemedPoints();
}
}
Now, if, in _getCustomerRedeeemedPoints(), I replace $this by Mage::getResourceModel('points/points_collection') it works fine. But as I already am insdide the class, I don't understand why I have to instance it through Mage: as far as I understand, $this is only available once.
So, am I doing something wrong?
thanks in advance.
I'm guessing this has to do with adding filters to the $this object for different purposes. Try adding this to the top of your methods:
$this->getSelect()->reset();
If that doesn't work, try echoing your queries before your getFirstItem calls and see if they behave as expected:
Mage::log($this->getSelect()."");
Hope that helps!
Thanks,
Joe
Related
I use in my model code to get a relation
class User extends Authenticatable
{
// ...
public function extensions()
{
return $this->belongsToMany(Extension::class, 'v_extension_users', 'user_uuid', 'extension_uuid');
}
// ...
}
The Extension has field password hidden.
class Extension extends Model
{
// ...
protected $hidden = [
'password',
];
// ...
}
Under some circumstances I want to makeVisible the password field.
How can I achieve this?
->makeVisible([...]) should work:
$model = \Model::first();
$model->makeVisible(['password']);
$models = \Model::get();
$models = $models->each(function ($i, $k) {
$i->makeVisible(['password']);
});
// belongs to many / has many
$related = $parent->relation->each(function ($i, $k) {
$i->makeVisible(['password']);
});
// belongs to many / has many - with loading
$related = $parent->relation()->get()->each(function ($i, $k) {
$i->makeVisible(['password']);
});
Well, I got the idea from https://stackoverflow.com/a/38297876/518704
Since my relation model Extension::class is called by name in my code return $this->belongsToMany(Extension::class,... I cannot even pass parameter to it's constructor.
So to pass something to the constructor I may use static class variables.
So in my Extension model I add static variables and run makeVisible method.
Later I destruct the variables to be sure next calls and instances use default model settings.
I moved this to a trait, but here I show at my model example.
class Extension extends Model
{
public static $staticMakeVisible;
public function __construct($attributes = array())
{
parent::__construct($attributes);
if (isset(self::$staticMakeVisible)){
$this->makeVisible(self::$staticMakeVisible);
}
}
.....
public function __destruct()
{
self::$staticMakeVisible = null;
}
}
And in my relation I use something like this
class User extends Authenticatable
{
...
public function extensions()
{
$class = Extension::class;
$class::$staticMakeVisible = ['password'];
return $this->belongsToMany(Extension::class, 'v_extension_users', 'user_uuid', 'extension_uuid');
}
...
}
The highest voted answer didn't seem to work for me (the relations attribute seems to be a protected array now so can't be used as a collection in #DevK's answer), I instead used:
$parent->setRelation('child', $parent->child->first()->setVisible(['id']));
I have a class called SubjectData:
class SubjectData extends Model
{
protected $table = 'subject_datas';
protected $fillable = ['firstname','lastname','birthdate','birthcity','months'];
protected $dates = ['birthdate'];
public function setBirthdateAttribute($date)
{
// So we can add the time, not just he php date
$this->attributes['birthdate'] = Carbon::createFromFormat('d/m/Y', $date);
}
public function anamnesis() {
return $this->belongsTo('App\Anamnesis');
}
}
And I have a class called Anamnesis:
class Anamnesis extends Model
{
public function meetingTest() {
return $this->belongsTo('App\MeetingTest');
}
public function subject() {
return $this->belongsTo('App\Subject','subject_id','id');
}
public function subjectData() {
return $this->hasOne('App\SubjectData');
}
public function scholarHistory() {
return $this->hasOne('App\ScholarHistory');
}
public function familyHistory() {
return $this->hasOne('App\FamilyHistory');
}
public function psicodiagnosis() {
return $this->hasOne('App\Psicodiagnosis');
}
}
The store function of the SubjectController class works like this:
public function store(CreateSubjectRequest $request)
{
$input = $request->all();
// Let's generate the anamnesis of the subject
$anamnesis = Anamnesis::create();
$anamnesis->save();
$newSubjectData = $this->saveSubjectData($input);
$anamnesis->subjectData()->save($newSubjectData);
......
......
}
where the function called is:
public function saveSubjectData($input)
{
$subjectData['firstname'] = $input['firstname'];
$subjectData['lastname'] = $input['lastname'];
$subjectData['birthcity'] = $input['birthcity'];
$subjectData['birthdate'] = $input['birthdate'];
return SubjectData::create($subjectData);
}
The problem is with the "birthdate" property.
If i check the value of $newSubjectData (dd($newSubjectdata)) after the call $this->saveSubjectData($input) the value of the birthdate is exactly the one i set on the calendar in the frontside (and also in the db the value is correct)
If I put the dd($anamnesis->subjectData) after the call $anamnesis->subjectData()->save($newSubjectData) the result is the "today" date and also in the DB the value is not the one I set but the date of today.
I can't find the error
P.S. The calendar is inside a Vue template
I think the problem is that, the date must be an instance of Carbon or is properly formatted according to your database table. Try the following inside your saveSubjectData() method
$subjectData['birthdate'] = Carbon\Carbon::parse($input['birthdate']
I write down the answer but i thank John Aldrin that guided me in the right direction.
You have to put the timestamp('birthdate') AFTER the default timestamps of the migration table (so at the end of the migration table)
I don't know why. If someone knows please explain !
I'm working with the M2e extension for Magento. Now I want to call a method of the class Ess_M2ePro_Adminhtml_ListingController in the file app/code/community/Ess/M2ePro/controllers/Adminhtml/ListingController.php.
But I don't know, how. I can't create an object or model to get access to the class to use the methods. Maybe it's not a good idea to call this controller methods directly, but in my case (remove a associated magento product to an ebay listing) it's required to call this methods.
In general these actions are called from the magento backend. I've also tried to create an admin_html session, but at the moment I don't have any further ideas.
Here's an example, how it looks like. I'm working with regular PHP-code, nothing special:
class Ess_M2ePro_Adminhtml_ListingController extends Ess_M2ePro_Controller_Adminhtml_MainController
{
//#############################################
protected function _initAction()
{
/** removed **/
}
protected function _isAllowed()
{
return Mage::getSingleton('admin/session')->isAllowed('m2epro/listings/listing');
}
//#############################################
public function indexAction()
{
/** removed **/
}
//#############################################
public function searchAction()
{
/** removed **/
}
public function searchGridAction()
{
/** removed **/
}
public function lockListingNowAction()
{
$listingId = (int)$this->getRequest()->getParam('id');
$component = $this->getRequest()->getParam('component');
$lockItemParams = array(
'id' => $listingId,
'component' => $component
);
$lockItem = Mage::getModel('M2ePro/Listing_LockItem',$lockItemParams);
if (!$lockItem->isExist()) {
$lockItem->create();
}
exit();
}
}
And I'm looking for something like this:
$test = Mage::getModel('M2ePro/Ess_M2ePro_Adminhtml_ListingController')->lockListingNowAction();
You shouldn't call methods from an other controller. Specially in your case, when you have exit at the end of the method.
You can use the _forward method if you are in a controller:
$this->_forward($action = 'lockListingNowAction', $controller = 'adminhtml_listing', $module = 'M2ePro', $params = array('id'=>$id)) //controller name may be different
But the cleanest way is to have the code you need in a helper and call the code from that helper in both controllers.
I've tried to understand a process of saving a model with multiple relationships but I still can't figure out how to do it "kosher" way.
To begin with - I have an Event model that belongs to a category (Eventcat) and a Location:
// Event.php
class Event extends Eloquent {
protected $table = 'events';
public function location()
{
return $this->belongsTo('Location');
}
public function eventcat()
{
return $this->belongsTo('Eventcat');
}
public function users()
{
return $this->belongsToMany('User');
}
}
// Location.php
class Location extends Eloquent
{
protected $table = 'locations';
public function events()
{
return $this->hasMany('Event');
}
}
// Eventcat.php
class Eventcat extends Eloquent
{
protected $table = 'eventcats';
public function events()
{
return $this->hasMany('Event');
}
}
I've seeded the database with a few categories and locations and now I trying to get events saving work. I thought that the $event->eventcat()->associate( $eventcat ) would work but I got a Call to undefined method eventcat() error.
public function postCreateEvent() {
$event = new Event();
$eventcat = Eventcat::find( Input::get('event-create-eventcat[]') );
$location = Location::find( Input::get('event-create-location[]') );
$event->title = Input::get('event-create-title');
$event->description = Input::get('event-create-description');
$event->price = Input::get('event-create-price');
$event->start_date = Input::get('event-create-start_date');
$event->end_date = Input::get('event-create-end_date');
$event->eventcat()->associate( $eventcat );
$event->location()->associate( $location );
$event->save();
}
I've read the documentation, API and a few threads here but I still can't figure out the best way to deal with this.
Thanks for replies!
I would actually bet that you have a conflict in your class name. Laravel contains an Event class and I wonder if that isn't what's being called in your code. As a quick test, you could rename your class FooEvent and see if it works.
The best solution is probably namespacing your model (see http://chrishayes.ca/blog/code/laravel-4-methods-staying-organized for a quick intro) so that your model can still be called Event without conflicting with the builtin class.
I wanted to ask how can I define a multiple layouts for the same controller in Laravel.
The scenario here is like the following:
I have a controller Home and i have two actions in this controller one called steps and the other called login.
I want the both of them load different layout.
The way that I used to make this is as follow:
protected $layout = "layouts.page";
public function index()
{
// Get to the page of the website making steps
$this->layout->content = View::make('steps');
}
Can I define multiple layouts? Maybe passing an array as follow:
protected $layout = array('first' => "layouts.page", 'second' => 'layouts.second');
Best solution is to create a method to generate your view, nesting your multiples layouts :
return View::make('layouts.master', array())
->nest('section_one', YOUR_SECOND_MASTER, array())
->nest...
and stop setting protected $layout with a layout.
I achieve in this way
$this->layout = View::make('layout.master');
$this->layout->content = View::make('step.demo')
Use View Composers or look at the section passing sub-views to views under http://laravel.com/docs/responses#views.
You can also specify multiple sections for the layout that is defined at http://laravel.com/docs/templates#blade-templating
EDIT:
If you want to define a master layout for different views from the same controller, then define the layout on the View it self. Take a look at the section Using A Blade Layout
The #extends is used to define the layout on the view itself.
Hope this helps for what you are looking for.
If you look at the BaseController, which your controller likely extends, you'll see the layout variable is ultimately used simply as th e result of any old View.
In other words, your $layout variable is just a View. You can create any $layout variable in your controller:
<?php
class MyController extends BaseController {
protected $layout;
protected $layout_alt;
// Here we're over-riding setupLayout() from
// the BaseController
protected function setupLayout()
{
if ( ! is_null($this->layout))
{
$this->layout = View::make($this->layout);
}
if ( ! is_null($this->layout_alt))
{
$this->layout_alt = View::make($this->layout_alt);
}
}
}
Then in your view, you can return:
$this->layout_alt->content = View::make('steps');
Of course, the possibilities are endless as Abishek R Srikaanth pointed out. You can do fancy things with Blade as well :D
The way i do this is quite similar to #fideloper's answer.
protected $layout;
private $_layout = null;
public function __construct()
{
}
private function _setupLayout()
{
if ( ! is_null($this->_layout))
{
$this->layout = View::make($this->_layout);
}
}
public function home() {
$this->_layout = 'layouts.1col_public';
$this->_setUpLayout();
$this->layout->content = View::make('static/home');
}
public function about() {
$this->_layout = 'layouts.2col_public';
$this->_setUpLayout();
$this->layout->active_menu = 'about';
$this->layout->content = View::make('static/default');
}
This isn't common practise, and I haven't tested it yet, but it's worth a try.
In your controller's method:
$this->layout = View::make('layouts.master1");