Arrays to database - php

I have a php file(users.php) which I save the user info. Every time I update or add employee I need to open the file in text editor and make some changes. This is the sample lists of employees in $users array.
$users = array(
'001' => array('id'=>'001', 'name'=>'first lastname', 'dept'=>'Sales', 'position'=>'Lead Team', 'rate'=>'800', 'dayoff'=>'SUN'),
'002' => array('id'=>'002', 'name'=>'sec lastname', 'dept'=>'Sales', 'position'=>'Designer', 'rate'=>'800', 'dayoff'=>'SUN'),
'003' => array('id'=>'003', 'name'=>'david, sample', 'dept'=>'IT', 'position'=>'', 'rate'=>'220.83', 'dayoff'=>'SUN'),
'004' => array('id'=>'004', 'name'=>'Test, Johny', 'dept'=>'', 'position'=>'', 'rate'=>'600', 'dayoff'=>''),
'005' => array('id'=>'005', 'name'=>'Name, Last', 'dept'=>'IT', 'position'=>'Programmer', 'rate'=>'500', 'dayoff'=>'SUN')
);
When I compute their salary I grab all the details of employee($users array) from that file. This is my sample function.
function compute(){
global $users;
include('users.php');
//import list of users;
foreach($the_log as $k=>$v){
if($users[$k]){
//codes here
//show user data with computed salary
}
}
}
How can I make a simple database(like csv file or text file) not MySql or any open source database, so that I can add, edit and delete a user(with just a click) easily whenever I want. What I want to achieve here is to be able to make $users array editable. Is it possible?
Edit: When I use or save data in .csv file, How can I edit or delete a specific user/row?

Just because it's fun, I created an example of how you could do it.
Bare in mind, it's not tested so it might have some bugs but it shows how you could do it.
Since you got so much finished code, I'll leave that up to you to find the bugs. ;-) (However, if you find bugs, leave them as a comment and I'll update the answer).
Important note: Just like #deceze mentioned in his comment, this works well if you know that there won't be any simultaneous "connections" (several people working with the files at the same time) and that you always "open, do stuff, save" and not "open, do stuff, open in a new browser tab, do stuff, save in first tab, save in second tab". Otherwise, your first changes will be overwritten with your second changes and so on...
Class to manage users:
class Users
{
/**
* #var string
*/
protected $path;
/**
* #var array
*/
protected $users = [];
/**
* #param string $path Path to the user file (must be writeable)
*/
public function __construct($path)
{
$this->path = $path;
if (!is_file($this->path)) {
// The file doesn't exist yet, let's create it
file_put_contents($this->path, json_encode([]));
} else {
// It does exist. Load it.
$this->users = json_decode(file_get_contents($this->path), true);
}
}
/**
* Get all users
*
* #return array
*/
public function all()
{
return $this->users;
}
/**
* Get a specific user
*
* #param string|integer $userId The array index for that user
* #return array|null Returns null if user doesn't exist
*/
public function get($userId)
{
if (!array_key_exists($userId, $this->users)) {
// The key doesn't exist, return null
return null;
}
return $this->users[$userId];
}
/**
* Update or add a user
*
* #param string|integer $userId The array index for that user
* #param array $data The user info
* #return boolean
*/
public function save($userId, array $data)
{
$this->users[$userId] = $data;
$written = file_put_contents($this->path, json_encode($this->users));
return $written !== false;
}
}
How you would use it:
// When you have created the instance, use the same instance
// through out your whole application (only do: new Users() once).
// You could do this with some factory class.
$users = new Users('/path/to/users.json');
// List all users
foreach($users->all() as $userId => $row) {
echo $row['first_name'];
// ...
}
// Get user
$user = $users->get('001');
// Change user
$user['first_name'] = "Magnus";
// Save user (this is both update and add)
$users->save('001', $user);

Related

Is it possible to change constants via Controller/Repository in TYPO3?

I want to change a constant in my Extension in the Controller via initializeAction.
It works the half way. Let me explain this:
TYPO3 Version 8.7.7 Extension build with Extension Builder.
If i use the following code in my UserController.php
/**
* initialize the controller
*
* #return void
*/
protected function initializeAction()
{
...
$this->settings['groupDefaultId'] = (string)$newUserGroup[$key]->getUid();
...
}
and i'll debug it after that in php i got the following Debuginformation:
settings
array(12 items)
groupDefaultId => '53' (2 chars)
This is the correct value in PHP for now. But if i check that value in the Backend under Template > Constant Editor the value isn't stored any more.
I tried the code above and the setConfiguration API function.
When i got the new ID, which one i want to set in constants i start the function with the following command:
File: BaseController.php
(my UserController extends BaseController, for splitting CRUD-function from Other-functions).
I give a string to it, because at the end of this "way" all Settings are stored as string in $this->settings.
// Set current Group Uid as defaultGroupId in Constants
$currentGroupIdHasSetInConstants = $this->setNewGroupIdInConstants((string)$newUserGroup[$key]->getUid());
We jumpt to the setNewGroupIdInConstants function:
File: BaseController.php
/**
* Sets the Constant 'defaultGroupId' with new Value
*
* Incoming Requirement for this function: defaultGroupId = 0 this means
* defaultGroupId is not set in Constants
*
* #param string $newdefaultGroupId New Default Group ID for New Users
* #return bool TRUE defaultGroupId has changed | FALSE no changes done
*/
public function setNewGroupIdInConstants(string $newdefaultGroupId)
{
// Rebuild constants with new property and value
$newConstantsValue = $this->addConstantsConfigurationForDefaultGroupId($newdefaultGroupId);
// Add the new property with value to constants
return $this->userRepository->updateConstants($newConstantsValue);
}
First this function jumps to addConstantsConfigurationForDefaultGroupId function:
In File: BaseController.php
/**
* Build new constants value for defaultGroupId
*
* #param string $value The new value for defaultGroupId
* #return string The complete Constants value
* including the defaultGroupId Configuration
*/
public function addConstantsConfigurationForDefaultGroupId($value)
{
$getConstants = $this->userRepository->fetchConstants()['constants'];
// This Value has to look like this with the new line (for getting original code incl. \n for constants)
$buildAdditionalConstant = '
plugin.tx_rmregistration.settings.defaultGroupId = '.$value;
return $getConstants.$buildAdditionalConstant;
}
fetchConstants function:
In File: UserRepository.php
(Usually it belongs to a SysTemplatesRepository.php, but those one doesn't exist. "Hello Core Team, we need a SysTemplatesRepository ;)".
/**
* Find Constants via sys_template Database Table
*
* #return array|NULL Result is array('constants' => queryResult) or NULL
*/
public function fetchConstants()
{ //
// Query Builder for Table: sys_template
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_template');
// Get Constants of Row, where RM Registration is included
$query = $queryBuilder
->select('constants')
->from('sys_template')
->where(
$queryBuilder->expr()->like(
'include_static_file',
$queryBuilder->createNamedParameter('%' . $queryBuilder->escapeLikeWildcards('EXT:rmregistration/Configuration/TypoScript') . '%')
)
);
// Execute Query and Return the Query-Fetch
$query = $queryBuilder->execute();
return $query->fetch();
}
Here is my code of the updateConstants function
In File: UserRepository.php
/**
* Update Constants via sys_template Database Table ( Updates $this->settings )
*
* #param string $constants The new settings, that has to be stored in $this->settings
*/
public function updateConstants(string $constants)
{
// Query Builder for Table: sys_template
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_template');
$query = $queryBuilder
->update('sys_template')
->where(
$queryBuilder->expr()->like(
'include_static_file',
$queryBuilder->createNamedParameter('%' . $queryBuilder->escapeLikeWildcards('EXT:rmregistration/Configuration/TypoScript') . '%')
)
)
->set('constants', $constants);
$query = $queryBuilder->execute();
return ($query > 0) ? TRUE : FALSE;
}

How to dynamically change a Model attribute in a controller?

I have two tables users and users_metadata, where a single user hasMany metadata.
When I'm fetching all of the users, I want to be able to select certain fields, some of which exist in the metadata table.
users - id:1
users_metadata - user_id:1, key:username, value: MyUsername
users_metadata - user_id:1, key:birthday, value: 2017-11-16
Through the url, I can add on a fields attribute which lists what fields I want to select rather than all of them.
/api/v1/users?fields=username
What I'd like to be able to do is, instead of fetching all the metadata is to just fetch the metadata which is listed in the fields.
// Are we selecting all the fields?
if(!is_array($fields))
{
// We are not, so lets build an array
$fields = explode(',', $fields);
// Loop through the users
foreach($users as $user)
{
// Loop through the fields
foreach($fields as $field)
{
// Try to fetch it as metadata
if(array_key_exists($field, $user->metadata->toArray()))
{
$metadata[] = $field;
}
}
// Adjust the user metadata
$user->metadata = $user->metadata->filter(function($value, $key) use($metadata)
{
return in_array($key, $metadata);
});
}
}
However this isn't updating my data with the new metadata, and when I dump the user data I'm still getting all my original metadata rather than just the username.
/**
* Fetch all the metadata for a user.
*
* #return objects
*/
public function metadata()
{
return $this->hasMany(UserMetadata::class);
}
/**
* Fetch the metadata as an attribute.
*
* #return array
*/
public function getMetadataAttribute()
{
return $this->metadata()->get()->flatMap(function($values)
{
return [$values['key'] => $values['value']];
});
}
/**
* Update the metadata attribute.
*
* #param varied $value The new metadata attribute.
* #return void
*/
public function setMetadataAttribute($value)
{
$this->attributes['metadata'] = $value;
}
Could you use the only() method at the collection level?
For example, you have your fields array from the URL. In this case it is only the one metadata field.
$fields = ['username'];
Then get all the users:
$users_all = User::all(); or however you wish to get the collection of users.
Then use the only() method to filter the results to just the fields you need:
$filtered = $users_all->only($fields);
Then return the filtered collection:
$filtered->all();
From: https://laravel.com/docs/5.5/collections#method-only

Magento2 addFieldToFilter call works with hardcoded value but not variable with same value

I'm building the admin for a Magento2 store (currently on 2.1.7, they want to use the newest version until we go live and then want to stabilize a particular version). The module in question is supposed to display all existing orders, with an actionsColumn that contains links to cancel, edit, and open a detailed overview of the purchased items associated with that order. The order detail page contains a grid view that should display all order items associated with an order number passed in the URL.
In order to filter out Order Items that don't relate to the specific Order Number, I've extended the \Magento\Framework\View\Element\UiComponent\DataProvider\SearchResult class. This works except for one weird caveat. If, in the addFieldToFilter call, I replace $ordNum with, say, '10000', it grabs the correct data. When using $ordNum to call this dynamically, however, it returns no rows at all. This despite trying all sorts of casting and === checks to ensure that there's no difference between the hardcoded and dynamic values. Is this a Magento bug? I can't at all figure out why this would be the case.
<?php
class OrderItems extends \Magento\Framework\View\Element\UiComponent\DataProvider\SearchResult
{
protected function _initSelect()
{
$this->filterByOrderNum();
parent::_initSelect();
return $this;
}
private function filterByOrderNum()
{
$request = \Magento\Framework\App\ObjectManager::getInstance()
->get('Magento\Framework\App\Request\Http');
$ordNum = $request->getParam('order_num');
$this->addFieldToFilter('order_num', ['eq' => $ordNum]); //if I switch this to hardcoded 10000, this works. With the variable, no dice.
return $this;
}
}
I just fixed it by using mentioned below steps
Store param value in session in controller
public function execute() {
$this->_catalogSession->setTokenId($this->request->getParam('entity_id'));
$this->_view->loadLayout();
$this->_view->loadLayoutUpdates();
$this->_view->getPage()->getConfig()->getTitle()->set(__('Redeem Token History'));
$this->_view->renderLayout();
}
Use session value in dataprovider
$tokensCollection->addFieldToFilter('token_id', ['eq' => $this->_catalogSession->getTokenId()]);
Enjoy :)
Try this in place of the getParam statement:
$url = parse_url($request);
$path = explode('/',$url['path']);
$ordNum = $path[3];
Just to make sure we are on the same page, this is the full code:
<?php
class OrderItems extends \Magento\Framework\View\Element\UiComponent\DataProvider\SearchResult
{
protected function _initSelect()
{
$this->filterByOrderNum();
parent::_initSelect();
return $this;
}
private function filterByOrderNum()
{
$request = \Magento\Framework\App\ObjectManager::getInstance()
->get('Magento\Framework\App\Request\Http');
$url = parse_url($request);
$path = explode('/',$url['path']);
$ordNum = $path[3];
$this->addFieldToFilter('order_num', $ordNum); //if I switch this to hardcoded 10000, this works. With the variable, no dice.
return $this;
}
}
We have solved this issue by doing the following :
/**
* CcCustompriceProductListingDataProvider constructor.
* #param string $name
* #param string $primaryFieldName
* #param string $requestFieldName
* #param \Magento\Framework\Api\Search\ReportingInterface $reporting
* #param \Magento\Framework\Api\Search\SearchCriteriaBuilder $searchCriteriaBuilder
* #param \Magento\Framework\App\RequestInterface $request
* #param \Magento\Framework\Api\FilterBuilder $filterBuilder
* #param array $meta
* #param array $data
* #throws \Exception
*/
public function __construct(
$name,
$primaryFieldName,
$requestFieldName,
ReportingInterface $reporting,
SearchCriteriaBuilder $searchCriteriaBuilder,
RequestInterface $request,
FilterBuilder $filterBuilder,
array $meta = [],
array $data = []
) {
$data['config']['filter_url_params']['product_id'] = $request->getParam('cppc_product_id', 0);
parent::__construct($name, $primaryFieldName, $requestFieldName, $reporting, $searchCriteriaBuilder, $request, $filterBuilder, $meta, $data);
}
You do not need to use any other function. The reason why this is is because it is also updated with an update URL and that does not have that parameter. By using adding that to the data it also parses that into the update url.
You can see that here (Parent function)
/**
* #return void
*/
protected function prepareUpdateUrl()
{
if (!isset($this->data['config']['filter_url_params'])) {
return;
}
foreach ($this->data['config']['filter_url_params'] as $paramName => $paramValue) {
if ('*' == $paramValue) {
$paramValue = $this->request->getParam($paramName);
}
if ($paramValue) {
$this->data['config']['update_url'] = sprintf(
'%s%s/%s/',
$this->data['config']['update_url'],
$paramName,
$paramValue
);
$this->addFilter(
$this->filterBuilder->setField($paramName)->setValue($paramValue)->setConditionType('eq')->create()
);
}
}
}

Extbase: Modified object does not saved in the repository correctly

I am using TYPO3 7.6.10 and I build my first extension.
I want to add a property to my object in the createAction function of my controller.
But the modifications are nt saved.
Here is my code:
/**
* action create
*
* #param \Typo3\LpSurvey\Domain\Model\Sigil $newSigil
* #param array $answers
* #internal param Survey $newSurvey
*/
public function createAction(Sigil $newSigil, Array $answers)
{
$newSurvey = $this->objectManager->get('Typo3\LpSurvey\Domain\Model\Survey');
$this->userID = $GLOBALS['TSFE']->fe_user->user['uid'];
//this modifications are saved
foreach ($answers as $key => $answer) {
$newSurveyItem = $this->objectManager->get('Typo3\LpSurvey\Domain\Model\SurveyItem');
$newSurveyItem->setQuestionId($key);
$newSurveyItem->setValue($answer);
$newSurvey->addAnswer($newSurveyItem);
}
//BUT this modification is not saved
$newSigil->setUserID($this->userID);
$newSigil->setSurvey($newSurvey);
$this->sigilRepository->add($newSigil);
$this->redirect('list');
}
If I debug my object $newSigil the userID is set, but after adding to the repository the default value will be saved.
I dont understand why.
I also try to persist manually with following code, but no solution:
/**
* #var \typo3\CMS\Extbase\Persistence\Generic\PersistenceManager
* #inject
*/
protected $persistenceManager;
public function createAction(Sigil $newSigil, Array $answers)
{
$newSurvey = $this->objectManager->get('Typo3\LpSurvey\Domain\Model\Survey');
$this->userID = $GLOBALS['TSFE']->fe_user->user['uid'];
foreach ($answers as $key => $answer) {
$newSurveyItem = $this->objectManager->get('Typo3\LpSurvey\Domain\Model\SurveyItem');
$newSurveyItem->setQuestionId($key);
$newSurveyItem->setValue($answer);
$newSurvey->addAnswer($newSurveyItem);
}
$newSigil->setUserID($this->userID);
$newSigil->setSurvey($newSurvey);
$this->persistenceManager->persistAll();
$this->sigilRepository->add($newSigil);
$this->redirect('list');
}
I hope the question is understandable
Best regards Felix
Maybe UserID is not correct named? If your database field is called user_id your property for the domain should userId. Only if your database field is called user_i_d it should userID.

Redirection in multistep form CakePHP

I am creating a multistep form in CakePHP using http://bakery.cakephp.org/2012/09/09/Multistep-forms.html?
But it's not redirecting well. As I click next in step 1, it redirects me to msf_index.
Probably I'm not proceeding the right step count in the msf_setup method.
Why is this happening ?
Here is the Controller Code that I have just copy-pasted.
class UsersController extends AppController {
/**
* use beforeRender to send session parameters to the layout view
*/
public function beforeRender() {
parent::beforeRender();
$params = $this->Session->read('form.params');
$this->set('params', $params);
}
/**
* delete session values when going back to index
* you may want to keep the session alive instead
*/
public function msf_index() {
$this->Session->delete('form');
}
/**
* this method is executed before starting the form and retrieves one important parameter:
* the form steps number
* you can hardcode it, but in this example we are getting it by counting the number of files that start with msf_step_
*/
public function msf_setup() {
App::uses('Folder', 'Utility');
$usersViewFolder = new Folder(APP.'View'.DS.'Users');
$steps = count($usersViewFolder->find('msf_step_.*\.ctp'));
$this->Session->write('form.params.steps', $steps);
$this->Session->write('form.params.maxProgress', 0);
$this->redirect(array('action' => 'msf_step', 1));
}
/**
* this is the core step handling method
* it gets passed the desired step number, performs some checks to prevent smart users skipping steps
* checks fields validation, and when succeding, it saves the array in a session, merging with previous results
* if we are at last step, data is saved
* when no form data is submitted (not a POST request) it sets this->request->data to the values stored in session
*/
public function msf_step($stepNumber) {
/**
* check if a view file for this step exists, otherwise redirect to index
*/
if (!file_exists(APP.'View'.DS.'Users'.DS.'msf_step_'.$stepNumber.'.ctp')) {
$this->redirect('/users/msf_index');
}
/**
* determines the max allowed step (the last completed + 1)
* if choosen step is not allowed (URL manually changed) the user gets redirected
* otherwise we store the current step value in the session
*/
$maxAllowed = $this->Session->read('form.params.maxProgress') + 1;
if ($stepNumber > $maxAllowed) {
$this->redirect('/users/msf_step/'.$maxAllowed);
} else {
$this->Session->write('form.params.currentStep', $stepNumber);
}
/**
* check if some data has been submitted via POST
* if not, sets the current data to the session data, to automatically populate previously saved fields
*/
if ($this->request->is('post')) {
/**
* set passed data to the model, so we can validate against it without saving
*/
$this->User->set($this->request->data);
/**
* if data validates we merge previous session data with submitted data, using CakePHP powerful Hash class (previously called Set)
*/
if ($this->User->validates()) {
$prevSessionData = $this->Session->read('form.data');
$currentSessionData = Hash::merge( (array) $prevSessionData, $this->request->data);
/**
* if this is not the last step we replace session data with the new merged array
* update the max progress value and redirect to the next step
*/
if ($stepNumber < $this->Session->read('form.params.steps')) {
$this->Session->write('form.data', $currentSessionData);
$this->Session->write('form.params.maxProgress', $stepNumber);
$this->redirect(array('action' => 'msf_step', $stepNumber+1));
} else {
/**
* otherwise, this is the final step, so we have to save the data to the database
*/
$this->User->save($currentSessionData);
$this->Session->setFlash('Account created!');
$this->redirect('/users/msf_index');
}
}
} else {
$this->request->data = $this->Session->read('form.data');
}
/**
* here we load the proper view file, depending on the stepNumber variable passed via GET
*/
$this->render('msf_step_'.$stepNumber);
}
}
The problem might be here:
public function msf_setup() {
App::uses('Folder', 'Utility');
$usersViewFolder = new Folder(APP.'View'.DS.'Users');
$steps = count($usersViewFolder->find('msf_step_.*\.ctp'));
$this->Session->write('form.params.steps', $steps);
$this->Session->write('form.params.maxProgress', 0);
$this->redirect(array('action' => 'msf_step', 1));
}
Also, I have added four msf_setp files in view/Users like
msf_step_1, msf_step_2, msf_setp_3, msf_step_4.
Please help. I'm Stuck. Thankx in advance.

Categories