joomla 1.6 component creation error on model - joomla

I am trying to develop a joomla 1.6 component. I am getting the following error
Fatal error: Call to a member function getKeyName() on a non-object in
D:\xampp\htdocs\lab\libraries\joomla\application\component\modeladmin.php
on line 327
my model code is below
<?php
// No direct access to this file
defined('_JEXEC') or die('Restricted access');
// import Joomla modelform library
jimport('joomla.application.component.modeladmin');
/**
* HelloWorld Model
*/
class CrudModelHiWorld extends JModelAdmin
{
/**
* Returns a reference to the a Table object, always creating it.
*
* #param type The table type to instantiate
* #param string A prefix for the table class name. Optional.
* #param array Configuration array for model. Optional.
* #return JTable A database object
* #since 1.6
*/
public function getTable($type = 'Crud', $prefix = 'CrudTable', $config = array())
{
return JTable::getInstance($type, $prefix, $config);
}
/**
* Method to get the record form.
*
* #param array $data Data for the form.
* #param boolean $loadData True if the form is to load its own data (default case), false if not.
* #return mixed A JForm object on success, false on failure
* #since 1.6
*/
public function getForm($data = array(), $loadData = true)
{
// Get the form.
$form = $this->loadForm('com_crud.hiworld', 'hiworlds', array('control' => 'jform', 'load_data' => $loadData));
if (empty($form))
{
return false;
}
return $form;
}
/**
* Method to get the data that should be injected in the form.
*
* #return mixed The data for the form.
* #since 1.6
*/
protected function loadFormData()
{
// Check the session for previously entered form data.
$data = JFactory::getApplication()->getUserState('com_crud.edit.hiworld.data', array());
if (empty($data))
{
$data = $this->getItem();
}
return $data;
}
}
Thanks

Related

Laravel and repository/gateway patterns. Did I lose the fillable property for future helper?

I'm following this answer with his pattern:
How to make a REST API first web application in Laravel
At the end my application works with these methods:
LanController
/**
*
* Store the data in database
*
* #param Request $request
* #return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|void
*/
public function store(Request $request)
{
$status = $this->lan_gateway->create($request->all());
/**
* Status is true if insert in database is OK
* or an array of errors
*/
if ($status===true) {
return redirect(route('lan'))
->with('success',trans('common.operation_completed_successfully'));
// validation ok
} else {
return redirect(route('lan-create'))
->withInput()
->withErrors($status);
// validation fails
}
}
LanGateway
/**
* Validate input and create the record into database
*
* #param array $data the values to insert
* #return array $validator errors on fails
* #return bool $status true on success
*/
public function create(array $data)
{
$validator = Validator::make($data, [
'ip_address' => 'required|string'
]);
if ($validator->fails()) {
return $validator->errors()->all();
} else {
$status = $this->lan_interface->createRecord($data);
return $status;
}
}
And this is the interface implemented by repository create method
<?php
/**
* Repository for LAN object.
* PRG paradigma, instead of "User"-like class Model
*
* #see https://stackoverflow.com/questions/23115291/how-to-make-a-rest-api-first-web-application-in-laravel
*/
namespace App\Repositories;
use App\Interfaces\LanInterface;
use Illuminate\Database\Eloquent\Model;
class LanRepository extends Model implements LanInterface
{
/**
* The name of table on database
* #var string The table name on database
*/
protected $table = "lans";
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = ['ip_address'];
public function getAllRecords()
{
$lan = $this->all();
return $lan;
}
/**
*
* Insert record inside database.
*
* #param array $data
* #return bool true on success, false on failure
*/
public function createRecord(array $data)
{
foreach ($data as $key => $value) {
if (in_array($key,$this->fillable)) {
$this->$key = $value;
}
}
$status = $this->save();
return $status;
}
You can see that I "lost" the fillable helper methods, at the end I use only as "needle/haystack".
Is there another implementation possible for my createRecord method to use, as much as possible, Laravel default methods/helpers or am I in the most right direction?
Thank you very much
As you can see in documentation, $fillable property only applies when you are using mass assignment statements.
Now if if (in_array($key,$this->fillable)) { conditional check is just to check if only some allowed set of columns are saved from API, you can create another property lets say protected $allowedToInsert = ['column1', 'column2],..; and then update the conditional :
public function createRecord(array $data)
{
foreach ($data as $key => $value) {
if (in_array($key,$this->allowedToInsert)) {
$this->$key = $value;
}
}
$status = $this->save();
return $status;
}
This way you can use fillable as it is supposed to be used, The approach you have can be the simplest one but you can improve lit of things. See this for your reference

Laravel Scout and TNTSearch search withTrashed

I've configured Laravel Scout and can use ::search() on my models.
The same models also use SoftDeletes. How can I combine the ::search() with withTrashed()?
The code below does not work.
MyModel::search($request->input('search'))->withTrashed()->paginate(10);
The below does work but does not include the trashed items.
MyModel::search($request->input('search'))->paginate(10);
Update 1
I found in the scout/ModelObserver that deleted items are made unsearchable. Which is a bummer; I wanted my users to be able to search through their trash.
Update 2
I tried using ::withoutSyncingToSearch, as suggested by #camelCase, which I had high hopes for, but this also didn't work.
$model = MyModel::withTrashed()->where('slug', $slug)->firstOrFail();
if ($model->deleted_at) {
$model->forceDelete();
} else {
MyModel::withoutSyncingToSearch(function () use ($model) {
$model->delete();
});
}
This caused an undefined offset when searching for a deleted item. By the way, I'm using the TNTSearch driver for Laravel Scout. I don't know if this is an error with TNTSearch or with Laravel Scout.
I've worked out a solution to your issue. I'll be submitting a pull request for Scout to hopefully get it merged with the official package.
This approach allows you to include soft deleted models in your search:
App\User::search('search query string')->withTrashed()->get();
To only show soft deleted models in your search:
App\User::search('search query string')->onlyTrashed()->get();
You need to modify 3 files:
Builder.php
In laravel\scout\src\Builder.php add the following:
/**
* Whether the search should include soft deleted models.
*
* #var boolean
*/
public $withTrashed = false;
/**
* Whether the search should only include soft deleted models.
*
* #var boolean
*/
public $onlyTrashed = false;
/**
* Specify the search should include soft deletes
*
* #return $this
*/
public function withTrashed()
{
$this->withTrashed = true;
return $this;
}
/**
* Specify the search should only include soft deletes
*
* #return $this
*/
public function onlyTrashed()
{
$this->onlyTrashed = true;
return $this;
}
/**
* Paginate the given query into a simple paginator.
*
* #param int $perPage
* #param string $pageName
* #param int|null $page
* #return \Illuminate\Contracts\Pagination\LengthAwarePaginator
*/
public function paginate($perPage = null, $pageName = 'page', $page = null)
{
$engine = $this->engine();
$page = $page ?: Paginator::resolveCurrentPage($pageName);
$perPage = $perPage ?: $this->model->getPerPage();
$results = Collection::make($engine->map(
$rawResults = $engine->paginate($this, $perPage, $page), $this->model, $this->withTrashed, $this->onlyTrashed
)); // $this->withTrashed, $this->onlyTrashed is new
$paginator = (new LengthAwarePaginator($results, $engine->getTotalCount($rawResults), $perPage, $page, [
'path' => Paginator::resolveCurrentPath(),
'pageName' => $pageName,
]));
return $paginator->appends('query', $this->query);
}
Engine.php
In laravel\scout\src\Engines\Engine.php modify the following:
/**
* Map the given results to instances of the given model.
*
* #param mixed $results
* #param \Illuminate\Database\Eloquent\Model $model
* #param boolean $withTrashed // New
* #return \Illuminate\Database\Eloquent\Collection
*/
abstract public function map($results, $model, $withTrashed, $onlyTrashed); // $withTrashed, $onlyTrashed is new
/**
* Get the results of the given query mapped onto models.
*
* #param \Laravel\Scout\Builder $builder
* #return \Illuminate\Database\Eloquent\Collection
*/
public function get(Builder $builder)
{
return Collection::make($this->map(
$this->search($builder), $builder->model, $builder->withTrashed, $builder->onlyTrashed // $builder->withTrashed, $builder->onlyTrashed is new
));
}
And finally, you just need to modify your relative search engine. I'm using Algolia, but the map method appears to be the same for TNTSearch.
AlgoliaEngine.php
In laravel\scout\src\Engines\AlgoliaEngine.php modify the map method to match the abstract class we modified above:
/**
* Map the given results to instances of the given model.
*
* #param mixed $results
* #param \Illuminate\Database\Eloquent\Model $model
* #param boolean $withTrashed // New
* #return \Illuminate\Database\Eloquent\Collection
*/
public function map($results, $model, $withTrashed, $onlyTrashed) // $withTrashed, $onlyTrashed is new
{
if (count($results['hits']) === 0) {
return Collection::make();
}
$keys = collect($results['hits'])
->pluck('objectID')->values()->all();
$modelQuery = $model->whereIn(
$model->getQualifiedKeyName(), $keys
);
if ($withTrashed) $modelQuery->withTrashed(); // This is where the query will include deleted items, if specified
if ($onlyTrashed) $modelQuery->onlyTrashed(); // This is where the query will only include deleted items, if specified
$models = $modelQuery->get()->keyBy($model->getKeyName());
return Collection::make($results['hits'])->map(function ($hit) use ($model, $models) {
$key = $hit['objectID'];
if (isset($models[$key])) {
return $models[$key];
}
})->filter();
}
TNTSearchEngine.php
/**
* Map the given results to instances of the given model.
*
* #param mixed $results
* #param \Illuminate\Database\Eloquent\Model $model
*
* #return Collection
*/
public function map($results, $model, $withTrashed, $onlyTrashed)
{
if (count($results['ids']) === 0) {
return Collection::make();
}
$keys = collect($results['ids'])->values()->all();
$model_query = $model->whereIn(
$model->getQualifiedKeyName(), $keys
);
if ($withTrashed) $model_query->withTrashed();
if ($onlyTrashed) $model_query->onlyTrashed();
$models = $model_query->get()->keyBy($model->getKeyName());
return collect($results['ids'])->map(function ($hit) use ($models) {
if (isset($models[$hit])) {
return $models[$hit];
}
})->filter();
}
Let me know how it works.
NOTE: This approach still requires you to manually pause syncing using the withoutSyncingToSearch method while deleting a model; otherwise the search criteria will be updated with unsearchable().
this is my solution.
// will return matched ids of my model instance
$searchResultIds = MyModel::search($request->input('search'))->raw()['ids'];
MyModel::whereId('id', $searchResultIds)->onlyTrashed()->get();

Magento 2 - Set collection limit in a Model

I created a model file which I would like a method inside me to return products with a limit.
Below my model:
<?php
namespace Test\Ice\Model;
class Data extends \Magento\Framework\App\Helper\AbstractHelper {
/**
* System configuration values
*
* #var array
*/
protected $_config;
/**
* Store manager interface
*
*/
protected $_storeManager;
/**
* Product interface
*
*/
protected $_product;
/**
* Initialize
*
* #param Magento\Framework\App\Helper\Context $context
* #param Magento\Catalog\Model\ProductFactory $productFactory
* #param Magento\Store\Model\StoreManagerInterface $storeManager
* #param Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
* #param array $data
*/
public function __construct(
\Magento\Framework\App\Helper\Context $context,
\Magento\Catalog\Model\ResourceModel\Product\Collection $collection,
\Magento\Store\Model\StoreManagerInterface $storeManager,
\Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
array $data = []
) {
$this->_product = $collection;
$this->_storeManager = $storeManager;
parent::__construct($context, $data);
}
public function getProducts() {
$limit = 10;
return $this->_product->getSelect()->limit($limit);
}
}
The problem is that it does not make the limit, but always returns all products in the collection.
Where am I wrong?
Thank you
Use
$this->_product->getCollection()->setPageSize(10)->setCurPag‌​e(1);

Laravel 5.0 | Changing default actions' names is not working for a resource controller

I have created a productController resource in the route.php file like this:-
Route::resource('products','ProductController',['names' => ['create' => 'products.add']]);
Here is how my productController.php file looks like:-
<?php namespace lvtest\Http\Controllers;
use lvtest\Http\Requests;
use lvtest\Product;
use lvtest\Http\Controllers\Controller;
use Illuminate\Http\Request;
class ProductController extends Controller {
/**
* Class constructor .. requires authentication
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Display a listing of the resource.
*
* #return Response
*/
public function index()
{
$products = Product::all();
return view('products.productsList', ['products' => $products]);
}
/**
* Show the form for creating a new resource.
*
* #return Response
*/
public function add()
{
return 'Add a product';
}
/**
* Store a newly created resource in storage.
*
* #return Response
*/
public function store()
{
return 'store new product?';
}
/**
* Display the specified resource.
*
* #param int $id
* #return Response
*/
public function show($id = null)
{
// $products = Product::all();
// print_r($products);
}
/**
* Show the form for editing the specified resource.
*
* #param int $id
* #return Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* #param int $id
* #return Response
*/
public function update($id)
{
return 'store new product?';
}
/**
* Remove the specified resource from storage.
*
* #param int $id
* #return Response
*/
public function destroy($id)
{
//
}
}
and passed the 'names' array to change the default name of the create method to add.
When I go to localhost:8000/products/add I get a blank page.
How do I fix this
Adding the ['names' => ['create' => 'products.add'] to your resource route will only change the Route Name, and not the Route Method. This means that you can refer to your route as route('products.add') and it will point to the create() method on your controller.
When you use Route::resource Laravel will expect that you have a create() method on your controller. To be able to do what you suggest, you might need to add the method to your controller, and then add a separate route:
Route::resource('products','ProductController');
Route::get('products/add', ['as' => 'products.add', 'uses' => 'ProductController#add']);

Typo3 Extbase Set and Get values from Session

I am writing an extbase extension on typo3 v6.1
That extension suppose to do a bus ticket booking.
Here what my plan is, user will select date and number of seats and submit the form.
Here my plan to push the date and rate of the selected seat to session (Basket).
And while making payment, I wanted to get that values from session and after payment I need to clear that particular session.
So In short, How to Push and retrieve the values to and from the session in extbase.
Any suggestions ?
Thank you.
There are different ways. The simplest would be for writing in the session
$GLOBALS['TSFE']->fe_user->setKey("ses","key",$value)
and for reading values from the session
$GLOBALS["TSFE"]->fe_user->getKey("ses","key")
I'm using for this a service class.
<?php
class Tx_EXTNAME_Service_SessionHandler implements t3lib_Singleton {
private $prefixKey = 'tx_extname_';
/**
* Returns the object stored in the user´s PHP session
* #return Object the stored object
*/
public function restoreFromSession($key) {
$sessionData = $GLOBALS['TSFE']->fe_user->getKey('ses', $this->prefixKey . $key);
return unserialize($sessionData);
}
/**
* Writes an object into the PHP session
* #param $object any serializable object to store into the session
* #return Tx_EXTNAME_Service_SessionHandler this
*/
public function writeToSession($object, $key) {
$sessionData = serialize($object);
$GLOBALS['TSFE']->fe_user->setKey('ses', $this->prefixKey . $key, $sessionData);
$GLOBALS['TSFE']->fe_user->storeSessionData();
return $this;
}
/**
* Cleans up the session: removes the stored object from the PHP session
* #return Tx_EXTNAME_Service_SessionHandler this
*/
public function cleanUpSession($key) {
$GLOBALS['TSFE']->fe_user->setKey('ses', $this->prefixKey . $key, NULL);
$GLOBALS['TSFE']->fe_user->storeSessionData();
return $this;
}
public function setPrefixKey($prefixKey) {
$this->prefixKey = $prefixKey;
}
}
?>
Inject this class into your controller
/**
*
* #var Tx_EXTNAME_Service_SessionHandler
*/
protected $sessionHandler;
/**
*
* #param Tx_EXTNAME_Service_SessionHandler $sessionHandler
*/
public function injectSessionHandler(Tx_EXTNAME_Service_SessionHandler $sessionHandler) {
$this->sessionHandler = $sessionHandler;
}
Now you can use this session handler like this.
// Write your object into session
$this->sessionHandler->writeToSession('KEY_FOR_THIS_PROCESS');
// Get your object from session
$this->sessionHandler->restoreFromSession('KEY_FOR_THIS_PROCESS');
// And after all maybe you will clean the session (delete)
$this->sessionHandler->cleanUpSession('KEY_FOR_THIS_PROCESS');
Rename Tx_EXTNAME and tx_extname with your extension name and pay attention to put the session handler class into the right directory (Classes -> Service -> SessionHandler.php).
You can store any data, not only objects.
HTH
From Typo3 v7 you can also copy the native session handler (\TYPO3\CMS\Form\Utility\SessionUtility) for forms and change it to your needs. The Class makes a different between normal and logged in users and it support multiple session data seperated by the sessionPrefix.
I did the same and generalized the class for a more common purpose. I only removed one method, change the variables name and added the method hasSessionKey(). Here is my complete example:
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
/**
* Class SessionUtility
*
* this is just a adapted version from \TYPO3\CMS\Form\Utility\SessionUtility,
* but more generalized without special behavior for form
*
*
*/
class SessionUtility {
/**
* Session data
*
* #var array
*/
protected $sessionData = array();
/**
* Prefix for the session
*
* #var string
*/
protected $sessionPrefix = '';
/**
* #var TypoScriptFrontendController
*/
protected $frontendController;
/**
* Constructor
*/
public function __construct()
{
$this->frontendController = $GLOBALS['TSFE'];
}
/**
* Init Session
*
* #param string $sessionPrefix
* #return void
*/
public function initSession($sessionPrefix = '')
{
$this->setSessionPrefix($sessionPrefix);
if ($this->frontendController->loginUser) {
$this->sessionData = $this->frontendController->fe_user->getKey('user', $this->sessionPrefix);
} else {
$this->sessionData = $this->frontendController->fe_user->getKey('ses', $this->sessionPrefix);
}
}
/**
* Stores current session
*
* #return void
*/
public function storeSession()
{
if ($this->frontendController->loginUser) {
$this->frontendController->fe_user->setKey('user', $this->sessionPrefix, $this->getSessionData());
} else {
$this->frontendController->fe_user->setKey('ses', $this->sessionPrefix, $this->getSessionData());
}
$this->frontendController->storeSessionData();
}
/**
* Destroy the session data for the form
*
* #return void
*/
public function destroySession()
{
if ($this->frontendController->loginUser) {
$this->frontendController->fe_user->setKey('user', $this->sessionPrefix, null);
} else {
$this->frontendController->fe_user->setKey('ses', $this->sessionPrefix, null);
}
$this->frontendController->storeSessionData();
}
/**
* Set the session Data by $key
*
* #param string $key
* #param string $value
* #return void
*/
public function setSessionData($key, $value)
{
$this->sessionData[$key] = $value;
$this->storeSession();
}
/**
* Retrieve a member of the $sessionData variable
*
* If no $key is passed, returns the entire $sessionData array
*
* #param string $key Parameter to search for
* #param mixed $default Default value to use if key not found
* #return mixed Returns NULL if key does not exist
*/
public function getSessionData($key = null, $default = null)
{
if ($key === null) {
return $this->sessionData;
}
return isset($this->sessionData[$key]) ? $this->sessionData[$key] : $default;
}
/**
* Set the s prefix
*
* #param string $sessionPrefix
*
*/
public function setSessionPrefix($sessionPrefix)
{
$this->sessionPrefix = $sessionPrefix;
}
/**
* #param string $key
*
* #return bool
*/
public function hasSessionKey($key) {
return isset($this->sessionData[$key]);
}
}
Don't forget to call the initSession first, every time you want use any method of this class

Resources